1//! UEFI services available during boot.
2
3use super::{Header, Revision};
4use crate::data_types::{Align, PhysicalAddress, VirtualAddress};
5use crate::proto::device_path::{DevicePath, FfiDevicePath};
6#[cfg(feature = "alloc")]
7use crate::proto::{loaded_image::LoadedImage, media::fs::SimpleFileSystem};
8use crate::proto::{Protocol, ProtocolPointer};
9use crate::{Char16, Event, Guid, Handle, Result, Status};
10#[cfg(feature = "alloc")]
11use ::alloc::vec::Vec;
12use bitflags::bitflags;
13use core::cell::UnsafeCell;
14use core::ffi::c_void;
15use core::fmt::{Debug, Formatter};
16use core::mem::{self, MaybeUninit};
17use core::ops::{Deref, DerefMut};
18use core::ptr::NonNull;
19use core::{ptr, slice};
20
21// TODO: this similar to `SyncUnsafeCell`. Once that is stabilized we
22// can use it instead.
23struct GlobalImageHandle {
24 handle: UnsafeCell<Option<Handle>>,
25}
26
27// Safety: reads and writes are managed via `set_image_handle` and
28// `BootServices::image_handle`.
29unsafe impl Sync for GlobalImageHandle {}
30
31static 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.
39pub 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)]
88pub 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
277impl 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")]
1450impl 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
1514impl super::Table for BootServices {
1515 const SIGNATURE: u64 = 0x5652_4553_544f_4f42;
1516}
1517
1518impl 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.
1647pub 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
1676newtype_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.
1686pub 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.
1704pub struct TplGuard<'boot> {
1705 boot_services: &'boot BootServices,
1706 old_tpl: Tpl,
1707}
1708
1709impl 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)]
1734pub 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`].
1766pub 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.
1786pub 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
1794impl<'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
1811impl<'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
1819impl<'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)]
1827pub 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
1836newtype_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.
1843pub 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
1882impl 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
1893pub const MEMORY_DESCRIPTOR_VERSION: u32 = 1;
1894
1895/// A structure describing a region of memory.
1896#[derive(Debug, Copy, Clone)]
1897#[repr(C)]
1898pub 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
1911impl 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
1923impl Align for MemoryDescriptor {
1924 fn alignment() -> usize {
1925 mem::align_of::<Self>()
1926 }
1927}
1928
1929bitflags! {
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)]
1983pub struct MemoryMapKey(usize);
1984
1985/// A structure containing the size of a memory descriptor and the size of the memory map
1986pub 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.
1998pub struct MemoryMap<'buf> {
1999 key: MemoryMapKey,
2000 buf: &'buf mut [u8],
2001 entry_size: usize,
2002 len: usize,
2003}
2004
2005impl<'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)]
2098pub struct MemoryMapIter<'buf> {
2099 buffer: &'buf [u8],
2100 entry_size: usize,
2101 index: usize,
2102 len: usize,
2103}
2104
2105impl<'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
2133impl 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)]
2141pub 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
2154impl<'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
2162bitflags! {
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
2196type EventNotifyFn = unsafe extern "efiapi" fn(event: Event, context: Option<NonNull<c_void>>);
2197
2198/// Timer events manipulation
2199pub 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`].
2214pub 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
2223impl<'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
2230impl<'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
2238impl<'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`].
2253pub 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
2261impl<'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
2268impl<'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
2276impl<'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
2288newtype_enum! {
2289/// Interface type of a protocol interface
2290///
2291/// Only has one variant when this was written (v2.10 of the UEFI spec)
2292pub 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)]
2302pub struct ProtocolSearchKey(NonNull<c_void>);
2303
2304#[cfg(test)]
2305mod 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