uefi_raw/table/
boot.rs

1//! UEFI services available during boot.
2
3use crate::protocol::device_path::DevicePathProtocol;
4use crate::table::Header;
5use crate::{Char16, Event, Guid, Handle, PhysicalAddress, Status, VirtualAddress};
6use bitflags::bitflags;
7use core::ffi::c_void;
8use core::ops::RangeInclusive;
9
10/// Table of pointers to all the boot services.
11#[derive(Debug)]
12#[repr(C)]
13pub struct BootServices {
14    pub header: Header,
15
16    // Task Priority services
17    pub raise_tpl: unsafe extern "efiapi" fn(new_tpl: Tpl) -> Tpl,
18    pub restore_tpl: unsafe extern "efiapi" fn(old_tpl: Tpl),
19
20    // Memory allocation functions
21    pub allocate_pages: unsafe extern "efiapi" fn(
22        alloc_ty: u32,
23        mem_ty: MemoryType,
24        count: usize,
25        addr: *mut PhysicalAddress,
26    ) -> Status,
27    pub free_pages: unsafe extern "efiapi" fn(addr: PhysicalAddress, pages: usize) -> Status,
28    pub get_memory_map: unsafe extern "efiapi" fn(
29        size: *mut usize,
30        map: *mut MemoryDescriptor,
31        key: *mut usize,
32        desc_size: *mut usize,
33        desc_version: *mut u32,
34    ) -> Status,
35    pub allocate_pool: unsafe extern "efiapi" fn(
36        pool_type: MemoryType,
37        size: usize,
38        buffer: *mut *mut u8,
39    ) -> Status,
40    pub free_pool: unsafe extern "efiapi" fn(buffer: *mut u8) -> Status,
41
42    // Event & timer functions
43    pub create_event: unsafe extern "efiapi" fn(
44        ty: EventType,
45        notify_tpl: Tpl,
46        notify_func: Option<EventNotifyFn>,
47        notify_ctx: *mut c_void,
48        out_event: *mut Event,
49    ) -> Status,
50    pub set_timer: unsafe extern "efiapi" fn(event: Event, ty: u32, trigger_time: u64) -> Status,
51    pub wait_for_event: unsafe extern "efiapi" fn(
52        number_of_events: usize,
53        events: *mut Event,
54        out_index: *mut usize,
55    ) -> Status,
56    pub signal_event: unsafe extern "efiapi" fn(event: Event) -> Status,
57    pub close_event: unsafe extern "efiapi" fn(event: Event) -> Status,
58    pub check_event: unsafe extern "efiapi" fn(event: Event) -> Status,
59
60    // Protocol handlers
61    pub install_protocol_interface: unsafe extern "efiapi" fn(
62        handle: *mut Handle,
63        guid: *const Guid,
64        interface_type: InterfaceType,
65        interface: *const c_void,
66    ) -> Status,
67    pub reinstall_protocol_interface: unsafe extern "efiapi" fn(
68        handle: Handle,
69        protocol: *const Guid,
70        old_interface: *const c_void,
71        new_interface: *const c_void,
72    ) -> Status,
73    pub uninstall_protocol_interface: unsafe extern "efiapi" fn(
74        handle: Handle,
75        protocol: *const Guid,
76        interface: *const c_void,
77    ) -> Status,
78    pub handle_protocol: unsafe extern "efiapi" fn(
79        handle: Handle,
80        proto: *const Guid,
81        out_proto: *mut *mut c_void,
82    ) -> Status,
83    pub reserved: *mut c_void,
84    pub register_protocol_notify: unsafe extern "efiapi" fn(
85        protocol: *const Guid,
86        event: Event,
87        registration: *mut *const c_void,
88    ) -> Status,
89    pub locate_handle: unsafe extern "efiapi" fn(
90        search_ty: i32,
91        proto: *const Guid,
92        key: *const c_void,
93        buf_sz: *mut usize,
94        buf: *mut Handle,
95    ) -> Status,
96    pub locate_device_path: unsafe extern "efiapi" fn(
97        proto: *const Guid,
98        device_path: *mut *const DevicePathProtocol,
99        out_handle: *mut Handle,
100    ) -> Status,
101    pub install_configuration_table:
102        unsafe extern "efiapi" fn(guid_entry: *const Guid, table_ptr: *const c_void) -> Status,
103
104    // Image services
105    pub load_image: unsafe extern "efiapi" fn(
106        boot_policy: u8,
107        parent_image_handle: Handle,
108        device_path: *const DevicePathProtocol,
109        source_buffer: *const u8,
110        source_size: usize,
111        image_handle: *mut Handle,
112    ) -> Status,
113    pub start_image: unsafe extern "efiapi" fn(
114        image_handle: Handle,
115        exit_data_size: *mut usize,
116        exit_data: *mut *mut Char16,
117    ) -> Status,
118    pub exit: unsafe extern "efiapi" fn(
119        image_handle: Handle,
120        exit_status: Status,
121        exit_data_size: usize,
122        exit_data: *mut Char16,
123    ) -> !,
124    pub unload_image: unsafe extern "efiapi" fn(image_handle: Handle) -> Status,
125    pub exit_boot_services:
126        unsafe extern "efiapi" fn(image_handle: Handle, map_key: usize) -> Status,
127
128    // Misc services
129    pub get_next_monotonic_count: unsafe extern "efiapi" fn(count: *mut u64) -> Status,
130    pub stall: unsafe extern "efiapi" fn(microseconds: usize) -> Status,
131    pub set_watchdog_timer: unsafe extern "efiapi" fn(
132        timeout: usize,
133        watchdog_code: u64,
134        data_size: usize,
135        watchdog_data: *const u16,
136    ) -> Status,
137
138    // Driver support services
139    pub connect_controller: unsafe extern "efiapi" fn(
140        controller: Handle,
141        driver_image: Handle,
142        remaining_device_path: *const DevicePathProtocol,
143        recursive: bool,
144    ) -> Status,
145    pub disconnect_controller: unsafe extern "efiapi" fn(
146        controller: Handle,
147        driver_image: Handle,
148        child: Handle,
149    ) -> Status,
150
151    // Protocol open / close services
152    pub open_protocol: unsafe extern "efiapi" fn(
153        handle: Handle,
154        protocol: *const Guid,
155        interface: *mut *mut c_void,
156        agent_handle: Handle,
157        controller_handle: Handle,
158        attributes: u32,
159    ) -> Status,
160    pub close_protocol: unsafe extern "efiapi" fn(
161        handle: Handle,
162        protocol: *const Guid,
163        agent_handle: Handle,
164        controller_handle: Handle,
165    ) -> Status,
166    pub open_protocol_information: unsafe extern "efiapi" fn(
167        handle: Handle,
168        protocol: *const Guid,
169        entry_buffer: *mut *const OpenProtocolInformationEntry,
170        entry_count: *mut usize,
171    ) -> Status,
172
173    // Library services
174    pub protocols_per_handle: unsafe extern "efiapi" fn(
175        handle: Handle,
176        protocol_buffer: *mut *mut *const Guid,
177        protocol_buffer_count: *mut usize,
178    ) -> Status,
179    pub locate_handle_buffer: unsafe extern "efiapi" fn(
180        search_ty: i32,
181        proto: *const Guid,
182        key: *const c_void,
183        no_handles: *mut usize,
184        buf: *mut *mut Handle,
185    ) -> Status,
186    pub locate_protocol: unsafe extern "efiapi" fn(
187        proto: *const Guid,
188        registration: *mut c_void,
189        out_proto: *mut *mut c_void,
190    ) -> Status,
191
192    /// Warning: this function pointer is declared as `extern "C"` rather than
193    /// `extern "efiapi". That means it will work correctly when called from a
194    /// UEFI target (`*-unknown-uefi`), but will not work when called from a
195    /// target with a different calling convention such as
196    /// `x86_64-unknown-linux-gnu`.
197    ///
198    /// Support for C-variadics with `efiapi` requires the unstable
199    /// [`extended_varargs_abi_support`](https://github.com/rust-lang/rust/issues/100189)
200    /// feature.
201    pub install_multiple_protocol_interfaces:
202        unsafe extern "C" fn(handle: *mut Handle, ...) -> Status,
203
204    /// Warning: this function pointer is declared as `extern "C"` rather than
205    /// `extern "efiapi". That means it will work correctly when called from a
206    /// UEFI target (`*-unknown-uefi`), but will not work when called from a
207    /// target with a different calling convention such as
208    /// `x86_64-unknown-linux-gnu`.
209    ///
210    /// Support for C-variadics with `efiapi` requires the unstable
211    /// [`extended_varargs_abi_support`](https://github.com/rust-lang/rust/issues/100189)
212    /// feature.
213    pub uninstall_multiple_protocol_interfaces: unsafe extern "C" fn(handle: Handle, ...) -> Status,
214
215    // CRC services
216    pub calculate_crc32:
217        unsafe extern "efiapi" fn(data: *const c_void, data_size: usize, crc32: *mut u32) -> Status,
218
219    // Misc services
220    pub copy_mem: unsafe extern "efiapi" fn(dest: *mut u8, src: *const u8, len: usize),
221    pub set_mem: unsafe extern "efiapi" fn(buffer: *mut u8, len: usize, value: u8),
222
223    // New event functions (UEFI 2.0 or newer)
224    pub create_event_ex: unsafe extern "efiapi" fn(
225        ty: EventType,
226        notify_tpl: Tpl,
227        notify_fn: Option<EventNotifyFn>,
228        notify_ctx: *mut c_void,
229        event_group: *mut Guid,
230        out_event: *mut Event,
231    ) -> Status,
232}
233
234bitflags! {
235    /// Flags describing the type of an UEFI event and its attributes.
236    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
237    #[repr(transparent)]
238    pub struct EventType: u32 {
239        /// The event is a timer event and may be passed to `BootServices::set_timer()`
240        /// Note that timers only function during boot services time.
241        const TIMER = 0x8000_0000;
242
243        /// The event is allocated from runtime memory.
244        /// This must be done if the event is to be signaled after ExitBootServices.
245        const RUNTIME = 0x4000_0000;
246
247        /// Calling wait_for_event or check_event will enqueue the notification
248        /// function if the event is not already in the signaled state.
249        /// Mutually exclusive with `NOTIFY_SIGNAL`.
250        const NOTIFY_WAIT = 0x0000_0100;
251
252        /// The notification function will be enqueued when the event is signaled
253        /// Mutually exclusive with `NOTIFY_WAIT`.
254        const NOTIFY_SIGNAL = 0x0000_0200;
255
256        /// The event will be signaled at ExitBootServices time.
257        /// This event type should not be combined with any other.
258        /// Its notification function must follow some special rules:
259        /// - Cannot use memory allocation services, directly or indirectly
260        /// - Cannot depend on timer events, since those will be deactivated
261        const SIGNAL_EXIT_BOOT_SERVICES = 0x0000_0201;
262
263        /// The event will be notified when SetVirtualAddressMap is performed.
264        /// This event type should not be combined with any other.
265        const SIGNAL_VIRTUAL_ADDRESS_CHANGE = 0x6000_0202;
266    }
267}
268
269newtype_enum! {
270/// Interface type of a protocol interface.
271pub enum InterfaceType: u32 => {
272    /// Native interface
273    NATIVE_INTERFACE = 0,
274}}
275
276/// Raw event notification function.
277pub type EventNotifyFn = unsafe extern "efiapi" fn(event: Event, context: *mut c_void);
278
279bitflags! {
280    /// Flags describing the capabilities of a memory range.
281    #[repr(transparent)]
282    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
283    pub struct MemoryAttribute: u64 {
284        /// Supports marking as uncacheable.
285        const UNCACHEABLE = 0x1;
286        /// Supports write-combining.
287        const WRITE_COMBINE = 0x2;
288        /// Supports write-through.
289        const WRITE_THROUGH = 0x4;
290        /// Support write-back.
291        const WRITE_BACK = 0x8;
292        /// Supports marking as uncacheable, exported and
293        /// supports the "fetch and add" semaphore mechanism.
294        const UNCACHABLE_EXPORTED = 0x10;
295        /// Supports write-protection.
296        const WRITE_PROTECT = 0x1000;
297        /// Supports read-protection.
298        const READ_PROTECT = 0x2000;
299        /// Supports disabling code execution.
300        const EXECUTE_PROTECT = 0x4000;
301        /// Persistent memory.
302        const NON_VOLATILE = 0x8000;
303        /// This memory region is more reliable than other memory.
304        const MORE_RELIABLE = 0x10000;
305        /// This memory range can be set as read-only.
306        const READ_ONLY = 0x20000;
307        /// This memory is earmarked for specific purposes such as for specific
308        /// device drivers or applications. This serves as a hint to the OS to
309        /// avoid this memory for core OS data or code that cannot be relocated.
310        const SPECIAL_PURPOSE = 0x4_0000;
311        /// This memory region is capable of being protected with the CPU's memory
312        /// cryptography capabilities.
313        const CPU_CRYPTO = 0x8_0000;
314        /// This memory must be mapped by the OS when a runtime service is called.
315        const RUNTIME = 0x8000_0000_0000_0000;
316        /// This memory region is described with additional ISA-specific memory
317        /// attributes as specified in `MemoryAttribute::ISA_MASK`.
318        const ISA_VALID = 0x4000_0000_0000_0000;
319        /// These bits are reserved for describing optional ISA-specific cache-
320        /// ability attributes that are not covered by the standard UEFI Memory
321        /// Attribute cacheability bits such as `UNCACHEABLE`, `WRITE_COMBINE`,
322        /// `WRITE_THROUGH`, `WRITE_BACK`, and `UNCACHEABLE_EXPORTED`.
323        ///
324        /// See Section 2.3 "Calling Conventions" in the UEFI Specification
325        /// for further information on each ISA that takes advantage of this.
326        const ISA_MASK = 0x0FFF_F000_0000_0000;
327    }
328}
329
330/// A structure describing a region of memory. This type corresponds to [version]
331/// of this struct in the UEFI spec and is always bound to a corresponding
332/// UEFI memory map.
333///
334/// # UEFI pitfalls
335/// As of May 2024:
336/// The memory descriptor struct might be extended in the future by a new UEFI
337/// spec revision, which will be reflected in another `version` of that
338/// descriptor. The version is reported when using `get_memory_map` of
339/// [`BootServices`].
340///
341/// Also note that you **must never** work with `size_of::<MemoryDescriptor>`
342/// but always with `desc_size`, which is reported when using  `get_memory_map`
343/// as well [[0]]. For example, although the actual size is of version 1
344/// descriptors is `40`, the reported `desc_size` is `48`.
345///
346/// [version]: MemoryDescriptor::VERSION
347/// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059
348#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
349#[repr(C)]
350pub struct MemoryDescriptor {
351    /// Type of memory occupying this range.
352    pub ty: MemoryType,
353    // Implicit 32-bit padding.
354    /// Starting physical address.
355    pub phys_start: PhysicalAddress,
356    /// Starting virtual address.
357    pub virt_start: VirtualAddress,
358    /// Number of 4 KiB pages contained in this range.
359    pub page_count: u64,
360    /// The capability attributes of this memory range.
361    pub att: MemoryAttribute,
362}
363
364impl MemoryDescriptor {
365    /// Memory descriptor version number.
366    pub const VERSION: u32 = 1;
367}
368
369impl Default for MemoryDescriptor {
370    fn default() -> Self {
371        Self {
372            ty: MemoryType::RESERVED,
373            phys_start: 0,
374            virt_start: 0,
375            page_count: 0,
376            att: MemoryAttribute::empty(),
377        }
378    }
379}
380
381newtype_enum! {
382/// The type of a memory range.
383///
384/// UEFI allows firmwares and operating systems to introduce new memory types
385/// in the `0x7000_0000..=0xFFFF_FFFF` range. Therefore, we don't know the full set
386/// of memory types at compile time, and it is _not_ safe to model this C enum
387/// as a Rust enum.
388pub enum MemoryType: u32 => {
389    /// Not usable.
390    RESERVED                =  0,
391    /// The code portions of a loaded UEFI application.
392    LOADER_CODE             =  1,
393    /// The data portions of a loaded UEFI applications,
394    /// as well as any memory allocated by it.
395    LOADER_DATA             =  2,
396    /// Code of the boot drivers.
397    ///
398    /// Can be reused after OS is loaded.
399    BOOT_SERVICES_CODE      =  3,
400    /// Memory used to store boot drivers' data.
401    ///
402    /// Can be reused after OS is loaded.
403    BOOT_SERVICES_DATA      =  4,
404    /// Runtime drivers' code.
405    RUNTIME_SERVICES_CODE   =  5,
406    /// Runtime services' code.
407    RUNTIME_SERVICES_DATA   =  6,
408    /// Free usable memory.
409    CONVENTIONAL            =  7,
410    /// Memory in which errors have been detected.
411    UNUSABLE                =  8,
412    /// Memory that holds ACPI tables.
413    /// Can be reclaimed after they are parsed.
414    ACPI_RECLAIM            =  9,
415    /// Firmware-reserved addresses.
416    ACPI_NON_VOLATILE       = 10,
417    /// A region used for memory-mapped I/O.
418    MMIO                    = 11,
419    /// Address space used for memory-mapped port I/O.
420    MMIO_PORT_SPACE         = 12,
421    /// Address space which is part of the processor.
422    PAL_CODE                = 13,
423    /// Memory region which is usable and is also non-volatile.
424    PERSISTENT_MEMORY       = 14,
425    /// Memory that must be accepted by the boot target before it can be used.
426    UNACCEPTED              = 15,
427    /// End of the defined memory types. Higher values are possible though, see
428    /// [`MemoryType::RESERVED_FOR_OEM`] and [`MemoryType::RESERVED_FOR_OS_LOADER`].
429    MAX                     = 16,
430}}
431
432impl MemoryType {
433    /// Range reserved for OEM use.
434    pub const RESERVED_FOR_OEM: RangeInclusive<u32> = 0x7000_0000..=0x7fff_ffff;
435
436    /// Range reserved for OS loaders.
437    pub const RESERVED_FOR_OS_LOADER: RangeInclusive<u32> = 0x8000_0000..=0xffff_ffff;
438
439    /// Construct a custom `MemoryType`. Values in the range `0x8000_0000..=0xffff_ffff` are free for use if you are
440    /// an OS loader.
441    #[must_use]
442    pub const fn custom(value: u32) -> Self {
443        assert!(value >= 0x80000000);
444        Self(value)
445    }
446}
447
448#[derive(Debug)]
449#[repr(C)]
450pub struct OpenProtocolInformationEntry {
451    pub agent_handle: Handle,
452    pub controller_handle: Handle,
453    pub attributes: u32,
454    pub open_count: u32,
455}
456
457newtype_enum! {
458/// Task priority level.
459///
460/// Although the UEFI specification repeatedly states that only the variants
461/// specified below should be used in application-provided input, as the other
462/// are reserved for internal firmware use, it might still happen that the
463/// firmware accidentally discloses one of these internal TPLs to us.
464///
465/// Since feeding an unexpected variant to a Rust enum is UB, this means that
466/// this C enum must be interfaced via the newtype pattern.
467pub enum Tpl: usize => {
468    /// Normal task execution level.
469    APPLICATION = 4,
470    /// Async interrupt-style callbacks run at this TPL.
471    CALLBACK    = 8,
472    /// Notifications are masked at this level.
473    ///
474    /// This is used in critical sections of code.
475    NOTIFY      = 16,
476    /// Highest priority level.
477    ///
478    /// Even processor interrupts are disable at this level.
479    HIGH_LEVEL  = 31,
480}}
481
482/// Size in bytes of a UEFI page.
483///
484/// Note that this is not necessarily the processor's page size. The UEFI page
485/// size is always 4 KiB.
486pub const PAGE_SIZE: usize = 4096;