Skip to content

Move the global image handle to uefi::boot #1262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion uefi/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,46 @@
//! 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;

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<c_void> = 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<uefi_raw::table::boot::BootServices> {
let st = table::system_table_raw_panicking();
// SAFETY: valid per requirements of `set_system_table`.
Expand Down
28 changes: 6 additions & 22 deletions uefi/src/table/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<c_void> = 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
Expand Down Expand Up @@ -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.
Expand Down