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;