diff --git a/uefi/src/boot.rs b/uefi/src/boot.rs index 3df02d827..6bb41bced 100644 --- a/uefi/src/boot.rs +++ b/uefi/src/boot.rs @@ -3,8 +3,10 @@ //! These functions will panic if called after exiting boot services. use crate::data_types::PhysicalAddress; +use core::ffi::c_void; use core::ptr::{self, NonNull}; -use uefi::{table, Result, StatusExt}; +use core::sync::atomic::{AtomicPtr, Ordering}; +use uefi::{table, Handle, Result, StatusExt}; #[cfg(doc)] use uefi::Status; @@ -12,6 +14,35 @@ use uefi::Status; pub use uefi::table::boot::AllocateType; pub use uefi_raw::table::boot::MemoryType; +/// Global image handle. This is only set by [`set_image_handle`], and it is +/// only read by [`image_handle`]. +static IMAGE_HANDLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +/// Get the [`Handle`] of the currently-executing image. +#[must_use] +pub fn image_handle() -> Handle { + let ptr = IMAGE_HANDLE.load(Ordering::Acquire); + // Safety: the image handle must be valid. We know it is, because it was set + // by `set_image_handle`, which has that same safety requirement. + unsafe { Handle::from_ptr(ptr) }.expect("set_image_handle has not been called") +} + +/// Update the global image [`Handle`]. +/// +/// This is called automatically in the `main` entry point as part of +/// [`uefi::entry`]. It should not be called at any other point in time, unless +/// the executable does not use [`uefi::entry`], in which case it should be +/// called once before calling other boot services functions. +/// +/// # Safety +/// +/// This function should only be called as described above, and the +/// `image_handle` must be a valid image [`Handle`]. The safety guarantees of +/// `open_protocol_exclusive` rely on the global image handle being correct. +pub unsafe fn set_image_handle(image_handle: Handle) { + IMAGE_HANDLE.store(image_handle.as_ptr(), Ordering::Release); +} + fn boot_services_raw_panicking() -> NonNull { let st = table::system_table_raw_panicking(); // SAFETY: valid per requirements of `set_system_table`. diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index eab1244ac..18122df28 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -19,13 +19,8 @@ use core::fmt::Debug; use core::mem::{self, MaybeUninit}; use core::ops::{Deref, DerefMut}; use core::ptr::NonNull; -use core::sync::atomic::{AtomicPtr, Ordering}; use core::{ptr, slice}; -/// Global image handle. This is only set by `BootServices::set_image_handle`, -/// and it is only read by `BootServices::image_handle`. -static IMAGE_HANDLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - /// Size in bytes of a UEFI page. /// /// Note that this is not necessarily the processor's page size. The UEFI page @@ -84,32 +79,21 @@ pub struct BootServices(uefi_raw::table::boot::BootServices); impl BootServices { /// Get the [`Handle`] of the currently-executing image. + #[must_use] pub fn image_handle(&self) -> Handle { - let ptr = IMAGE_HANDLE.load(Ordering::Acquire); - // Safety: the image handle must be valid. We know it is, because it was - // set by `set_image_handle`, which has that same safety requirement. - unsafe { Handle::from_ptr(ptr) }.expect("set_image_handle has not been called") + uefi::boot::image_handle() } /// Update the global image [`Handle`]. /// - /// This is called automatically in the `main` entry point as part - /// of [`uefi::entry`]. It should not be called at any other - /// point in time, unless the executable does not use - /// [`uefi::entry`], in which case it should be called once - /// before calling other `BootServices` functions. + /// This is the same as calling [`uefi::boot::set_image_handle`]. See that + /// function for details. /// /// # Safety /// - /// This function should only be called as described above, - /// and the `image_handle` must be a valid image [`Handle`]. Then - /// safety guarantees of [`BootServices::open_protocol_exclusive`] - /// rely on the global image handle being correct. + /// See [`uefi::boot::set_image_handle`] for safety requirements. pub unsafe fn set_image_handle(&self, image_handle: Handle) { - // As with `image_handle`, `&self` isn't actually used, but it - // enforces that this function is only called while boot - // services are active. - IMAGE_HANDLE.store(image_handle.as_ptr(), Ordering::Release); + uefi::boot::set_image_handle(image_handle) } /// Raises a task's priority level and returns its previous level.