mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-05 21:15:45 +00:00
pvh: Write start_info structure to guest memory
Fill the hvm_start_info and related memory map structures as specified in the PVH boot protocol. Write the data structures to guest memory at the GPA that will be stored in %rbx when the guest starts. Signed-off-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
This commit is contained in:
parent
840a9a97ff
commit
a22bc3559f
@ -154,15 +154,153 @@ pub fn configure_system(
|
|||||||
num_cpus: u8,
|
num_cpus: u8,
|
||||||
setup_hdr: Option<setup_header>,
|
setup_hdr: Option<setup_header>,
|
||||||
rsdp_addr: Option<GuestAddress>,
|
rsdp_addr: Option<GuestAddress>,
|
||||||
|
boot_prot: BootProtocol,
|
||||||
|
) -> super::Result<()> {
|
||||||
|
// Note that this puts the mptable at the last 1k of Linux's 640k base RAM
|
||||||
|
mptable::setup_mptable(guest_mem, num_cpus).map_err(Error::MpTableSetup)?;
|
||||||
|
|
||||||
|
match boot_prot {
|
||||||
|
BootProtocol::PvhBoot => {
|
||||||
|
configure_pvh(guest_mem, cmdline_addr, rsdp_addr)?;
|
||||||
|
}
|
||||||
|
BootProtocol::LinuxBoot => {
|
||||||
|
configure_64bit_boot(guest_mem, cmdline_addr, cmdline_size, setup_hdr, rsdp_addr)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_pvh(
|
||||||
|
guest_mem: &GuestMemoryMmap,
|
||||||
|
cmdline_addr: GuestAddress,
|
||||||
|
rsdp_addr: Option<GuestAddress>,
|
||||||
|
) -> super::Result<()> {
|
||||||
|
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
|
||||||
|
|
||||||
|
let mut start_info: StartInfoWrapper = StartInfoWrapper(hvm_start_info::default());
|
||||||
|
|
||||||
|
start_info.0.magic = XEN_HVM_START_MAGIC_VALUE;
|
||||||
|
start_info.0.version = 1; // pvh has version 1
|
||||||
|
start_info.0.nr_modules = 0;
|
||||||
|
start_info.0.cmdline_paddr = cmdline_addr.raw_value() as u64;
|
||||||
|
start_info.0.memmap_paddr = layout::MEMMAP_START.raw_value();
|
||||||
|
|
||||||
|
if let Some(rsdp_addr) = rsdp_addr {
|
||||||
|
start_info.0.rsdp_paddr = rsdp_addr.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vector to hold the memory maps which needs to be written to guest memory
|
||||||
|
// at MEMMAP_START after all of the mappings are recorded.
|
||||||
|
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
|
||||||
|
|
||||||
|
// Create the memory map entries.
|
||||||
|
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM)?;
|
||||||
|
|
||||||
|
let mem_end = guest_mem.last_addr();
|
||||||
|
|
||||||
|
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
||||||
|
add_memmap_entry(
|
||||||
|
&mut memmap,
|
||||||
|
layout::HIGH_RAM_START.raw_value(),
|
||||||
|
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
|
||||||
|
E820_RAM,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
add_memmap_entry(
|
||||||
|
&mut memmap,
|
||||||
|
layout::HIGH_RAM_START.raw_value(),
|
||||||
|
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
|
||||||
|
E820_RAM,
|
||||||
|
)?;
|
||||||
|
if mem_end > layout::RAM_64BIT_START {
|
||||||
|
add_memmap_entry(
|
||||||
|
&mut memmap,
|
||||||
|
layout::RAM_64BIT_START.raw_value(),
|
||||||
|
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
|
||||||
|
E820_RAM,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_memmap_entry(
|
||||||
|
&mut memmap,
|
||||||
|
layout::PCI_MMCONFIG_START.0,
|
||||||
|
layout::PCI_MMCONFIG_SIZE,
|
||||||
|
E820_RESERVED,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
start_info.0.memmap_entries = memmap.len() as u32;
|
||||||
|
|
||||||
|
// Copy the vector with the memmap table to the MEMMAP_START address
|
||||||
|
// which is already saved in the memmap_paddr field of hvm_start_info struct.
|
||||||
|
let mut memmap_start_addr = layout::MEMMAP_START;
|
||||||
|
|
||||||
|
guest_mem
|
||||||
|
.checked_offset(
|
||||||
|
memmap_start_addr,
|
||||||
|
mem::size_of::<hvm_memmap_table_entry>() * start_info.0.memmap_entries as usize,
|
||||||
|
)
|
||||||
|
.ok_or(super::Error::MemmapTablePastRamEnd)?;
|
||||||
|
|
||||||
|
// For every entry in the memmap vector, create a MemmapTableEntryWrapper
|
||||||
|
// and write it to guest memory.
|
||||||
|
for memmap_entry in memmap {
|
||||||
|
let map_entry_wrapper: MemmapTableEntryWrapper = MemmapTableEntryWrapper(memmap_entry);
|
||||||
|
|
||||||
|
guest_mem
|
||||||
|
.write_obj(map_entry_wrapper, memmap_start_addr)
|
||||||
|
.map_err(|_| super::Error::MemmapTableSetup)?;
|
||||||
|
memmap_start_addr =
|
||||||
|
memmap_start_addr.unchecked_add(mem::size_of::<hvm_memmap_table_entry>() as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The hvm_start_info struct itself must be stored at PVH_START_INFO
|
||||||
|
// address, and %rbx will be initialized to contain PVH_INFO_START prior to
|
||||||
|
// starting the guest, as required by the PVH ABI.
|
||||||
|
let start_info_addr = layout::PVH_INFO_START;
|
||||||
|
|
||||||
|
guest_mem
|
||||||
|
.checked_offset(start_info_addr, mem::size_of::<hvm_start_info>())
|
||||||
|
.ok_or(super::Error::StartInfoPastRamEnd)?;
|
||||||
|
|
||||||
|
// Write the start_info struct to guest memory.
|
||||||
|
guest_mem
|
||||||
|
.write_obj(start_info, start_info_addr)
|
||||||
|
.map_err(|_| super::Error::StartInfoSetup)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_memmap_entry(
|
||||||
|
memmap: &mut Vec<hvm_memmap_table_entry>,
|
||||||
|
addr: u64,
|
||||||
|
size: u64,
|
||||||
|
mem_type: u32,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
// Add the table entry to the vector
|
||||||
|
memmap.push(hvm_memmap_table_entry {
|
||||||
|
addr,
|
||||||
|
size,
|
||||||
|
type_: mem_type,
|
||||||
|
reserved: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_64bit_boot(
|
||||||
|
guest_mem: &GuestMemoryMmap,
|
||||||
|
cmdline_addr: GuestAddress,
|
||||||
|
cmdline_size: usize,
|
||||||
|
setup_hdr: Option<setup_header>,
|
||||||
|
rsdp_addr: Option<GuestAddress>,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
|
const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
|
||||||
const KERNEL_HDR_MAGIC: u32 = 0x53726448;
|
const KERNEL_HDR_MAGIC: u32 = 0x53726448;
|
||||||
const KERNEL_LOADER_OTHER: u8 = 0xff;
|
const KERNEL_LOADER_OTHER: u8 = 0xff;
|
||||||
const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero.
|
const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero.
|
||||||
|
|
||||||
// Note that this puts the mptable at the last 1k of Linux's 640k base RAM
|
|
||||||
mptable::setup_mptable(guest_mem, num_cpus).map_err(Error::MpTableSetup)?;
|
|
||||||
|
|
||||||
let mut params: BootParamsWrapper = BootParamsWrapper(boot_params::default());
|
let mut params: BootParamsWrapper = BootParamsWrapper(boot_params::default());
|
||||||
|
|
||||||
if let Some(hdr) = setup_hdr {
|
if let Some(hdr) = setup_hdr {
|
||||||
@ -272,7 +410,15 @@ mod tests {
|
|||||||
fn test_system_configuration() {
|
fn test_system_configuration() {
|
||||||
let no_vcpus = 4;
|
let no_vcpus = 4;
|
||||||
let gm = GuestMemoryMmap::from_ranges(&vec![(GuestAddress(0), 0x10000)]).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&vec![(GuestAddress(0), 0x10000)]).unwrap();
|
||||||
let config_err = configure_system(&gm, GuestAddress(0), 0, 1, None, None);
|
let config_err = configure_system(
|
||||||
|
&gm,
|
||||||
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
BootProtocol::LinuxBoot,
|
||||||
|
);
|
||||||
assert!(config_err.is_err());
|
assert!(config_err.is_err());
|
||||||
|
|
||||||
// Now assigning some memory that falls before the 32bit memory hole.
|
// Now assigning some memory that falls before the 32bit memory hole.
|
||||||
@ -284,7 +430,16 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(&gm, GuestAddress(0), 0, no_vcpus, None, None).unwrap();
|
configure_system(
|
||||||
|
&gm,
|
||||||
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
|
no_vcpus,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
BootProtocol::LinuxBoot,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
||||||
let mem_size = 3328 << 20;
|
let mem_size = 3328 << 20;
|
||||||
@ -295,7 +450,16 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(&gm, GuestAddress(0), 0, no_vcpus, None, None).unwrap();
|
configure_system(
|
||||||
|
&gm,
|
||||||
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
|
no_vcpus,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
BootProtocol::LinuxBoot,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Now assigning some memory that falls after the 32bit memory hole.
|
// Now assigning some memory that falls after the 32bit memory hole.
|
||||||
let mem_size = 3330 << 20;
|
let mem_size = 3330 << 20;
|
||||||
@ -306,7 +470,16 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(&gm, GuestAddress(0), 0, no_vcpus, None, None).unwrap();
|
configure_system(
|
||||||
|
&gm,
|
||||||
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
|
no_vcpus,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
BootProtocol::LinuxBoot,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -446,6 +446,7 @@ impl Vm {
|
|||||||
boot_vcpus,
|
boot_vcpus,
|
||||||
Some(hdr),
|
Some(hdr),
|
||||||
rsdp_addr,
|
rsdp_addr,
|
||||||
|
BootProtocol::LinuxBoot,
|
||||||
)
|
)
|
||||||
.map_err(Error::ConfigureSystem)?;
|
.map_err(Error::ConfigureSystem)?;
|
||||||
|
|
||||||
@ -480,6 +481,7 @@ impl Vm {
|
|||||||
boot_vcpus,
|
boot_vcpus,
|
||||||
None,
|
None,
|
||||||
rsdp_addr,
|
rsdp_addr,
|
||||||
|
boot_prot,
|
||||||
)
|
)
|
||||||
.map_err(Error::ConfigureSystem)?;
|
.map_err(Error::ConfigureSystem)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user