/rust/registry/src/index.crates.io-1949cf8c6b5b557f/r-efi-3.2.0/src/base.rs
Line | Count | Source |
1 | | //! UEFI Base Environment |
2 | | //! |
3 | | //! This module defines the base environment for UEFI development. It provides types and macros as |
4 | | //! declared in the UEFI specification, as well as de-facto standard additions provided by the |
5 | | //! reference implementation by Intel. |
6 | | //! |
7 | | //! # Target Configuration |
8 | | //! |
9 | | //! Wherever possible, native rust types are used to represent their UEFI counter-parts. However, |
10 | | //! this means the ABI depends on the implementation of said rust types. Hence, native rust types |
11 | | //! are only used where rust supports a stable ABI of said types, and their ABI matches the ABI |
12 | | //! defined by the UEFI specification. |
13 | | //! |
14 | | //! Nevertheless, even if the ABI of a specific type is marked stable, this does not imply that it |
15 | | //! is the same across architectures. For instance, rust's `u64` type has the same binary |
16 | | //! representation as the `UINT64` type in UEFI. But this does not imply that it has the same |
17 | | //! binary representation on `x86_64` and on `ppc64be`. As a result of this, the compilation of |
18 | | //! this module is tied to the target-configuration you passed to the rust compiler. Wherever |
19 | | //! possible and reasonable, any architecture differences are abstracted, though. This means that |
20 | | //! in most cases you can use this module even though your target-configuration might not match |
21 | | //! the native UEFI target-configuration. |
22 | | //! |
23 | | //! The recommend way to compile your code, is to use the native target-configuration for UEFI. |
24 | | //! These configurations are not necessarily included in the upstream rust compiler. Hence, you |
25 | | //! might have to craft one yourself. For all systems that we can test on, we make sure to push |
26 | | //! the target configuration into upstream rust-lang. |
27 | | //! |
28 | | //! However, there are situations where you want to access UEFI data from a non-native host. For |
29 | | //! instance, a UEFI boot loader might store data in boot variables, formatted according to types |
30 | | //! declared in the UEFI specification. An OS booted thereafter might want to access these |
31 | | //! variables, but it might be compiled with a different target-configuration than the UEFI |
32 | | //! environment that it was booted from. A similar situation occurs when you call UEFI runtime |
33 | | //! functions from your OS. In all those cases, you should very likely be able to use this module |
34 | | //! to interact with UEFI as well. This is, because most bits of the target-configuration of UEFI |
35 | | //! and your OS very likely match. In fact, to figure out whether this is safe, you need to make |
36 | | //! sure that the rust ABI would match in both target-configurations. If it is, all other details |
37 | | //! are handled within this module just fine. |
38 | | //! |
39 | | //! In case of doubt, contact us! |
40 | | //! |
41 | | //! # Core Primitives |
42 | | //! |
43 | | //! Several of the UEFI primitives are represented by native Rust. These have no type aliases or |
44 | | //! other definitions here, but you are recommended to use native rust directly. These include: |
45 | | //! |
46 | | //! * `NULL`, `void *`: Void pointers have a native rust implementation in |
47 | | //! [`c_void`](core::ffi::c_void). `NULL` is represented through |
48 | | //! [`null`](core::ptr::null) and [`is_null()`](core::ptr) for |
49 | | //! all pointer types. |
50 | | //! * `uint8_t`..`uint64_t`, |
51 | | //! `int8_t`..`int64_t`: Fixed-size integers are represented by their native rust equivalents |
52 | | //! (`u8`..`u64`, `i8`..`i64`). |
53 | | //! |
54 | | //! * `UINTN`, `INTN`: Native-sized (or instruction-width sized) integers are represented by |
55 | | //! their native rust equivalents (`usize`, `isize`). |
56 | | //! |
57 | | //! # UEFI Details |
58 | | //! |
59 | | //! The UEFI Specification describes its target environments in detail. Each supported |
60 | | //! architecture has a separate section with details on calling conventions, CPU setup, and more. |
61 | | //! You are highly recommended to conduct the UEFI Specification for details on the programming |
62 | | //! environment. Following a summary of key parts relevant to rust developers: |
63 | | //! |
64 | | //! * Similar to rust, integers are either fixed-size, or native size. This maps nicely to the |
65 | | //! native rust types. The common `long`, `int`, `short` types known from ISO-C are not used. |
66 | | //! Whenever you refer to memory (either pointing to it, or remember the size of a memory |
67 | | //! block), the native size integers should be your tool of choice. |
68 | | //! |
69 | | //! * Even though the CPU might run in any endianness, all stored data is little-endian. That |
70 | | //! means, if you encounter integers split into byte-arrays (e.g., |
71 | | //! `CEfiDevicePathProtocol.length`), you must assume it is little-endian encoded. But if you |
72 | | //! encounter native integers, you must assume they are encoded in native endianness. |
73 | | //! For now the UEFI specification only defines little-endian architectures, hence this did not |
74 | | //! pop up as actual issue. Future extensions might change this, though. |
75 | | //! |
76 | | //! * The Microsoft calling-convention is used. That is, all external calls to UEFI functions |
77 | | //! follow a calling convention that is very similar to that used on Microsoft Windows. All |
78 | | //! such ABI functions must be marked with the right calling-convention. The UEFI Specification |
79 | | //! defines some additional common rules for all its APIs, though. You will most likely not see |
80 | | //! any of these mentioned in the individual API documentions. So here is a short reminder: |
81 | | //! |
82 | | //! * Pointers must reference physical-memory locations (no I/O mappings, no |
83 | | //! virtual addresses, etc.). Once ExitBootServices() was called, and the |
84 | | //! virtual address mapping was set, you must provide virtual-memory |
85 | | //! locations instead. |
86 | | //! * Pointers must be correctly aligned. |
87 | | //! * NULL is disallowed, unless explicitly mentioned otherwise. |
88 | | //! * Data referenced by pointers is undefined on error-return from a |
89 | | //! function. |
90 | | //! * You must not pass data larger than native-size (sizeof(CEfiUSize)) on |
91 | | //! the stack. You must pass them by reference. |
92 | | //! |
93 | | //! * Stack size is at least 128KiB and 16-byte aligned. All stack space might be marked |
94 | | //! non-executable! Once ExitBootServices() was called, you must guarantee at least 4KiB of |
95 | | //! stack space, 16-byte aligned for all runtime services you call. |
96 | | //! Details might differ depending on architectures. But the numbers here should serve as |
97 | | //! ball-park figures. |
98 | | |
99 | | // Target Architecture |
100 | | // |
101 | | // The UEFI Specification explicitly lists all supported target architectures. While external |
102 | | // implementors are free to port UEFI to other targets, we need information on the target |
103 | | // architecture to successfully compile for it. This includes calling-conventions, register |
104 | | // layouts, endianness, and more. Most of these details are hidden in the rust-target-declaration. |
105 | | // However, some details are still left to the actual rust code. |
106 | | // |
107 | | // This initial check just makes sure the compilation is halted with a suitable error message if |
108 | | // the target architecture is not supported. |
109 | | // |
110 | | // We try to minimize conditional compilations as much as possible. A simple search for |
111 | | // `target_arch` should reveal all uses throughout the code-base. If you add your target to this |
112 | | // error-check, you must adjust all other uses as well. |
113 | | // |
114 | | // Similarly, UEFI only defines configurations for little-endian architectures so far. Several |
115 | | // bits of the specification are thus unclear how they would be applied on big-endian systems. We |
116 | | // therefore mark it as unsupported. If you override this, you are on your own. |
117 | | #[cfg(not(any( |
118 | | target_arch = "arm", |
119 | | target_arch = "aarch64", |
120 | | target_arch = "x86", |
121 | | target_arch = "x86_64" |
122 | | )))] |
123 | | compile_error!("The target architecture is not supported."); |
124 | | #[cfg(not(any(target_endian = "little")))] |
125 | | compile_error!("The target endianness is not supported."); |
126 | | |
127 | | // eficall_abi!() |
128 | | // |
129 | | // This macro is the architecture-dependent implementation of eficall!(). See the documentation of |
130 | | // the eficall!() macro for a description. |
131 | | |
132 | | #[cfg(target_arch = "arm")] |
133 | | #[macro_export] |
134 | | #[doc(hidden)] |
135 | | macro_rules! eficall_abi { |
136 | | (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "aapcs" $($suffix)* }; |
137 | | } |
138 | | |
139 | | // XXX: Rust does not define aapcs64, yet. Once it does, we should switch to it, rather than |
140 | | // referring to the system default. |
141 | | #[cfg(target_arch = "aarch64")] |
142 | | #[macro_export] |
143 | | #[doc(hidden)] |
144 | | macro_rules! eficall_abi { |
145 | | (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "C" $($suffix)* }; |
146 | | } |
147 | | |
148 | | #[cfg(target_arch = "x86")] |
149 | | #[macro_export] |
150 | | #[doc(hidden)] |
151 | | macro_rules! eficall_abi { |
152 | | (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "cdecl" $($suffix)* }; |
153 | | } |
154 | | |
155 | | #[cfg(target_arch = "x86_64")] |
156 | | #[macro_export] |
157 | | #[doc(hidden)] |
158 | | macro_rules! eficall_abi { |
159 | | (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "win64" $($suffix)* }; |
160 | | } |
161 | | |
162 | | #[cfg(not(any( |
163 | | target_arch = "arm", |
164 | | target_arch = "aarch64", |
165 | | target_arch = "x86", |
166 | | target_arch = "x86_64" |
167 | | )))] |
168 | | #[macro_export] |
169 | | #[doc(hidden)] |
170 | | macro_rules! eficall_abi { |
171 | | (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "C" $($suffix)* }; |
172 | | } |
173 | | |
174 | | /// Annotate function with UEFI calling convention |
175 | | /// |
176 | | /// This macro takes a function-declaration as argument and produces the same function-declaration |
177 | | /// but annotated with the correct calling convention. Since the default `extern "C"` annotation |
178 | | /// depends on your compiler defaults, we cannot use it. Instead, this macro selects the default |
179 | | /// for your target platform. |
180 | | /// |
181 | | /// Ideally, the macro would expand to `extern "<abi>"` so you would be able to write: |
182 | | /// |
183 | | /// ```ignore |
184 | | /// // THIS DOES NOT WORK! |
185 | | /// pub fn eficall!{} foobar() { |
186 | | /// // ... |
187 | | /// } |
188 | | /// ``` |
189 | | /// |
190 | | /// However, macros are evaluated too late for this to work. Instead, the entire construct must be |
191 | | /// wrapped in a macro, which then expands to the same construct but with `extern "<abi>"` |
192 | | /// inserted at the correct place: |
193 | | /// |
194 | | /// ``` |
195 | | /// use r_efi::{eficall, eficall_abi}; |
196 | | /// |
197 | | /// eficall!{pub fn foobar() { |
198 | | /// // ... |
199 | | /// }} |
200 | | /// |
201 | | /// type FooBar = eficall!{fn(u8) -> (u8)}; |
202 | | /// ``` |
203 | | /// |
204 | | /// The `eficall!{}` macro takes either a function-type or function-definition as argument. It |
205 | | /// inserts `extern "<abi>"` after the function qualifiers, but before the `fn` keyword. |
206 | | /// |
207 | | /// # Internals |
208 | | /// |
209 | | /// The `eficall!{}` macro tries to parse the function header so it can insert `extern "<abi>"` at |
210 | | /// the right place. If, for whatever reason, this does not work with a particular syntax, you can |
211 | | /// use the internal `eficall_abi!{}` macro. This macro takes two token-streams as input and |
212 | | /// evaluates to the concatenation of both token-streams, but separated by the selected ABI. |
213 | | /// |
214 | | /// For instance, the following 3 type definitions are equivalent, assuming the selected ABI |
215 | | /// is "C": |
216 | | /// |
217 | | /// ``` |
218 | | /// use r_efi::{eficall, eficall_abi}; |
219 | | /// |
220 | | /// type FooBar1 = unsafe extern "C" fn(u8) -> (u8); |
221 | | /// type FooBar2 = eficall!{unsafe fn(u8) -> (u8)}; |
222 | | /// type FooBar3 = eficall_abi!{(unsafe), (fn(u8) -> (u8))}; |
223 | | /// ``` |
224 | | /// |
225 | | /// # Calling Conventions |
226 | | /// |
227 | | /// The UEFI specification defines the calling convention for each platform individually. It |
228 | | /// usually refers to other standards for details, but adds some restrictions on top. As of this |
229 | | /// writing, it mentions: |
230 | | /// |
231 | | /// * aarch32 / arm: The `aapcs` calling-convention is used. It is native to aarch32 and described |
232 | | /// in a document called |
233 | | /// "Procedure Call Standard for the ARM Architecture". It is openly distributed |
234 | | /// by ARM and widely known under the keyword `aapcs`. |
235 | | /// * aarch64: The `aapcs64` calling-convention is used. It is native to aarch64 and described in |
236 | | /// a document called |
237 | | /// "Procedure Call Standard for the ARM 64-bit Architecture (AArch64)". It is openly |
238 | | /// distributed by ARM and widely known under the keyword `aapcs64`. |
239 | | /// * ia-64: The "P64 C Calling Convention" as described in the |
240 | | /// "Itanium Software Conventions and Runtime Architecture Guide". It is also |
241 | | /// standardized in the "Intel Itanium SAL Specification". |
242 | | /// * RISC-V: The "Standard RISC-V C Calling Convention" is used. The UEFI specification |
243 | | /// describes it in detail, but also refers to the official RISC-V resources for |
244 | | /// detailed information. |
245 | | /// * x86 / ia-32: The `cdecl` C calling convention is used. Originated in the C Language and |
246 | | /// originally tightly coupled to C specifics. Unclear whether a formal |
247 | | /// specification exists (does anyone know?). Most compilers support it under the |
248 | | /// `cdecl` keyword, and in nearly all situations it is the default on x86. |
249 | | /// * x86_64 / amd64 / x64: The `win64` calling-convention is used. It is similar to the `sysv64` |
250 | | /// convention that is used on most non-windows x86_64 systems, but not |
251 | | /// exactly the same. Microsoft provides open documentation on it. See |
252 | | /// MSDN "x64 Software Conventions -> Calling Conventions". |
253 | | /// The UEFI Specification does not directly refer to `win64`, but |
254 | | /// contains a full specification of the calling convention itself. |
255 | | /// |
256 | | /// Note that in most cases the UEFI Specification adds several more restrictions on top of the |
257 | | /// common calling-conventions. These restrictions usually do not affect how the compiler will lay |
258 | | /// out the function calls. Instead, it usually only restricts the set of APIs that are allowed in |
259 | | /// UEFI. Therefore, most compilers already support the calling conventions used on UEFI. |
260 | | /// |
261 | | /// # Variadics |
262 | | /// |
263 | | /// For some reason, the rust compiler allows variadics only in combination with the `"C"` calling |
264 | | /// convention, even if the selected calling-convention matches what `"C"` would select on the |
265 | | /// target platform. Hence, you will very likely be unable to use variadics with this macro. |
266 | | /// Luckily, all of the UEFI functions that use variadics are wrappers around more low-level |
267 | | /// accessors, so they are not necessarily required. |
268 | | #[macro_export] |
269 | | macro_rules! eficall { |
270 | | // Muncher |
271 | | // |
272 | | // The `@munch()` rules are internal and should not be invoked directly. We walk through the |
273 | | // input, moving one token after the other from the suffix into the prefix until we find the |
274 | | // position where to insert `extern "<abi>"`. This muncher never drops any tokens, hence we |
275 | | // can safely match invalid statements just fine, as the compiler will later print proper |
276 | | // diagnostics when parsing the macro output. |
277 | | // Once done, we invoke the `eficall_abi!{}` macro, which simply inserts the correct ABI. |
278 | | (@munch(($($prefix:tt)*),(pub $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* pub),($($suffix)*))} }; |
279 | | (@munch(($($prefix:tt)*),(unsafe $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* unsafe),($($suffix)*))} }; |
280 | | (@munch(($($prefix:tt)*),($($suffix:tt)*))) => { eficall_abi!{($($prefix)*),($($suffix)*)} }; |
281 | | |
282 | | // Entry Point |
283 | | // |
284 | | // This captures the entire argument and invokes its own TT-muncher, but splits the input into |
285 | | // prefix and suffix, so the TT-muncher can walk through it. Note that initially everything is |
286 | | // in the suffix and the prefix is empty. |
287 | | ($($arg:tt)*) => { eficall!{@munch((),($($arg)*))} }; |
288 | | } |
289 | | |
290 | | /// Boolean Type |
291 | | /// |
292 | | /// This boolean type works very similar to the rust primitive type of [`bool`]. However, the rust |
293 | | /// primitive type has no stable ABI, hence we provide this type to represent booleans on the FFI |
294 | | /// interface. |
295 | | /// |
296 | | /// UEFI defines booleans to be 1-byte integers, which can only have the values of `0` or `1`. |
297 | | /// However, in practice anything non-zero is considered `true` by nearly all UEFI systems. Hence, |
298 | | /// this type implements a boolean over `u8` and maps `0` to `false`, everything else to `true`. |
299 | | /// |
300 | | /// The binary representation of this type is ABI. That is, you are allowed to transmute from and |
301 | | /// to `u8`. Furthermore, this type never modifies its binary representation. If it was |
302 | | /// initialized as, or transmuted from, a specific integer value, this value will be retained. |
303 | | /// However, on the rust side you will never see the integer value. It instead behaves truly as a |
304 | | /// boolean. If you need access to the integer value, you have to transmute it back to `u8`. |
305 | | #[repr(C)] |
306 | | #[derive(Copy, Clone, Debug, Eq)] |
307 | | pub struct Boolean(u8); |
308 | | |
309 | | /// Single-byte Character Type |
310 | | /// |
311 | | /// The `Char8` type represents single-byte characters. UEFI defines them to be ASCII compatible, |
312 | | /// using the ISO-Latin-1 character set. |
313 | | pub type Char8 = u8; |
314 | | |
315 | | /// Dual-byte Character Type |
316 | | /// |
317 | | /// The `Char16` type represents dual-byte characters. UEFI defines them to be UCS-2 encoded. |
318 | | pub type Char16 = u16; |
319 | | |
320 | | /// Status Codes |
321 | | /// |
322 | | /// UEFI uses the `Status` type to represent all kinds of status codes. This includes return codes |
323 | | /// from functions, but also complex state of different devices and drivers. It is a simple |
324 | | /// `usize`, but wrapped in a rust-type to allow us to implement helpers on this type. Depending |
325 | | /// on the context, different state is stored in it. Note that it is always binary compatible to a |
326 | | /// usize! |
327 | | #[repr(C)] |
328 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
329 | | pub struct Status(usize); |
330 | | |
331 | | /// Object Handles |
332 | | /// |
333 | | /// Handles represent access to an opaque object. Handles are untyped by default, but get a |
334 | | /// meaning when you combine them with an interface. Internally, they are simple void pointers. It |
335 | | /// is the UEFI driver model that applies meaning to them. |
336 | | pub type Handle = *mut core::ffi::c_void; |
337 | | |
338 | | /// Event Objects |
339 | | /// |
340 | | /// Event objects represent hooks into the main-loop of a UEFI environment. They allow to register |
341 | | /// callbacks, to be invoked when a specific event happens. In most cases you use events to |
342 | | /// register timer-based callbacks, as well as chaining events together. Internally, they are |
343 | | /// simple void pointers. It is the UEFI task management that applies meaning to them. |
344 | | pub type Event = *mut core::ffi::c_void; |
345 | | |
346 | | /// Logical Block Addresses |
347 | | /// |
348 | | /// The LBA type is used to denote logical block addresses of block devices. It is a simple 64-bit |
349 | | /// integer, that is used to denote addresses when working with block devices. |
350 | | pub type Lba = u64; |
351 | | |
352 | | /// Thread Priority Levels |
353 | | /// |
354 | | /// The process model of UEFI systems is highly simplified. Priority levels are used to order |
355 | | /// execution of pending tasks. The TPL type denotes a priority level of a specific task. The |
356 | | /// higher the number, the higher the priority. It is a simple integer type, but its range is |
357 | | /// usually highly restricted. The UEFI task management provides constants and accessors for TPLs. |
358 | | pub type Tpl = usize; |
359 | | |
360 | | /// Physical Memory Address |
361 | | /// |
362 | | /// A simple 64bit integer containing a physical memory address. |
363 | | pub type PhysicalAddress = u64; |
364 | | |
365 | | /// Virtual Memory Address |
366 | | /// |
367 | | /// A simple 64bit integer containing a virtual memory address. |
368 | | pub type VirtualAddress = u64; |
369 | | |
370 | | /// Application Entry Point |
371 | | /// |
372 | | /// This type defines the entry-point of UEFI applications. It is ABI and cannot be changed. |
373 | | /// Whenever you load UEFI images, the entry-point is called with this signature. |
374 | | /// |
375 | | /// In most cases the UEFI image (or application) is unloaded when control returns from the entry |
376 | | /// point. In case of UEFI drivers, they can request to stay loaded until an explicit unload. |
377 | | /// |
378 | | /// The system table is provided as mutable pointer. This is, because there is no guarantee that |
379 | | /// timer interrupts do not modify the table. Furthermore, exiting boot services causes several |
380 | | /// modifications on that table. And lastly, the system table lives longer than the function |
381 | | /// invocation, if invoked as an UEFI driver. |
382 | | /// In most cases it is perfectly fine to cast the pointer to a real rust reference. However, this |
383 | | /// should be an explicit decision by the caller. |
384 | | pub type ImageEntryPoint = fn(Handle, *mut crate::system::SystemTable) -> Status; |
385 | | |
386 | | /// Globally Unique Identifiers |
387 | | /// |
388 | | /// The `Guid` type represents globally unique identifiers as defined by RFC-4122 (i.e., only the |
389 | | /// `10x` variant is used), with the caveat that LE is used instead of BE. The type must be 64-bit |
390 | | /// aligned. |
391 | | /// |
392 | | /// Note that only the binary representation of Guids is stable. You are highly recommended to |
393 | | /// interpret Guids as 128bit integers. |
394 | | /// |
395 | | /// UEFI uses the Microsoft-style Guid format. Hence, a lot of documentation and code refers to |
396 | | /// these Guids. If you thusly cannot treat Guids as 128-bit integers, this Guid type allows you |
397 | | /// to access the individual fields of the Microsoft-style Guid. A reminder of the Guid encoding: |
398 | | /// |
399 | | /// ```text |
400 | | /// 0 1 2 3 |
401 | | /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
402 | | /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
403 | | /// | time_low | |
404 | | /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
405 | | /// | time_mid | time_hi_and_version | |
406 | | /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
407 | | /// |clk_seq_hi_res | clk_seq_low | node (0-1) | |
408 | | /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
409 | | /// | node (2-5) | |
410 | | /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
411 | | /// ``` |
412 | | /// |
413 | | /// The individual fields are encoded as little-endian. Accessors are provided for the Guid |
414 | | /// structure allowing access to these fields in native endian byte order. |
415 | | #[repr(C, align(8))] |
416 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
417 | | pub struct Guid { |
418 | | time_low: [u8; 4], |
419 | | time_mid: [u8; 2], |
420 | | time_hi_and_version: [u8; 2], |
421 | | clk_seq_hi_res: u8, |
422 | | clk_seq_low: u8, |
423 | | node: [u8; 6], |
424 | | } |
425 | | |
426 | | /// Network MAC Address |
427 | | /// |
428 | | /// This type encapsulates a single networking media access control address |
429 | | /// (MAC). It is a simple 32 bytes buffer with no special alignment. Note that |
430 | | /// no comparison function are defined by default, since trailing bytes of the |
431 | | /// address might be random. |
432 | | /// |
433 | | /// The interpretation of the content differs depending on the protocol it is |
434 | | /// used with. See each documentation for details. In most cases this contains |
435 | | /// an Ethernet address. |
436 | | #[repr(C)] |
437 | | #[derive(Copy, Clone, Debug)] |
438 | | pub struct MacAddress { |
439 | | pub addr: [u8; 32], |
440 | | } |
441 | | |
442 | | /// IPv4 Address |
443 | | /// |
444 | | /// Binary representation of an IPv4 address. It is encoded in network byte |
445 | | /// order (i.e., big endian). Note that no special alignment restrictions are |
446 | | /// defined by the standard specification. |
447 | | #[repr(C)] |
448 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
449 | | pub struct Ipv4Address { |
450 | | pub addr: [u8; 4], |
451 | | } |
452 | | |
453 | | /// IPv6 Address |
454 | | /// |
455 | | /// Binary representation of an IPv6 address, encoded in network byte order |
456 | | /// (i.e., big endian). Similar to the IPv4 address, no special alignment |
457 | | /// restrictions are defined by the standard specification. |
458 | | #[repr(C)] |
459 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
460 | | pub struct Ipv6Address { |
461 | | pub addr: [u8; 16], |
462 | | } |
463 | | |
464 | | /// IP Address |
465 | | /// |
466 | | /// A union type over the different IP addresses available. Alignment is always |
467 | | /// fixed to 4-bytes. Note that trailing bytes might be random, so no |
468 | | /// comparison functions are derived. |
469 | | #[repr(C, align(4))] |
470 | | #[derive(Copy, Clone)] |
471 | | pub union IpAddress { |
472 | | pub addr: [u32; 4], |
473 | | pub v4: Ipv4Address, |
474 | | pub v6: Ipv6Address, |
475 | | } |
476 | | |
477 | | impl Boolean { |
478 | | /// Literal False |
479 | | /// |
480 | | /// This constant represents the `false` value of the `Boolean` type. |
481 | | pub const FALSE: Boolean = Boolean(0u8); |
482 | | |
483 | | /// Literal True |
484 | | /// |
485 | | /// This constant represents the `true` value of the `Boolean` type. |
486 | | pub const TRUE: Boolean = Boolean(1u8); |
487 | | } |
488 | | |
489 | | impl From<u8> for Boolean { |
490 | 0 | fn from(v: u8) -> Self { |
491 | 0 | Boolean(v) |
492 | 0 | } |
493 | | } |
494 | | |
495 | | impl From<bool> for Boolean { |
496 | 0 | fn from(v: bool) -> Self { |
497 | 0 | match v { |
498 | 0 | false => Boolean::FALSE, |
499 | 0 | true => Boolean::TRUE, |
500 | | } |
501 | 0 | } |
502 | | } |
503 | | |
504 | | impl From<Boolean> for bool { |
505 | 0 | fn from(v: Boolean) -> Self { |
506 | 0 | match v.0 { |
507 | 0 | 0 => false, |
508 | 0 | _ => true, |
509 | | } |
510 | 0 | } |
511 | | } |
512 | | |
513 | | impl PartialEq for Boolean { |
514 | 0 | fn eq(&self, other: &Boolean) -> bool { |
515 | 0 | <bool as From<Boolean>>::from(*self) == (*other).into() |
516 | 0 | } |
517 | | } |
518 | | |
519 | | impl PartialEq<bool> for Boolean { |
520 | 0 | fn eq(&self, other: &bool) -> bool { |
521 | 0 | *other == (*self).into() |
522 | 0 | } |
523 | | } |
524 | | |
525 | | impl Status { |
526 | | const WIDTH: usize = 8usize * core::mem::size_of::<Status>(); |
527 | | const MASK: usize = 0xc0 << (Status::WIDTH - 8); |
528 | | const ERROR_MASK: usize = 0x80 << (Status::WIDTH - 8); |
529 | | const WARNING_MASK: usize = 0x00 << (Status::WIDTH - 8); |
530 | | |
531 | | /// Success Code |
532 | | /// |
533 | | /// This code represents a successfull function invocation. Its value is guaranteed to be 0. |
534 | | /// However, note that warnings are considered success as well, so this is not the only code |
535 | | /// that can be returned by UEFI functions on success. However, in nearly all situations |
536 | | /// warnings are not allowed, so the effective result will be SUCCESS. |
537 | | pub const SUCCESS: Status = Status::from_usize(0); |
538 | | |
539 | | // List of predefined error codes |
540 | | pub const LOAD_ERROR: Status = Status::from_usize(1 | Status::ERROR_MASK); |
541 | | pub const INVALID_PARAMETER: Status = Status::from_usize(2 | Status::ERROR_MASK); |
542 | | pub const UNSUPPORTED: Status = Status::from_usize(3 | Status::ERROR_MASK); |
543 | | pub const BAD_BUFFER_SIZE: Status = Status::from_usize(4 | Status::ERROR_MASK); |
544 | | pub const BUFFER_TOO_SMALL: Status = Status::from_usize(5 | Status::ERROR_MASK); |
545 | | pub const NOT_READY: Status = Status::from_usize(6 | Status::ERROR_MASK); |
546 | | pub const DEVICE_ERROR: Status = Status::from_usize(7 | Status::ERROR_MASK); |
547 | | pub const WRITE_PROTECTED: Status = Status::from_usize(8 | Status::ERROR_MASK); |
548 | | pub const OUT_OF_RESOURCES: Status = Status::from_usize(9 | Status::ERROR_MASK); |
549 | | pub const VOLUME_CORRUPTED: Status = Status::from_usize(10 | Status::ERROR_MASK); |
550 | | pub const VOLUME_FULL: Status = Status::from_usize(11 | Status::ERROR_MASK); |
551 | | pub const NO_MEDIA: Status = Status::from_usize(12 | Status::ERROR_MASK); |
552 | | pub const MEDIA_CHANGED: Status = Status::from_usize(13 | Status::ERROR_MASK); |
553 | | pub const NOT_FOUND: Status = Status::from_usize(14 | Status::ERROR_MASK); |
554 | | pub const ACCESS_DENIED: Status = Status::from_usize(15 | Status::ERROR_MASK); |
555 | | pub const NO_RESPONSE: Status = Status::from_usize(16 | Status::ERROR_MASK); |
556 | | pub const NO_MAPPING: Status = Status::from_usize(17 | Status::ERROR_MASK); |
557 | | pub const TIMEOUT: Status = Status::from_usize(18 | Status::ERROR_MASK); |
558 | | pub const NOT_STARTED: Status = Status::from_usize(19 | Status::ERROR_MASK); |
559 | | pub const ALREADY_STARTED: Status = Status::from_usize(20 | Status::ERROR_MASK); |
560 | | pub const ABORTED: Status = Status::from_usize(21 | Status::ERROR_MASK); |
561 | | pub const ICMP_ERROR: Status = Status::from_usize(22 | Status::ERROR_MASK); |
562 | | pub const TFTP_ERROR: Status = Status::from_usize(23 | Status::ERROR_MASK); |
563 | | pub const PROTOCOL_ERROR: Status = Status::from_usize(24 | Status::ERROR_MASK); |
564 | | pub const INCOMPATIBLE_VERSION: Status = Status::from_usize(25 | Status::ERROR_MASK); |
565 | | pub const SECURITY_VIOLATION: Status = Status::from_usize(26 | Status::ERROR_MASK); |
566 | | pub const CRC_ERROR: Status = Status::from_usize(27 | Status::ERROR_MASK); |
567 | | pub const END_OF_MEDIA: Status = Status::from_usize(28 | Status::ERROR_MASK); |
568 | | pub const END_OF_FILE: Status = Status::from_usize(31 | Status::ERROR_MASK); |
569 | | pub const INVALID_LANGUAGE: Status = Status::from_usize(32 | Status::ERROR_MASK); |
570 | | pub const COMPROMISED_DATA: Status = Status::from_usize(33 | Status::ERROR_MASK); |
571 | | pub const IP_ADDRESS_CONFLICT: Status = Status::from_usize(34 | Status::ERROR_MASK); |
572 | | pub const HTTP_ERROR: Status = Status::from_usize(35 | Status::ERROR_MASK); |
573 | | |
574 | | // List of predefined warning codes |
575 | | pub const WARN_UNKNOWN_GLYPH: Status = Status::from_usize(1 | Status::WARNING_MASK); |
576 | | pub const WARN_DELETE_FAILURE: Status = Status::from_usize(2 | Status::WARNING_MASK); |
577 | | pub const WARN_WRITE_FAILURE: Status = Status::from_usize(3 | Status::WARNING_MASK); |
578 | | pub const WARN_BUFFER_TOO_SMALL: Status = Status::from_usize(4 | Status::WARNING_MASK); |
579 | | pub const WARN_STALE_DATA: Status = Status::from_usize(5 | Status::WARNING_MASK); |
580 | | pub const WARN_FILE_SYSTEM: Status = Status::from_usize(6 | Status::WARNING_MASK); |
581 | | pub const WARN_RESET_REQUIRED: Status = Status::from_usize(7 | Status::WARNING_MASK); |
582 | | |
583 | | /// Create Status Code from Integer |
584 | | /// |
585 | | /// This takes the literal value of a status code and turns it into a `Status` object. Note |
586 | | /// that we want it as `const fn` so we cannot use `core::convert::From`. |
587 | 0 | pub const fn from_usize(v: usize) -> Status { |
588 | 0 | Status(v) |
589 | 0 | } |
590 | | |
591 | | /// Return Underlying Integer Representation |
592 | | /// |
593 | | /// This takes the `Status` object and returns the underlying integer representation as |
594 | | /// defined by the UEFI specification. |
595 | 0 | pub const fn as_usize(&self) -> usize { |
596 | 0 | self.0 |
597 | 0 | } |
598 | | |
599 | 0 | fn value(&self) -> usize { |
600 | 0 | self.0 |
601 | 0 | } |
602 | | |
603 | 0 | fn mask(&self) -> usize { |
604 | 0 | self.value() & Status::MASK |
605 | 0 | } |
606 | | |
607 | | /// Check whether this is an error |
608 | | /// |
609 | | /// This returns true if the given status code is considered an error. Errors mean the |
610 | | /// operation did not succeed, nor produce any valuable output. Output parameters must be |
611 | | /// considered invalid if an error was returned. That is, its content is not well defined. |
612 | 0 | pub fn is_error(&self) -> bool { |
613 | 0 | self.mask() == Status::ERROR_MASK |
614 | 0 | } |
615 | | |
616 | | /// Check whether this is a warning |
617 | | /// |
618 | | /// This returns true if the given status code is considered a warning. Warnings are to be |
619 | | /// treated as success, but might indicate data loss or other device errors. However, if an |
620 | | /// operation returns with a warning code, it must be considered successfull, and the output |
621 | | /// parameters are valid. |
622 | 0 | pub fn is_warning(&self) -> bool { |
623 | 0 | self.value() != 0 && self.mask() == Status::WARNING_MASK |
624 | 0 | } |
625 | | } |
626 | | |
627 | | impl From<Status> for Result<Status, Status> { |
628 | 0 | fn from(status: Status) -> Self { |
629 | 0 | if status.is_error() { |
630 | 0 | Err(status) |
631 | | } else { |
632 | 0 | Ok(status) |
633 | | } |
634 | 0 | } |
635 | | } |
636 | | |
637 | | impl Guid { |
638 | 0 | const fn u32_to_bytes_le(num: u32) -> [u8; 4] { |
639 | 0 | [ |
640 | 0 | num as u8, |
641 | 0 | (num >> 8) as u8, |
642 | 0 | (num >> 16) as u8, |
643 | 0 | (num >> 24) as u8, |
644 | 0 | ] |
645 | 0 | } |
646 | | |
647 | 0 | const fn u32_from_bytes_le(bytes: &[u8; 4]) -> u32 { |
648 | 0 | (bytes[0] as u32) |
649 | 0 | | ((bytes[1] as u32) << 8) |
650 | 0 | | ((bytes[2] as u32) << 16) |
651 | 0 | | ((bytes[3] as u32) << 24) |
652 | 0 | } |
653 | | |
654 | 0 | const fn u16_to_bytes_le(num: u16) -> [u8; 2] { |
655 | 0 | [num as u8, (num >> 8) as u8] |
656 | 0 | } |
657 | | |
658 | 0 | const fn u16_from_bytes_le(bytes: &[u8; 2]) -> u16 { |
659 | 0 | (bytes[0] as u16) | ((bytes[1] as u16) << 8) |
660 | 0 | } |
661 | | |
662 | | /// Initialize a Guid from its individual fields |
663 | | /// |
664 | | /// This function initializes a Guid object given the individual fields as specified in the |
665 | | /// UEFI specification. That is, if you simply copy the literals from the specification into |
666 | | /// your code, this function will correctly initialize the Guid object. |
667 | | /// |
668 | | /// In other words, this takes the individual fields in native endian and converts them to the |
669 | | /// correct endianness for a UEFI Guid. |
670 | 0 | pub const fn from_fields( |
671 | 0 | time_low: u32, |
672 | 0 | time_mid: u16, |
673 | 0 | time_hi_and_version: u16, |
674 | 0 | clk_seq_hi_res: u8, |
675 | 0 | clk_seq_low: u8, |
676 | 0 | node: &[u8; 6], |
677 | 0 | ) -> Guid { |
678 | 0 | Guid { |
679 | 0 | time_low: Self::u32_to_bytes_le(time_low), |
680 | 0 | time_mid: Self::u16_to_bytes_le(time_mid), |
681 | 0 | time_hi_and_version: Self::u16_to_bytes_le(time_hi_and_version), |
682 | 0 | clk_seq_hi_res: clk_seq_hi_res, |
683 | 0 | clk_seq_low: clk_seq_low, |
684 | 0 | node: *node, |
685 | 0 | } |
686 | 0 | } |
687 | | |
688 | | /// Access a Guid as individual fields |
689 | | /// |
690 | | /// This decomposes a Guid back into the individual fields as given in the specification. The |
691 | | /// individual fields are returned in native-endianness. |
692 | 0 | pub const fn as_fields(&self) -> (u32, u16, u16, u8, u8, &[u8; 6]) { |
693 | 0 | ( |
694 | 0 | Self::u32_from_bytes_le(&self.time_low), |
695 | 0 | Self::u16_from_bytes_le(&self.time_mid), |
696 | 0 | Self::u16_from_bytes_le(&self.time_hi_and_version), |
697 | 0 | self.clk_seq_hi_res, |
698 | 0 | self.clk_seq_low, |
699 | 0 | &self.node, |
700 | 0 | ) |
701 | 0 | } |
702 | | |
703 | | /// Access a Guid as raw byte array |
704 | | /// |
705 | | /// This provides access to a Guid through a byte array. It is a simple re-interpretation of |
706 | | /// the Guid value as a 128-bit byte array. No conversion is performed. This is a simple cast. |
707 | 11.2k | pub fn as_bytes(&self) -> &[u8; 16] { |
708 | 11.2k | unsafe { core::mem::transmute::<&Guid, &[u8; 16]>(self) } |
709 | 11.2k | } |
710 | | } |
711 | | |
712 | | #[cfg(test)] |
713 | | mod tests { |
714 | | use super::*; |
715 | | use std::mem::{align_of, size_of}; |
716 | | |
717 | | // Verify Type Size and Alignemnt |
718 | | // |
719 | | // Since UEFI defines explicitly the ABI of their types, we can verify that our implementation |
720 | | // is correct by checking the size and alignment of the ABI types matches what the spec |
721 | | // mandates. |
722 | | #[test] |
723 | | fn type_size_and_alignment() { |
724 | | // |
725 | | // Booleans |
726 | | // |
727 | | |
728 | | assert_eq!(size_of::<Boolean>(), 1); |
729 | | assert_eq!(align_of::<Boolean>(), 1); |
730 | | |
731 | | // |
732 | | // Char8 / Char16 |
733 | | // |
734 | | |
735 | | assert_eq!(size_of::<Char8>(), 1); |
736 | | assert_eq!(align_of::<Char8>(), 1); |
737 | | assert_eq!(size_of::<Char16>(), 2); |
738 | | assert_eq!(align_of::<Char16>(), 2); |
739 | | |
740 | | assert_eq!(size_of::<Char8>(), size_of::<u8>()); |
741 | | assert_eq!(align_of::<Char8>(), align_of::<u8>()); |
742 | | assert_eq!(size_of::<Char16>(), size_of::<u16>()); |
743 | | assert_eq!(align_of::<Char16>(), align_of::<u16>()); |
744 | | |
745 | | // |
746 | | // Status |
747 | | // |
748 | | |
749 | | assert_eq!(size_of::<Status>(), size_of::<usize>()); |
750 | | assert_eq!(align_of::<Status>(), align_of::<usize>()); |
751 | | |
752 | | // |
753 | | // Handles / Events |
754 | | // |
755 | | |
756 | | assert_eq!(size_of::<Handle>(), size_of::<usize>()); |
757 | | assert_eq!(align_of::<Handle>(), align_of::<usize>()); |
758 | | assert_eq!(size_of::<Event>(), size_of::<usize>()); |
759 | | assert_eq!(align_of::<Event>(), align_of::<usize>()); |
760 | | |
761 | | assert_eq!(size_of::<Handle>(), size_of::<*mut ()>()); |
762 | | assert_eq!(align_of::<Handle>(), align_of::<*mut ()>()); |
763 | | assert_eq!(size_of::<Event>(), size_of::<*mut ()>()); |
764 | | assert_eq!(align_of::<Event>(), align_of::<*mut ()>()); |
765 | | |
766 | | // |
767 | | // Lba / Tpl |
768 | | // |
769 | | |
770 | | assert_eq!(size_of::<Lba>(), size_of::<u64>()); |
771 | | assert_eq!(align_of::<Lba>(), align_of::<u64>()); |
772 | | assert_eq!(size_of::<Tpl>(), size_of::<usize>()); |
773 | | assert_eq!(align_of::<Tpl>(), align_of::<usize>()); |
774 | | |
775 | | // |
776 | | // PhysicalAddress / VirtualAddress |
777 | | // |
778 | | |
779 | | assert_eq!(size_of::<PhysicalAddress>(), size_of::<u64>()); |
780 | | assert_eq!(align_of::<PhysicalAddress>(), align_of::<u64>()); |
781 | | assert_eq!(size_of::<VirtualAddress>(), size_of::<u64>()); |
782 | | assert_eq!(align_of::<VirtualAddress>(), align_of::<u64>()); |
783 | | |
784 | | // |
785 | | // ImageEntryPoint |
786 | | // |
787 | | |
788 | | assert_eq!(size_of::<ImageEntryPoint>(), size_of::<fn()>()); |
789 | | assert_eq!(align_of::<ImageEntryPoint>(), align_of::<fn()>()); |
790 | | |
791 | | // |
792 | | // Guid |
793 | | // |
794 | | |
795 | | assert_eq!(size_of::<Guid>(), 16); |
796 | | assert_eq!(align_of::<Guid>(), 8); |
797 | | |
798 | | // |
799 | | // Networking Types |
800 | | // |
801 | | |
802 | | assert_eq!(size_of::<MacAddress>(), 32); |
803 | | assert_eq!(align_of::<MacAddress>(), 1); |
804 | | assert_eq!(size_of::<Ipv4Address>(), 4); |
805 | | assert_eq!(align_of::<Ipv4Address>(), 1); |
806 | | assert_eq!(size_of::<Ipv6Address>(), 16); |
807 | | assert_eq!(align_of::<Ipv6Address>(), 1); |
808 | | assert_eq!(size_of::<IpAddress>(), 16); |
809 | | assert_eq!(align_of::<IpAddress>(), 4); |
810 | | } |
811 | | |
812 | | #[test] |
813 | | fn eficall() { |
814 | | // |
815 | | // Make sure the eficall!{} macro can deal with all kinds of function callbacks. |
816 | | // |
817 | | |
818 | | let _: eficall! {fn()}; |
819 | | let _: eficall! {unsafe fn()}; |
820 | | let _: eficall! {fn(i32)}; |
821 | | let _: eficall! {fn(i32) -> i32}; |
822 | | let _: eficall! {fn(i32, i32) -> (i32, i32)}; |
823 | | |
824 | | eficall! {fn _unused00() {}} |
825 | | eficall! {unsafe fn _unused01() {}} |
826 | | eficall! {pub unsafe fn _unused02() {}} |
827 | | } |
828 | | |
829 | | // Verify Boolean ABI |
830 | | // |
831 | | // Even though booleans are strictly 1-bit, and thus 0 or 1, in practice all UEFI systems |
832 | | // treat it more like C does, and a boolean formatted as `u8` now allows any value other than |
833 | | // 0 to represent `true`. Make sure we support the same. |
834 | | #[test] |
835 | | fn booleans() { |
836 | | // Verify PartialEq works. |
837 | | assert_ne!(Boolean::FALSE, Boolean::TRUE); |
838 | | |
839 | | // Verify Boolean<->bool conversion and comparison works. |
840 | | assert_eq!(Boolean::FALSE, false); |
841 | | assert_eq!(Boolean::TRUE, true); |
842 | | |
843 | | // Iterate all possible values for `u8` and verify 0 behaves as `false`, and everything |
844 | | // else behaves as `true`. We verify both, the natural constructor through `From`, as well |
845 | | // as a transmute. |
846 | | for i in 0u8..=255u8 { |
847 | | let v1: Boolean = i.into(); |
848 | | let v2: Boolean = unsafe { std::mem::transmute::<u8, Boolean>(i) }; |
849 | | |
850 | | assert_eq!(v1, v2); |
851 | | assert_eq!(v1, v1); |
852 | | assert_eq!(v2, v2); |
853 | | |
854 | | match i { |
855 | | 0 => { |
856 | | assert_eq!(v1, Boolean::FALSE); |
857 | | assert_eq!(v1, false); |
858 | | assert_eq!(v2, Boolean::FALSE); |
859 | | assert_eq!(v2, false); |
860 | | |
861 | | assert_ne!(v1, Boolean::TRUE); |
862 | | assert_ne!(v1, true); |
863 | | assert_ne!(v2, Boolean::TRUE); |
864 | | assert_ne!(v2, true); |
865 | | } |
866 | | _ => { |
867 | | assert_eq!(v1, Boolean::TRUE); |
868 | | assert_eq!(v1, true); |
869 | | assert_eq!(v2, Boolean::TRUE); |
870 | | assert_eq!(v2, true); |
871 | | |
872 | | assert_ne!(v1, Boolean::FALSE); |
873 | | assert_ne!(v1, false); |
874 | | assert_ne!(v2, Boolean::FALSE); |
875 | | assert_ne!(v2, false); |
876 | | } |
877 | | } |
878 | | } |
879 | | } |
880 | | } |