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 <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2019-09-18 15:11:56 +01:00
parent f9b0875a60
commit f0360c92d9
3 changed files with 71 additions and 9 deletions

View File

@ -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 <dsdt.asl>"
@ -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<u64> = 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)

View File

@ -130,6 +130,7 @@ pub fn configure_system(
num_cpus: u8,
setup_hdr: Option<setup_header>,
_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]

View File

@ -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)?;