1 | //! UEFI services available during boot. |
2 | |
3 | use super::{Header, Revision}; |
4 | use crate::data_types::{Align, PhysicalAddress, VirtualAddress}; |
5 | use crate::proto::device_path::{DevicePath, FfiDevicePath}; |
6 | #[cfg (feature = "alloc" )] |
7 | use crate::proto::{loaded_image::LoadedImage, media::fs::SimpleFileSystem}; |
8 | use crate::proto::{Protocol, ProtocolPointer}; |
9 | use crate::{Char16, Event, Guid, Handle, Result, Status}; |
10 | #[cfg (feature = "alloc" )] |
11 | use ::alloc::vec::Vec; |
12 | use bitflags::bitflags; |
13 | use core::cell::UnsafeCell; |
14 | use core::ffi::c_void; |
15 | use core::fmt::{Debug, Formatter}; |
16 | use core::mem::{self, MaybeUninit}; |
17 | use core::ops::{Deref, DerefMut}; |
18 | use core::ptr::NonNull; |
19 | use core::{ptr, slice}; |
20 | |
21 | // TODO: this similar to `SyncUnsafeCell`. Once that is stabilized we |
22 | // can use it instead. |
23 | struct GlobalImageHandle { |
24 | handle: UnsafeCell<Option<Handle>>, |
25 | } |
26 | |
27 | // Safety: reads and writes are managed via `set_image_handle` and |
28 | // `BootServices::image_handle`. |
29 | unsafe impl Sync for GlobalImageHandle {} |
30 | |
31 | static IMAGE_HANDLE: GlobalImageHandle = GlobalImageHandle { |
32 | handle: UnsafeCell::new(None), |
33 | }; |
34 | |
35 | /// Size in bytes of a UEFI page. |
36 | /// |
37 | /// Note that this is not necessarily the processor's page size. The UEFI page |
38 | /// size is always 4 KiB. |
39 | pub const PAGE_SIZE: usize = 4096; |
40 | |
41 | /// Contains pointers to all of the boot services. |
42 | /// |
43 | /// # Accessing `BootServices` |
44 | /// |
45 | /// A reference to `BootServices` can only be accessed by calling [`SystemTable::boot_services`]. |
46 | /// |
47 | /// [`SystemTable::boot_services`]: crate::table::SystemTable::boot_services |
48 | /// |
49 | /// # Accessing protocols |
50 | /// |
51 | /// Protocols can be opened using several methods of `BootServices`. Most |
52 | /// commonly, [`open_protocol_exclusive`] should be used. This ensures that |
53 | /// nothing else can use the protocol until it is closed, and returns a |
54 | /// [`ScopedProtocol`] that takes care of closing the protocol when it is |
55 | /// dropped. |
56 | /// |
57 | /// Other methods for opening protocols: |
58 | /// |
59 | /// * [`open_protocol`] |
60 | /// * [`get_image_file_system`] |
61 | /// |
62 | /// For protocol definitions, see the [`proto`] module. |
63 | /// |
64 | /// [`proto`]: crate::proto |
65 | /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive |
66 | /// [`open_protocol`]: BootServices::open_protocol |
67 | /// [`get_image_file_system`]: BootServices::get_image_file_system |
68 | /// |
69 | /// ## Use of [`UnsafeCell`] for protocol references |
70 | /// |
71 | /// Some protocols require mutable access to themselves. For example, |
72 | /// most of the methods of the [`Output`] protocol take `&mut self`, |
73 | /// because the internal function pointers specified by UEFI for that |
74 | /// protocol take a mutable `*This` pointer. We don't want to directly |
75 | /// return a mutable reference to a protocol though because the lifetime |
76 | /// of the protocol is tied to `BootServices`. (That lifetime improves |
77 | /// safety by ensuring protocols aren't accessed after exiting boot |
78 | /// services.) If methods like [`open_protocol`] protocol took a mutable |
79 | /// reference to `BootServices` and returned a mutable reference to a |
80 | /// protocol it would prevent all other access to `BootServices` until |
81 | /// the protocol reference was dropped. To work around this, the |
82 | /// protocol reference is wrapped in an [`UnsafeCell`]. Callers can then |
83 | /// get a mutable reference to the protocol if needed. |
84 | /// |
85 | /// [`Output`]: crate::proto::console::text::Output |
86 | /// [`open_protocol`]: BootServices::open_protocol |
87 | #[repr (C)] |
88 | pub struct BootServices { |
89 | header: Header, |
90 | |
91 | // Task Priority services |
92 | raise_tpl: unsafe extern "efiapi" fn(new_tpl: Tpl) -> Tpl, |
93 | restore_tpl: unsafe extern "efiapi" fn(old_tpl: Tpl), |
94 | |
95 | // Memory allocation functions |
96 | allocate_pages: extern "efiapi" fn( |
97 | alloc_ty: u32, |
98 | mem_ty: MemoryType, |
99 | count: usize, |
100 | addr: &mut PhysicalAddress, |
101 | ) -> Status, |
102 | free_pages: extern "efiapi" fn(addr: PhysicalAddress, pages: usize) -> Status, |
103 | get_memory_map: unsafe extern "efiapi" fn( |
104 | size: &mut usize, |
105 | map: *mut MemoryDescriptor, |
106 | key: &mut MemoryMapKey, |
107 | desc_size: &mut usize, |
108 | desc_version: &mut u32, |
109 | ) -> Status, |
110 | allocate_pool: |
111 | extern "efiapi" fn(pool_type: MemoryType, size: usize, buffer: &mut *mut u8) -> Status, |
112 | free_pool: extern "efiapi" fn(buffer: *mut u8) -> Status, |
113 | |
114 | // Event & timer functions |
115 | create_event: unsafe extern "efiapi" fn( |
116 | ty: EventType, |
117 | notify_tpl: Tpl, |
118 | notify_func: Option<EventNotifyFn>, |
119 | notify_ctx: Option<NonNull<c_void>>, |
120 | out_event: *mut Event, |
121 | ) -> Status, |
122 | set_timer: unsafe extern "efiapi" fn(event: Event, ty: u32, trigger_time: u64) -> Status, |
123 | wait_for_event: unsafe extern "efiapi" fn( |
124 | number_of_events: usize, |
125 | events: *mut Event, |
126 | out_index: *mut usize, |
127 | ) -> Status, |
128 | signal_event: extern "efiapi" fn(event: Event) -> Status, |
129 | close_event: unsafe extern "efiapi" fn(event: Event) -> Status, |
130 | check_event: unsafe extern "efiapi" fn(event: Event) -> Status, |
131 | |
132 | // Protocol handlers |
133 | install_protocol_interface: unsafe extern "efiapi" fn( |
134 | handle: &mut Option<Handle>, |
135 | guid: &Guid, |
136 | interface_type: InterfaceType, |
137 | interface: *mut c_void, |
138 | ) -> Status, |
139 | reinstall_protocol_interface: unsafe extern "efiapi" fn( |
140 | handle: Handle, |
141 | protocol: &Guid, |
142 | old_interface: *mut c_void, |
143 | new_interface: *mut c_void, |
144 | ) -> Status, |
145 | uninstall_protocol_interface: unsafe extern "efiapi" fn( |
146 | handle: Handle, |
147 | protocol: &Guid, |
148 | interface: *mut c_void, |
149 | ) -> Status, |
150 | #[deprecated = "open_protocol and open_protocol_exclusive are better alternatives and available since EFI 1.10 (2002)" ] |
151 | handle_protocol: |
152 | extern "efiapi" fn(handle: Handle, proto: &Guid, out_proto: &mut *mut c_void) -> Status, |
153 | _reserved: usize, |
154 | register_protocol_notify: extern "efiapi" fn( |
155 | protocol: &Guid, |
156 | event: Event, |
157 | registration: *mut ProtocolSearchKey, |
158 | ) -> Status, |
159 | locate_handle: unsafe extern "efiapi" fn( |
160 | search_ty: i32, |
161 | proto: Option<&Guid>, |
162 | key: Option<ProtocolSearchKey>, |
163 | buf_sz: &mut usize, |
164 | buf: *mut MaybeUninit<Handle>, |
165 | ) -> Status, |
166 | locate_device_path: unsafe extern "efiapi" fn( |
167 | proto: &Guid, |
168 | device_path: &mut *const FfiDevicePath, |
169 | out_handle: &mut MaybeUninit<Handle>, |
170 | ) -> Status, |
171 | install_configuration_table: usize, |
172 | |
173 | // Image services |
174 | load_image: unsafe extern "efiapi" fn( |
175 | boot_policy: u8, |
176 | parent_image_handle: Handle, |
177 | device_path: *const FfiDevicePath, |
178 | source_buffer: *const u8, |
179 | source_size: usize, |
180 | image_handle: &mut MaybeUninit<Handle>, |
181 | ) -> Status, |
182 | start_image: unsafe extern "efiapi" fn( |
183 | image_handle: Handle, |
184 | exit_data_size: *mut usize, |
185 | exit_data: &mut *mut Char16, |
186 | ) -> Status, |
187 | exit: extern "efiapi" fn( |
188 | image_handle: Handle, |
189 | exit_status: Status, |
190 | exit_data_size: usize, |
191 | exit_data: *mut Char16, |
192 | ) -> !, |
193 | unload_image: extern "efiapi" fn(image_handle: Handle) -> Status, |
194 | exit_boot_services: |
195 | unsafe extern "efiapi" fn(image_handle: Handle, map_key: MemoryMapKey) -> Status, |
196 | |
197 | // Misc services |
198 | get_next_monotonic_count: usize, |
199 | stall: extern "efiapi" fn(microseconds: usize) -> Status, |
200 | set_watchdog_timer: unsafe extern "efiapi" fn( |
201 | timeout: usize, |
202 | watchdog_code: u64, |
203 | data_size: usize, |
204 | watchdog_data: *const u16, |
205 | ) -> Status, |
206 | |
207 | // Driver support services |
208 | connect_controller: unsafe extern "efiapi" fn( |
209 | controller: Handle, |
210 | driver_image: Option<Handle>, |
211 | remaining_device_path: *const FfiDevicePath, |
212 | recursive: bool, |
213 | ) -> Status, |
214 | disconnect_controller: unsafe extern "efiapi" fn( |
215 | controller: Handle, |
216 | driver_image: Option<Handle>, |
217 | child: Option<Handle>, |
218 | ) -> Status, |
219 | |
220 | // Protocol open / close services |
221 | open_protocol: extern "efiapi" fn( |
222 | handle: Handle, |
223 | protocol: &Guid, |
224 | interface: &mut *mut c_void, |
225 | agent_handle: Handle, |
226 | controller_handle: Option<Handle>, |
227 | attributes: u32, |
228 | ) -> Status, |
229 | close_protocol: extern "efiapi" fn( |
230 | handle: Handle, |
231 | protocol: &Guid, |
232 | agent_handle: Handle, |
233 | controller_handle: Option<Handle>, |
234 | ) -> Status, |
235 | open_protocol_information: usize, |
236 | |
237 | // Library services |
238 | protocols_per_handle: unsafe extern "efiapi" fn( |
239 | handle: Handle, |
240 | protocol_buffer: *mut *mut *const Guid, |
241 | protocol_buffer_count: *mut usize, |
242 | ) -> Status, |
243 | locate_handle_buffer: unsafe extern "efiapi" fn( |
244 | search_ty: i32, |
245 | proto: Option<&Guid>, |
246 | key: Option<ProtocolSearchKey>, |
247 | no_handles: &mut usize, |
248 | buf: &mut *mut Handle, |
249 | ) -> Status, |
250 | #[deprecated = "open_protocol and open_protocol_exclusive are better alternatives and available since EFI 1.10 (2002)" ] |
251 | locate_protocol: extern "efiapi" fn( |
252 | proto: &Guid, |
253 | registration: *mut c_void, |
254 | out_proto: &mut *mut c_void, |
255 | ) -> Status, |
256 | install_multiple_protocol_interfaces: usize, |
257 | uninstall_multiple_protocol_interfaces: usize, |
258 | |
259 | // CRC services |
260 | calculate_crc32: usize, |
261 | |
262 | // Misc services |
263 | copy_mem: unsafe extern "efiapi" fn(dest: *mut u8, src: *const u8, len: usize), |
264 | set_mem: unsafe extern "efiapi" fn(buffer: *mut u8, len: usize, value: u8), |
265 | |
266 | // New event functions (UEFI 2.0 or newer) |
267 | create_event_ex: unsafe extern "efiapi" fn( |
268 | ty: EventType, |
269 | notify_tpl: Tpl, |
270 | notify_fn: Option<EventNotifyFn>, |
271 | notify_ctx: Option<NonNull<c_void>>, |
272 | event_group: Option<NonNull<Guid>>, |
273 | out_event: *mut Event, |
274 | ) -> Status, |
275 | } |
276 | |
277 | impl BootServices { |
278 | /// Get the [`Handle`] of the currently-executing image. |
279 | pub fn image_handle(&self) -> Handle { |
280 | // Safety: |
281 | // |
282 | // `IMAGE_HANDLE` is only set by `set_image_handle`, see that |
283 | // documentation for more details. |
284 | // |
285 | // Additionally, `image_handle` takes a `&self` which ensures it |
286 | // can only be called while boot services are active. (After |
287 | // exiting boot services, the image handle should not be |
288 | // considered valid.) |
289 | unsafe { |
290 | IMAGE_HANDLE |
291 | .handle |
292 | .get() |
293 | .read() |
294 | .expect("set_image_handle has not been called" ) |
295 | } |
296 | } |
297 | |
298 | /// Update the global image [`Handle`]. |
299 | /// |
300 | /// This is called automatically in the `main` entry point as part |
301 | /// of [`uefi_macros::entry`]. It should not be called at any other |
302 | /// point in time, unless the executable does not use |
303 | /// [`uefi_macros::entry`], in which case it should be called once |
304 | /// before calling other `BootServices` functions. |
305 | /// |
306 | /// # Safety |
307 | /// |
308 | /// This function should only be called as described above. The |
309 | /// safety guarantees of [`BootServices::open_protocol_exclusive`] |
310 | /// rely on the global image handle being correct. |
311 | pub unsafe fn set_image_handle(&self, image_handle: Handle) { |
312 | // As with `image_handle`, `&self` isn't actually used, but it |
313 | // enforces that this function is only called while boot |
314 | // services are active. |
315 | IMAGE_HANDLE.handle.get().write(Some(image_handle)); |
316 | } |
317 | |
318 | /// Raises a task's priority level and returns its previous level. |
319 | /// |
320 | /// The effect of calling `raise_tpl` with a `Tpl` that is below the current |
321 | /// one (which, sadly, cannot be queried) is undefined by the UEFI spec, |
322 | /// which also warns against remaining at high `Tpl`s for a long time. |
323 | /// |
324 | /// This function outputs an RAII guard that will automatically restore the |
325 | /// original `Tpl` when dropped. |
326 | /// |
327 | /// # Safety |
328 | /// |
329 | /// Raising a task's priority level can affect other running tasks and |
330 | /// critical processes run by UEFI. The highest priority level is the |
331 | /// most dangerous, since it disables interrupts. |
332 | #[must_use ] |
333 | pub unsafe fn raise_tpl(&self, tpl: Tpl) -> TplGuard<'_> { |
334 | TplGuard { |
335 | boot_services: self, |
336 | old_tpl: (self.raise_tpl)(tpl), |
337 | } |
338 | } |
339 | |
340 | /// Allocates memory pages from the system. |
341 | /// |
342 | /// UEFI OS loaders should allocate memory of the type `LoaderData`. An `u64` |
343 | /// is returned even on 32-bit platforms because some hardware configurations |
344 | /// like Intel PAE enable 64-bit physical addressing on a 32-bit processor. |
345 | /// |
346 | /// # Errors |
347 | /// |
348 | /// See section `EFI_BOOT_SERVICES.AllocatePages()` in the UEFI Specification for more details. |
349 | /// |
350 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
351 | /// * [`uefi::Status::INVALID_PARAMETER`] |
352 | /// * [`uefi::Status::NOT_FOUND`] |
353 | pub fn allocate_pages( |
354 | &self, |
355 | ty: AllocateType, |
356 | mem_ty: MemoryType, |
357 | count: usize, |
358 | ) -> Result<PhysicalAddress> { |
359 | let (ty, mut addr) = match ty { |
360 | AllocateType::AnyPages => (0, 0), |
361 | AllocateType::MaxAddress(addr) => (1, addr), |
362 | AllocateType::Address(addr) => (2, addr), |
363 | }; |
364 | (self.allocate_pages)(ty, mem_ty, count, &mut addr).into_with_val(|| addr) |
365 | } |
366 | |
367 | /// Frees memory pages allocated by UEFI. |
368 | /// |
369 | /// # Errors |
370 | /// |
371 | /// See section `EFI_BOOT_SERVICES.FreePages()` in the UEFI Specification for more details. |
372 | /// |
373 | /// * [`uefi::Status::NOT_FOUND`] |
374 | /// * [`uefi::Status::INVALID_PARAMETER`] |
375 | pub fn free_pages(&self, addr: PhysicalAddress, count: usize) -> Result { |
376 | (self.free_pages)(addr, count).into() |
377 | } |
378 | |
379 | /// Returns struct which contains the size of a single memory descriptor |
380 | /// as well as the size of the current memory map. |
381 | /// |
382 | /// Note that the size of the memory map can increase any time an allocation happens, |
383 | /// so when creating a buffer to put the memory map into, it's recommended to allocate a few extra |
384 | /// elements worth of space above the size of the current memory map. |
385 | #[must_use ] |
386 | pub fn memory_map_size(&self) -> MemoryMapSize { |
387 | let mut map_size = 0; |
388 | let mut map_key = MemoryMapKey(0); |
389 | let mut entry_size = 0; |
390 | let mut entry_version = 0; |
391 | |
392 | let status = unsafe { |
393 | (self.get_memory_map)( |
394 | &mut map_size, |
395 | ptr::null_mut(), |
396 | &mut map_key, |
397 | &mut entry_size, |
398 | &mut entry_version, |
399 | ) |
400 | }; |
401 | assert_eq!(status, Status::BUFFER_TOO_SMALL); |
402 | |
403 | MemoryMapSize { |
404 | entry_size, |
405 | map_size, |
406 | } |
407 | } |
408 | |
409 | /// Retrieves the current memory map. |
410 | /// |
411 | /// The allocated buffer should be big enough to contain the memory map, |
412 | /// and a way of estimating how big it should be is by calling `memory_map_size`. |
413 | /// |
414 | /// The buffer must be aligned like a `MemoryDescriptor`. |
415 | /// |
416 | /// The returned key is a unique identifier of the current configuration of memory. |
417 | /// Any allocations or such will change the memory map's key. |
418 | /// |
419 | /// If you want to store the resulting memory map without having to keep |
420 | /// the buffer around, you can use `.copied().collect()` on the iterator. |
421 | /// |
422 | /// # Errors |
423 | /// |
424 | /// See section `EFI_BOOT_SERVICES.GetMemoryMap()` in the UEFI Specification for more details. |
425 | /// |
426 | /// * [`uefi::Status::BUFFER_TOO_SMALL`] |
427 | /// * [`uefi::Status::INVALID_PARAMETER`] |
428 | pub fn memory_map<'buf>(&self, buffer: &'buf mut [u8]) -> Result<MemoryMap<'buf>> { |
429 | let mut map_size = buffer.len(); |
430 | MemoryDescriptor::assert_aligned(buffer); |
431 | let map_buffer = buffer.as_mut_ptr().cast::<MemoryDescriptor>(); |
432 | let mut map_key = MemoryMapKey(0); |
433 | let mut entry_size = 0; |
434 | let mut entry_version = 0; |
435 | |
436 | assert_eq!( |
437 | (map_buffer as usize) % mem::align_of::<MemoryDescriptor>(), |
438 | 0, |
439 | "Memory map buffers must be aligned like a MemoryDescriptor" |
440 | ); |
441 | |
442 | unsafe { |
443 | (self.get_memory_map)( |
444 | &mut map_size, |
445 | map_buffer, |
446 | &mut map_key, |
447 | &mut entry_size, |
448 | &mut entry_version, |
449 | ) |
450 | } |
451 | .into_with_val(move || { |
452 | let len = map_size / entry_size; |
453 | |
454 | MemoryMap { |
455 | key: map_key, |
456 | buf: buffer, |
457 | entry_size, |
458 | len, |
459 | } |
460 | }) |
461 | } |
462 | |
463 | /// Allocates from a memory pool. The pointer will be 8-byte aligned. |
464 | /// |
465 | /// # Errors |
466 | /// |
467 | /// See section `EFI_BOOT_SERVICES.AllocatePool()` in the UEFI Specification for more details. |
468 | /// |
469 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
470 | /// * [`uefi::Status::INVALID_PARAMETER`] |
471 | pub fn allocate_pool(&self, mem_ty: MemoryType, size: usize) -> Result<*mut u8> { |
472 | let mut buffer = ptr::null_mut(); |
473 | (self.allocate_pool)(mem_ty, size, &mut buffer).into_with_val(|| buffer) |
474 | } |
475 | |
476 | /// Frees memory allocated from a pool. |
477 | /// |
478 | /// # Errors |
479 | /// |
480 | /// See section `EFI_BOOT_SERVICES.FreePool()` in the UEFI Specification for more details. |
481 | /// |
482 | /// * [`uefi::Status::INVALID_PARAMETER`] |
483 | pub fn free_pool(&self, addr: *mut u8) -> Result { |
484 | (self.free_pool)(addr).into() |
485 | } |
486 | |
487 | /// Creates an event |
488 | /// |
489 | /// This function creates a new event of the specified type and returns it. |
490 | /// |
491 | /// Events are created in a "waiting" state, and may switch to a "signaled" |
492 | /// state. If the event type has flag `NotifySignal` set, this will result in |
493 | /// a callback for the event being immediately enqueued at the `notify_tpl` |
494 | /// priority level. If the event type has flag `NotifyWait`, the notification |
495 | /// will be delivered next time `wait_for_event` or `check_event` is called. |
496 | /// In both cases, a `notify_fn` callback must be specified. |
497 | /// |
498 | /// # Safety |
499 | /// |
500 | /// This function is unsafe because callbacks must handle exit from boot |
501 | /// services correctly. |
502 | /// |
503 | /// # Errors |
504 | /// |
505 | /// See section `EFI_BOOT_SERVICES.CreateEvent()` in the UEFI Specification for more details. |
506 | /// |
507 | /// * [`uefi::Status::INVALID_PARAMETER`] |
508 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
509 | pub unsafe fn create_event( |
510 | &self, |
511 | event_ty: EventType, |
512 | notify_tpl: Tpl, |
513 | notify_fn: Option<EventNotifyFn>, |
514 | notify_ctx: Option<NonNull<c_void>>, |
515 | ) -> Result<Event> { |
516 | // Prepare storage for the output Event |
517 | let mut event = MaybeUninit::<Event>::uninit(); |
518 | |
519 | // Now we're ready to call UEFI |
520 | (self.create_event)( |
521 | event_ty, |
522 | notify_tpl, |
523 | notify_fn, |
524 | notify_ctx, |
525 | event.as_mut_ptr(), |
526 | ) |
527 | .into_with_val(|| event.assume_init()) |
528 | } |
529 | |
530 | /// Creates a new `Event` of type `event_type`. The event's notification function, context, |
531 | /// and task priority are specified by `notify_fn`, `notify_ctx`, and `notify_tpl`, respectively. |
532 | /// The `Event` will be added to the group of `Event`s identified by `event_group`. |
533 | /// |
534 | /// If no group is specified by `event_group`, this function behaves as if the same parameters |
535 | /// had been passed to `create_event()`. |
536 | /// |
537 | /// Event groups are collections of events identified by a shared `Guid` where, when one member |
538 | /// event is signaled, all other events are signaled and their individual notification actions |
539 | /// are taken. All events are guaranteed to be signaled before the first notification action is |
540 | /// taken. All notification functions will be executed in the order specified by their `Tpl`. |
541 | /// |
542 | /// A single event can only be part of a single event group. An event may be removed from an |
543 | /// event group by using `close_event()`. |
544 | /// |
545 | /// The `EventType` of an event uses the same values as `create_event()`, except that |
546 | /// `EventType::SIGNAL_EXIT_BOOT_SERVICES` and `EventType::SIGNAL_VIRTUAL_ADDRESS_CHANGE` |
547 | /// are not valid. |
548 | /// |
549 | /// If `event_type` has `EventType::NOTIFY_SIGNAL` or `EventType::NOTIFY_WAIT`, then `notify_fn` |
550 | /// mus be `Some` and `notify_tpl` must be a valid task priority level, otherwise these parameters |
551 | /// are ignored. |
552 | /// |
553 | /// More than one event of type `EventType::TIMER` may be part of a single event group. However, |
554 | /// there is no mechanism for determining which of the timers was signaled. |
555 | /// |
556 | /// This operation is only supported starting with UEFI 2.0; earlier |
557 | /// versions will fail with [`Status::UNSUPPORTED`]. |
558 | /// |
559 | /// # Safety |
560 | /// |
561 | /// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable. |
562 | /// |
563 | /// # Errors |
564 | /// |
565 | /// See section `EFI_BOOT_SERVICES.CreateEventEx()` in the UEFI Specification for more details. |
566 | /// |
567 | /// * [`uefi::Status::INVALID_PARAMETER`] |
568 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
569 | pub unsafe fn create_event_ex( |
570 | &self, |
571 | event_type: EventType, |
572 | notify_tpl: Tpl, |
573 | notify_fn: Option<EventNotifyFn>, |
574 | notify_ctx: Option<NonNull<c_void>>, |
575 | event_group: Option<NonNull<Guid>>, |
576 | ) -> Result<Event> { |
577 | if self.header.revision < Revision::EFI_2_00 { |
578 | return Err(Status::UNSUPPORTED.into()); |
579 | } |
580 | |
581 | let mut event = MaybeUninit::<Event>::uninit(); |
582 | |
583 | (self.create_event_ex)( |
584 | event_type, |
585 | notify_tpl, |
586 | notify_fn, |
587 | notify_ctx, |
588 | event_group, |
589 | event.as_mut_ptr(), |
590 | ) |
591 | .into_with_val(|| event.assume_init()) |
592 | } |
593 | |
594 | /// Sets the trigger for `EventType::TIMER` event. |
595 | /// |
596 | /// # Errors |
597 | /// |
598 | /// See section `EFI_BOOT_SERVICES.SetTimer()` in the UEFI Specification for more details. |
599 | /// |
600 | /// * [`uefi::Status::INVALID_PARAMETER`] |
601 | pub fn set_timer(&self, event: &Event, trigger_time: TimerTrigger) -> Result { |
602 | let (ty, time) = match trigger_time { |
603 | TimerTrigger::Cancel => (0, 0), |
604 | TimerTrigger::Periodic(hundreds_ns) => (1, hundreds_ns), |
605 | TimerTrigger::Relative(hundreds_ns) => (2, hundreds_ns), |
606 | }; |
607 | unsafe { (self.set_timer)(event.unsafe_clone(), ty, time) }.into() |
608 | } |
609 | |
610 | /// Stops execution until an event is signaled. |
611 | /// |
612 | /// This function must be called at priority level `Tpl::APPLICATION`. If an |
613 | /// attempt is made to call it at any other priority level, an `Unsupported` |
614 | /// error is returned. |
615 | /// |
616 | /// The input `Event` slice is repeatedly iterated from first to last until |
617 | /// an event is signaled or an error is detected. The following checks are |
618 | /// performed on each event: |
619 | /// |
620 | /// * If an event is of type `NotifySignal`, then an `InvalidParameter` |
621 | /// error is returned with the index of the event that caused the failure. |
622 | /// * If an event is in the signaled state, the signaled state is cleared |
623 | /// and the index of the event that was signaled is returned. |
624 | /// * If an event is not in the signaled state but does have a notification |
625 | /// function, the notification function is queued at the event's |
626 | /// notification task priority level. If the execution of the event's |
627 | /// notification function causes the event to be signaled, then the |
628 | /// signaled state is cleared and the index of the event that was signaled |
629 | /// is returned. |
630 | /// |
631 | /// To wait for a specified time, a timer event must be included in the |
632 | /// Event slice. |
633 | /// |
634 | /// To check if an event is signaled without waiting, an already signaled |
635 | /// event can be used as the last event in the slice being checked, or the |
636 | /// check_event() interface may be used. |
637 | /// |
638 | /// # Errors |
639 | /// |
640 | /// See section `EFI_BOOT_SERVICES.WaitForEvent()` in the UEFI Specification for more details. |
641 | /// |
642 | /// * [`uefi::Status::INVALID_PARAMETER`] |
643 | /// * [`uefi::Status::UNSUPPORTED`] |
644 | pub fn wait_for_event(&self, events: &mut [Event]) -> Result<usize, Option<usize>> { |
645 | let (number_of_events, events) = (events.len(), events.as_mut_ptr()); |
646 | let mut index = MaybeUninit::<usize>::uninit(); |
647 | unsafe { (self.wait_for_event)(number_of_events, events, index.as_mut_ptr()) }.into_with( |
648 | || unsafe { index.assume_init() }, |
649 | |s| { |
650 | if s == Status::INVALID_PARAMETER { |
651 | unsafe { Some(index.assume_init()) } |
652 | } else { |
653 | None |
654 | } |
655 | }, |
656 | ) |
657 | } |
658 | |
659 | /// Place 'event' in the signaled stated. If 'event' is already in the signaled state, |
660 | /// then nothing further occurs and `Status::SUCCESS` is returned. If `event` is of type |
661 | /// `EventType::NOTIFY_SIGNAL`, then the event's notification function is scheduled to |
662 | /// be invoked at the event's notification task priority level. |
663 | /// |
664 | /// This function may be invoked from any task priority level. |
665 | /// |
666 | /// If `event` is part of an event group, then all of the events in the event group are |
667 | /// also signaled and their notification functions are scheduled. |
668 | /// |
669 | /// When signaling an event group, it is possible to create an event in the group, signal |
670 | /// it, and then close the event to remove it from the group. |
671 | /// |
672 | /// # Errors |
673 | /// |
674 | /// See section `EFI_BOOT_SERVICES.SignalEvent()` in the UEFI Specification for more details. |
675 | /// |
676 | /// Currently, (as of UEFI Spec v2.9) this only returns `EFI_SUCCESS`. |
677 | pub fn signal_event(&self, event: &Event) -> Result { |
678 | // Safety: cloning this event should be safe, as we're directly passing it to firmware |
679 | // and not keeping the clone around. |
680 | unsafe { (self.signal_event)(event.unsafe_clone()).into() } |
681 | } |
682 | |
683 | /// Removes `event` from any event group to which it belongs and closes it. If `event` was |
684 | /// registered with `register_protocol_notify()`, then the corresponding registration will |
685 | /// be removed. It is safe to call this function within the corresponding notify function. |
686 | /// |
687 | /// # Errors |
688 | /// |
689 | /// See section `EFI_BOOT_SERVICES.CloseEvent()` in the UEFI Specification for more details. |
690 | /// |
691 | /// Note: The UEFI Specification v2.9 states that this may only return `EFI_SUCCESS`, but, |
692 | /// at least for application based on EDK2 (such as OVMF), it may also return `EFI_INVALID_PARAMETER`. |
693 | /// To be safe, ensure that error codes are handled properly. |
694 | /// |
695 | /// * [`uefi::Status::INVALID_PARAMETER`] |
696 | pub fn close_event(&self, event: Event) -> Result { |
697 | unsafe { (self.close_event)(event).into() } |
698 | } |
699 | |
700 | /// Checks to see if an event is signaled, without blocking execution to wait for it. |
701 | /// |
702 | /// The returned value will be `true` if the event is in the signaled state, |
703 | /// otherwise `false` is returned. |
704 | /// |
705 | /// # Errors |
706 | /// |
707 | /// See section `EFI_BOOT_SERVICES.CheckEvent()` in the UEFI Specification for more details. |
708 | /// |
709 | /// Note: Instead of returning the `EFI_NOT_READY` error, as listed in the UEFI |
710 | /// Specification, this function will return `false`. |
711 | /// |
712 | /// * [`uefi::Status::INVALID_PARAMETER`] |
713 | pub fn check_event(&self, event: Event) -> Result<bool> { |
714 | let status = unsafe { (self.check_event)(event) }; |
715 | match status { |
716 | Status::SUCCESS => Ok(true), |
717 | Status::NOT_READY => Ok(false), |
718 | _ => Err(status.into()), |
719 | } |
720 | } |
721 | |
722 | /// Installs a protocol interface on a device handle. If the inner `Option` in `handle` is `None`, |
723 | /// one will be created and added to the list of handles in the system and then returned. |
724 | /// |
725 | /// When a protocol interface is installed, firmware will call all functions that have registered |
726 | /// to wait for that interface to be installed. |
727 | /// |
728 | /// # Safety |
729 | /// |
730 | /// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`. |
731 | /// |
732 | /// # Errors |
733 | /// |
734 | /// See section `EFI_BOOT_SERVICES.InstallProtocolInterface()` in the UEFI Specification for |
735 | /// more details. |
736 | /// |
737 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
738 | /// * [`uefi::Status::INVALID_PARAMETER`] |
739 | pub unsafe fn install_protocol_interface( |
740 | &self, |
741 | mut handle: Option<Handle>, |
742 | protocol: &Guid, |
743 | interface: *mut c_void, |
744 | ) -> Result<Handle> { |
745 | ((self.install_protocol_interface)( |
746 | &mut handle, |
747 | protocol, |
748 | InterfaceType::NATIVE_INTERFACE, |
749 | interface, |
750 | )) |
751 | // this `unwrapped_unchecked` is safe, `handle` is guaranteed to be Some() if this call is |
752 | // successful |
753 | .into_with_val(|| handle.unwrap_unchecked()) |
754 | } |
755 | |
756 | /// Reinstalls a protocol interface on a device handle. `old_interface` is replaced with `new_interface`. |
757 | /// These interfaces may be the same, in which case the registered protocol notifies occur for the handle |
758 | /// without replacing the interface. |
759 | /// |
760 | /// As with `install_protocol_interface`, any process that has registered to wait for the installation of |
761 | /// the interface is notified. |
762 | /// |
763 | /// # Safety |
764 | /// |
765 | /// The caller is responsible for ensuring that there are no references to the `old_interface` that is being |
766 | /// removed. |
767 | /// |
768 | /// # Errors |
769 | /// |
770 | /// See section `EFI_BOOT_SERVICES.ReinstallProtocolInterface()` in the UEFI Specification for more details. |
771 | /// |
772 | /// * [`uefi::Status::NOT_FOUND`] |
773 | /// * [`uefi::Status::ACCESS_DENIED`] |
774 | /// * [`uefi::Status::INVALID_PARAMETER`] |
775 | pub unsafe fn reinstall_protocol_interface( |
776 | &self, |
777 | handle: Handle, |
778 | protocol: &Guid, |
779 | old_interface: *mut c_void, |
780 | new_interface: *mut c_void, |
781 | ) -> Result<()> { |
782 | (self.reinstall_protocol_interface)(handle, protocol, old_interface, new_interface).into() |
783 | } |
784 | |
785 | /// Removes a protocol interface from a device handle. |
786 | /// |
787 | /// # Safety |
788 | /// |
789 | /// The caller is responsible for ensuring that there are no references to a protocol interface |
790 | /// that has been removed. Some protocols may not be able to be removed as there is no information |
791 | /// available regarding the references. This includes Console I/O, Block I/O, Disk I/o, and handles |
792 | /// to device protocols. |
793 | /// |
794 | /// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`. |
795 | /// |
796 | /// # Errors |
797 | /// |
798 | /// See section `EFI_BOOT_SERVICES.UninstallProtocolInterface()` in the UEFI Specification for |
799 | /// more details. |
800 | /// |
801 | /// * [`uefi::Status::NOT_FOUND`] |
802 | /// * [`uefi::Status::ACCESS_DENIED`] |
803 | /// * [`uefi::Status::INVALID_PARAMETER`] |
804 | pub unsafe fn uninstall_protocol_interface( |
805 | &self, |
806 | handle: Handle, |
807 | protocol: &Guid, |
808 | interface: *mut c_void, |
809 | ) -> Result<()> { |
810 | (self.uninstall_protocol_interface)(handle, protocol, interface).into() |
811 | } |
812 | |
813 | /// Registers `event` to be signalled whenever a protocol interface is registered for |
814 | /// `protocol` by `install_protocol_interface()` or `reinstall_protocol_interface()`. |
815 | /// |
816 | /// Once `event` has been signalled, `BootServices::locate_handle()` can be used to identify |
817 | /// the newly (re)installed handles that support `protocol`. The returned `SearchKey` on success |
818 | /// corresponds to the `search_key` parameter in `locate_handle()`. |
819 | /// |
820 | /// Events can be unregistered from protocol interface notification by calling `close_event()`. |
821 | /// |
822 | /// # Errors |
823 | /// |
824 | /// See section `EFI_BOOT_SERVICES.RegisterProtocolNotify()` in the UEFI Specification for |
825 | /// more details. |
826 | /// |
827 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
828 | /// * [`uefi::Status::INVALID_PARAMETER`] |
829 | pub fn register_protocol_notify( |
830 | &self, |
831 | protocol: &Guid, |
832 | event: Event, |
833 | ) -> Result<(Event, SearchType)> { |
834 | let mut key: MaybeUninit<ProtocolSearchKey> = MaybeUninit::uninit(); |
835 | // Safety: we clone `event` a couple times, but there will be only one left once we return. |
836 | unsafe { (self.register_protocol_notify)(protocol, event.unsafe_clone(), key.as_mut_ptr()) } |
837 | // Safety: as long as this call is successful, `key` will be valid. |
838 | .into_with_val(|| unsafe { |
839 | ( |
840 | event.unsafe_clone(), |
841 | SearchType::ByRegisterNotify(key.assume_init()), |
842 | ) |
843 | }) |
844 | } |
845 | |
846 | /// Enumerates all handles installed on the system which match a certain query. |
847 | /// |
848 | /// You should first call this function with `None` for the output buffer, |
849 | /// in order to retrieve the length of the buffer you need to allocate. |
850 | /// |
851 | /// The next call will fill the buffer with the requested data. |
852 | /// |
853 | /// # Errors |
854 | /// |
855 | /// See section `EFI_BOOT_SERVICES.LocateHandle()` in the UEFI Specification for more details. |
856 | /// |
857 | /// * [`uefi::Status::NOT_FOUND`] |
858 | /// * [`uefi::Status::BUFFER_TOO_SMALL`] |
859 | /// * [`uefi::Status::INVALID_PARAMETER`] |
860 | pub fn locate_handle( |
861 | &self, |
862 | search_ty: SearchType, |
863 | output: Option<&mut [MaybeUninit<Handle>]>, |
864 | ) -> Result<usize> { |
865 | let handle_size = mem::size_of::<Handle>(); |
866 | |
867 | const NULL_BUFFER: *mut MaybeUninit<Handle> = ptr::null_mut(); |
868 | |
869 | let (mut buffer_size, buffer) = match output { |
870 | Some(buffer) => (buffer.len() * handle_size, buffer.as_mut_ptr()), |
871 | None => (0, NULL_BUFFER), |
872 | }; |
873 | |
874 | // Obtain the needed data from the parameters. |
875 | let (ty, guid, key) = match search_ty { |
876 | SearchType::AllHandles => (0, None, None), |
877 | SearchType::ByRegisterNotify(registration) => (1, None, Some(registration)), |
878 | SearchType::ByProtocol(guid) => (2, Some(guid), None), |
879 | }; |
880 | |
881 | let status = unsafe { (self.locate_handle)(ty, guid, key, &mut buffer_size, buffer) }; |
882 | |
883 | // Must convert the returned size (in bytes) to length (number of elements). |
884 | let buffer_len = buffer_size / handle_size; |
885 | |
886 | match (buffer, status) { |
887 | (NULL_BUFFER, Status::BUFFER_TOO_SMALL) => Ok(buffer_len), |
888 | (_, other_status) => other_status.into_with_val(|| buffer_len), |
889 | } |
890 | } |
891 | |
892 | /// Locates the handle to a device on the device path that supports the specified protocol. |
893 | /// |
894 | /// The `device_path` is updated to point at the remaining part of the [`DevicePath`] after |
895 | /// the part that matched the protocol. For example, it can be used with a device path |
896 | /// that contains a file path to strip off the file system portion of the device path, |
897 | /// leaving the file path and handle to the file system driver needed to access the file. |
898 | /// |
899 | /// If the first node of `device_path` matches the |
900 | /// protocol, the `device_path` is advanced to the device path terminator node. If `device_path` |
901 | /// is a multi-instance device path, the function will operate on the first instance. |
902 | /// |
903 | /// # Errors |
904 | /// |
905 | /// See section `EFI_BOOT_SERVICES.LocateDevicePath()` in the UEFI Specification for more details. |
906 | /// |
907 | /// * [`uefi::Status::NOT_FOUND`] |
908 | /// * [`uefi::Status::INVALID_PARAMETER`] |
909 | pub fn locate_device_path<P: ProtocolPointer + ?Sized>( |
910 | &self, |
911 | device_path: &mut &DevicePath, |
912 | ) -> Result<Handle> { |
913 | let mut handle = MaybeUninit::uninit(); |
914 | let mut device_path_ptr = device_path.as_ffi_ptr(); |
915 | unsafe { |
916 | (self.locate_device_path)(&P::GUID, &mut device_path_ptr, &mut handle).into_with_val( |
917 | || { |
918 | *device_path = DevicePath::from_ffi_ptr(device_path_ptr); |
919 | handle.assume_init() |
920 | }, |
921 | ) |
922 | } |
923 | } |
924 | |
925 | /// Find an arbitrary handle that supports a particular |
926 | /// [`Protocol`]. Returns [`NOT_FOUND`] if no handles support the |
927 | /// protocol. |
928 | /// |
929 | /// This method is a convenient wrapper around |
930 | /// [`BootServices::locate_handle_buffer`] for getting just one |
931 | /// handle. This is useful when you don't care which handle the |
932 | /// protocol is opened on. For example, [`DevicePathToText`] isn't |
933 | /// tied to a particular device, so only a single handle is expected |
934 | /// to exist. |
935 | /// |
936 | /// [`NOT_FOUND`]: Status::NOT_FOUND |
937 | /// [`DevicePathToText`]: uefi::proto::device_path::text::DevicePathToText |
938 | /// |
939 | /// # Example |
940 | /// |
941 | /// ``` |
942 | /// use uefi::proto::device_path::text::DevicePathToText; |
943 | /// use uefi::table::boot::{BootServices, OpenProtocolAttributes, OpenProtocolParams}; |
944 | /// use uefi::Handle; |
945 | /// # use uefi::Result; |
946 | /// |
947 | /// # fn get_fake_val<T>() -> T { todo!() } |
948 | /// # fn test() -> Result { |
949 | /// # let boot_services: &BootServices = get_fake_val(); |
950 | /// # let image_handle: Handle = get_fake_val(); |
951 | /// let handle = boot_services.get_handle_for_protocol::<DevicePathToText>()?; |
952 | /// let device_path_to_text = boot_services.open_protocol_exclusive::<DevicePathToText>(handle)?; |
953 | /// # Ok(()) |
954 | /// # } |
955 | /// ``` |
956 | /// |
957 | /// # Errors |
958 | /// |
959 | /// Returns [`NOT_FOUND`] if no handles support the requested protocol. |
960 | pub fn get_handle_for_protocol<P: ProtocolPointer + ?Sized>(&self) -> Result<Handle> { |
961 | // Delegate to a non-generic function to potentially reduce code size. |
962 | self.get_handle_for_protocol_impl(&P::GUID) |
963 | } |
964 | |
965 | fn get_handle_for_protocol_impl(&self, guid: &Guid) -> Result<Handle> { |
966 | self.locate_handle_buffer(SearchType::ByProtocol(guid))? |
967 | .first() |
968 | .cloned() |
969 | .ok_or_else(|| Status::NOT_FOUND.into()) |
970 | } |
971 | |
972 | /// Load an EFI image into memory and return a [`Handle`] to the image. |
973 | /// |
974 | /// There are two ways to load the image: by copying raw image data |
975 | /// from a source buffer, or by loading the image via the |
976 | /// [`SimpleFileSystem`] protocol. See [`LoadImageSource`] for more |
977 | /// details of the `source` parameter. |
978 | /// |
979 | /// The `parent_image_handle` is used to initialize the |
980 | /// `parent_handle` field of the [`LoadedImage`] protocol for the |
981 | /// image. |
982 | /// |
983 | /// If the image is successfully loaded, a [`Handle`] supporting the |
984 | /// [`LoadedImage`] and `LoadedImageDevicePath` protocols is |
985 | /// returned. The image can be started with [`start_image`] or |
986 | /// unloaded with [`unload_image`]. |
987 | /// |
988 | /// [`start_image`]: BootServices::start_image |
989 | /// [`unload_image`]: BootServices::unload_image |
990 | /// |
991 | /// # Errors |
992 | /// |
993 | /// See section `EFI_BOOT_SERVICES.LoadImage()` in the UEFI Specification for more details. |
994 | /// |
995 | /// * [`uefi::Status::NOT_FOUND`] |
996 | /// * [`uefi::Status::INVALID_PARAMETER`] |
997 | /// * [`uefi::Status::UNSUPPORTED`] |
998 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
999 | /// * [`uefi::Status::LOAD_ERROR`] |
1000 | /// * [`uefi::Status::DEVICE_ERROR`] |
1001 | /// * [`uefi::Status::ACCESS_DENIED`] |
1002 | /// * [`uefi::Status::SECURITY_VIOLATION`] |
1003 | pub fn load_image( |
1004 | &self, |
1005 | parent_image_handle: Handle, |
1006 | source: LoadImageSource, |
1007 | ) -> uefi::Result<Handle> { |
1008 | let boot_policy; |
1009 | let device_path; |
1010 | let source_buffer; |
1011 | let source_size; |
1012 | match source { |
1013 | LoadImageSource::FromBuffer { buffer, file_path } => { |
1014 | // Boot policy is ignored when loading from source buffer. |
1015 | boot_policy = 0; |
1016 | |
1017 | device_path = file_path.map(|p| p.as_ffi_ptr()).unwrap_or(ptr::null()); |
1018 | source_buffer = buffer.as_ptr(); |
1019 | source_size = buffer.len(); |
1020 | } |
1021 | LoadImageSource::FromFilePath { |
1022 | file_path, |
1023 | from_boot_manager, |
1024 | } => { |
1025 | boot_policy = u8::from(from_boot_manager); |
1026 | device_path = file_path.as_ffi_ptr(); |
1027 | source_buffer = ptr::null(); |
1028 | source_size = 0; |
1029 | } |
1030 | }; |
1031 | |
1032 | let mut image_handle = MaybeUninit::uninit(); |
1033 | unsafe { |
1034 | (self.load_image)( |
1035 | boot_policy, |
1036 | parent_image_handle, |
1037 | device_path, |
1038 | source_buffer, |
1039 | source_size, |
1040 | &mut image_handle, |
1041 | ) |
1042 | .into_with_val(|| image_handle.assume_init()) |
1043 | } |
1044 | } |
1045 | |
1046 | /// Unload an EFI image. |
1047 | /// |
1048 | /// # Errors |
1049 | /// |
1050 | /// See section `EFI_BOOT_SERVICES.UnloadImage()` in the UEFI Specification for more details. |
1051 | /// |
1052 | /// As this function can return an error code from the unloaded image, any error type |
1053 | /// can be returned by this function. |
1054 | /// |
1055 | /// The following error codes can also be returned while unloading an image: |
1056 | /// |
1057 | /// * [`uefi::Status::UNSUPPORTED`] |
1058 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1059 | pub fn unload_image(&self, image_handle: Handle) -> Result { |
1060 | (self.unload_image)(image_handle).into() |
1061 | } |
1062 | |
1063 | /// Transfer control to a loaded image's entry point. |
1064 | /// |
1065 | /// # Errors |
1066 | /// |
1067 | /// See section `EFI_BOOT_SERVICES.StartImage()` in the UEFI Specification for more details. |
1068 | /// |
1069 | /// As this function can return an error code from the started image, any error type |
1070 | /// can be returned by this function. |
1071 | /// |
1072 | /// The following error code can also be returned while starting an image: |
1073 | /// |
1074 | /// * [`uefi::Status::UNSUPPORTED`] |
1075 | pub fn start_image(&self, image_handle: Handle) -> Result { |
1076 | unsafe { |
1077 | // TODO: implement returning exit data to the caller. |
1078 | let mut exit_data_size: usize = 0; |
1079 | let mut exit_data: *mut Char16 = ptr::null_mut(); |
1080 | (self.start_image)(image_handle, &mut exit_data_size, &mut exit_data).into() |
1081 | } |
1082 | } |
1083 | |
1084 | /// Exits the UEFI application and returns control to the UEFI component |
1085 | /// that started the UEFI application. |
1086 | /// |
1087 | /// # Safety |
1088 | /// |
1089 | /// This function is unsafe because it is up to the caller to ensure that |
1090 | /// all resources allocated by the application is freed before invoking |
1091 | /// exit and returning control to the UEFI component that started the UEFI |
1092 | /// application. |
1093 | pub unsafe fn exit( |
1094 | &self, |
1095 | image_handle: Handle, |
1096 | exit_status: Status, |
1097 | exit_data_size: usize, |
1098 | exit_data: *mut Char16, |
1099 | ) -> ! { |
1100 | (self.exit)(image_handle, exit_status, exit_data_size, exit_data) |
1101 | } |
1102 | |
1103 | /// Exits the UEFI boot services |
1104 | /// |
1105 | /// This unsafe method is meant to be an implementation detail of the safe |
1106 | /// `SystemTable<Boot>::exit_boot_services()` method, which is why it is not |
1107 | /// public. |
1108 | /// |
1109 | /// Everything that is explained in the documentation of the high-level |
1110 | /// `SystemTable<Boot>` method is also true here, except that this function |
1111 | /// is one-shot (no automatic retry) and does not prevent you from shooting |
1112 | /// yourself in the foot by calling invalid boot services after a failure. |
1113 | /// |
1114 | /// # Errors |
1115 | /// |
1116 | /// See section `EFI_BOOT_SERVICES.ExitBootServices()` in the UEFI Specification for more details. |
1117 | /// |
1118 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1119 | pub(super) unsafe fn exit_boot_services( |
1120 | &self, |
1121 | image: Handle, |
1122 | mmap_key: MemoryMapKey, |
1123 | ) -> Result { |
1124 | (self.exit_boot_services)(image, mmap_key).into() |
1125 | } |
1126 | |
1127 | /// Stalls the processor for an amount of time. |
1128 | /// |
1129 | /// The time is in microseconds. |
1130 | pub fn stall(&self, time: usize) { |
1131 | assert_eq!((self.stall)(time), Status::SUCCESS); |
1132 | } |
1133 | |
1134 | /// Set the watchdog timer. |
1135 | /// |
1136 | /// UEFI will start a 5-minute countdown after an UEFI image is loaded. |
1137 | /// The image must either successfully load an OS and call `ExitBootServices` |
1138 | /// in that time, or disable the watchdog. |
1139 | /// |
1140 | /// Otherwise, the firmware will log the event using the provided numeric |
1141 | /// code and data, then reset the system. |
1142 | /// |
1143 | /// This function allows you to change the watchdog timer's timeout to a |
1144 | /// certain amount of seconds or to disable the watchdog entirely. It also |
1145 | /// allows you to change what will be logged when the timer expires. |
1146 | /// |
1147 | /// The watchdog codes from 0 to 0xffff (65535) are reserved for internal |
1148 | /// firmware use. Higher values can be used freely by applications. |
1149 | /// |
1150 | /// If provided, the watchdog data must be a null-terminated string |
1151 | /// optionally followed by other binary data. |
1152 | /// |
1153 | /// # Errors |
1154 | /// |
1155 | /// See section `EFI_BOOT_SERVICES.SetWatchdogTimer()` in the UEFI Specification for more details. |
1156 | /// |
1157 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1158 | /// * [`uefi::Status::UNSUPPORTED`] |
1159 | /// * [`uefi::Status::DEVICE_ERROR`] |
1160 | pub fn set_watchdog_timer( |
1161 | &self, |
1162 | timeout: usize, |
1163 | watchdog_code: u64, |
1164 | data: Option<&mut [u16]>, |
1165 | ) -> Result { |
1166 | assert!( |
1167 | watchdog_code > 0xffff, |
1168 | "Invalid use of a reserved firmware watchdog code" |
1169 | ); |
1170 | |
1171 | let (data_len, data) = data |
1172 | .map(|d| { |
1173 | assert!( |
1174 | d.contains(&0), |
1175 | "Watchdog data must start with a null-terminated string" |
1176 | ); |
1177 | (d.len(), d.as_mut_ptr()) |
1178 | }) |
1179 | .unwrap_or((0, ptr::null_mut())); |
1180 | |
1181 | unsafe { (self.set_watchdog_timer)(timeout, watchdog_code, data_len, data) }.into() |
1182 | } |
1183 | |
1184 | /// Connect one or more drivers to a controller. |
1185 | /// |
1186 | /// Usually one disconnects and then reconnects certain drivers |
1187 | /// to make them rescan some state that changed, e.g. reconnecting |
1188 | /// a `BlockIO` handle after your app changed the partitions somehow. |
1189 | /// |
1190 | /// # Errors |
1191 | /// |
1192 | /// See section `EFI_BOOT_SERVICES.ConnectController()` in the UEFI Specification for more details. |
1193 | /// |
1194 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1195 | /// * [`uefi::Status::NOT_FOUND`] |
1196 | /// * [`uefi::Status::SECURITY_VIOLATION`] |
1197 | pub fn connect_controller( |
1198 | &self, |
1199 | controller: Handle, |
1200 | driver_image: Option<Handle>, |
1201 | remaining_device_path: Option<&DevicePath>, |
1202 | recursive: bool, |
1203 | ) -> Result { |
1204 | unsafe { |
1205 | (self.connect_controller)( |
1206 | controller, |
1207 | driver_image, |
1208 | remaining_device_path |
1209 | .map(|dp| dp.as_ffi_ptr()) |
1210 | .unwrap_or(ptr::null()), |
1211 | recursive, |
1212 | ) |
1213 | } |
1214 | .into_with_err(|_| ()) |
1215 | } |
1216 | |
1217 | /// Disconnect one or more drivers from a controller. |
1218 | /// |
1219 | /// See [`connect_controller`][Self::connect_controller]. |
1220 | /// |
1221 | /// # Errors |
1222 | /// |
1223 | /// See section `EFI_BOOT_SERVICES.DisconnectController()` in the UEFI Specification for more details. |
1224 | /// |
1225 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1226 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
1227 | /// * [`uefi::Status::DEVICE_ERROR`] |
1228 | pub fn disconnect_controller( |
1229 | &self, |
1230 | controller: Handle, |
1231 | driver_image: Option<Handle>, |
1232 | child: Option<Handle>, |
1233 | ) -> Result { |
1234 | unsafe { (self.disconnect_controller)(controller, driver_image, child) } |
1235 | .into_with_err(|_| ()) |
1236 | } |
1237 | |
1238 | /// Open a protocol interface for a handle. |
1239 | /// |
1240 | /// See also [`open_protocol_exclusive`], which provides a safe |
1241 | /// subset of this functionality. |
1242 | /// |
1243 | /// This function attempts to get the protocol implementation of a |
1244 | /// handle, based on the protocol GUID. It is recommended that all |
1245 | /// new drivers and applications use [`open_protocol_exclusive`] or |
1246 | /// [`open_protocol`]. |
1247 | /// |
1248 | /// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for |
1249 | /// details of the input parameters. |
1250 | /// |
1251 | /// If successful, a [`ScopedProtocol`] is returned that will |
1252 | /// automatically close the protocol interface when dropped. |
1253 | /// |
1254 | /// UEFI protocols are neither thread-safe nor reentrant, but the firmware |
1255 | /// provides no mechanism to protect against concurrent usage. Such |
1256 | /// protections must be implemented by user-level code, for example via a |
1257 | /// global `HashSet`. |
1258 | /// |
1259 | /// # Safety |
1260 | /// |
1261 | /// This function is unsafe because it can be used to open a |
1262 | /// protocol in ways that don't get tracked by the UEFI |
1263 | /// implementation. This could allow the protocol to be removed from |
1264 | /// a handle, or for the handle to be deleted entirely, while a |
1265 | /// reference to the protocol is still active. The caller is |
1266 | /// responsible for ensuring that the handle and protocol remain |
1267 | /// valid until the `ScopedProtocol` is dropped. |
1268 | /// |
1269 | /// [`open_protocol`]: BootServices::open_protocol |
1270 | /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive |
1271 | /// |
1272 | /// # Errors |
1273 | /// |
1274 | /// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. |
1275 | /// |
1276 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1277 | /// * [`uefi::Status::UNSUPPORTED`] |
1278 | /// * [`uefi::Status::ACCESS_DENIED`] |
1279 | /// * [`uefi::Status::ALREADY_STARTED`] |
1280 | pub unsafe fn open_protocol<P: ProtocolPointer + ?Sized>( |
1281 | &self, |
1282 | params: OpenProtocolParams, |
1283 | attributes: OpenProtocolAttributes, |
1284 | ) -> Result<ScopedProtocol<P>> { |
1285 | let mut interface = ptr::null_mut(); |
1286 | (self.open_protocol)( |
1287 | params.handle, |
1288 | &P::GUID, |
1289 | &mut interface, |
1290 | params.agent, |
1291 | params.controller, |
1292 | attributes as u32, |
1293 | ) |
1294 | .into_with_val(|| { |
1295 | let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell<P>; |
1296 | |
1297 | ScopedProtocol { |
1298 | interface: &*interface, |
1299 | open_params: params, |
1300 | boot_services: self, |
1301 | } |
1302 | }) |
1303 | } |
1304 | |
1305 | /// Open a protocol interface for a handle in exclusive mode. |
1306 | /// |
1307 | /// If successful, a [`ScopedProtocol`] is returned that will |
1308 | /// automatically close the protocol interface when dropped. |
1309 | /// |
1310 | /// # Errors |
1311 | /// |
1312 | /// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. |
1313 | /// |
1314 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1315 | /// * [`uefi::Status::UNSUPPORTED`] |
1316 | /// * [`uefi::Status::ACCESS_DENIED`] |
1317 | /// * [`uefi::Status::ALREADY_STARTED`] |
1318 | pub fn open_protocol_exclusive<P: ProtocolPointer + ?Sized>( |
1319 | &self, |
1320 | handle: Handle, |
1321 | ) -> Result<ScopedProtocol<P>> { |
1322 | // Safety: opening in exclusive mode with the correct agent |
1323 | // handle set ensures that the protocol cannot be modified or |
1324 | // removed while it is open, so this usage is safe. |
1325 | unsafe { |
1326 | self.open_protocol::<P>( |
1327 | OpenProtocolParams { |
1328 | handle, |
1329 | agent: self.image_handle(), |
1330 | controller: None, |
1331 | }, |
1332 | OpenProtocolAttributes::Exclusive, |
1333 | ) |
1334 | } |
1335 | } |
1336 | |
1337 | /// Test whether a handle supports a protocol. |
1338 | /// |
1339 | /// # Errors |
1340 | /// |
1341 | /// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. |
1342 | /// |
1343 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1344 | /// * [`uefi::Status::UNSUPPORTED`] |
1345 | /// * [`uefi::Status::ACCESS_DENIED`] |
1346 | /// * [`uefi::Status::ALREADY_STARTED`] |
1347 | pub fn test_protocol<P: ProtocolPointer + ?Sized>( |
1348 | &self, |
1349 | params: OpenProtocolParams, |
1350 | ) -> Result<()> { |
1351 | const TEST_PROTOCOL: u32 = 0x04; |
1352 | let mut interface = ptr::null_mut(); |
1353 | (self.open_protocol)( |
1354 | params.handle, |
1355 | &P::GUID, |
1356 | &mut interface, |
1357 | params.agent, |
1358 | params.controller, |
1359 | TEST_PROTOCOL, |
1360 | ) |
1361 | .into_with_val(|| ()) |
1362 | } |
1363 | |
1364 | /// Get the list of protocol interface [`Guids`][Guid] that are installed |
1365 | /// on a [`Handle`]. |
1366 | /// |
1367 | /// # Errors |
1368 | /// |
1369 | /// See section `EFI_BOOT_SERVICES.ProtocolsPerHandle()` in the UEFI Specification for more details. |
1370 | /// |
1371 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1372 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
1373 | pub fn protocols_per_handle(&self, handle: Handle) -> Result<ProtocolsPerHandle> { |
1374 | let mut protocols = ptr::null_mut(); |
1375 | let mut count = 0; |
1376 | |
1377 | let mut status = unsafe { (self.protocols_per_handle)(handle, &mut protocols, &mut count) }; |
1378 | |
1379 | if !status.is_error() { |
1380 | // Ensure that protocols isn't null, and that none of the GUIDs |
1381 | // returned are null. |
1382 | if protocols.is_null() { |
1383 | status = Status::OUT_OF_RESOURCES; |
1384 | } else { |
1385 | let protocols: &[*const Guid] = unsafe { slice::from_raw_parts(protocols, count) }; |
1386 | if protocols.iter().any(|ptr| ptr.is_null()) { |
1387 | status = Status::OUT_OF_RESOURCES; |
1388 | } |
1389 | } |
1390 | } |
1391 | |
1392 | status.into_with_val(|| ProtocolsPerHandle { |
1393 | boot_services: self, |
1394 | protocols: protocols.cast::<&Guid>(), |
1395 | count, |
1396 | }) |
1397 | } |
1398 | |
1399 | /// Returns an array of handles that support the requested protocol in a buffer allocated from |
1400 | /// pool. |
1401 | /// |
1402 | /// # Errors |
1403 | /// |
1404 | /// See section `EFI_BOOT_SERVICES.LocateHandleBuffer()` in the UEFI Specification for more details. |
1405 | /// |
1406 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1407 | /// * [`uefi::Status::NOT_FOUND`] |
1408 | /// * [`uefi::Status::OUT_OF_RESOURCES`] |
1409 | pub fn locate_handle_buffer(&self, search_ty: SearchType) -> Result<HandleBuffer> { |
1410 | let mut num_handles: usize = 0; |
1411 | let mut buffer: *mut Handle = ptr::null_mut(); |
1412 | |
1413 | // Obtain the needed data from the parameters. |
1414 | let (ty, guid, key) = match search_ty { |
1415 | SearchType::AllHandles => (0, None, None), |
1416 | SearchType::ByRegisterNotify(registration) => (1, None, Some(registration)), |
1417 | SearchType::ByProtocol(guid) => (2, Some(guid), None), |
1418 | }; |
1419 | |
1420 | unsafe { (self.locate_handle_buffer)(ty, guid, key, &mut num_handles, &mut buffer) } |
1421 | .into_with_val(|| HandleBuffer { |
1422 | boot_services: self, |
1423 | count: num_handles, |
1424 | buffer, |
1425 | }) |
1426 | } |
1427 | |
1428 | /// Copies memory from source to destination. The buffers can overlap. |
1429 | /// |
1430 | /// # Safety |
1431 | /// |
1432 | /// This function is unsafe as it can be used to violate most safety |
1433 | /// invariants of the Rust type system. |
1434 | pub unsafe fn memmove(&self, dest: *mut u8, src: *const u8, size: usize) { |
1435 | (self.copy_mem)(dest, src, size); |
1436 | } |
1437 | |
1438 | /// Sets a buffer to a certain value. |
1439 | /// |
1440 | /// # Safety |
1441 | /// |
1442 | /// This function is unsafe as it can be used to violate most safety |
1443 | /// invariants of the Rust type system. |
1444 | pub unsafe fn set_mem(&self, buffer: *mut u8, size: usize, value: u8) { |
1445 | (self.set_mem)(buffer, size, value); |
1446 | } |
1447 | } |
1448 | |
1449 | #[cfg (feature = "alloc" )] |
1450 | impl BootServices { |
1451 | /// Returns all the handles implementing a certain protocol. |
1452 | /// |
1453 | /// # Errors |
1454 | /// |
1455 | /// All errors come from calls to [`locate_handle`]. |
1456 | /// |
1457 | /// [`locate_handle`]: Self::locate_handle |
1458 | pub fn find_handles<P: ProtocolPointer + ?Sized>(&self) -> Result<Vec<Handle>> { |
1459 | // Search by protocol. |
1460 | let search_type = SearchType::from_proto::<P>(); |
1461 | |
1462 | // Determine how much we need to allocate. |
1463 | let buffer_size = self.locate_handle(search_type, None)?; |
1464 | |
1465 | // Allocate a large enough buffer without pointless initialization. |
1466 | let mut handles = Vec::with_capacity(buffer_size); |
1467 | let buffer = handles.spare_capacity_mut(); |
1468 | |
1469 | // Perform the search. |
1470 | let buffer_size = self.locate_handle(search_type, Some(buffer))?; |
1471 | |
1472 | // Mark the returned number of elements as initialized. |
1473 | unsafe { |
1474 | handles.set_len(buffer_size); |
1475 | } |
1476 | |
1477 | // Emit output, with warnings |
1478 | Ok(handles) |
1479 | } |
1480 | |
1481 | /// Retrieves the `SimpleFileSystem` protocol associated with |
1482 | /// the device the given image was loaded from. |
1483 | /// |
1484 | /// You can retrieve the SFS protocol associated with the boot partition |
1485 | /// by passing the image handle received by the UEFI entry point to this function. |
1486 | /// |
1487 | /// # Errors |
1488 | /// |
1489 | /// This function can return errors from [`open_protocol_exclusive`] and [`locate_device_path`]. |
1490 | /// See those functions for more details. |
1491 | /// |
1492 | /// [`open_protocol_exclusive`]: Self::open_protocol_exclusive |
1493 | /// [`locate_device_path`]: Self::locate_device_path |
1494 | /// |
1495 | /// * [`uefi::Status::INVALID_PARAMETER`] |
1496 | /// * [`uefi::Status::UNSUPPORTED`] |
1497 | /// * [`uefi::Status::ACCESS_DENIED`] |
1498 | /// * [`uefi::Status::ALREADY_STARTED`] |
1499 | /// * [`uefi::Status::NOT_FOUND`] |
1500 | pub fn get_image_file_system( |
1501 | &self, |
1502 | image_handle: Handle, |
1503 | ) -> Result<ScopedProtocol<SimpleFileSystem>> { |
1504 | let loaded_image = self.open_protocol_exclusive::<LoadedImage>(image_handle)?; |
1505 | |
1506 | let device_path = self.open_protocol_exclusive::<DevicePath>(loaded_image.device())?; |
1507 | |
1508 | let device_handle = self.locate_device_path::<SimpleFileSystem>(&mut &*device_path)?; |
1509 | |
1510 | self.open_protocol_exclusive(device_handle) |
1511 | } |
1512 | } |
1513 | |
1514 | impl super::Table for BootServices { |
1515 | const SIGNATURE: u64 = 0x5652_4553_544f_4f42; |
1516 | } |
1517 | |
1518 | impl Debug for BootServices { |
1519 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { |
1520 | #[allow (deprecated)] |
1521 | f.debug_struct("BootServices" ) |
1522 | .field("header" , &self.header) |
1523 | .field("raise_tpl (fn ptr)" , &(self.raise_tpl as *const usize)) |
1524 | .field("restore_tpl (fn ptr)" , &(self.restore_tpl as *const usize)) |
1525 | .field( |
1526 | "allocate_pages (fn ptr)" , |
1527 | &(self.allocate_pages as *const usize), |
1528 | ) |
1529 | .field("free_pages (fn ptr)" , &(self.free_pages as *const usize)) |
1530 | .field( |
1531 | "get_memory_map (fn ptr)" , |
1532 | &(self.get_memory_map as *const usize), |
1533 | ) |
1534 | .field( |
1535 | "allocate_pool (fn ptr)" , |
1536 | &(self.allocate_pool as *const usize), |
1537 | ) |
1538 | .field("free_pool (fn ptr)" , &(self.free_pool as *const usize)) |
1539 | .field( |
1540 | "create_event (fn ptr)" , |
1541 | &(self.create_event as *const usize), |
1542 | ) |
1543 | .field("set_timer (fn ptr)" , &(self.set_timer as *const usize)) |
1544 | .field( |
1545 | "wait_for_event (fn ptr)" , |
1546 | &(self.wait_for_event as *const usize), |
1547 | ) |
1548 | .field("signal_event" , &(self.signal_event as *const usize)) |
1549 | .field("close_event" , &(self.close_event as *const usize)) |
1550 | .field("check_event" , &(self.check_event as *const usize)) |
1551 | .field( |
1552 | "install_protocol_interface" , |
1553 | &(self.install_protocol_interface as *const usize), |
1554 | ) |
1555 | .field( |
1556 | "reinstall_protocol_interface" , |
1557 | &(self.reinstall_protocol_interface as *const usize), |
1558 | ) |
1559 | .field( |
1560 | "uninstall_protocol_interface" , |
1561 | &(self.uninstall_protocol_interface as *const usize), |
1562 | ) |
1563 | .field( |
1564 | "handle_protocol (fn ptr)" , |
1565 | &(self.handle_protocol as *const usize), |
1566 | ) |
1567 | .field( |
1568 | "register_protocol_notify" , |
1569 | &(self.register_protocol_notify as *const usize), |
1570 | ) |
1571 | .field( |
1572 | "locate_handle (fn ptr)" , |
1573 | &(self.locate_handle as *const usize), |
1574 | ) |
1575 | .field( |
1576 | "locate_device_path (fn ptr)" , |
1577 | &(self.locate_device_path as *const usize), |
1578 | ) |
1579 | .field( |
1580 | "install_configuration_table" , |
1581 | &(self.install_configuration_table as *const usize), |
1582 | ) |
1583 | .field("load_image (fn ptr)" , &(self.load_image as *const usize)) |
1584 | .field("start_image (fn ptr)" , &(self.start_image as *const usize)) |
1585 | .field("exit" , &(self.exit as *const usize)) |
1586 | .field( |
1587 | "unload_image (fn ptr)" , |
1588 | &(self.unload_image as *const usize), |
1589 | ) |
1590 | .field( |
1591 | "exit_boot_services (fn ptr)" , |
1592 | &(self.exit_boot_services as *const usize), |
1593 | ) |
1594 | .field( |
1595 | "get_next_monotonic_count" , |
1596 | &(self.get_next_monotonic_count as *const usize), |
1597 | ) |
1598 | .field("stall (fn ptr)" , &(self.stall as *const usize)) |
1599 | .field( |
1600 | "set_watchdog_timer (fn ptr)" , |
1601 | &(self.set_watchdog_timer as *const usize), |
1602 | ) |
1603 | .field( |
1604 | "connect_controller" , |
1605 | &(self.connect_controller as *const usize), |
1606 | ) |
1607 | .field( |
1608 | "disconnect_controller" , |
1609 | &(self.disconnect_controller as *const usize), |
1610 | ) |
1611 | .field("open_protocol" , &(self.open_protocol as *const usize)) |
1612 | .field("close_protocol" , &(self.close_protocol as *const usize)) |
1613 | .field( |
1614 | "open_protocol_information" , |
1615 | &(self.open_protocol_information as *const usize), |
1616 | ) |
1617 | .field( |
1618 | "protocols_per_handle" , |
1619 | &(self.protocols_per_handle as *const usize), |
1620 | ) |
1621 | .field( |
1622 | "locate_handle_buffer" , |
1623 | &(self.locate_handle_buffer as *const usize), |
1624 | ) |
1625 | .field( |
1626 | "locate_protocol (fn ptr)" , |
1627 | &(self.locate_protocol as *const usize), |
1628 | ) |
1629 | .field( |
1630 | "install_multiple_protocol_interfaces" , |
1631 | &(self.install_multiple_protocol_interfaces as *const usize), |
1632 | ) |
1633 | .field( |
1634 | "uninstall_multiple_protocol_interfaces" , |
1635 | &(self.uninstall_multiple_protocol_interfaces as *const usize), |
1636 | ) |
1637 | .field("calculate_crc32" , &(self.calculate_crc32 as *const usize)) |
1638 | .field("copy_mem (fn ptr)" , &(self.copy_mem as *const usize)) |
1639 | .field("set_mem (fn ptr)" , &(self.set_mem as *const usize)) |
1640 | .field("create_event_ex" , &(self.create_event_ex as *const usize)) |
1641 | .finish() |
1642 | } |
1643 | } |
1644 | |
1645 | /// Used as a parameter of [`BootServices::load_image`] to provide the |
1646 | /// image source. |
1647 | pub enum LoadImageSource<'a> { |
1648 | /// Load an image from a buffer. The data will copied from the |
1649 | /// buffer, so the input reference doesn't need to remain valid |
1650 | /// after the image is loaded. |
1651 | FromBuffer { |
1652 | /// Raw image data. |
1653 | buffer: &'a [u8], |
1654 | |
1655 | /// If set, this path will be added as the file path of the |
1656 | /// loaded image. This is not required to load the image, but |
1657 | /// may be used by the image itself to load other resources |
1658 | /// relative to the image's path. |
1659 | file_path: Option<&'a DevicePath>, |
1660 | }, |
1661 | |
1662 | /// Load an image via the [`SimpleFileSystem`] protocol. If there is |
1663 | /// no instance of that protocol associated with the path then the |
1664 | /// behavior depends on `from_boot_manager`. If `true`, attempt to |
1665 | /// load via the `LoadFile` protocol. If `false`, attempt to load |
1666 | /// via the `LoadFile2` protocol, then fall back to `LoadFile`. |
1667 | FromFilePath { |
1668 | /// Device path from which to load the image. |
1669 | file_path: &'a DevicePath, |
1670 | |
1671 | /// Whether the request originates from the boot manager. |
1672 | from_boot_manager: bool, |
1673 | }, |
1674 | } |
1675 | |
1676 | newtype_enum! { |
1677 | /// Task priority level. |
1678 | /// |
1679 | /// Although the UEFI specification repeatedly states that only the variants |
1680 | /// specified below should be used in application-provided input, as the other |
1681 | /// are reserved for internal firmware use, it might still happen that the |
1682 | /// firmware accidentally discloses one of these internal TPLs to us. |
1683 | /// |
1684 | /// Since feeding an unexpected variant to a Rust enum is UB, this means that |
1685 | /// this C enum must be interfaced via the newtype pattern. |
1686 | pub enum Tpl: usize => { |
1687 | /// Normal task execution level. |
1688 | APPLICATION = 4, |
1689 | /// Async interrupt-style callbacks run at this TPL. |
1690 | CALLBACK = 8, |
1691 | /// Notifications are masked at this level. |
1692 | /// |
1693 | /// This is used in critical sections of code. |
1694 | NOTIFY = 16, |
1695 | /// Highest priority level. |
1696 | /// |
1697 | /// Even processor interrupts are disable at this level. |
1698 | HIGH_LEVEL = 31, |
1699 | }} |
1700 | |
1701 | /// RAII guard for task priority level changes |
1702 | /// |
1703 | /// Will automatically restore the former task priority level when dropped. |
1704 | pub struct TplGuard<'boot> { |
1705 | boot_services: &'boot BootServices, |
1706 | old_tpl: Tpl, |
1707 | } |
1708 | |
1709 | impl Drop for TplGuard<'_> { |
1710 | fn drop(&mut self) { |
1711 | unsafe { |
1712 | (self.boot_services.restore_tpl)(self.old_tpl); |
1713 | } |
1714 | } |
1715 | } |
1716 | |
1717 | // OpenProtocolAttributes is safe to model as a regular enum because it |
1718 | // is only used as an input. The attributes are bitflags, but all valid |
1719 | // combinations are listed in the spec and only ByDriver and Exclusive |
1720 | // can actually be combined. |
1721 | // |
1722 | // Some values intentionally excluded: |
1723 | // |
1724 | // ByHandleProtocol (0x01) excluded because it is only intended to be |
1725 | // used in an implementation of `HandleProtocol`. |
1726 | // |
1727 | // TestProtocol (0x04) excluded because it doesn't actually open the |
1728 | // protocol, just tests if it's present on the handle. Since that |
1729 | // changes the interface significantly, that's exposed as a separate |
1730 | // method: `BootServices::test_protocol`. |
1731 | |
1732 | /// Attributes for [`BootServices::open_protocol`]. |
1733 | #[repr (u32)] |
1734 | pub enum OpenProtocolAttributes { |
1735 | /// Used by drivers to get a protocol interface for a handle. The |
1736 | /// driver will not be informed if the interface is uninstalled or |
1737 | /// reinstalled. |
1738 | GetProtocol = 0x02, |
1739 | |
1740 | /// Used by bus drivers to show that a protocol is being used by one |
1741 | /// of the child controllers of the bus. |
1742 | ByChildController = 0x08, |
1743 | |
1744 | /// Used by a driver to gain access to a protocol interface. When |
1745 | /// this mode is used, the driver's `Stop` function will be called |
1746 | /// if the protocol interface is reinstalled or uninstalled. Once a |
1747 | /// protocol interface is opened with this attribute, no other |
1748 | /// drivers will be allowed to open the same protocol interface with |
1749 | /// the `ByDriver` attribute. |
1750 | ByDriver = 0x10, |
1751 | |
1752 | /// Used by a driver to gain exclusive access to a protocol |
1753 | /// interface. If any other drivers have the protocol interface |
1754 | /// opened with an attribute of `ByDriver`, then an attempt will be |
1755 | /// made to remove them with `DisconnectController`. |
1756 | ByDriverExclusive = 0x30, |
1757 | |
1758 | /// Used by applications to gain exclusive access to a protocol |
1759 | /// interface. If any drivers have the protocol opened with an |
1760 | /// attribute of `ByDriver`, then an attempt will be made to remove |
1761 | /// them by calling the driver's `Stop` function. |
1762 | Exclusive = 0x20, |
1763 | } |
1764 | |
1765 | /// Parameters passed to [`BootServices::open_protocol`]. |
1766 | pub struct OpenProtocolParams { |
1767 | /// The handle for the protocol to open. |
1768 | pub handle: Handle, |
1769 | |
1770 | /// The handle of the calling agent. For drivers, this is the handle |
1771 | /// containing the `EFI_DRIVER_BINDING_PROTOCOL` instance. For |
1772 | /// applications, this is the image handle. |
1773 | pub agent: Handle, |
1774 | |
1775 | /// For drivers, this is the controller handle that requires the |
1776 | /// protocol interface. For applications this should be set to |
1777 | /// `None`. |
1778 | pub controller: Option<Handle>, |
1779 | } |
1780 | |
1781 | /// An open protocol interface. Automatically closes the protocol |
1782 | /// interface on drop. |
1783 | /// |
1784 | /// See also the [`BootServices`] documentation for details of how to open a |
1785 | /// protocol and why [`UnsafeCell`] is used. |
1786 | pub struct ScopedProtocol<'a, P: Protocol + ?Sized> { |
1787 | /// The protocol interface. |
1788 | interface: &'a UnsafeCell<P>, |
1789 | |
1790 | open_params: OpenProtocolParams, |
1791 | boot_services: &'a BootServices, |
1792 | } |
1793 | |
1794 | impl<'a, P: Protocol + ?Sized> Drop for ScopedProtocol<'a, P> { |
1795 | fn drop(&mut self) { |
1796 | let status: Status = (self.boot_services.close_protocol)( |
1797 | self.open_params.handle, |
1798 | &P::GUID, |
1799 | self.open_params.agent, |
1800 | self.open_params.controller, |
1801 | ); |
1802 | // All of the error cases for close_protocol boil down to |
1803 | // calling it with a different set of parameters than what was |
1804 | // passed to open_protocol. The public API prevents such errors, |
1805 | // and the error can't be propagated out of drop anyway, so just |
1806 | // assert success. |
1807 | assert_eq!(status, Status::SUCCESS); |
1808 | } |
1809 | } |
1810 | |
1811 | impl<'a, P: Protocol + ?Sized> Deref for ScopedProtocol<'a, P> { |
1812 | type Target = P; |
1813 | |
1814 | fn deref(&self) -> &Self::Target { |
1815 | unsafe { &*self.interface.get() } |
1816 | } |
1817 | } |
1818 | |
1819 | impl<'a, P: Protocol + ?Sized> DerefMut for ScopedProtocol<'a, P> { |
1820 | fn deref_mut(&mut self) -> &mut Self::Target { |
1821 | unsafe { &mut *self.interface.get() } |
1822 | } |
1823 | } |
1824 | |
1825 | /// Type of allocation to perform. |
1826 | #[derive (Debug, Copy, Clone)] |
1827 | pub enum AllocateType { |
1828 | /// Allocate any possible pages. |
1829 | AnyPages, |
1830 | /// Allocate pages at any address below the given address. |
1831 | MaxAddress(PhysicalAddress), |
1832 | /// Allocate pages at the specified address. |
1833 | Address(PhysicalAddress), |
1834 | } |
1835 | |
1836 | newtype_enum! { |
1837 | /// The type of a memory range. |
1838 | /// |
1839 | /// UEFI allows firmwares and operating systems to introduce new memory types |
1840 | /// in the 0x70000000..0xFFFFFFFF range. Therefore, we don't know the full set |
1841 | /// of memory types at compile time, and it is _not_ safe to model this C enum |
1842 | /// as a Rust enum. |
1843 | pub enum MemoryType: u32 => { |
1844 | /// This enum variant is not used. |
1845 | RESERVED = 0, |
1846 | /// The code portions of a loaded UEFI application. |
1847 | LOADER_CODE = 1, |
1848 | /// The data portions of a loaded UEFI applications, |
1849 | /// as well as any memory allocated by it. |
1850 | LOADER_DATA = 2, |
1851 | /// Code of the boot drivers. |
1852 | /// |
1853 | /// Can be reused after OS is loaded. |
1854 | BOOT_SERVICES_CODE = 3, |
1855 | /// Memory used to store boot drivers' data. |
1856 | /// |
1857 | /// Can be reused after OS is loaded. |
1858 | BOOT_SERVICES_DATA = 4, |
1859 | /// Runtime drivers' code. |
1860 | RUNTIME_SERVICES_CODE = 5, |
1861 | /// Runtime services' code. |
1862 | RUNTIME_SERVICES_DATA = 6, |
1863 | /// Free usable memory. |
1864 | CONVENTIONAL = 7, |
1865 | /// Memory in which errors have been detected. |
1866 | UNUSABLE = 8, |
1867 | /// Memory that holds ACPI tables. |
1868 | /// Can be reclaimed after they are parsed. |
1869 | ACPI_RECLAIM = 9, |
1870 | /// Firmware-reserved addresses. |
1871 | ACPI_NON_VOLATILE = 10, |
1872 | /// A region used for memory-mapped I/O. |
1873 | MMIO = 11, |
1874 | /// Address space used for memory-mapped port I/O. |
1875 | MMIO_PORT_SPACE = 12, |
1876 | /// Address space which is part of the processor. |
1877 | PAL_CODE = 13, |
1878 | /// Memory region which is usable and is also non-volatile. |
1879 | PERSISTENT_MEMORY = 14, |
1880 | }} |
1881 | |
1882 | impl MemoryType { |
1883 | /// Construct a custom `MemoryType`. Values in the range `0x80000000..=0xffffffff` are free for use if you are |
1884 | /// an OS loader. |
1885 | #[must_use ] |
1886 | pub const fn custom(value: u32) -> MemoryType { |
1887 | assert!(value >= 0x80000000); |
1888 | MemoryType(value) |
1889 | } |
1890 | } |
1891 | |
1892 | /// Memory descriptor version number |
1893 | pub const MEMORY_DESCRIPTOR_VERSION: u32 = 1; |
1894 | |
1895 | /// A structure describing a region of memory. |
1896 | #[derive (Debug, Copy, Clone)] |
1897 | #[repr (C)] |
1898 | pub struct MemoryDescriptor { |
1899 | /// Type of memory occupying this range. |
1900 | pub ty: MemoryType, |
1901 | /// Starting physical address. |
1902 | pub phys_start: PhysicalAddress, |
1903 | /// Starting virtual address. |
1904 | pub virt_start: VirtualAddress, |
1905 | /// Number of 4 KiB pages contained in this range. |
1906 | pub page_count: u64, |
1907 | /// The capability attributes of this memory range. |
1908 | pub att: MemoryAttribute, |
1909 | } |
1910 | |
1911 | impl Default for MemoryDescriptor { |
1912 | fn default() -> MemoryDescriptor { |
1913 | MemoryDescriptor { |
1914 | ty: MemoryType::RESERVED, |
1915 | phys_start: 0, |
1916 | virt_start: 0, |
1917 | page_count: 0, |
1918 | att: MemoryAttribute::empty(), |
1919 | } |
1920 | } |
1921 | } |
1922 | |
1923 | impl Align for MemoryDescriptor { |
1924 | fn alignment() -> usize { |
1925 | mem::align_of::<Self>() |
1926 | } |
1927 | } |
1928 | |
1929 | bitflags! { |
1930 | /// Flags describing the capabilities of a memory range. |
1931 | pub struct MemoryAttribute: u64 { |
1932 | /// Supports marking as uncacheable. |
1933 | const UNCACHEABLE = 0x1; |
1934 | /// Supports write-combining. |
1935 | const WRITE_COMBINE = 0x2; |
1936 | /// Supports write-through. |
1937 | const WRITE_THROUGH = 0x4; |
1938 | /// Support write-back. |
1939 | const WRITE_BACK = 0x8; |
1940 | /// Supports marking as uncacheable, exported and |
1941 | /// supports the "fetch and add" semaphore mechanism. |
1942 | const UNCACHABLE_EXPORTED = 0x10; |
1943 | /// Supports write-protection. |
1944 | const WRITE_PROTECT = 0x1000; |
1945 | /// Supports read-protection. |
1946 | const READ_PROTECT = 0x2000; |
1947 | /// Supports disabling code execution. |
1948 | const EXECUTE_PROTECT = 0x4000; |
1949 | /// Persistent memory. |
1950 | const NON_VOLATILE = 0x8000; |
1951 | /// This memory region is more reliable than other memory. |
1952 | const MORE_RELIABLE = 0x10000; |
1953 | /// This memory range can be set as read-only. |
1954 | const READ_ONLY = 0x20000; |
1955 | /// This memory is earmarked for specific purposes such as for specific |
1956 | /// device drivers or applications. This serves as a hint to the OS to |
1957 | /// avoid this memory for core OS data or code that cannot be relocated. |
1958 | const SPECIAL_PURPOSE = 0x4_0000; |
1959 | /// This memory region is capable of being protected with the CPU's memory |
1960 | /// cryptography capabilities. |
1961 | const CPU_CRYPTO = 0x8_0000; |
1962 | /// This memory must be mapped by the OS when a runtime service is called. |
1963 | const RUNTIME = 0x8000_0000_0000_0000; |
1964 | /// This memory region is described with additional ISA-specific memory |
1965 | /// attributes as specified in `MemoryAttribute::ISA_MASK`. |
1966 | const ISA_VALID = 0x4000_0000_0000_0000; |
1967 | /// These bits are reserved for describing optional ISA-specific cache- |
1968 | /// ability attributes that are not covered by the standard UEFI Memory |
1969 | /// Attribute cacheability bits such as `UNCACHEABLE`, `WRITE_COMBINE`, |
1970 | /// `WRITE_THROUGH`, `WRITE_BACK`, and `UNCACHEABLE_EXPORTED`. |
1971 | /// |
1972 | /// See Section 2.3 "Calling Conventions" in the UEFI Specification |
1973 | /// for further information on each ISA that takes advantage of this. |
1974 | const ISA_MASK = 0x0FFF_F000_0000_0000; |
1975 | } |
1976 | } |
1977 | |
1978 | /// A unique identifier of a memory map. |
1979 | /// |
1980 | /// If the memory map changes, this value is no longer valid. |
1981 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
1982 | #[repr (C)] |
1983 | pub struct MemoryMapKey(usize); |
1984 | |
1985 | /// A structure containing the size of a memory descriptor and the size of the memory map |
1986 | pub struct MemoryMapSize { |
1987 | /// Size of a single memory descriptor in bytes |
1988 | pub entry_size: usize, |
1989 | /// Size of the entire memory map in bytes |
1990 | pub map_size: usize, |
1991 | } |
1992 | |
1993 | /// An iterator of [`MemoryDescriptor`] that is always associated with the |
1994 | /// unique [`MemoryMapKey`] contained in the struct. |
1995 | /// |
1996 | /// To iterate over the entries, call [`MemoryMap::entries`]. To get a sorted |
1997 | /// map, you manually have to call [`MemoryMap::sort`] first. |
1998 | pub struct MemoryMap<'buf> { |
1999 | key: MemoryMapKey, |
2000 | buf: &'buf mut [u8], |
2001 | entry_size: usize, |
2002 | len: usize, |
2003 | } |
2004 | |
2005 | impl<'buf> MemoryMap<'buf> { |
2006 | #[must_use ] |
2007 | /// Returns the unique [`MemoryMapKey`] associated with the memory map. |
2008 | pub fn key(&self) -> MemoryMapKey { |
2009 | self.key |
2010 | } |
2011 | |
2012 | /// Sorts the memory map by physical address in place. |
2013 | /// This operation is optional and should be invoked only once. |
2014 | pub fn sort(&mut self) { |
2015 | unsafe { |
2016 | self.qsort(0, self.len - 1); |
2017 | } |
2018 | } |
2019 | |
2020 | /// Hoare partition scheme for quicksort. |
2021 | /// Must be called with `low` and `high` being indices within bounds. |
2022 | unsafe fn qsort(&mut self, low: usize, high: usize) { |
2023 | if low >= high { |
2024 | return; |
2025 | } |
2026 | |
2027 | let p = self.partition(low, high); |
2028 | self.qsort(low, p); |
2029 | self.qsort(p + 1, high); |
2030 | } |
2031 | |
2032 | unsafe fn partition(&mut self, low: usize, high: usize) -> usize { |
2033 | let pivot = self.get_element_phys_addr(low + (high - low) / 2); |
2034 | |
2035 | let mut left_index = low.wrapping_sub(1); |
2036 | let mut right_index = high.wrapping_add(1); |
2037 | |
2038 | loop { |
2039 | while { |
2040 | left_index = left_index.wrapping_add(1); |
2041 | |
2042 | self.get_element_phys_addr(left_index) < pivot |
2043 | } {} |
2044 | |
2045 | while { |
2046 | right_index = right_index.wrapping_sub(1); |
2047 | |
2048 | self.get_element_phys_addr(right_index) > pivot |
2049 | } {} |
2050 | |
2051 | if left_index >= right_index { |
2052 | return right_index; |
2053 | } |
2054 | |
2055 | self.swap(left_index, right_index); |
2056 | } |
2057 | } |
2058 | |
2059 | /// Indices must be smaller than len. |
2060 | unsafe fn swap(&mut self, index1: usize, index2: usize) { |
2061 | if index1 == index2 { |
2062 | return; |
2063 | } |
2064 | |
2065 | let base = self.buf.as_mut_ptr(); |
2066 | |
2067 | unsafe { |
2068 | ptr::swap_nonoverlapping( |
2069 | base.add(index1 * self.entry_size), |
2070 | base.add(index2 * self.entry_size), |
2071 | self.entry_size, |
2072 | ); |
2073 | } |
2074 | } |
2075 | |
2076 | fn get_element_phys_addr(&self, index: usize) -> PhysicalAddress { |
2077 | let offset = index.checked_mul(self.entry_size).unwrap(); |
2078 | let elem = unsafe { &*self.buf.as_ptr().add(offset).cast::<MemoryDescriptor>() }; |
2079 | elem.phys_start |
2080 | } |
2081 | |
2082 | /// Returns an iterator over the contained memory map. To get a sorted map, |
2083 | /// call [`MemoryMap::sort`] first. |
2084 | #[must_use ] |
2085 | pub fn entries(&self) -> MemoryMapIter { |
2086 | MemoryMapIter { |
2087 | buffer: self.buf, |
2088 | entry_size: self.entry_size, |
2089 | index: 0, |
2090 | len: self.len, |
2091 | } |
2092 | } |
2093 | } |
2094 | |
2095 | /// An iterator of [`MemoryDescriptor`]. The underlying memory map is always |
2096 | /// associated with a unique [`MemoryMapKey`]. |
2097 | #[derive (Debug, Clone)] |
2098 | pub struct MemoryMapIter<'buf> { |
2099 | buffer: &'buf [u8], |
2100 | entry_size: usize, |
2101 | index: usize, |
2102 | len: usize, |
2103 | } |
2104 | |
2105 | impl<'buf> Iterator for MemoryMapIter<'buf> { |
2106 | type Item = &'buf MemoryDescriptor; |
2107 | |
2108 | fn size_hint(&self) -> (usize, Option<usize>) { |
2109 | let sz = self.len - self.index; |
2110 | |
2111 | (sz, Some(sz)) |
2112 | } |
2113 | |
2114 | fn next(&mut self) -> Option<Self::Item> { |
2115 | if self.index < self.len { |
2116 | let descriptor = unsafe { |
2117 | &*self |
2118 | .buffer |
2119 | .as_ptr() |
2120 | .add(self.entry_size * self.index) |
2121 | .cast::<MemoryDescriptor>() |
2122 | }; |
2123 | |
2124 | self.index += 1; |
2125 | |
2126 | Some(descriptor) |
2127 | } else { |
2128 | None |
2129 | } |
2130 | } |
2131 | } |
2132 | |
2133 | impl ExactSizeIterator for MemoryMapIter<'_> { |
2134 | fn len(&self) -> usize { |
2135 | self.len |
2136 | } |
2137 | } |
2138 | |
2139 | /// The type of handle search to perform. |
2140 | #[derive (Debug, Copy, Clone)] |
2141 | pub enum SearchType<'guid> { |
2142 | /// Return all handles present on the system. |
2143 | AllHandles, |
2144 | /// Returns all handles supporting a certain protocol, specified by its GUID. |
2145 | /// |
2146 | /// If the protocol implements the `Protocol` interface, |
2147 | /// you can use the `from_proto` function to construct a new `SearchType`. |
2148 | ByProtocol(&'guid Guid), |
2149 | /// Return all handles that implement a protocol when an interface for that protocol |
2150 | /// is (re)installed. |
2151 | ByRegisterNotify(ProtocolSearchKey), |
2152 | } |
2153 | |
2154 | impl<'guid> SearchType<'guid> { |
2155 | /// Constructs a new search type for a specified protocol. |
2156 | #[must_use ] |
2157 | pub const fn from_proto<P: ProtocolPointer + ?Sized>() -> Self { |
2158 | SearchType::ByProtocol(&P::GUID) |
2159 | } |
2160 | } |
2161 | |
2162 | bitflags! { |
2163 | /// Flags describing the type of an UEFI event and its attributes. |
2164 | pub struct EventType: u32 { |
2165 | /// The event is a timer event and may be passed to `BootServices::set_timer()` |
2166 | /// Note that timers only function during boot services time. |
2167 | const TIMER = 0x8000_0000; |
2168 | |
2169 | /// The event is allocated from runtime memory. |
2170 | /// This must be done if the event is to be signaled after ExitBootServices. |
2171 | const RUNTIME = 0x4000_0000; |
2172 | |
2173 | /// Calling wait_for_event or check_event will enqueue the notification |
2174 | /// function if the event is not already in the signaled state. |
2175 | /// Mutually exclusive with `NOTIFY_SIGNAL`. |
2176 | const NOTIFY_WAIT = 0x0000_0100; |
2177 | |
2178 | /// The notification function will be enqueued when the event is signaled |
2179 | /// Mutually exclusive with `NOTIFY_WAIT`. |
2180 | const NOTIFY_SIGNAL = 0x0000_0200; |
2181 | |
2182 | /// The event will be signaled at ExitBootServices time. |
2183 | /// This event type should not be combined with any other. |
2184 | /// Its notification function must follow some special rules: |
2185 | /// - Cannot use memory allocation services, directly or indirectly |
2186 | /// - Cannot depend on timer events, since those will be deactivated |
2187 | const SIGNAL_EXIT_BOOT_SERVICES = 0x0000_0201; |
2188 | |
2189 | /// The event will be notified when SetVirtualAddressMap is performed. |
2190 | /// This event type should not be combined with any other. |
2191 | const SIGNAL_VIRTUAL_ADDRESS_CHANGE = 0x6000_0202; |
2192 | } |
2193 | } |
2194 | |
2195 | /// Raw event notification function |
2196 | type EventNotifyFn = unsafe extern "efiapi" fn(event: Event, context: Option<NonNull<c_void>>); |
2197 | |
2198 | /// Timer events manipulation |
2199 | pub enum TimerTrigger { |
2200 | /// Cancel event's timer |
2201 | Cancel, |
2202 | /// The event is to be signaled periodically. |
2203 | /// Parameter is the period in 100ns units. |
2204 | /// Delay of 0 will be signalled on every timer tick. |
2205 | Periodic(u64), |
2206 | /// The event is to be signaled once in 100ns units. |
2207 | /// Parameter is the delay in 100ns units. |
2208 | /// Delay of 0 will be signalled on next timer tick. |
2209 | Relative(u64), |
2210 | } |
2211 | |
2212 | /// Protocol interface [`Guids`][Guid] that are installed on a [`Handle`] as |
2213 | /// returned by [`BootServices::protocols_per_handle`]. |
2214 | pub struct ProtocolsPerHandle<'a> { |
2215 | // The pointer returned by `protocols_per_handle` has to be free'd with |
2216 | // `free_pool`, so keep a reference to boot services for that purpose. |
2217 | boot_services: &'a BootServices, |
2218 | |
2219 | protocols: *mut &'a Guid, |
2220 | count: usize, |
2221 | } |
2222 | |
2223 | impl<'a> Drop for ProtocolsPerHandle<'a> { |
2224 | fn drop(&mut self) { |
2225 | // Ignore the result, we can't do anything about an error here. |
2226 | let _ = self.boot_services.free_pool(self.protocols.cast::<u8>()); |
2227 | } |
2228 | } |
2229 | |
2230 | impl<'a> Deref for ProtocolsPerHandle<'a> { |
2231 | type Target = [&'a Guid]; |
2232 | |
2233 | fn deref(&self) -> &Self::Target { |
2234 | unsafe { slice::from_raw_parts(self.protocols, self.count) } |
2235 | } |
2236 | } |
2237 | |
2238 | impl<'a> ProtocolsPerHandle<'a> { |
2239 | /// Get the protocol interface [`Guids`][Guid] that are installed on the |
2240 | /// [`Handle`]. |
2241 | #[allow (clippy::missing_const_for_fn)] // Required until we bump the MSRV. |
2242 | #[deprecated = "use Deref instead" ] |
2243 | #[must_use ] |
2244 | pub fn protocols<'b>(&'b self) -> &'b [&'a Guid] { |
2245 | // convert raw pointer to slice here so that we can get |
2246 | // appropriate lifetime of the slice. |
2247 | unsafe { slice::from_raw_parts(self.protocols, self.count) } |
2248 | } |
2249 | } |
2250 | |
2251 | /// A buffer that contains an array of [`Handles`][Handle] that support the requested protocol. |
2252 | /// Returned by [`BootServices::locate_handle_buffer`]. |
2253 | pub struct HandleBuffer<'a> { |
2254 | // The pointer returned by `locate_handle_buffer` has to be free'd with |
2255 | // `free_pool`, so keep a reference to boot services for that purpose. |
2256 | boot_services: &'a BootServices, |
2257 | count: usize, |
2258 | buffer: *mut Handle, |
2259 | } |
2260 | |
2261 | impl<'a> Drop for HandleBuffer<'a> { |
2262 | fn drop(&mut self) { |
2263 | // Ignore the result, we can't do anything about an error here. |
2264 | let _ = self.boot_services.free_pool(self.buffer.cast::<u8>()); |
2265 | } |
2266 | } |
2267 | |
2268 | impl<'a> Deref for HandleBuffer<'a> { |
2269 | type Target = [Handle]; |
2270 | |
2271 | fn deref(&self) -> &Self::Target { |
2272 | unsafe { slice::from_raw_parts(self.buffer, self.count) } |
2273 | } |
2274 | } |
2275 | |
2276 | impl<'a> HandleBuffer<'a> { |
2277 | /// Get an array of [`Handles`][Handle] that support the requested protocol. |
2278 | #[allow (clippy::missing_const_for_fn)] // Required until we bump the MSRV. |
2279 | #[deprecated = "use Deref instead" ] |
2280 | #[must_use ] |
2281 | pub fn handles(&self) -> &[Handle] { |
2282 | // convert raw pointer to slice here so that we can get |
2283 | // appropriate lifetime of the slice. |
2284 | unsafe { slice::from_raw_parts(self.buffer, self.count) } |
2285 | } |
2286 | } |
2287 | |
2288 | newtype_enum! { |
2289 | /// Interface type of a protocol interface |
2290 | /// |
2291 | /// Only has one variant when this was written (v2.10 of the UEFI spec) |
2292 | pub enum InterfaceType: i32 => { |
2293 | /// Native interface |
2294 | NATIVE_INTERFACE = 0, |
2295 | } |
2296 | } |
2297 | |
2298 | /// Opaque pointer returned by [`BootServices::register_protocol_notify`] to be used |
2299 | /// with [`BootServices::locate_handle`] via [`SearchType::ByRegisterNotify`]. |
2300 | #[derive (Debug, Clone, Copy)] |
2301 | #[repr (transparent)] |
2302 | pub struct ProtocolSearchKey(NonNull<c_void>); |
2303 | |
2304 | #[cfg (test)] |
2305 | mod tests { |
2306 | use core::mem::size_of; |
2307 | |
2308 | use crate::table::boot::{MemoryAttribute, MemoryMap, MemoryMapKey, MemoryType}; |
2309 | |
2310 | use super::{MemoryDescriptor, MemoryMapIter}; |
2311 | |
2312 | #[test ] |
2313 | fn mem_map_sorting() { |
2314 | // Doesn't matter what type it is. |
2315 | const TY: MemoryType = MemoryType::RESERVED; |
2316 | |
2317 | const BASE: MemoryDescriptor = MemoryDescriptor { |
2318 | ty: TY, |
2319 | phys_start: 0, |
2320 | virt_start: 0, |
2321 | page_count: 0, |
2322 | att: MemoryAttribute::empty(), |
2323 | }; |
2324 | |
2325 | let mut buffer = [ |
2326 | MemoryDescriptor { |
2327 | phys_start: 2000, |
2328 | ..BASE |
2329 | }, |
2330 | MemoryDescriptor { |
2331 | phys_start: 3000, |
2332 | ..BASE |
2333 | }, |
2334 | BASE, |
2335 | MemoryDescriptor { |
2336 | phys_start: 1000, |
2337 | ..BASE |
2338 | }, |
2339 | ]; |
2340 | |
2341 | let desc_count = buffer.len(); |
2342 | |
2343 | let byte_buffer = { |
2344 | let size = desc_count * size_of::<MemoryDescriptor>(); |
2345 | unsafe { core::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, size) } |
2346 | }; |
2347 | |
2348 | let mut mem_map = MemoryMap { |
2349 | // Key doesn't matter |
2350 | key: MemoryMapKey(0), |
2351 | len: desc_count, |
2352 | buf: byte_buffer, |
2353 | entry_size: size_of::<MemoryDescriptor>(), |
2354 | }; |
2355 | |
2356 | mem_map.sort(); |
2357 | |
2358 | if !is_sorted(&mem_map.entries()) { |
2359 | panic!("mem_map is not sorted: {}" , mem_map); |
2360 | } |
2361 | } |
2362 | |
2363 | // Added for debug purposes on test failure |
2364 | impl core::fmt::Display for MemoryMap<'_> { |
2365 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
2366 | writeln!(f)?; |
2367 | for desc in self.entries() { |
2368 | writeln!(f, " {:?}" , desc)?; |
2369 | } |
2370 | Ok(()) |
2371 | } |
2372 | } |
2373 | |
2374 | fn is_sorted(iter: &MemoryMapIter) -> bool { |
2375 | let mut iter = iter.clone(); |
2376 | let mut curr_start; |
2377 | |
2378 | if let Some(val) = iter.next() { |
2379 | curr_start = val.phys_start; |
2380 | } else { |
2381 | return true; |
2382 | } |
2383 | |
2384 | for desc in iter { |
2385 | if desc.phys_start <= curr_start { |
2386 | return false; |
2387 | } |
2388 | curr_start = desc.phys_start |
2389 | } |
2390 | true |
2391 | } |
2392 | } |
2393 | |