arch: x86_64: acpi: Generate MADT aka APIC table

This provides important APIC configuration details for the CPU. Even
though it duplicates some of the information already included in the
mptable it is necessary when booting with ACPI as the mptable is not
used.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2019-08-19 17:28:35 +01:00 committed by Samuel Ortiz
parent ee83c2d44e
commit 98f81c36ec
3 changed files with 59 additions and 14 deletions

View File

@ -7,7 +7,27 @@ use vm_memory::{GuestAddress, GuestMemoryMmap};
use vm_memory::{Address, ByteValued, Bytes};
pub fn create_acpi_tables(guest_mem: &GuestMemoryMmap) -> GuestAddress {
#[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,
}
pub fn create_acpi_tables(guest_mem: &GuestMemoryMmap, num_cpus: u8) -> GuestAddress {
// RSDP is at the EBDA
let rsdp_offset = super::EBDA_START;
let mut tables: Vec<u64> = Vec::new();
@ -43,19 +63,44 @@ pub fn create_acpi_tables(guest_mem: &GuestMemoryMmap) -> GuestAddress {
.expect("Error writing FACP table");
tables.push(facp_offset.0);
// 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()
});
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);
// XSDT
let mut xsdt = SDT::new(
*b"XSDT",
36 + 8 * tables.len() as u32,
1,
*b"CLOUDH",
*b"CHXSDT ",
1,
);
xsdt.write(36, tables[0]);
let mut xsdt = SDT::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT ", 1);
for table in tables {
xsdt.append(table);
}
xsdt.update_checksum();
let xsdt_offset = facp_offset.checked_add(facp.len() as u64).unwrap();
let xsdt_offset = madt_offset.checked_add(madt.len() as u64).unwrap();
guest_mem
.write_slice(xsdt.as_slice(), xsdt_offset)
.expect("Error writing XSDT table");

View File

@ -182,7 +182,7 @@ pub fn configure_system(
}
}
let rsdp_addr = acpi::create_acpi_tables(guest_mem);
let rsdp_addr = acpi::create_acpi_tables(guest_mem, num_cpus);
params.0.acpi_rsdp_addr = rsdp_addr.0;
let zero_page_addr = layout::ZERO_PAGE_START;

View File

@ -92,8 +92,8 @@ const MPC_SPEC: i8 = 4;
const MPC_OEM: [c_char; 8] = char_array!(c_char; 'F', 'C', ' ', ' ', ' ', ' ', ' ', ' ');
const MPC_PRODUCT_ID: [c_char; 12] = ['0' as c_char; 12];
const BUS_TYPE_ISA: [u8; 6] = char_array!(u8; 'I', 'S', 'A', ' ', ' ', ' ');
const IO_APIC_DEFAULT_PHYS_BASE: u32 = 0xfec00000; // source: linux/arch/x86/include/asm/apicdef.h
const APIC_DEFAULT_PHYS_BASE: u32 = 0xfee00000; // source: linux/arch/x86/include/asm/apicdef.h
pub const IO_APIC_DEFAULT_PHYS_BASE: u32 = 0xfec00000; // source: linux/arch/x86/include/asm/apicdef.h
pub const APIC_DEFAULT_PHYS_BASE: u32 = 0xfee00000; // source: linux/arch/x86/include/asm/apicdef.h
const APIC_VERSION: u8 = 0x14;
const CPU_STEPPING: u32 = 0x600;
const CPU_FEATURE_APIC: u32 = 0x200;