diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 40df8664f..8e1c30941 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -154,15 +154,153 @@ pub fn configure_system( num_cpus: u8, setup_hdr: Option, rsdp_addr: Option, + 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, +) -> 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 = 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::() * 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::() 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::()) + .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, + 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, + rsdp_addr: Option, ) -> super::Result<()> { const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; const KERNEL_HDR_MAGIC: u32 = 0x53726448; const KERNEL_LOADER_OTHER: u8 = 0xff; 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()); if let Some(hdr) = setup_hdr { @@ -272,7 +410,15 @@ mod tests { fn test_system_configuration() { let no_vcpus = 4; 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()); // Now assigning some memory that falls before the 32bit memory hole. @@ -284,7 +430,16 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); 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. let mem_size = 3328 << 20; @@ -295,7 +450,16 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); 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. let mem_size = 3330 << 20; @@ -306,7 +470,16 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); 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] diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index c833f8384..980d6125d 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -446,6 +446,7 @@ impl Vm { boot_vcpus, Some(hdr), rsdp_addr, + BootProtocol::LinuxBoot, ) .map_err(Error::ConfigureSystem)?; @@ -480,6 +481,7 @@ impl Vm { boot_vcpus, None, rsdp_addr, + boot_prot, ) .map_err(Error::ConfigureSystem)?;