diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 5460b6f5f..2f4089125 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -98,8 +98,8 @@ pub mod x86_64; #[cfg(target_arch = "x86_64")] pub use x86_64::{ arch_memory_regions, configure_system, configure_vcpu, get_host_cpu_phys_bits, - initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, - BootProtocol, CpuidPatch, CpuidReg, EntryPoint, + initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, CpuidPatch, + CpuidReg, EntryPoint, }; /// Safe wrapper for `sysconf(_SC_PAGESIZE)`. diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 3b33cd11c..cbbf27442 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -14,7 +14,7 @@ pub mod regs; use crate::InitramfsConfig; use crate::RegionType; use hypervisor::{CpuId, CpuIdEntry, CPUID_FLAG_VALID_INDEX}; -use linux_loader::loader::bootparam::{boot_params, setup_header}; +use linux_loader::loader::bootparam::boot_params; use linux_loader::loader::elf::start_info::{ hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, }; @@ -28,21 +28,6 @@ use std::arch::x86_64; #[cfg(feature = "tdx")] pub mod tdx; -#[derive(Debug, Copy, Clone)] -pub enum BootProtocol { - LinuxBoot, - PvhBoot, -} - -impl ::std::fmt::Display for BootProtocol { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - match self { - BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"), - BootProtocol::PvhBoot => write!(f, "PVH boot protocol"), - } - } -} - #[derive(Debug, Copy, Clone)] /// Specifies the entry point address where the guest must start /// executing code, as well as which of the supported boot protocols @@ -50,10 +35,6 @@ impl ::std::fmt::Display for BootProtocol { pub struct EntryPoint { /// Address in guest memory where the guest must start execution pub entry_addr: GuestAddress, - /// Specifies which boot protocol to use - pub protocol: BootProtocol, - /// This field is used for bzImage to fill zero page - pub setup_header: Option, } const E820_RAM: u32 = 1; @@ -351,17 +332,10 @@ pub fn configure_vcpu( regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?; if let Some(kernel_entry_point) = kernel_entry_point { // Safe to unwrap because this method is called after the VM is configured - regs::setup_regs( - fd, - kernel_entry_point.entry_addr.raw_value(), - layout::BOOT_STACK_POINTER.raw_value(), - layout::ZERO_PAGE_START.raw_value(), - kernel_entry_point.protocol, - ) - .map_err(Error::RegsConfiguration)?; + regs::setup_regs(fd, kernel_entry_point.entry_addr.raw_value()) + .map_err(Error::RegsConfiguration)?; regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?; - regs::setup_sregs(&vm_memory.memory(), fd, kernel_entry_point.protocol) - .map_err(Error::SregsConfiguration)?; + regs::setup_sregs(&vm_memory.memory(), fd).map_err(Error::SregsConfiguration)?; } interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?; Ok(()) @@ -426,12 +400,9 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region pub fn configure_system( guest_mem: &GuestMemoryMmap, cmdline_addr: GuestAddress, - cmdline_size: usize, initramfs: &Option, _num_cpus: u8, - setup_hdr: Option, rsdp_addr: Option, - boot_prot: BootProtocol, sgx_epc_region: Option, ) -> super::Result<()> { let size = smbios::setup_smbios(guest_mem).map_err(Error::SmbiosSetup)?; @@ -448,31 +419,13 @@ pub fn configure_system( } } - match boot_prot { - BootProtocol::PvhBoot => { - configure_pvh( - guest_mem, - cmdline_addr, - initramfs, - rsdp_addr, - sgx_epc_region, - )?; - } - BootProtocol::LinuxBoot => { - error!("Using deprecated LinuxBoot protocol: Please configure your kernel with CONFIG_PVH=y and supply the `vmlinux` file to `--kernel`"); - configure_64bit_boot( - guest_mem, - cmdline_addr, - cmdline_size, - initramfs, - setup_hdr, - rsdp_addr, - sgx_epc_region, - )?; - } - } - - Ok(()) + configure_pvh( + guest_mem, + cmdline_addr, + initramfs, + rsdp_addr, + sgx_epc_region, + ) } fn configure_pvh( @@ -615,121 +568,6 @@ fn add_memmap_entry(memmap: &mut Vec, addr: u64, size: u }); } -fn configure_64bit_boot( - guest_mem: &GuestMemoryMmap, - cmdline_addr: GuestAddress, - cmdline_size: usize, - initramfs: &Option, - setup_hdr: Option, - rsdp_addr: Option, - sgx_epc_region: 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. - - let mut params: BootParamsWrapper = BootParamsWrapper(boot_params::default()); - - if let Some(hdr) = setup_hdr { - // We should use the header if the loader provides one (e.g. from a bzImage). - params.0.hdr = hdr; - } else { - params.0.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC; - params.0.hdr.header = KERNEL_HDR_MAGIC; - params.0.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES; - }; - - // Common bootparams settings - if params.0.hdr.type_of_loader == 0 { - params.0.hdr.type_of_loader = KERNEL_LOADER_OTHER; - } - params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32; - params.0.hdr.cmdline_size = cmdline_size as u32; - - if let Some(initramfs_config) = initramfs { - params.0.hdr.ramdisk_image = initramfs_config.address.raw_value() as u32; - params.0.hdr.ramdisk_size = initramfs_config.size as u32; - } - - add_e820_entry(&mut params.0, 0, layout::EBDA_START.raw_value(), E820_RAM)?; - - let mem_end = guest_mem.last_addr(); - if mem_end < layout::MEM_32BIT_RESERVED_START { - add_e820_entry( - &mut params.0, - layout::HIGH_RAM_START.raw_value(), - mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1, - E820_RAM, - )?; - } else { - add_e820_entry( - &mut params.0, - 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_e820_entry( - &mut params.0, - layout::RAM_64BIT_START.raw_value(), - mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1, - E820_RAM, - )?; - } - } - - add_e820_entry( - &mut params.0, - layout::PCI_MMCONFIG_START.0, - layout::PCI_MMCONFIG_SIZE, - E820_RESERVED, - )?; - - if let Some(sgx_epc_region) = sgx_epc_region { - add_e820_entry( - &mut params.0, - sgx_epc_region.start().raw_value(), - sgx_epc_region.size() as u64, - E820_RESERVED, - )?; - } - - if let Some(rsdp_addr) = rsdp_addr { - params.0.acpi_rsdp_addr = rsdp_addr.0; - } - - let zero_page_addr = layout::ZERO_PAGE_START; - guest_mem - .checked_offset(zero_page_addr, mem::size_of::()) - .ok_or(super::Error::ZeroPagePastRamEnd)?; - guest_mem - .write_obj(params, zero_page_addr) - .map_err(super::Error::ZeroPageSetup)?; - - Ok(()) -} - -/// Add an e820 region to the e820 map. -/// Returns Ok(()) if successful, or an error if there is no space left in the map. -fn add_e820_entry( - params: &mut boot_params, - addr: u64, - size: u64, - mem_type: u32, -) -> Result<(), Error> { - if params.e820_entries >= params.e820_table.len() as u8 { - return Err(Error::E820Configuration); - } - - params.e820_table[params.e820_entries as usize].addr = addr; - params.e820_table[params.e820_entries as usize].size = size; - params.e820_table[params.e820_entries as usize].type_ = mem_type; - params.e820_entries += 1; - - Ok(()) -} - /// Returns the memory address where the initramfs could be loaded. pub fn initramfs_load_addr( guest_mem: &GuestMemoryMmap, @@ -888,7 +726,6 @@ pub fn update_cpuid_sgx(cpuid: &mut CpuId, epc_sections: Vec) -> #[cfg(test)] mod tests { use super::*; - use linux_loader::loader::bootparam::boot_e820_entry; #[test] fn regions_lt_4gb() { @@ -913,12 +750,9 @@ mod tests { let config_err = configure_system( &gm, GuestAddress(0), - 0, &None, 1, - None, Some(layout::RSDP_POINTER), - BootProtocol::LinuxBoot, None, ); assert!(config_err.is_err()); @@ -932,31 +766,8 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); - configure_system( - &gm, - GuestAddress(0), - 0, - &None, - no_vcpus, - None, - None, - BootProtocol::LinuxBoot, - None, - ) - .unwrap(); - configure_system( - &gm, - GuestAddress(0), - 0, - &None, - no_vcpus, - None, - None, - BootProtocol::PvhBoot, - None, - ) - .unwrap(); + configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap(); // Now assigning some memory that is equal to the start of the 32bit memory hole. let mem_size = 3328 << 20; @@ -967,31 +778,9 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); - configure_system( - &gm, - GuestAddress(0), - 0, - &None, - no_vcpus, - None, - None, - BootProtocol::LinuxBoot, - None, - ) - .unwrap(); + configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap(); - configure_system( - &gm, - GuestAddress(0), - 0, - &None, - no_vcpus, - None, - None, - BootProtocol::PvhBoot, - None, - ) - .unwrap(); + configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap(); // Now assigning some memory that falls after the 32bit memory hole. let mem_size = 3330 << 20; @@ -1002,71 +791,9 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); - configure_system( - &gm, - GuestAddress(0), - 0, - &None, - no_vcpus, - None, - None, - BootProtocol::LinuxBoot, - None, - ) - .unwrap(); + configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap(); - configure_system( - &gm, - GuestAddress(0), - 0, - &None, - no_vcpus, - None, - None, - BootProtocol::PvhBoot, - None, - ) - .unwrap(); - } - - #[test] - fn test_add_e820_entry() { - let e820_table = [(boot_e820_entry { - addr: 0x1, - size: 4, - type_: 1, - }); 128]; - - let expected_params = boot_params { - e820_table, - e820_entries: 1, - ..Default::default() - }; - - let mut params: boot_params = Default::default(); - add_e820_entry( - &mut params, - e820_table[0].addr, - e820_table[0].size, - e820_table[0].type_, - ) - .unwrap(); - assert_eq!( - format!("{:?}", params.e820_table[0]), - format!("{:?}", expected_params.e820_table[0]) - ); - assert_eq!(params.e820_entries, expected_params.e820_entries); - - // Exercise the scenario where the field storing the length of the e820 entry table is - // is bigger than the allocated memory. - params.e820_entries = params.e820_table.len() as u8 + 1; - assert!(add_e820_entry( - &mut params, - e820_table[0].addr, - e820_table[0].size, - e820_table[0].type_ - ) - .is_err()); + configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap(); } #[test] diff --git a/arch/src/x86_64/regs.rs b/arch/src/x86_64/regs.rs index 1887484f9..47f3ff3fd 100644 --- a/arch/src/x86_64/regs.rs +++ b/arch/src/x86_64/regs.rs @@ -9,13 +9,10 @@ use std::sync::Arc; use std::{mem, result}; -use super::BootProtocol; use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt}; use hypervisor::arch::x86::regs::*; use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters}; -use layout::{ - BOOT_GDT_START, BOOT_IDT_START, PDE_START, PDPTE_START, PML4_START, PML5_START, PVH_INFO_START, -}; +use layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START}; use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryMmap}; #[derive(Debug)] @@ -81,32 +78,12 @@ pub fn setup_msrs(vcpu: &Arc) -> Result<()> { /// /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. /// * `boot_ip` - Starting instruction pointer. -/// * `boot_sp` - Starting stack pointer. -/// * `boot_si` - Must point to zero page address per Linux ABI. -pub fn setup_regs( - vcpu: &Arc, - boot_ip: u64, - boot_sp: u64, - boot_si: u64, - boot_prot: BootProtocol, -) -> Result<()> { - let regs: StandardRegisters = match boot_prot { - // Configure regs as required by PVH boot protocol. - BootProtocol::PvhBoot => StandardRegisters { - rflags: 0x0000000000000002u64, - rbx: PVH_INFO_START.raw_value(), - rip: boot_ip, - ..Default::default() - }, - // Configure regs as required by Linux 64-bit boot protocol. - BootProtocol::LinuxBoot => StandardRegisters { - rflags: 0x0000000000000002u64, - rip: boot_ip, - rsp: boot_sp, - rbp: boot_sp, - rsi: boot_si, - ..Default::default() - }, +pub fn setup_regs(vcpu: &Arc, boot_ip: u64) -> Result<()> { + let regs = StandardRegisters { + rflags: 0x0000000000000002u64, + rbx: PVH_INFO_START.raw_value(), + rip: boot_ip, + ..Default::default() }; vcpu.set_regs(®s).map_err(Error::SetBaseRegisters) } @@ -117,19 +94,9 @@ pub fn setup_regs( /// /// * `mem` - The memory that will be passed to the guest. /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. -pub fn setup_sregs( - mem: &GuestMemoryMmap, - vcpu: &Arc, - boot_prot: BootProtocol, -) -> Result<()> { +pub fn setup_sregs(mem: &GuestMemoryMmap, vcpu: &Arc) -> Result<()> { let mut sregs: SpecialRegisters = vcpu.get_sregs().map_err(Error::GetStatusRegisters)?; - - configure_segments_and_sregs(mem, &mut sregs, boot_prot)?; - - if let BootProtocol::LinuxBoot = boot_prot { - setup_page_tables(mem, &mut sregs)?; // TODO(dgreid) - Can this be done once per system instead? - } - + configure_segments_and_sregs(mem, &mut sregs)?; vcpu.set_sregs(&sregs).map_err(Error::SetStatusRegisters) } @@ -156,27 +123,15 @@ fn write_idt_value(val: u64, guest_mem: &GuestMemoryMmap) -> Result<()> { pub fn configure_segments_and_sregs( mem: &GuestMemoryMmap, sregs: &mut SpecialRegisters, - boot_prot: BootProtocol, ) -> Result<()> { - let gdt_table: [u64; BOOT_GDT_MAX as usize] = match boot_prot { - BootProtocol::PvhBoot => { - // Configure GDT entries as specified by PVH boot protocol - [ - gdt_entry(0, 0, 0), // NULL - gdt_entry(0xc09b, 0, 0xffffffff), // CODE - gdt_entry(0xc093, 0, 0xffffffff), // DATA - gdt_entry(0x008b, 0, 0x67), // TSS - ] - } - BootProtocol::LinuxBoot => { - // Configure GDT entries as specified by Linux 64bit boot protocol - [ - gdt_entry(0, 0, 0), // NULL - gdt_entry(0xa09b, 0, 0xfffff), // CODE - gdt_entry(0xc093, 0, 0xfffff), // DATA - gdt_entry(0x808b, 0, 0xfffff), // TSS - ] - } + let gdt_table: [u64; BOOT_GDT_MAX as usize] = { + // Configure GDT entries as specified by PVH boot protocol + [ + gdt_entry(0, 0, 0), // NULL + gdt_entry(0xc09b, 0, 0xffffffff), // CODE + gdt_entry(0xc093, 0, 0xffffffff), // DATA + gdt_entry(0x008b, 0, 0x67), // TSS + ] }; let code_seg = segment_from_gdt(gdt_table[1], 1); @@ -200,51 +155,8 @@ pub fn configure_segments_and_sregs( sregs.ss = data_seg; sregs.tr = tss_seg; - match boot_prot { - BootProtocol::PvhBoot => { - sregs.cr0 = CR0_PE; - sregs.cr4 = 0; - } - BootProtocol::LinuxBoot => { - /* 64-bit protected mode */ - sregs.cr0 |= CR0_PE; - sregs.efer |= EFER_LME | EFER_LMA; - } - } - - Ok(()) -} - -pub fn setup_page_tables(mem: &GuestMemoryMmap, sregs: &mut SpecialRegisters) -> Result<()> { - // Puts PML5 or PML4 right after zero page but aligned to 4k. - if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 { - // Entry covering VA [0..256TB) - mem.write_obj(PML4_START.raw_value() | 0x03, PML5_START) - .map_err(Error::WritePml5Address)?; - - sregs.cr3 = PML5_START.raw_value(); - sregs.cr4 |= CR4_LA57; - } else { - sregs.cr3 = PML4_START.raw_value(); - } - - // Entry covering VA [0..512GB) - mem.write_obj(PDPTE_START.raw_value() | 0x03, PML4_START) - .map_err(Error::WritePml4Address)?; - - // Entry covering VA [0..1GB) - mem.write_obj(PDE_START.raw_value() | 0x03, PDPTE_START) - .map_err(Error::WritePdpteAddress)?; - - // 512 2MB entries together covering VA [0..1GB). Note we are assuming - // CPU supports 2MB pages (/proc/cpuinfo has 'pse'). All modern CPUs do. - for i in 0..512 { - mem.write_obj((i << 21) + 0x83u64, PDE_START.unchecked_add(i * 8)) - .map_err(Error::WritePdeAddress)?; - } - - sregs.cr4 |= CR4_PAE; - sregs.cr0 |= CR0_PG; + sregs.cr0 = CR0_PE; + sregs.cr4 = 0; Ok(()) } @@ -268,36 +180,7 @@ mod tests { fn segments_and_sregs() { let mut sregs: SpecialRegisters = Default::default(); let gm = create_guest_mem(); - configure_segments_and_sregs(&gm, &mut sregs, BootProtocol::LinuxBoot).unwrap(); - - assert_eq!(0x0, read_u64(&gm, BOOT_GDT_START)); - assert_eq!( - 0xaf9b000000ffff, - read_u64(&gm, BOOT_GDT_START.unchecked_add(8)) - ); - assert_eq!( - 0xcf93000000ffff, - read_u64(&gm, BOOT_GDT_START.unchecked_add(16)) - ); - assert_eq!( - 0x8f8b000000ffff, - read_u64(&gm, BOOT_GDT_START.unchecked_add(24)) - ); - assert_eq!(0x0, read_u64(&gm, BOOT_IDT_START)); - - assert_eq!(0, sregs.cs.base); - assert_eq!(0xffffffff, sregs.ds.limit); - assert_eq!(0x10, sregs.es.selector); - assert_eq!(1, sregs.fs.present); - assert_eq!(1, sregs.gs.g); - assert_eq!(0, sregs.ss.avl); - assert_eq!(0, sregs.tr.base); - assert_eq!(0xffffffff, sregs.tr.limit); - assert_eq!(0, sregs.tr.avl); - assert_eq!(CR0_PE, sregs.cr0); - assert_eq!(EFER_LME | EFER_LMA, sregs.efer); - - configure_segments_and_sregs(&gm, &mut sregs, BootProtocol::PvhBoot).unwrap(); + configure_segments_and_sregs(&gm, &mut sregs).unwrap(); assert_eq!(0x0, read_u64(&gm, BOOT_GDT_START)); assert_eq!( 0xcf9b000000ffff, @@ -327,31 +210,4 @@ mod tests { assert_eq!(CR0_PE, sregs.cr0); assert_eq!(0, sregs.cr4); } - - #[test] - fn page_tables() { - let mut sregs: SpecialRegisters = Default::default(); - let gm = create_guest_mem(); - setup_page_tables(&gm, &mut sregs).unwrap(); - - if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 { - assert_eq!(0xa003, read_u64(&gm, PML5_START)); - } - assert_eq!(0xb003, read_u64(&gm, PML4_START)); - assert_eq!(0xc003, read_u64(&gm, PDPTE_START)); - for i in 0..512 { - assert_eq!( - (i << 21) + 0x83u64, - read_u64(&gm, PDE_START.unchecked_add(i * 8)) - ); - } - - if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 { - assert_eq!(PML5_START.raw_value(), sregs.cr3); - } else { - assert_eq!(PML4_START.raw_value(), sregs.cr3); - } - assert_eq!(CR4_PAE, sregs.cr4); - assert_eq!(CR0_PG, sregs.cr0); - } } diff --git a/src/main.rs b/src/main.rs index 42dffee56..30f22d9fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -194,7 +194,7 @@ fn create_app<'a, 'b>( .long("kernel") .help( "Path to loaded kernel. This may be a kernel or firmware that supports a PVH \ - entry point, a vmlinux ELF file or a Linux bzImage or achitecture equivalent", + entry point (e.g. vmlinux) or architecture equivalent", ) .takes_value(true) .group("vm-config"), diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 92dfcfec8..86a02754e 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -1558,13 +1558,9 @@ impl Migratable for CpuManager {} #[cfg(all(feature = "kvm", target_arch = "x86_64"))] #[cfg(test)] mod tests { - - use super::*; use arch::x86_64::interrupts::*; use arch::x86_64::regs::*; - use arch::x86_64::BootProtocol; - use hypervisor::x86_64::{FpuState, LapicState, SpecialRegisters, StandardRegisters}; - use vm_memory::GuestAddress; + use hypervisor::x86_64::{FpuState, LapicState, StandardRegisters}; #[test] fn test_setlint() { @@ -1652,41 +1648,16 @@ mod tests { let expected_regs: StandardRegisters = StandardRegisters { rflags: 0x0000000000000002u64, + rbx: arch::layout::PVH_INFO_START.0, rip: 1, - rsp: 2, - rbp: 2, - rsi: 3, ..Default::default() }; - setup_regs( - &vcpu, - expected_regs.rip, - expected_regs.rsp, - expected_regs.rsi, - BootProtocol::LinuxBoot, - ) - .unwrap(); + setup_regs(&vcpu, expected_regs.rip).unwrap(); let actual_regs: StandardRegisters = vcpu.get_regs().unwrap(); assert_eq!(actual_regs, expected_regs); } - - #[test] - fn test_setup_sregs() { - let hv = hypervisor::new().unwrap(); - let vm = hv.create_vm().expect("new VM fd creation failed"); - let vcpu = vm.create_vcpu(0, None).unwrap(); - - let mut expected_sregs: SpecialRegisters = vcpu.get_sregs().unwrap(); - let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap(); - configure_segments_and_sregs(&gm, &mut expected_sregs, BootProtocol::LinuxBoot).unwrap(); - setup_page_tables(&gm, &mut expected_sregs).unwrap(); - - setup_sregs(&gm, &vcpu, BootProtocol::LinuxBoot).unwrap(); - let actual_sregs: SpecialRegisters = vcpu.get_sregs().unwrap(); - assert_eq!(expected_sregs, actual_sregs); - } } #[cfg(target_arch = "aarch64")] diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 45e529d2e..ee324119d 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -41,15 +41,11 @@ use crate::{ }; use anyhow::anyhow; use arch::get_host_cpu_phys_bits; -#[cfg(target_arch = "x86_64")] -use arch::BootProtocol; use arch::EntryPoint; use devices::AcpiNotificationFlags; use hypervisor::vm::{HypervisorVmError, VmmOps}; use linux_loader::cmdline::Cmdline; #[cfg(target_arch = "x86_64")] -use linux_loader::loader::elf::Error::InvalidElfMagicNumber; -#[cfg(target_arch = "x86_64")] use linux_loader::loader::elf::PvhBootCapability::PvhEntryPresent; use linux_loader::loader::KernelLoader; use seccomp::{SeccompAction, SeccompFilter}; @@ -89,10 +85,6 @@ use arch::aarch64::gic::gicv3::kvm::{KvmGicV3, GIC_V3_SNAPSHOT_ID}; #[cfg(target_arch = "aarch64")] use arch::aarch64::gic::kvm::create_gic; -// 64 bit direct boot entry offset for bzImage -#[cfg(target_arch = "x86_64")] -const KERNEL_64BIT_ENTRY_OFFSET: u64 = 0x200; - /// Errors associated with VM management #[derive(Debug)] pub enum Error { @@ -245,6 +237,9 @@ pub enum Error { /// Error triggering power button PowerButton(device_manager::DeviceManagerError), + /// Kernel lacks PVH header + KernelMissingPvhHeader, + /// Error doing I/O on TDX firmware file #[cfg(feature = "tdx")] LoadTdvf(std::io::Error), @@ -924,15 +919,6 @@ impl Vm { Some(arch::layout::HIGH_RAM_START), ) { Ok(entry_addr) => entry_addr, - Err(linux_loader::loader::Error::Elf(InvalidElfMagicNumber)) => { - linux_loader::loader::bzimage::BzImage::load( - mem.deref(), - None, - &mut kernel, - Some(arch::layout::HIGH_RAM_START), - ) - .map_err(Error::KernelLoad)? - } Err(e) => { return Err(Error::KernelLoad(e)); } @@ -945,43 +931,20 @@ impl Vm { ) .map_err(Error::LoadCmdLine)?; - if entry_addr.setup_header.is_some() { - let load_addr = entry_addr - .kernel_load - .raw_value() - .checked_add(KERNEL_64BIT_ENTRY_OFFSET) - .ok_or(Error::MemOverflow)?; - - Ok(EntryPoint { - entry_addr: GuestAddress(load_addr), - protocol: BootProtocol::LinuxBoot, - setup_header: entry_addr.setup_header, - }) - } else { + if let PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap { + // Use the PVH kernel entry point to boot the guest let entry_point_addr: GuestAddress; - let boot_prot: BootProtocol; - - if let PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap { - // Use the PVH kernel entry point to boot the guest - entry_point_addr = pvh_entry_addr; - boot_prot = BootProtocol::PvhBoot; - } else { - // Use the Linux 64-bit boot protocol - entry_point_addr = entry_addr.kernel_load; - boot_prot = BootProtocol::LinuxBoot; - } - + entry_point_addr = pvh_entry_addr; Ok(EntryPoint { entry_addr: entry_point_addr, - protocol: boot_prot, - setup_header: None, }) + } else { + Err(Error::KernelMissingPvhHeader) } } #[cfg(target_arch = "x86_64")] - fn configure_system(&mut self, entry_addr: EntryPoint) -> Result<()> { - let cmdline_cstring = self.get_cmdline()?; + fn configure_system(&mut self) -> Result<()> { let mem = self.memory_manager.lock().unwrap().boot_guest_memory(); let initramfs_config = match self.initramfs { @@ -1013,41 +976,20 @@ impl Vm { .as_ref() .cloned(); - match entry_addr.setup_header { - Some(hdr) => { - arch::configure_system( - &mem, - arch::layout::CMDLINE_START, - cmdline_cstring.to_bytes().len() + 1, - &initramfs_config, - boot_vcpus, - Some(hdr), - rsdp_addr, - BootProtocol::LinuxBoot, - sgx_epc_region, - ) - .map_err(Error::ConfigureSystem)?; - } - None => { - arch::configure_system( - &mem, - arch::layout::CMDLINE_START, - cmdline_cstring.to_bytes().len() + 1, - &initramfs_config, - boot_vcpus, - None, - rsdp_addr, - entry_addr.protocol, - sgx_epc_region, - ) - .map_err(Error::ConfigureSystem)?; - } - } + arch::configure_system( + &mem, + arch::layout::CMDLINE_START, + &initramfs_config, + boot_vcpus, + rsdp_addr, + sgx_epc_region, + ) + .map_err(Error::ConfigureSystem)?; Ok(()) } #[cfg(target_arch = "aarch64")] - fn configure_system(&mut self, _entry_addr: EntryPoint) -> Result<()> { + fn configure_system(&mut self) -> Result<()> { let cmdline_cstring = self.get_cmdline()?; let vcpu_mpidrs = self.cpu_manager.lock().unwrap().get_mpidrs(); let mem = self.memory_manager.lock().unwrap().boot_guest_memory(); @@ -1715,9 +1657,7 @@ impl Vm { }; // Configure shared state based on loaded kernel - entry_point - .map(|entry_point| self.configure_system(entry_point)) - .transpose()?; + entry_point.map(|_| self.configure_system()).transpose()?; #[cfg(feature = "tdx")] if let Some(hob_address) = hob_address {