@@ -10,6 +10,7 @@ use crate::table::{self, Revision};
10
10
use crate :: { CStr16 , Error , Result , Status , StatusExt } ;
11
11
use core:: mem;
12
12
use core:: ptr:: { self , NonNull } ;
13
+ use uefi_raw:: table:: boot:: MemoryDescriptor ;
13
14
14
15
#[ cfg( feature = "alloc" ) ]
15
16
use {
@@ -467,3 +468,47 @@ pub fn reset(reset_type: ResetType, status: Status, data: Option<&[u8]>) -> ! {
467
468
468
469
unsafe { ( rt. reset_system ) ( reset_type, status, size, data) }
469
470
}
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