Skip to content

Commit

Permalink
Add uefi::boot module
Browse files Browse the repository at this point in the history
The initial version contains allocate_pages/allocate_pool and the corresponding
`free` functions.
  • Loading branch information
nicholasbishop committed Jul 21, 2024
1 parent 4fd9aed commit b9c6a8c
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
29 changes: 29 additions & 0 deletions uefi-test-runner/src/boot/memory.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
use uefi::boot;
use uefi::table::boot::{AllocateType, BootServices, MemoryMap, MemoryMapMut, MemoryType};

use alloc::vec::Vec;

pub fn test(bt: &BootServices) {
info!("Testing memory functions");

test_allocate_pages_freestanding();
test_allocate_pool_freestanding();

allocate_pages(bt);
vec_alloc();
alloc_alignment();

memory_map(bt);
}

fn test_allocate_pages_freestanding() {
let num_pages = 1;
let addr =
boot::allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, num_pages).unwrap();
assert_eq!(addr % 4096, 0, "Page pointer is not page-aligned");

// Verify the page can be written to.
{
let buf = unsafe { &mut *(addr as *mut [u8; 4096]) };
*buf = [0xff; 4096];
}

unsafe { boot::free_pages(addr, num_pages) }.unwrap();
}

fn test_allocate_pool_freestanding() {
let allocation = boot::allocate_pool(MemoryType::LOADER_DATA, 10).unwrap();
// Verify the allocation can be written to.
{
let buf: &mut [u8; 10] = unsafe { &mut *allocation.as_ptr().cast() };
*buf = [0xff; 10];
}
unsafe { boot::free_pool(allocation.as_ptr()) }.unwrap();
}

fn allocate_pages(bt: &BootServices) {
info!("Allocating some pages of memory");

Expand Down
2 changes: 2 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## Added
- `uefi::system` is a new module that provides freestanding functions for
accessing fields of the global system table.
- `uefi::boot` is a new module that provides freestanding functions for
boot services using the global system table.
- `uefi::runtime` is a new module that provides freestanding functions for
runtime services using the global system table.
- Add standard derives for `ConfigTableEntry`.
Expand Down
98 changes: 98 additions & 0 deletions uefi/src/boot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//! UEFI boot services.
//!
//! These functions will panic if called after exiting boot services.

use crate::data_types::PhysicalAddress;
use core::ptr::{self, NonNull};
use uefi::{table, Result, StatusExt};

pub use uefi::table::boot::AllocateType;
pub use uefi_raw::table::boot::MemoryType;

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`.
let st = unsafe { st.as_ref() };
NonNull::new(st.boot_services).expect("boot services are not active")
}

/// Allocates memory pages from the system.
///
/// UEFI OS loaders should allocate memory of the type `LoaderData`. An `u64`
/// is returned even on 32-bit platforms because some hardware configurations
/// like Intel PAE enable 64-bit physical addressing on a 32-bit processor.
///
/// # Errors
///
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT`],
/// [`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<PhysicalAddress> {
let bt = boot_services_raw_panicking();
let bt = unsafe { bt.as_ref() };

let (ty, mut addr) = match ty {
AllocateType::AnyPages => (0, 0),
AllocateType::MaxAddress(addr) => (1, addr),
AllocateType::Address(addr) => (2, addr),
};
unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr) }.to_result_with_val(|| addr)
}

/// Frees memory pages allocated by [`allocate_pages`].
///
/// # Safety
///
/// The caller must ensure that no references into the allocation remain,
/// and that the memory at the allocation is not used after it is freed.
///
/// # Errors
///
/// * [`Status::NOT_FOUND`]: `addr` was not allocated by [`allocate_pages`].
/// * [`Status::INVALID_PARAMETER`]: `addr` is not page aligned or is otherwise invalid.
pub unsafe fn free_pages(addr: PhysicalAddress, count: usize) -> Result {
let bt = boot_services_raw_panicking();
let bt = unsafe { bt.as_ref() };

unsafe { (bt.free_pages)(addr, count) }.to_result()
}

/// Allocates from a memory pool. The pointer will be 8-byte aligned.
///
/// # Errors
///
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT`],
/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`.
pub fn allocate_pool(mem_ty: 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)?;

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

/// Frees memory allocated by [`allocate_pool`].
///
/// # Safety
///
/// The caller must ensure that no references into the allocation remain,
/// and that the memory at the allocation is not used after it is freed.
///
/// # Errors
///
/// * [`Status::INVALID_PARAMETER`]: `addr` is invalid.
pub unsafe fn free_pool(addr: *mut u8) -> Result {
let bt = boot_services_raw_panicking();
let bt = unsafe { bt.as_ref() };

unsafe { (bt.free_pool)(addr) }.to_result()
}
1 change: 1 addition & 0 deletions uefi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub use uguid::guid;
mod result;
pub use result::{Error, Result, ResultExt, Status, StatusExt};

pub mod boot;
pub mod runtime;
pub mod system;
pub mod table;
Expand Down

0 comments on commit b9c6a8c

Please sign in to comment.