Skip to content

Commit e251d03

Browse files
authored
Merge pull request #1301 from rust-osdev/bishop-set-virt-map
runtime: Add freestanding set_virtual_address_map
2 parents 60a4934 + 1d388e2 commit e251d03

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

uefi/src/runtime.rs

+45
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::table::{self, Revision};
1010
use crate::{CStr16, Error, Result, Status, StatusExt};
1111
use core::mem;
1212
use core::ptr::{self, NonNull};
13+
use uefi_raw::table::boot::MemoryDescriptor;
1314

1415
#[cfg(feature = "alloc")]
1516
use {
@@ -467,3 +468,47 @@ pub fn reset(reset_type: ResetType, status: Status, data: Option<&[u8]>) -> ! {
467468

468469
unsafe { (rt.reset_system)(reset_type, status, size, data) }
469470
}
471+
472+
/// Changes the runtime addressing mode of EFI firmware from physical to
473+
/// virtual. It is up to the caller to translate the old system table address
474+
/// to a new virtual address and provide it for this function.
475+
///
476+
/// If successful, this function will call [`set_system_table`] with
477+
/// `new_system_table_virtual_addr`.
478+
///
479+
/// [`set_system_table`]: table::set_system_table
480+
///
481+
/// # Safety
482+
///
483+
/// The caller must ensure the memory map is valid.
484+
///
485+
/// # Errors
486+
///
487+
/// * [`Status::UNSUPPORTED`]: either boot services haven't been exited, the
488+
/// firmware's addressing mode is already virtual, or the firmware does not
489+
/// support this operation.
490+
/// * [`Status::NO_MAPPING`]: `map` is missing a required range.
491+
/// * [`Status::NOT_FOUND`]: `map` contains an address that is not in the
492+
/// current memory map.
493+
pub unsafe fn set_virtual_address_map(
494+
map: &mut [MemoryDescriptor],
495+
new_system_table_virtual_addr: *const uefi_raw::table::system::SystemTable,
496+
) -> Result {
497+
let rt = runtime_services_raw_panicking();
498+
let rt = unsafe { rt.as_ref() };
499+
500+
// Unsafe Code Guidelines guarantees that there is no padding in an array or a slice
501+
// between its elements if the element type is `repr(C)`, which is our case.
502+
//
503+
// See https://rust-lang.github.io/unsafe-code-guidelines/layout/arrays-and-slices.html
504+
let map_size = core::mem::size_of_val(map);
505+
let entry_size = core::mem::size_of::<MemoryDescriptor>();
506+
let entry_version = MemoryDescriptor::VERSION;
507+
let map_ptr = map.as_mut_ptr();
508+
(rt.set_virtual_address_map)(map_size, entry_size, entry_version, map_ptr).to_result()?;
509+
510+
// Update the global system table pointer.
511+
table::set_system_table(new_system_table_virtual_addr);
512+
513+
Ok(())
514+
}

uefi/src/table/mod.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,21 @@ pub(crate) fn system_table_raw_panicking() -> NonNull<uefi_raw::table::system::S
3333
/// Update the global system table pointer.
3434
///
3535
/// This is called automatically in the `main` entry point as part of
36-
/// [`uefi::entry`]. It should not be called at any other point in time, unless
37-
/// the executable does not use [`uefi::entry`], in which case it should be
38-
/// called once before calling any other API in this crate.
36+
/// [`uefi::entry`].
37+
///
38+
/// It is also called by [`set_virtual_address_map`] to transition from a
39+
/// physical address to a virtual address.
40+
///
41+
/// This function should not be called at any other point in time, unless the
42+
/// executable does not use [`uefi::entry`], in which case it should be called
43+
/// once before calling any other API in this crate.
3944
///
4045
/// # Safety
4146
///
4247
/// This function should only be called as described above, and the
4348
/// `ptr` must be a valid [`SystemTable`].
49+
///
50+
/// [`set_virtual_address_map`]: uefi::runtime::set_virtual_address_map
4451
pub unsafe fn set_system_table(ptr: *const uefi_raw::table::system::SystemTable) {
4552
SYSTEM_TABLE.store(ptr.cast_mut(), Ordering::Release);
4653
}

0 commit comments

Comments
 (0)