vmm: Delegate device related ACPI DSDT table work to DeviceManager

Move the code for handling the creation of the DSDT entries for devices
into the DeviceManager.

This will make it easier to handle device hotplug and also in the future
remove some hardcoded ACPI constants.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford
2019-12-06 16:14:32 +00:00
parent 60e6609011
commit 9b1ba14f2d
3 changed files with 219 additions and 204 deletions
+62 -182
View File
@@ -3,7 +3,6 @@
// SPDX-License-Identifier: Apache-2.0
//
use acpi_tables::{
aml,
aml::Aml,
rsdp::RSDP,
sdt::{GenericAddress, SDT},
@@ -16,6 +15,7 @@ use std::convert::TryInto;
use std::sync::{Arc, Mutex};
use crate::cpu::CpuManager;
use crate::device_manager::DeviceManager;
use arch::layout;
#[repr(packed)]
@@ -79,127 +79,14 @@ struct IortIdMapping {
pub flags: u32,
}
fn create_ged_device() -> Vec<u8> {
aml::Device::new(
"_SB_.GED_".into(),
vec![
&aml::Name::new("_HID".into(), &"ACPI0013"),
&aml::Name::new("_UID".into(), &aml::ZERO),
&aml::Name::new(
"_CRS".into(),
&aml::ResourceTemplate::new(vec![&aml::Interrupt::new(
true, true, false, false, 5,
)]),
),
&aml::OpRegion::new("GDST".into(), aml::OpRegionSpace::SystemIO, 0xb000, 0x1),
&aml::Field::new(
"GDST".into(),
aml::FieldAccessType::Byte,
aml::FieldUpdateRule::WriteAsZeroes,
vec![aml::FieldEntry::Named(*b"GDAT", 8)],
),
&aml::Method::new(
"_EVT".into(),
1,
true,
vec![&aml::If::new(
&aml::Equal::new(&aml::Path::new("GDAT"), &aml::ONE),
vec![&aml::MethodCall::new("\\_SB_.CPUS.CTFY".into(), vec![])],
)],
),
],
)
.to_aml_bytes()
}
pub fn create_dsdt_table(
serial_enabled: bool,
start_of_device_area: GuestAddress,
end_of_device_area: GuestAddress,
device_manager: &DeviceManager,
cpu_manager: &Arc<Mutex<CpuManager>>,
) -> SDT {
let pci_dsdt_data = aml::Device::new(
"_SB_.PCI0".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A08")),
&aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0A03")),
&aml::Name::new("_ADR".into(), &aml::ZERO),
&aml::Name::new("_SEG".into(), &aml::ZERO),
&aml::Name::new("_UID".into(), &aml::ZERO),
&aml::Name::new("SUPP".into(), &aml::ZERO),
&aml::Name::new(
"_CRS".into(),
&aml::ResourceTemplate::new(vec![
&aml::AddressSpace::new_bus_number(0x0u16, 0xffu16),
&aml::IO::new(0xcf8, 0xcf8, 1, 0x8),
&aml::AddressSpace::new_io(0x0u16, 0xcf7u16),
&aml::AddressSpace::new_io(0xd00u16, 0xffffu16),
&aml::AddressSpace::new_memory(
aml::AddressSpaceCachable::NotCacheable,
true,
layout::MEM_32BIT_DEVICES_START.0 as u32,
(layout::MEM_32BIT_DEVICES_START.0 + layout::MEM_32BIT_DEVICES_SIZE - 1)
as u32,
),
&aml::AddressSpace::new_memory(
aml::AddressSpaceCachable::NotCacheable,
true,
start_of_device_area.0,
end_of_device_area.0,
),
]),
),
],
)
.to_aml_bytes();
let mbrd_dsdt_data = aml::Device::new(
"_SB_.MBRD".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0C02")),
&aml::Name::new("_UID".into(), &aml::ZERO),
&aml::Name::new(
"_CRS".into(),
&aml::ResourceTemplate::new(vec![&aml::Memory32Fixed::new(
true,
layout::PCI_MMCONFIG_START.0 as u32,
layout::PCI_MMCONFIG_SIZE as u32,
)]),
),
],
)
.to_aml_bytes();
let com1_dsdt_data = aml::Device::new(
"_SB_.COM1".into(),
vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0501")),
&aml::Name::new("_UID".into(), &aml::ZERO),
&aml::Name::new(
"_CRS".into(),
&aml::ResourceTemplate::new(vec![
&aml::Interrupt::new(true, true, false, false, 4),
&aml::IO::new(0x3f8, 0x3f8, 0, 0x8),
]),
),
],
)
.to_aml_bytes();
let s5_sleep_data =
aml::Name::new("_S5_".into(), &aml::Package::new(vec![&5u8])).to_aml_bytes();
let ged_data = create_ged_device();
// DSDT
let mut dsdt = SDT::new(*b"DSDT", 36, 6, *b"CLOUDH", *b"CHDSDT ", 1);
dsdt.append_slice(pci_dsdt_data.as_slice());
dsdt.append_slice(mbrd_dsdt_data.as_slice());
if serial_enabled {
dsdt.append_slice(com1_dsdt_data.as_slice());
}
dsdt.append_slice(s5_sleep_data.as_slice());
dsdt.append_slice(ged_data.as_slice());
dsdt.append_slice(device_manager.to_aml_bytes().as_slice());
dsdt.append_slice(cpu_manager.lock().unwrap().to_aml_bytes().as_slice());
dsdt
@@ -207,10 +94,7 @@ pub fn create_dsdt_table(
pub fn create_acpi_tables(
guest_mem: &GuestMemoryMmap,
serial_enabled: bool,
start_of_device_area: GuestAddress,
end_of_device_area: GuestAddress,
virt_iommu: Option<(u32, &[u32])>,
device_manager: &DeviceManager,
cpu_manager: &Arc<Mutex<CpuManager>>,
) -> GuestAddress {
// RSDP is at the EBDA
@@ -218,12 +102,7 @@ pub fn create_acpi_tables(
let mut tables: Vec<u64> = Vec::new();
// DSDT
let dsdt = create_dsdt_table(
serial_enabled,
start_of_device_area,
end_of_device_area,
cpu_manager,
);
let dsdt = create_dsdt_table(device_manager, cpu_manager);
let dsdt_offset = rsdp_offset.checked_add(RSDP::len() as u64).unwrap();
guest_mem
.write_slice(dsdt.as_slice(), dsdt_offset)
@@ -288,64 +167,65 @@ pub fn create_acpi_tables(
.expect("Error writing MCFG table");
tables.push(mcfg_offset.0);
let (prev_tbl_len, prev_tbl_off) = if let Some((iommu_id, dev_ids)) = &virt_iommu {
// IORT
let mut iort = SDT::new(*b"IORT", 36, 1, *b"CLOUDH", *b"CHIORT ", 1);
// IORT number of nodes
iort.append(2u32);
// IORT offset to array of IORT nodes
iort.append(48u32);
// IORT reserved 4 bytes
iort.append(0u32);
// IORT paravirtualized IOMMU node
iort.append(IortParavirtIommuNode {
type_: 128,
length: 56,
revision: 0,
num_id_mappings: 0,
ref_id_mappings: 56,
device_id: *iommu_id,
model: 1,
..Default::default()
});
let num_entries = dev_ids.len();
let length: u16 = (36 + (20 * num_entries)).try_into().unwrap();
// IORT PCI root complex node
iort.append(IortPciRootComplexNode {
type_: 2,
length,
revision: 0,
num_id_mappings: num_entries as u32,
ref_id_mappings: 36,
ats_attr: 0,
pci_seg_num: 0,
mem_addr_size_limit: 255,
..Default::default()
});
for dev_id in dev_ids.iter() {
// IORT ID mapping
iort.append(IortIdMapping {
input_base: *dev_id,
num_of_ids: 1,
ouput_base: *dev_id,
output_ref: 48,
flags: 0,
let (prev_tbl_len, prev_tbl_off) =
if let Some((iommu_id, dev_ids)) = &device_manager.virt_iommu() {
// IORT
let mut iort = SDT::new(*b"IORT", 36, 1, *b"CLOUDH", *b"CHIORT ", 1);
// IORT number of nodes
iort.append(2u32);
// IORT offset to array of IORT nodes
iort.append(48u32);
// IORT reserved 4 bytes
iort.append(0u32);
// IORT paravirtualized IOMMU node
iort.append(IortParavirtIommuNode {
type_: 128,
length: 56,
revision: 0,
num_id_mappings: 0,
ref_id_mappings: 56,
device_id: *iommu_id,
model: 1,
..Default::default()
});
}
let iort_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap();
guest_mem
.write_slice(iort.as_slice(), iort_offset)
.expect("Error writing IORT table");
tables.push(iort_offset.0);
let num_entries = dev_ids.len();
let length: u16 = (36 + (20 * num_entries)).try_into().unwrap();
(iort.len(), iort_offset)
} else {
(mcfg.len(), mcfg_offset)
};
// IORT PCI root complex node
iort.append(IortPciRootComplexNode {
type_: 2,
length,
revision: 0,
num_id_mappings: num_entries as u32,
ref_id_mappings: 36,
ats_attr: 0,
pci_seg_num: 0,
mem_addr_size_limit: 255,
..Default::default()
});
for dev_id in dev_ids.iter() {
// IORT ID mapping
iort.append(IortIdMapping {
input_base: *dev_id,
num_of_ids: 1,
ouput_base: *dev_id,
output_ref: 48,
flags: 0,
});
}
let iort_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap();
guest_mem
.write_slice(iort.as_slice(), iort_offset)
.expect("Error writing IORT table");
tables.push(iort_offset.0);
(iort.len(), iort_offset)
} else {
(mcfg.len(), mcfg_offset)
};
// XSDT
let mut xsdt = SDT::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT ", 1);