|
| 1 | +//! UEFI boot services. |
| 2 | +//! |
| 3 | +//! These functions will panic if called after exiting boot services. |
| 4 | +
|
| 5 | +use crate::data_types::PhysicalAddress; |
| 6 | +use core::ptr::{self, NonNull}; |
| 7 | +use uefi::{table, Result, StatusExt}; |
| 8 | + |
| 9 | +#[cfg(doc)] |
| 10 | +use uefi::Status; |
| 11 | + |
| 12 | +pub use uefi::table::boot::AllocateType; |
| 13 | +pub use uefi_raw::table::boot::MemoryType; |
| 14 | + |
| 15 | +fn boot_services_raw_panicking() -> NonNull<uefi_raw::table::boot::BootServices> { |
| 16 | + let st = table::system_table_raw_panicking(); |
| 17 | + // SAFETY: valid per requirements of `set_system_table`. |
| 18 | + let st = unsafe { st.as_ref() }; |
| 19 | + NonNull::new(st.boot_services).expect("boot services are not active") |
| 20 | +} |
| 21 | + |
| 22 | +/// Allocates memory pages from the system. |
| 23 | +/// |
| 24 | +/// UEFI OS loaders should allocate memory of the type `LoaderData`. |
| 25 | +/// |
| 26 | +/// # Errors |
| 27 | +/// |
| 28 | +/// * [`Status::OUT_OF_RESOURCES`]: allocation failed. |
| 29 | +/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`], |
| 30 | +/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`. |
| 31 | +/// * [`Status::NOT_FOUND`]: the requested pages could not be found. |
| 32 | +pub fn allocate_pages(ty: AllocateType, mem_ty: MemoryType, count: usize) -> Result<NonNull<u8>> { |
| 33 | + let bt = boot_services_raw_panicking(); |
| 34 | + let bt = unsafe { bt.as_ref() }; |
| 35 | + |
| 36 | + let (ty, mut addr) = match ty { |
| 37 | + AllocateType::AnyPages => (0, 0), |
| 38 | + AllocateType::MaxAddress(addr) => (1, addr), |
| 39 | + AllocateType::Address(addr) => (2, addr), |
| 40 | + }; |
| 41 | + let addr = |
| 42 | + unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr) }.to_result_with_val(|| addr)?; |
| 43 | + let ptr = addr as *mut u8; |
| 44 | + Ok(NonNull::new(ptr).expect("allocate_pages must not return a null pointer if successful")) |
| 45 | +} |
| 46 | + |
| 47 | +/// Frees memory pages allocated by [`allocate_pages`]. |
| 48 | +/// |
| 49 | +/// # Safety |
| 50 | +/// |
| 51 | +/// The caller must ensure that no references into the allocation remain, |
| 52 | +/// and that the memory at the allocation is not used after it is freed. |
| 53 | +/// |
| 54 | +/// # Errors |
| 55 | +/// |
| 56 | +/// * [`Status::NOT_FOUND`]: `ptr` was not allocated by [`allocate_pages`]. |
| 57 | +/// * [`Status::INVALID_PARAMETER`]: `ptr` is not page aligned or is otherwise invalid. |
| 58 | +pub unsafe fn free_pages(ptr: NonNull<u8>, count: usize) -> Result { |
| 59 | + let bt = boot_services_raw_panicking(); |
| 60 | + let bt = unsafe { bt.as_ref() }; |
| 61 | + |
| 62 | + let addr = ptr.as_ptr() as PhysicalAddress; |
| 63 | + unsafe { (bt.free_pages)(addr, count) }.to_result() |
| 64 | +} |
| 65 | + |
| 66 | +/// Allocates from a memory pool. The pointer will be 8-byte aligned. |
| 67 | +/// |
| 68 | +/// # Errors |
| 69 | +/// |
| 70 | +/// * [`Status::OUT_OF_RESOURCES`]: allocation failed. |
| 71 | +/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`], |
| 72 | +/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`. |
| 73 | +pub fn allocate_pool(mem_ty: MemoryType, size: usize) -> Result<NonNull<u8>> { |
| 74 | + let bt = boot_services_raw_panicking(); |
| 75 | + let bt = unsafe { bt.as_ref() }; |
| 76 | + |
| 77 | + let mut buffer = ptr::null_mut(); |
| 78 | + let ptr = |
| 79 | + unsafe { (bt.allocate_pool)(mem_ty, size, &mut buffer) }.to_result_with_val(|| buffer)?; |
| 80 | + |
| 81 | + Ok(NonNull::new(ptr).expect("allocate_pool must not return a null pointer if successful")) |
| 82 | +} |
| 83 | + |
| 84 | +/// Frees memory allocated by [`allocate_pool`]. |
| 85 | +/// |
| 86 | +/// # Safety |
| 87 | +/// |
| 88 | +/// The caller must ensure that no references into the allocation remain, |
| 89 | +/// and that the memory at the allocation is not used after it is freed. |
| 90 | +/// |
| 91 | +/// # Errors |
| 92 | +/// |
| 93 | +/// * [`Status::INVALID_PARAMETER`]: `ptr` is invalid. |
| 94 | +pub unsafe fn free_pool(ptr: NonNull<u8>) -> Result { |
| 95 | + let bt = boot_services_raw_panicking(); |
| 96 | + let bt = unsafe { bt.as_ref() }; |
| 97 | + |
| 98 | + unsafe { (bt.free_pool)(ptr.as_ptr()) }.to_result() |
| 99 | +} |
0 commit comments