Skip to content

doc: improved documentation for boot allocation functions #1665

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
46 changes: 35 additions & 11 deletions uefi/src/boot.rs
Original file line number Diff line number Diff line change
@@ -120,28 +120,43 @@ pub unsafe fn raise_tpl(tpl: Tpl) -> TplGuard {
}
}

/// Allocates memory pages from the system.
/// Allocates a consecutive set of memory pages using the UEFI allocator.
///
/// UEFI OS loaders should allocate memory of the type `LoaderData`.
/// The caller is responsible to free the memory using [`free_pages`].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The caller is responsible to free the memory using [`free_pages`].
/// The caller is responsible for freeing the memory using [`free_pages`].

///
/// # Arguments
/// - `allocation_type`: The [`AllocateType`] to alter the allocation strategy.
/// - `memory_type`: The [`MemoryType`] used to persist the allocation in the
/// UEFI memory map. Typically, UEFI OS loaders should allocate memory of
/// type [`MemoryType::LOADER_DATA`].
///- `size`: Amount of bytes to allocate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
///- `size`: Amount of bytes to allocate.
///- `count: Number of pages to allocate.

///
/// # Safety
/// Using this function is safe but reading on initialized memory is not.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Using this function is safe but reading on initialized memory is not.
/// Using this function is safe, but it returns a raw pointer to uninitialized memory. The memory must be initialized before creating a reference to it.

(Reference: https://doc.rust-lang.org/nomicon/unchecked-uninit.html "It is illegal to construct a reference to uninitialized data")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yikes, typos/weird wording from my side.

Thanks

/// Please look into the example code.
///
/// # Errors
///
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`],
/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`.
/// * [`Status::NOT_FOUND`]: the requested pages could not be found.
pub fn allocate_pages(ty: AllocateType, mem_ty: MemoryType, count: usize) -> Result<NonNull<u8>> {
pub fn allocate_pages(
allocation_type: AllocateType,
memory_type: MemoryType,
count: usize,
) -> Result<NonNull<u8>> {
let bt = boot_services_raw_panicking();
let bt = unsafe { bt.as_ref() };

let (ty, initial_addr) = match ty {
let (ty, initial_addr) = match allocation_type {
AllocateType::AnyPages => (0, 0),
AllocateType::MaxAddress(addr) => (1, addr),
AllocateType::Address(addr) => (2, addr),
};

let mut addr1 = initial_addr;
unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr1) }.to_result()?;
unsafe { (bt.allocate_pages)(ty, memory_type, count, &mut addr1) }.to_result()?;

// The UEFI spec allows `allocate_pages` to return a valid allocation at
// address zero. Rust does not allow writes through a null pointer (which
@@ -155,7 +170,7 @@ pub fn allocate_pages(ty: AllocateType, mem_ty: MemoryType, count: usize) -> Res
// not yet been freed, so if this allocation succeeds it should be at a
// non-zero address.
let mut addr2 = initial_addr;
let r = unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr2) }.to_result();
let r = unsafe { (bt.allocate_pages)(ty, memory_type, count, &mut addr2) }.to_result();

// Free the original allocation (ignoring errors).
let _unused = unsafe { (bt.free_pages)(addr1, count) };
@@ -189,22 +204,31 @@ pub unsafe fn free_pages(ptr: NonNull<u8>, count: usize) -> Result {
unsafe { (bt.free_pages)(addr, count) }.to_result()
}

/// Allocates from a memory pool. The pointer will be 8-byte aligned.
/// Allocates a consecutive region of bytes using the UEFI allocator. The buffer
/// will be 8-byte aligned.
///
/// The caller is responsible to free the memory using [`free_pool`].
///
/// # Arguments
/// - `memory_type`: The [`MemoryType`] used to persist the allocation in the
/// UEFI memory map. Typically, UEFI OS loaders should allocate memory of
/// type [`MemoryType::LOADER_DATA`].
///- `size`: Amount of bytes to allocate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
///- `size`: Amount of bytes to allocate.
///- `size`: Number of bytes to allocate.

(This is a nitpicky grammar thing, "number" should be used for countable things)

///
/// # Errors
///
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`],
/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`.
pub fn allocate_pool(mem_ty: MemoryType, size: usize) -> Result<NonNull<u8>> {
pub fn allocate_pool(memory_type: MemoryType, size: usize) -> Result<NonNull<u8>> {
let bt = boot_services_raw_panicking();
let bt = unsafe { bt.as_ref() };

let mut buffer = ptr::null_mut();
let ptr =
unsafe { (bt.allocate_pool)(mem_ty, size, &mut buffer) }.to_result_with_val(|| buffer)?;
let ptr = unsafe { (bt.allocate_pool)(memory_type, size, &mut buffer) }
.to_result_with_val(|| buffer)?;

Ok(NonNull::new(ptr).expect("allocate_pool must not return a null pointer if successful"))
NonNull::new(ptr).ok_or(Status::OUT_OF_RESOURCES.into())
}

/// Frees memory allocated by [`allocate_pool`].