2019-08-14 16:14:34 +00:00
|
|
|
// Copyright © 2019 Intel Corporation
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//
|
2019-08-29 13:58:25 +00:00
|
|
|
use acpi_tables::{
|
|
|
|
rsdp::RSDP,
|
|
|
|
sdt::{GenericAddress, SDT},
|
|
|
|
};
|
2019-08-14 16:14:34 +00:00
|
|
|
use vm_memory::{GuestAddress, GuestMemoryMmap};
|
|
|
|
|
|
|
|
use vm_memory::{Address, ByteValued, Bytes};
|
|
|
|
|
2019-08-19 16:28:35 +00:00
|
|
|
#[repr(packed)]
|
|
|
|
struct LocalAPIC {
|
|
|
|
pub r#type: u8,
|
|
|
|
pub length: u8,
|
|
|
|
pub processor_id: u8,
|
|
|
|
pub apic_id: u8,
|
|
|
|
pub flags: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(packed)]
|
|
|
|
#[derive(Default)]
|
|
|
|
struct IOAPIC {
|
|
|
|
pub r#type: u8,
|
|
|
|
pub length: u8,
|
|
|
|
pub ioapic_id: u8,
|
|
|
|
_reserved: u8,
|
|
|
|
pub apic_address: u32,
|
|
|
|
pub gsi_base: u32,
|
|
|
|
}
|
|
|
|
|
2019-08-23 20:20:02 +00:00
|
|
|
#[repr(packed)]
|
|
|
|
#[derive(Default)]
|
|
|
|
struct InterruptSourceOverride {
|
|
|
|
pub r#type: u8,
|
|
|
|
pub length: u8,
|
|
|
|
pub bus: u8,
|
|
|
|
pub source: u8,
|
|
|
|
pub gsi: u32,
|
|
|
|
pub flags: u16,
|
|
|
|
}
|
|
|
|
|
2019-08-20 06:31:44 +00:00
|
|
|
#[repr(packed)]
|
|
|
|
#[derive(Default)]
|
|
|
|
struct PCIRangeEntry {
|
|
|
|
pub base_address: u64,
|
|
|
|
pub segment: u16,
|
|
|
|
pub start: u8,
|
|
|
|
pub end: u8,
|
2019-09-03 13:54:06 +00:00
|
|
|
_reserved: u32,
|
2019-08-20 06:31:44 +00:00
|
|
|
}
|
|
|
|
|
2019-09-18 14:11:56 +00:00
|
|
|
pub fn create_dsdt_table(
|
|
|
|
serial_enabled: bool,
|
|
|
|
start_of_device_area: GuestAddress,
|
|
|
|
end_of_device_area: GuestAddress,
|
|
|
|
) -> SDT {
|
2019-08-21 11:12:24 +00:00
|
|
|
/*
|
|
|
|
The hex tables in this file are generated from the ASL below with:
|
|
|
|
"iasl -tc <dsdt.asl>"
|
|
|
|
|
|
|
|
As the output contains a table header that is not required the first 40 bytes
|
|
|
|
should be disregarded.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Device (_SB.PCI0)
|
|
|
|
{
|
|
|
|
Name (_HID, EisaId ("PNP0A08") /* PCI Express Bus */) // _HID: Hardware ID
|
|
|
|
Name (_CID, EisaId ("PNP0A03") /* PCI Bus */) // _CID: Compatible ID
|
|
|
|
Name (_ADR, Zero) // _ADR: Address
|
|
|
|
Name (_SEG, Zero) // _SEG: PCI Segment
|
|
|
|
Name (_UID, Zero) // _UID: Unique ID
|
|
|
|
Name (SUPP, Zero)
|
|
|
|
}
|
|
|
|
|
|
|
|
Scope (_SB.PCI0)
|
|
|
|
{
|
|
|
|
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
|
|
|
|
{
|
|
|
|
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
|
|
|
|
0x0000, // Granularity
|
|
|
|
0x0000, // Range Minimum
|
|
|
|
0x00FF, // Range Maximum
|
|
|
|
0x0000, // Translation Offset
|
|
|
|
0x0100, // Length
|
|
|
|
,, )
|
|
|
|
IO (Decode16,
|
|
|
|
0x0CF8, // Range Minimum
|
|
|
|
0x0CF8, // Range Maximum
|
|
|
|
0x01, // Alignment
|
|
|
|
0x08, // Length
|
|
|
|
)
|
|
|
|
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
|
|
|
0x0000, // Granularity
|
|
|
|
0x0000, // Range Minimum
|
|
|
|
0x0CF7, // Range Maximum
|
|
|
|
0x0000, // Translation Offset
|
|
|
|
0x0CF8, // Length
|
|
|
|
,, , TypeStatic, DenseTranslation)
|
|
|
|
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
|
|
|
0x0000, // Granularity
|
|
|
|
0x0D00, // Range Minimum
|
|
|
|
0xFFFF, // Range Maximum
|
|
|
|
0x0000, // Translation Offset
|
|
|
|
0xF300, // Length
|
|
|
|
,, , TypeStatic, DenseTranslation)
|
|
|
|
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
|
|
|
|
0x00000000, // Granularity
|
|
|
|
0x000A0000, // Range Minimum
|
|
|
|
0x000BFFFF, // Range Maximum
|
|
|
|
0x00000000, // Translation Offset
|
|
|
|
0x00020000, // Length
|
|
|
|
,, , AddressRangeMemory, TypeStatic)
|
|
|
|
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
|
|
|
|
0x00000000, // Granularity
|
|
|
|
0xC0000000, // Range Minimum
|
2019-09-18 14:07:03 +00:00
|
|
|
0xFEBFFFFF, // Range Maximum
|
2019-08-21 11:12:24 +00:00
|
|
|
0x00000000, // Translation Offset
|
2019-09-18 14:07:03 +00:00
|
|
|
0x3EC00000, // Length
|
2019-08-21 11:12:24 +00:00
|
|
|
,, , AddressRangeMemory, TypeStatic)
|
|
|
|
QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
|
|
|
|
0x0000000000000000, // Granularity
|
|
|
|
0x0000000800000000, // Range Minimum
|
|
|
|
0x0000000FFFFFFFFF, // Range Maximum
|
|
|
|
0x0000000000000000, // Translation Offset
|
|
|
|
0x0000000800000000, // Length
|
|
|
|
,, , AddressRangeMemory, TypeStatic)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
*/
|
2019-09-18 14:11:56 +00:00
|
|
|
let mut pci_dsdt_data = [
|
2019-08-21 11:12:24 +00:00
|
|
|
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,
|
|
|
|
0x5F, 0x55, 0x49, 0x44, 0x00, 0x08, 0x53, 0x55, 0x50, 0x50, 0x00, 0x10, 0x41, 0x0B, 0x2E,
|
|
|
|
0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x40,
|
|
|
|
0x0A, 0x0A, 0x9C, 0x88, 0x0D, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x01, 0x47, 0x01, 0xF8, 0x0C, 0xF8, 0x0C, 0x01, 0x08, 0x88, 0x0D, 0x00,
|
|
|
|
0x01, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x0C, 0x00, 0x00, 0xF8, 0x0C, 0x88, 0x0D,
|
|
|
|
0x00, 0x01, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF3, 0x87,
|
|
|
|
0x17, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xFF, 0xFF,
|
|
|
|
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x87, 0x17, 0x00, 0x00, 0x0C,
|
2019-09-18 14:07:03 +00:00
|
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xBF, 0xFE, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0xC0, 0x3E, 0x8A, 0x2B, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x00,
|
2019-08-21 11:12:24 +00:00
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
|
|
|
0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x79, 0x00,
|
|
|
|
];
|
|
|
|
|
2019-09-18 14:11:56 +00:00
|
|
|
// 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(),
|
|
|
|
);
|
|
|
|
|
2019-08-23 20:20:02 +00:00
|
|
|
/*
|
|
|
|
Device (_SB.COM1)
|
|
|
|
{
|
|
|
|
Name (_HID, EisaId ("PNP0501") /* 16550A-compatible COM Serial Port */) // _HID: Hardware ID
|
|
|
|
Name (_UID, Zero) // _UID: Unique ID
|
|
|
|
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
|
|
|
|
{
|
|
|
|
Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
|
|
|
|
{
|
|
|
|
0x00000004,
|
|
|
|
}
|
|
|
|
IO (Decode16,
|
|
|
|
0x03F8, // Range Minimum
|
|
|
|
0x03F8, // Range Maximum
|
|
|
|
0x00, // Alignment
|
|
|
|
0x08, // Length
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
*/
|
2019-08-21 11:12:24 +00:00
|
|
|
let com1_dsdt_data = [
|
2019-08-23 20:20:02 +00:00
|
|
|
0x5Bu8, 0x82, 0x36, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x43, 0x4F, 0x4D, 0x31, 0x08, 0x5F, 0x48,
|
|
|
|
0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, 0x01, 0x08, 0x5F, 0x55, 0x49, 0x44, 0x00, 0x08, 0x5F,
|
|
|
|
0x43, 0x52, 0x53, 0x11, 0x16, 0x0A, 0x13, 0x89, 0x06, 0x00, 0x03, 0x01, 0x04, 0x00, 0x00,
|
|
|
|
0x00, 0x47, 0x01, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x08, 0x79, 0x00,
|
2019-08-21 11:12:24 +00:00
|
|
|
];
|
|
|
|
|
2019-08-29 13:58:25 +00:00
|
|
|
/*
|
|
|
|
Name (\_S5, Package (0x01) // _S5_: S5 System State
|
|
|
|
{
|
|
|
|
0x05
|
|
|
|
})
|
|
|
|
*/
|
|
|
|
let s5_sleep_data = [0x08u8, 0x5F, 0x53, 0x35, 0x5F, 0x12, 0x04, 0x01, 0x0A, 0x05];
|
|
|
|
|
2019-08-21 11:12:24 +00:00
|
|
|
// DSDT
|
|
|
|
let mut dsdt = SDT::new(*b"DSDT", 36, 6, *b"CLOUDH", *b"CHDSDT ", 1);
|
|
|
|
dsdt.append(pci_dsdt_data);
|
2019-08-22 10:18:48 +00:00
|
|
|
if serial_enabled {
|
|
|
|
dsdt.append(com1_dsdt_data);
|
|
|
|
}
|
2019-08-29 13:58:25 +00:00
|
|
|
dsdt.append(s5_sleep_data);
|
2019-08-21 11:12:24 +00:00
|
|
|
|
|
|
|
dsdt
|
|
|
|
}
|
2019-08-22 10:18:48 +00:00
|
|
|
pub fn create_acpi_tables(
|
|
|
|
guest_mem: &GuestMemoryMmap,
|
|
|
|
num_cpus: u8,
|
|
|
|
serial_enabled: bool,
|
2019-09-18 14:11:56 +00:00
|
|
|
start_of_device_area: GuestAddress,
|
|
|
|
end_of_device_area: GuestAddress,
|
2019-08-22 10:18:48 +00:00
|
|
|
) -> GuestAddress {
|
2019-08-14 16:14:34 +00:00
|
|
|
// RSDP is at the EBDA
|
|
|
|
let rsdp_offset = super::EBDA_START;
|
|
|
|
let mut tables: Vec<u64> = Vec::new();
|
|
|
|
|
|
|
|
// DSDT
|
2019-09-18 14:11:56 +00:00
|
|
|
let dsdt = create_dsdt_table(serial_enabled, start_of_device_area, end_of_device_area);
|
2019-08-14 16:14:34 +00:00
|
|
|
let dsdt_offset = rsdp_offset.checked_add(RSDP::len() as u64).unwrap();
|
|
|
|
guest_mem
|
|
|
|
.write_slice(dsdt.as_slice(), dsdt_offset)
|
|
|
|
.expect("Error writing DSDT table");
|
|
|
|
|
|
|
|
// FACP aka FADT
|
|
|
|
// Revision 6 of the ACPI FADT table is 276 bytes long
|
|
|
|
let mut facp = SDT::new(*b"FACP", 276, 6, *b"CLOUDH", *b"CHFACP ", 1);
|
|
|
|
|
2019-08-29 13:58:25 +00:00
|
|
|
// HW_REDUCED_ACPI and RESET_REG_SUP
|
|
|
|
let fadt_flags: u32 = 1 << 20 | 1 << 10;
|
2019-08-14 16:14:34 +00:00
|
|
|
facp.write(112, fadt_flags);
|
|
|
|
|
2019-08-29 13:58:25 +00:00
|
|
|
// RESET_REG
|
|
|
|
facp.write(116, GenericAddress::io_port_address(0x3c0));
|
|
|
|
// RESET_VALUE
|
|
|
|
facp.write(128, 1u8);
|
2019-08-14 16:14:34 +00:00
|
|
|
|
|
|
|
facp.write(131, 3u8); // FADT minor version
|
|
|
|
facp.write(140, dsdt_offset.0); // X_DSDT
|
|
|
|
|
2019-08-29 13:58:25 +00:00
|
|
|
// SLEEP_CONTROL_REG
|
|
|
|
facp.write(244, GenericAddress::io_port_address(0x3c0));
|
|
|
|
// SLEEP_STATUS_REG
|
|
|
|
facp.write(256, GenericAddress::io_port_address(0x3c0));
|
2019-08-14 16:14:34 +00:00
|
|
|
|
|
|
|
facp.write(268, b"CLOUDHYP"); // Hypervisor Vendor Identity
|
|
|
|
|
|
|
|
facp.update_checksum();
|
|
|
|
let facp_offset = dsdt_offset.checked_add(dsdt.len() as u64).unwrap();
|
|
|
|
guest_mem
|
|
|
|
.write_slice(facp.as_slice(), facp_offset)
|
|
|
|
.expect("Error writing FACP table");
|
|
|
|
tables.push(facp_offset.0);
|
|
|
|
|
2019-08-19 16:28:35 +00:00
|
|
|
// MADT
|
|
|
|
let mut madt = SDT::new(*b"APIC", 44, 5, *b"CLOUDH", *b"CHMADT ", 1);
|
|
|
|
madt.write(36, super::mptable::APIC_DEFAULT_PHYS_BASE);
|
|
|
|
|
|
|
|
for cpu in 0..num_cpus {
|
|
|
|
let lapic = LocalAPIC {
|
|
|
|
r#type: 0,
|
|
|
|
length: 8,
|
|
|
|
processor_id: cpu,
|
|
|
|
apic_id: cpu,
|
|
|
|
flags: 1,
|
|
|
|
};
|
|
|
|
madt.append(lapic);
|
|
|
|
}
|
|
|
|
|
|
|
|
madt.append(IOAPIC {
|
|
|
|
r#type: 1,
|
|
|
|
length: 12,
|
|
|
|
ioapic_id: 0,
|
|
|
|
apic_address: super::mptable::IO_APIC_DEFAULT_PHYS_BASE,
|
|
|
|
gsi_base: 0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
|
2019-08-23 20:20:02 +00:00
|
|
|
madt.append(InterruptSourceOverride {
|
|
|
|
r#type: 2,
|
|
|
|
length: 10,
|
|
|
|
bus: 0,
|
|
|
|
source: 4,
|
|
|
|
gsi: 4,
|
|
|
|
flags: 0,
|
|
|
|
});
|
|
|
|
|
2019-08-19 16:28:35 +00:00
|
|
|
let madt_offset = facp_offset.checked_add(facp.len() as u64).unwrap();
|
|
|
|
guest_mem
|
|
|
|
.write_slice(madt.as_slice(), madt_offset)
|
|
|
|
.expect("Error writing MADT table");
|
|
|
|
tables.push(madt_offset.0);
|
|
|
|
|
2019-08-20 06:31:44 +00:00
|
|
|
// MCFG
|
2019-09-16 16:51:30 +00:00
|
|
|
let mut mcfg = SDT::new(*b"MCFG", 36, 1, *b"CLOUDH", *b"CHMCFG ", 1);
|
|
|
|
|
|
|
|
// MCFG reserved 8 bytes
|
|
|
|
mcfg.append(0u64);
|
2019-08-20 06:31:44 +00:00
|
|
|
|
|
|
|
// 32-bit PCI enhanced configuration mechanism
|
|
|
|
mcfg.append(PCIRangeEntry {
|
|
|
|
base_address: super::MEM_32BIT_DEVICES_GAP_SIZE,
|
|
|
|
segment: 0,
|
|
|
|
start: 0,
|
|
|
|
end: 0xff,
|
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
|
|
|
|
let mcfg_offset = madt_offset.checked_add(madt.len() as u64).unwrap();
|
|
|
|
guest_mem
|
|
|
|
.write_slice(mcfg.as_slice(), mcfg_offset)
|
|
|
|
.expect("Error writing MCFG table");
|
|
|
|
tables.push(mcfg_offset.0);
|
|
|
|
|
2019-08-14 16:14:34 +00:00
|
|
|
// XSDT
|
2019-08-19 16:28:35 +00:00
|
|
|
let mut xsdt = SDT::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT ", 1);
|
|
|
|
for table in tables {
|
|
|
|
xsdt.append(table);
|
|
|
|
}
|
2019-08-14 16:14:34 +00:00
|
|
|
xsdt.update_checksum();
|
|
|
|
|
2019-08-20 06:31:44 +00:00
|
|
|
let xsdt_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap();
|
2019-08-14 16:14:34 +00:00
|
|
|
guest_mem
|
|
|
|
.write_slice(xsdt.as_slice(), xsdt_offset)
|
|
|
|
.expect("Error writing XSDT table");
|
|
|
|
|
|
|
|
// RSDP
|
|
|
|
let rsdp = RSDP::new(*b"CLOUDH", xsdt_offset.0);
|
|
|
|
guest_mem
|
|
|
|
.write_slice(rsdp.as_slice(), rsdp_offset)
|
|
|
|
.expect("Error writing RSDP");
|
|
|
|
|
|
|
|
rsdp_offset
|
|
|
|
}
|