From f0360c92d9fdf028b15a098cf62586b10a683a90 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Wed, 18 Sep 2019 15:11:56 +0100 Subject: [PATCH] arch: acpi: Set the upper device range based on RAM levels After the 32-bit gap the memory is shared between the devices and the RAM. Ensure that the ACPI tables correctly indicate where the RAM ends and the device area starts by patching the precompiled tables. We get the following valid output now from the PCI bus probing (8GiB guest) [ 0.317757] pci_bus 0000:00: resource 4 [io 0x0000-0x0cf7 window] [ 0.319035] pci_bus 0000:00: resource 5 [io 0x0d00-0xffff window] [ 0.320215] pci_bus 0000:00: resource 6 [mem 0x000a0000-0x000bffff window] [ 0.321431] pci_bus 0000:00: resource 7 [mem 0xc0000000-0xfebfffff window] [ 0.322613] pci_bus 0000:00: resource 8 [mem 0x240000000-0xfffffffff window] Signed-off-by: Rob Bradford --- arch/src/x86_64/acpi.rs | 19 +++++++++++--- arch/src/x86_64/mod.rs | 57 +++++++++++++++++++++++++++++++++++++---- vmm/src/vm.rs | 4 ++- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/arch/src/x86_64/acpi.rs b/arch/src/x86_64/acpi.rs index 7147937ef..8148fc6b9 100644 --- a/arch/src/x86_64/acpi.rs +++ b/arch/src/x86_64/acpi.rs @@ -51,7 +51,11 @@ struct PCIRangeEntry { _reserved: u32, } -pub fn create_dsdt_table(serial_enabled: bool) -> SDT { +pub fn create_dsdt_table( + serial_enabled: bool, + start_of_device_area: GuestAddress, + end_of_device_area: GuestAddress, +) -> SDT { /* The hex tables in this file are generated from the ASL below with: "iasl -tc " @@ -126,7 +130,7 @@ pub fn create_dsdt_table(serial_enabled: bool) -> SDT { }) } */ - let pci_dsdt_data = [ + let mut pci_dsdt_data = [ 0x5Bu8, 0x82, 0x36, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x0A, 0x08, 0x08, 0x5F, 0x43, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x0A, 0x03, 0x08, 0x5F, 0x41, 0x44, 0x52, 0x00, 0x08, 0x5F, 0x53, 0x45, 0x47, 0x00, 0x08, @@ -145,6 +149,13 @@ pub fn create_dsdt_table(serial_enabled: bool) -> SDT { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x79, 0x00, ]; + // Patch the Range Minimum/Range Maximum/Length for the the 64-bit device area + pci_dsdt_data[200..208].copy_from_slice(&(start_of_device_area.0).to_le_bytes()); + pci_dsdt_data[208..216].copy_from_slice(&end_of_device_area.0.to_le_bytes()); + pci_dsdt_data[224..232].copy_from_slice( + &(end_of_device_area.unchecked_offset_from(start_of_device_area)).to_le_bytes(), + ); + /* Device (_SB.COM1) { @@ -194,13 +205,15 @@ pub fn create_acpi_tables( guest_mem: &GuestMemoryMmap, num_cpus: u8, serial_enabled: bool, + start_of_device_area: GuestAddress, + end_of_device_area: GuestAddress, ) -> GuestAddress { // RSDP is at the EBDA let rsdp_offset = super::EBDA_START; let mut tables: Vec = Vec::new(); // DSDT - let dsdt = create_dsdt_table(serial_enabled); + let dsdt = create_dsdt_table(serial_enabled, start_of_device_area, end_of_device_area); let dsdt_offset = rsdp_offset.checked_add(RSDP::len() as u64).unwrap(); guest_mem .write_slice(dsdt.as_slice(), dsdt_offset) diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 8baf1fd24..c2ee5295f 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -130,6 +130,7 @@ pub fn configure_system( num_cpus: u8, setup_hdr: Option, _serial_enabled: bool, + _end_of_range: GuestAddress, ) -> super::Result<()> { const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; const KERNEL_HDR_MAGIC: u32 = 0x53726448; @@ -187,7 +188,18 @@ pub fn configure_system( #[cfg(feature = "acpi")] { - let rsdp_addr = acpi::create_acpi_tables(guest_mem, num_cpus, _serial_enabled); + let start_of_device_area = if mem_end < end_32bit_gap_start { + first_addr_past_32bits + } else { + guest_mem.end_addr().unchecked_add(1) + }; + let rsdp_addr = acpi::create_acpi_tables( + guest_mem, + num_cpus, + _serial_enabled, + start_of_device_area, + _end_of_range, + ); params.0.acpi_rsdp_addr = rsdp_addr.0; } @@ -257,7 +269,15 @@ mod tests { fn test_system_configuration() { let no_vcpus = 4; let gm = GuestMemoryMmap::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); - let config_err = configure_system(&gm, GuestAddress(0), 0, 1, None, false); + let config_err = configure_system( + &gm, + GuestAddress(0), + 0, + 1, + None, + false, + GuestAddress((1 << 36) - 1), + ); assert!(config_err.is_err()); assert_eq!( config_err.unwrap_err(), @@ -275,7 +295,16 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::new(&ram_regions).unwrap(); - configure_system(&gm, GuestAddress(0), 0, no_vcpus, None, false).unwrap(); + configure_system( + &gm, + GuestAddress(0), + 0, + no_vcpus, + None, + false, + GuestAddress((1 << 36) - 1), + ) + .unwrap(); // Now assigning some memory that is equal to the start of the 32bit memory hole. let mem_size = 3328 << 20; @@ -286,7 +315,16 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::new(&ram_regions).unwrap(); - configure_system(&gm, GuestAddress(0), 0, no_vcpus, None, false).unwrap(); + configure_system( + &gm, + GuestAddress(0), + 0, + no_vcpus, + None, + false, + GuestAddress((1 << 36) - 1), + ) + .unwrap(); // Now assigning some memory that falls after the 32bit memory hole. let mem_size = 3330 << 20; @@ -297,7 +335,16 @@ mod tests { .map(|r| (r.0, r.1)) .collect(); let gm = GuestMemoryMmap::new(&ram_regions).unwrap(); - configure_system(&gm, GuestAddress(0), 0, no_vcpus, None, false).unwrap(); + configure_system( + &gm, + GuestAddress(0), + 0, + no_vcpus, + None, + false, + GuestAddress((1 << 36) - 1), + ) + .unwrap(); } #[test] diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index dfd58a826..d600c4fd1 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -787,7 +787,7 @@ impl<'a> Vm<'a> { .map_err(|_| Error::CmdLine)?; let vcpu_count = u8::from(&self.config.cpus); - + let end_of_range = GuestAddress((1 << 36) - 1); match entry_addr.setup_header { Some(hdr) => { arch::configure_system( @@ -797,6 +797,7 @@ impl<'a> Vm<'a> { vcpu_count, Some(hdr), self.config.serial.mode != ConsoleOutputMode::Off, + end_of_range, ) .map_err(|_| Error::CmdLine)?; @@ -816,6 +817,7 @@ impl<'a> Vm<'a> { vcpu_count, None, self.config.serial.mode != ConsoleOutputMode::Off, + end_of_range, ) .map_err(|_| Error::CmdLine)?;