Skip to content

Commit d1b2a3f

Browse files
michael2012zrbradford
authored andcommitted
aarch64: Add a memory-simulated flash for UEFI
EDK2 execution requires a flash device at address 0. The new added device is not a fully functional flash. It doesn't implement any spec of a flash device. Instead, a piece of memory is used to simulate the flash simply. Signed-off-by: Michael Zhao <[email protected]>
1 parent 9dd107b commit d1b2a3f

File tree

3 files changed

+56
-3
lines changed

3 files changed

+56
-3
lines changed

arch/src/aarch64/layout.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@
4242
// | Legacy devices space |
4343
// | |
4444
// 144 M +---------------------------------------------------------------|
45-
// | Reserved (now GIC is here) |
46-
// 64 M +---------------------------------------------------------------+
4745
// | |
48-
// | UEFI space |
46+
// | Reserved (now GIC is here) |
4947
// | |
48+
// 4 M +---------------------------------------------------------------+
49+
// | UEFI flash |
5050
// 0GB +---------------------------------------------------------------+
5151
//
5252
//

vmm/src/device_manager.rs

+50
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use crate::pci_segment::PciSegment;
2525
use crate::seccomp_filters::{get_seccomp_filter, Thread};
2626
use crate::serial_manager::{Error as SerialManagerError, SerialManager};
2727
use crate::sigwinch_listener::start_sigwinch_listener;
28+
#[cfg(target_arch = "aarch64")]
29+
use crate::GuestMemoryMmap;
2830
use crate::GuestRegionMmap;
2931
use crate::PciDeviceInfo;
3032
use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID};
@@ -96,6 +98,8 @@ use vm_device::interrupt::{
9698
};
9799
use vm_device::{Bus, BusDevice, Resource};
98100
use vm_memory::guest_memory::FileOffset;
101+
#[cfg(target_arch = "aarch64")]
102+
use vm_memory::GuestMemoryAtomic;
99103
use vm_memory::GuestMemoryRegion;
100104
use vm_memory::{Address, GuestAddress, GuestUsize, MmapRegion};
101105
#[cfg(target_arch = "x86_64")]
@@ -473,6 +477,9 @@ pub enum DeviceManagerError {
473477

474478
/// Cannot hotplug device behind vIOMMU
475479
InvalidIommuHotplug,
480+
481+
/// Failed to create UEFI flash
482+
CreateUefiFlash(hypervisor::vm::HypervisorVmError),
476483
}
477484
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
478485

@@ -924,6 +931,10 @@ pub struct DeviceManager {
924931
// GPIO device for AArch64
925932
gpio_device: Option<Arc<Mutex<devices::legacy::Gpio>>>,
926933

934+
#[cfg(target_arch = "aarch64")]
935+
// Flash device for UEFI on AArch64
936+
uefi_flash: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
937+
927938
// Flag to force setting the iommu on virtio devices
928939
force_iommu: bool,
929940

@@ -1067,6 +1078,8 @@ impl DeviceManager {
10671078
virtio_mem_devices: Vec::new(),
10681079
#[cfg(target_arch = "aarch64")]
10691080
gpio_device: None,
1081+
#[cfg(target_arch = "aarch64")]
1082+
uefi_flash: None,
10701083
force_iommu,
10711084
restoring,
10721085
io_uring_supported: None,
@@ -1602,6 +1615,38 @@ impl DeviceManager {
16021615
.unwrap()
16031616
.insert(id.clone(), device_node!(id, gpio_device));
16041617

1618+
// On AArch64, the UEFI binary requires a flash device at address 0.
1619+
// 4 MiB memory is mapped to simulate the flash.
1620+
let uefi_mem_slot = self.memory_manager.lock().unwrap().allocate_memory_slot();
1621+
let uefi_region = GuestRegionMmap::new(
1622+
MmapRegion::new(arch::layout::UEFI_SIZE as usize).unwrap(),
1623+
arch::layout::UEFI_START,
1624+
)
1625+
.unwrap();
1626+
let uefi_mem_region = self
1627+
.memory_manager
1628+
.lock()
1629+
.unwrap()
1630+
.vm
1631+
.make_user_memory_region(
1632+
uefi_mem_slot,
1633+
uefi_region.start_addr().raw_value(),
1634+
uefi_region.len() as u64,
1635+
uefi_region.as_ptr() as u64,
1636+
false,
1637+
false,
1638+
);
1639+
self.memory_manager
1640+
.lock()
1641+
.unwrap()
1642+
.vm
1643+
.create_user_memory_region(uefi_mem_region)
1644+
.map_err(DeviceManagerError::CreateUefiFlash)?;
1645+
1646+
let uefi_flash =
1647+
GuestMemoryAtomic::new(GuestMemoryMmap::from_regions(vec![uefi_region]).unwrap());
1648+
self.uefi_flash = Some(uefi_flash);
1649+
16051650
Ok(())
16061651
}
16071652

@@ -4141,6 +4186,11 @@ impl DeviceManager {
41414186
pub fn iommu_attached_devices(&self) -> &Option<(PciBdf, Vec<PciBdf>)> {
41424187
&self.iommu_attached_devices
41434188
}
4189+
4190+
#[cfg(target_arch = "aarch64")]
4191+
pub fn uefi_flash(&self) -> GuestMemoryAtomic<GuestMemoryMmap> {
4192+
self.uefi_flash.as_ref().unwrap().clone()
4193+
}
41444194
}
41454195

41464196
fn numa_node_id_from_memory_zone_id(numa_nodes: &NumaNodes, memory_zone_id: &str) -> Option<u32> {

vmm/src/vm.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1001,8 +1001,11 @@ impl Vm {
10011001
// If failed, retry to load it as UEFI binary.
10021002
// As the UEFI binary is formatless, it must be the last option to try.
10031003
Err(linux_loader::loader::Error::Pe(InvalidImageMagicNumber)) => {
1004+
let uefi_flash = self.device_manager.lock().as_ref().unwrap().uefi_flash();
1005+
let mem = uefi_flash.memory();
10041006
arch::aarch64::uefi::load_uefi(mem.deref(), arch::layout::UEFI_START, &mut kernel)
10051007
.map_err(Error::UefiLoad)?;
1008+
10061009
// The entry point offset in UEFI image is always 0.
10071010
return Ok(EntryPoint {
10081011
entry_addr: arch::layout::UEFI_START,

0 commit comments

Comments
 (0)