vmm: acpi: Support compiling ACPI code on aarch64

This skeleton commit brings in the support for compiling aarch64 with
the "acpi" feature ready to the ACPI enabling. It builds on the work to
move the ACPI hotplug devices from I/O ports to MMIO and conditionalises
any code that is x86_64 only (i.e. because it uses an I/O port.)

Filling in the aarch64 specific details in tables such as the MADT it
out of the scope.

See: #2178

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-01-25 10:48:45 +00:00 committed by Michael
parent 7659055eec
commit 76e15a4240
4 changed files with 96 additions and 61 deletions

View File

@ -6,12 +6,10 @@ use crate::cpu::CpuManager;
use crate::device_manager::DeviceManager;
use crate::memory_manager::MemoryManager;
use crate::vm::NumaNodes;
use acpi_tables::{
aml::Aml,
rsdp::RSDP,
sdt::{GenericAddress, SDT},
};
use arch::layout;
#[cfg(target_arch = "x86_64")]
use acpi_tables::sdt::GenericAddress;
use acpi_tables::{aml::Aml, rsdp::RSDP, sdt::SDT};
use bitflags::bitflags;
use std::sync::{Arc, Mutex};
use vm_memory::GuestRegionMmap;
@ -114,8 +112,16 @@ pub fn create_acpi_tables(
memory_manager: &Arc<Mutex<MemoryManager>>,
numa_nodes: &NumaNodes,
) -> GuestAddress {
#[cfg(target_arch = "x86_64")]
// RSDP is at the EBDA
let rsdp_offset = layout::RSDP_POINTER;
let rsdp_offset = arch::layout::RSDP_POINTER;
#[cfg(target_arch = "aarch64")]
// TODO: For aarch64 place the ACPI tables in the last MiB of guest RAM
let rsdp_offset = {
use vm_memory::GuestMemory;
guest_mem.last_addr().checked_sub(1 << 20).unwrap()
};
let mut tables: Vec<u64> = Vec::new();
// DSDT
@ -130,6 +136,7 @@ pub fn create_acpi_tables(
let mut facp = SDT::new(*b"FACP", 276, 6, *b"CLOUDH", *b"CHFACP ", 1);
// PM_TMR_BLK I/O port
#[cfg(target_arch = "x86_64")]
facp.write(76, 0xb008u32);
// HW_REDUCED_ACPI, RESET_REG_SUP, TMR_VAL_EXT
@ -137,19 +144,24 @@ pub fn create_acpi_tables(
facp.write(112, fadt_flags);
// RESET_REG
#[cfg(target_arch = "x86_64")]
facp.write(116, GenericAddress::io_port_address::<u8>(0x3c0));
// RESET_VALUE
#[cfg(target_arch = "x86_64")]
facp.write(128, 1u8);
facp.write(131, 3u8); // FADT minor version
facp.write(140, dsdt_offset.0); // X_DSDT
// X_PM_TMR_BLK
#[cfg(target_arch = "x86_64")]
facp.write(208, GenericAddress::io_port_address::<u32>(0xb008));
// SLEEP_CONTROL_REG
#[cfg(target_arch = "x86_64")]
facp.write(244, GenericAddress::io_port_address::<u8>(0x3c0));
// SLEEP_STATUS_REG
#[cfg(target_arch = "x86_64")]
facp.write(256, GenericAddress::io_port_address::<u8>(0x3c0));
facp.write(268, b"CLOUDHYP"); // Hypervisor Vendor Identity
@ -177,7 +189,7 @@ pub fn create_acpi_tables(
// 32-bit PCI enhanced configuration mechanism
mcfg.append(PCIRangeEntry {
base_address: layout::PCI_MMCONFIG_START.0,
base_address: arch::layout::PCI_MMCONFIG_START.0,
segment: 0,
start: 0,
end: 0,

View File

@ -22,8 +22,6 @@ use crate::CPU_MANAGER_SNAPSHOT_ID;
#[cfg(feature = "acpi")]
use acpi_tables::{aml, aml::Aml, sdt::SDT};
use anyhow::anyhow;
#[cfg(feature = "acpi")]
use arch::layout;
#[cfg(target_arch = "x86_64")]
use arch::x86_64::SgxEpcSection;
#[cfg(target_arch = "x86_64")]
@ -1031,40 +1029,48 @@ impl CpuManager {
assert!(self.config.boot_vcpus <= self.config.max_vcpus);
let mut madt = SDT::new(*b"APIC", 44, 5, *b"CLOUDH", *b"CHMADT ", 1);
madt.write(36, layout::APIC_START);
#[cfg(target_arch = "x86_64")]
{
madt.write(36, arch::layout::APIC_START);
for cpu in 0..self.config.max_vcpus {
let lapic = LocalAPIC {
r#type: 0,
length: 8,
processor_id: cpu,
apic_id: cpu,
flags: if cpu < self.config.boot_vcpus {
1 << MADT_CPU_ENABLE_FLAG
} else {
0
},
};
madt.append(lapic);
for cpu in 0..self.config.max_vcpus {
let lapic = LocalAPIC {
r#type: 0,
length: 8,
processor_id: cpu,
apic_id: cpu,
flags: if cpu < self.config.boot_vcpus {
1 << MADT_CPU_ENABLE_FLAG
} else {
0
},
};
madt.append(lapic);
}
madt.append(IOAPIC {
r#type: 1,
length: 12,
ioapic_id: 0,
apic_address: arch::layout::IOAPIC_START.0 as u32,
gsi_base: 0,
..Default::default()
});
madt.append(InterruptSourceOverride {
r#type: 2,
length: 10,
bus: 0,
source: 4,
gsi: 4,
flags: 0,
});
}
madt.append(IOAPIC {
r#type: 1,
length: 12,
ioapic_id: 0,
apic_address: layout::IOAPIC_START.0 as u32,
gsi_base: 0,
..Default::default()
});
madt.append(InterruptSourceOverride {
r#type: 2,
length: 10,
bus: 0,
source: 4,
gsi: 4,
flags: 0,
});
#[cfg(target_arch = "aarch64")]
{
madt.update_checksum();
}
madt
}

View File

@ -1201,17 +1201,20 @@ impl DeviceManager {
self.bus_devices
.push(Arc::clone(&shutdown_device) as Arc<Mutex<dyn BusDevice>>);
self.address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0x3c0)), 0x8, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
#[cfg(target_arch = "x86_64")]
{
self.address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0x3c0)), 0x8, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
self.address_manager
.io_bus
.insert(shutdown_device, 0x3c0, 0x4)
.map_err(DeviceManagerError::BusError)?;
self.address_manager
.io_bus
.insert(shutdown_device, 0x3c0, 0x4)
.map_err(DeviceManagerError::BusError)?;
}
let ged_irq = self
.address_manager
@ -1253,17 +1256,20 @@ impl DeviceManager {
self.bus_devices
.push(Arc::clone(&pm_timer_device) as Arc<Mutex<dyn BusDevice>>);
self.address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0xb008)), 0x4, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
#[cfg(target_arch = "x86_64")]
{
self.address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0xb008)), 0x4, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
self.address_manager
.io_bus
.insert(pm_timer_device, 0xb008, 0x4)
.map_err(DeviceManagerError::BusError)?;
self.address_manager
.io_bus
.insert(pm_timer_device, 0xb008, 0x4)
.map_err(DeviceManagerError::BusError)?;
}
Ok(Some(ged_device))
}

View File

@ -1033,6 +1033,17 @@ impl Vm {
let pci_space = (pci_space_start.0, pci_space_size);
#[cfg(feature = "acpi")]
{
let _ = crate::acpi::create_acpi_tables(
&mem,
&self.device_manager,
&self.cpu_manager,
&self.memory_manager,
&self.numa_nodes,
);
}
// Call `configure_system` and pass the GIC devices out, so that
// we can register the GIC device to the device manager.
let gic_device = arch::configure_system(