@@ -10,6 +10,7 @@ use crate::table::{self, Revision};
1010use crate :: { CStr16 , Error , Result , Status , StatusExt } ;
1111use core:: mem;
1212use core:: ptr:: { self , NonNull } ;
13+ use uefi_raw:: table:: boot:: MemoryDescriptor ;
1314
1415#[ cfg( feature = "alloc" ) ]
1516use {
@@ -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+ }
0 commit comments