devices: Add e820/memory_map to fw_cfg device

We build the memory map in the fw_cfg device based on the memory size.

Signed-off-by: Alex Orozco <alexorozco@google.com>
This commit is contained in:
Alex Orozco
2025-04-18 16:20:58 +00:00
committed by Bo Chen
parent 623fadfa9d
commit f0b69d56d0
2 changed files with 90 additions and 0 deletions

View File

@@ -19,15 +19,35 @@ use std::{
sync::{Arc, Barrier},
};
#[cfg(target_arch = "aarch64")]
use arch::aarch64::layout::{
MEM_32BIT_DEVICES_START, MEM_32BIT_RESERVED_START, RAM_64BIT_START, RAM_START as HIGH_RAM_START,
};
#[cfg(target_arch = "x86_64")]
use arch::layout::{
EBDA_START, HIGH_RAM_START, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START,
MEM_32BIT_RESERVED_START, PCI_MMCONFIG_SIZE, PCI_MMCONFIG_START, RAM_64BIT_START,
};
use arch::RegionType;
#[cfg(target_arch = "x86_64")]
use linux_loader::bootparam::boot_params;
#[cfg(target_arch = "aarch64")]
use linux_loader::loader::pe::arm64_image_header as boot_params;
use vm_device::BusDevice;
use vm_memory::ByteValued;
#[cfg(target_arch = "x86_64")]
use vm_memory::GuestAddress;
use vmm_sys_util::sock_ctrl_msg::IntoIovec;
use zerocopy::{FromBytes, IntoBytes};
#[cfg(target_arch = "x86_64")]
// https://github.com/project-oak/oak/tree/main/stage0_bin#memory-layout
const STAGE0_START_ADDRESS: GuestAddress = GuestAddress(0xfffe_0000);
#[cfg(target_arch = "x86_64")]
const STAGE0_SIZE: usize = 0x2_0000;
const E820_RAM: u32 = 1;
const E820_RESERVED: u32 = 2;
#[cfg(target_arch = "x86_64")]
const PORT_FW_CFG_SELECTOR: u64 = 0x510;
#[cfg(target_arch = "x86_64")]
@@ -165,6 +185,63 @@ impl FwCfg {
}
}
pub fn add_e820(&mut self, mem_size: usize) -> Result<()> {
#[cfg(target_arch = "x86_64")]
let mut mem_regions = vec![
(GuestAddress(0), EBDA_START.0 as usize, RegionType::Ram),
(
MEM_32BIT_DEVICES_START,
MEM_32BIT_DEVICES_SIZE as usize,
RegionType::Reserved,
),
(
PCI_MMCONFIG_START,
PCI_MMCONFIG_SIZE as usize,
RegionType::Reserved,
),
(STAGE0_START_ADDRESS, STAGE0_SIZE, RegionType::Reserved),
];
#[cfg(target_arch = "aarch64")]
let mut mem_regions = arch::aarch64::arch_memory_regions();
if mem_size < MEM_32BIT_DEVICES_START.0 as usize {
mem_regions.push((
HIGH_RAM_START,
mem_size - HIGH_RAM_START.0 as usize,
RegionType::Ram,
));
} else {
mem_regions.push((
HIGH_RAM_START,
MEM_32BIT_RESERVED_START.0 as usize - HIGH_RAM_START.0 as usize,
RegionType::Ram,
));
mem_regions.push((
RAM_64BIT_START,
mem_size - (MEM_32BIT_DEVICES_START.0 as usize),
RegionType::Ram,
));
}
let mut bytes = vec![];
for (addr, size, region) in mem_regions.iter() {
let type_ = match region {
RegionType::Ram => E820_RAM,
RegionType::Reserved => E820_RESERVED,
RegionType::SubRegion => continue,
};
let mut entry = BootE820Entry {
addr: addr.0,
size: *size as u64,
type_,
};
bytes.extend_from_slice(entry.as_mut_bytes());
}
let item = FwCfgItem {
name: "etc/e820".to_owned(),
content: FwCfgContent::Bytes(bytes),
};
self.add_item(item)
}
fn file_dir_mut(&mut self) -> &mut Vec<u8> {
let FwCfgContent::Bytes(file_buf) = &mut self.known_items[FW_CFG_FILE_DIR as usize] else {
unreachable!("fw_cfg: selector {FW_CFG_FILE_DIR:#x} should be FwCfgContent::Byte!")

View File

@@ -351,6 +351,10 @@ pub enum Error {
#[cfg(feature = "fw_cfg")]
#[error("Fw Cfg missing kernel cmdline")]
MissingFwCfgCmdline,
#[cfg(feature = "fw_cfg")]
#[error("Error creating e820 map")]
CreatingE820Map(#[source] io::Error),
}
pub type Result<T> = result::Result<T, Error>;
@@ -801,6 +805,15 @@ impl Vm {
device_manager: &Arc<Mutex<DeviceManager>>,
config: &Arc<Mutex<VmConfig>>,
) -> Result<()> {
device_manager
.lock()
.unwrap()
.fw_cfg()
.expect("fw_cfg device must be present")
.lock()
.unwrap()
.add_e820(config.lock().unwrap().memory.size as usize)
.map_err(Error::CreatingE820Map)?;
let kernel = config
.lock()
.unwrap()