From 98f81c36ec9986861fdbb605d5f963478cb2ae92 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 19 Aug 2019 17:28:35 +0100 Subject: [PATCH] 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 --- arch/src/x86_64/acpi.rs | 67 +++++++++++++++++++++++++++++++------- arch/src/x86_64/mod.rs | 2 +- arch/src/x86_64/mptable.rs | 4 +-- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/arch/src/x86_64/acpi.rs b/arch/src/x86_64/acpi.rs index 8cc538294..19e78fecb 100644 --- a/arch/src/x86_64/acpi.rs +++ b/arch/src/x86_64/acpi.rs @@ -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 = 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"); diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 3e58da672..b287b05a5 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -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; diff --git a/arch/src/x86_64/mptable.rs b/arch/src/x86_64/mptable.rs index 50b7b1dce..ea28b3488 100644 --- a/arch/src/x86_64/mptable.rs +++ b/arch/src/x86_64/mptable.rs @@ -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;