diff options
Diffstat (limited to 'x86_64')
-rw-r--r-- | x86_64/Cargo.toml | 1 | ||||
-rw-r--r-- | x86_64/src/acpi.rs | 212 | ||||
-rw-r--r-- | x86_64/src/bootparam.rs | 3 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 8 | ||||
-rw-r--r-- | x86_64/src/mptable.rs | 6 |
5 files changed, 226 insertions, 4 deletions
diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml index 3f5ba3e..bb1c445 100644 --- a/x86_64/Cargo.toml +++ b/x86_64/Cargo.toml @@ -19,3 +19,4 @@ remain = "*" resources = { path = "../resources" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } +acpi_tables = {path = "../acpi_tables" } diff --git a/x86_64/src/acpi.rs b/x86_64/src/acpi.rs new file mode 100644 index 0000000..7030bd8 --- /dev/null +++ b/x86_64/src/acpi.rs @@ -0,0 +1,212 @@ +// Copyright 2020 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +use acpi_tables::{rsdp::RSDP, sdt::SDT}; +use data_model::DataInit; +use sys_util::{GuestAddress, GuestMemory}; + +#[repr(C)] +#[derive(Clone, Copy, Default)] +struct LocalAPIC { + _type: u8, + _length: u8, + _processor_id: u8, + _apic_id: u8, + _flags: u32, +} + +// Safe as LocalAPIC structure only contains raw data +unsafe impl DataInit for LocalAPIC {} + +#[repr(C)] +#[derive(Clone, Copy, Default)] +struct IOAPIC { + _type: u8, + _length: u8, + _ioapic_id: u8, + _reserved: u8, + _apic_address: u32, + _gsi_base: u32, +} + +// Safe as IOAPIC structure only contains raw data +unsafe impl DataInit for IOAPIC {} + +const OEM_REVISION: u32 = 1; +//DSDT +const DSDT_REVISION: u8 = 6; +// FADT +const FADT_LEN: u32 = 276; +const FADT_REVISION: u8 = 6; +const FADT_MINOR_REVISION: u8 = 3; +// FADT flags +const FADT_POWER_BUTTON: u32 = (1 << 4); +const FADT_SLEEP_BUTTON: u32 = (1 << 5); +// FADT fields offset +const FADT_FIELD_SCI_INTERRUPT: usize = 46; +const FADT_FIELD_PM1A_EVENT_BLK_ADDR: usize = 56; +const FADT_FIELD_PM1A_CONTROL_BLK_ADDR: usize = 64; +const FADT_FIELD_PM1A_EVENT_BLK_LEN: usize = 88; +const FADT_FIELD_PM1A_CONTROL_BLK_LEN: usize = 89; +const FADT_FIELD_FLAGS: usize = 112; +const FADT_FIELD_MINOR_REVISION: usize = 131; +const FADT_FIELD_DSDT_ADDR: usize = 140; +const FADT_FIELD_HYPERVISOR_ID: usize = 268; +// MADT +const MADT_LEN: u32 = 44; +const MADT_REVISION: u8 = 5; +// MADT fields offset +const MADT_FIELD_LAPIC_ADDR: usize = 36; +// MADT types +const MADT_TYPE_LOCAL_APIC: u8 = 0; +const MADT_TYPE_IO_APIC: u8 = 1; +// MADT flags +const MADT_ENABLED: u32 = 1; +// XSDT +const XSDT_REVISION: u8 = 1; + +/// Create ACPI tables and return the RSDP. +/// The basic tables DSDT/FACP/MADT/XSDT are constructed in this function. +/// # Arguments +/// +/// * `guest_mem` - The guest memory where the tables will be stored. +/// * `num_cpus` - Used to construct the MADT. +/// * `sci_irq` - Used to fill the FACP SCI_INTERRUPT field, which +/// is going to be used by the ACPI drivers to register +/// sci handler. +pub fn create_acpi_tables(guest_mem: &GuestMemory, num_cpus: u8, sci_irq: u32) -> GuestAddress { + // RSDP is at the HI RSDP WINDOW + let rsdp_offset = GuestAddress(super::ACPI_HI_RSDP_WINDOW_BASE); + let mut tables: Vec<u64> = Vec::new(); + + // DSDT + let dsdt = SDT::new( + *b"DSDT", + acpi_tables::HEADER_LEN, + DSDT_REVISION, + *b"CROSVM", + *b"CROSVMDT", + OEM_REVISION, + ); + let dsdt_offset = rsdp_offset.checked_add(RSDP::len() as u64).unwrap(); + guest_mem + .write_at_addr(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", + FADT_LEN, + FADT_REVISION, + *b"CROSVM", + *b"CROSVMDT", + OEM_REVISION, + ); + + let fadt_flags: u32 = FADT_POWER_BUTTON | FADT_SLEEP_BUTTON; // mask POWER and SLEEP BUTTON + facp.write(FADT_FIELD_FLAGS, fadt_flags); + + // SCI Interrupt + facp.write(FADT_FIELD_SCI_INTERRUPT, sci_irq as u16); + + // PM1A Event Block Address + facp.write( + FADT_FIELD_PM1A_EVENT_BLK_ADDR, + devices::acpi::ACPIPM_RESOURCE_BASE as u32, + ); + + // PM1A Control Block Address + facp.write( + FADT_FIELD_PM1A_CONTROL_BLK_ADDR, + devices::acpi::ACPIPM_RESOURCE_BASE as u32 + + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32, + ); + + // PM1 Event Block Length + facp.write( + FADT_FIELD_PM1A_EVENT_BLK_LEN, + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u8, + ); + + // PM1 Control Block Length + facp.write( + FADT_FIELD_PM1A_CONTROL_BLK_LEN, + devices::acpi::ACPIPM_RESOURCE_CONTROLBLK_LEN as u8, + ); + + facp.write(FADT_FIELD_MINOR_REVISION, FADT_MINOR_REVISION); // FADT minor version + facp.write(FADT_FIELD_DSDT_ADDR, dsdt_offset.0 as u64); // X_DSDT + + facp.write(FADT_FIELD_HYPERVISOR_ID, *b"CROSVM"); // Hypervisor Vendor Identity + + let facp_offset = dsdt_offset.checked_add(dsdt.len() as u64).unwrap(); + guest_mem + .write_at_addr(facp.as_slice(), facp_offset) + .expect("Error writing FACP table"); + tables.push(facp_offset.0); + + // MADT + let mut madt = SDT::new( + *b"APIC", + MADT_LEN, + MADT_REVISION, + *b"CROSVM", + *b"CROSVMDT", + OEM_REVISION, + ); + madt.write( + MADT_FIELD_LAPIC_ADDR, + super::mptable::APIC_DEFAULT_PHYS_BASE as u32, + ); + + for cpu in 0..num_cpus { + let lapic = LocalAPIC { + _type: MADT_TYPE_LOCAL_APIC, + _length: std::mem::size_of::<LocalAPIC>() as u8, + _processor_id: cpu, + _apic_id: cpu, + _flags: MADT_ENABLED, + }; + madt.append(lapic); + } + + madt.append(IOAPIC { + _type: MADT_TYPE_IO_APIC, + _length: std::mem::size_of::<IOAPIC>() as u8, + _apic_address: super::mptable::IO_APIC_DEFAULT_PHYS_BASE, + ..Default::default() + }); + + let madt_offset = facp_offset.checked_add(facp.len() as u64).unwrap(); + guest_mem + .write_at_addr(madt.as_slice(), madt_offset) + .expect("Error writing MADT table"); + tables.push(madt_offset.0); + + // XSDT + let mut xsdt = SDT::new( + *b"XSDT", + acpi_tables::HEADER_LEN, + XSDT_REVISION, + *b"CROSVM", + *b"CROSVMDT", + OEM_REVISION, + ); + for table in tables { + xsdt.append(table); + } + + let xsdt_offset = madt_offset.checked_add(madt.len() as u64).unwrap(); + guest_mem + .write_at_addr(xsdt.as_slice(), xsdt_offset) + .expect("Error writing XSDT table"); + + // RSDP + let rsdp = RSDP::new(*b"CROSVM", xsdt_offset.0); + guest_mem + .write_at_addr(rsdp.as_slice(), rsdp_offset) + .expect("Error writing RSDP"); + + rsdp_offset +} diff --git a/x86_64/src/bootparam.rs b/x86_64/src/bootparam.rs index 33bd90a..fd8e1d5 100644 --- a/x86_64/src/bootparam.rs +++ b/x86_64/src/bootparam.rs @@ -401,7 +401,8 @@ pub struct boot_params { pub _pad2: [__u8; 4usize], pub tboot_addr: __u64, pub ist_info: ist_info, - pub _pad3: [__u8; 16usize], + pub acpi_rsdp_addr: __u64, + pub _pad3: [__u8; 8usize], pub hd0_info: [__u8; 16usize], pub hd1_info: [__u8; 16usize], pub sys_desc_table: sys_desc_table, diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 487273e..20831cd 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -35,6 +35,7 @@ unsafe impl data_model::DataInit for mpspec::mpc_table {} unsafe impl data_model::DataInit for mpspec::mpc_lintsrc {} unsafe impl data_model::DataInit for mpspec::mpf_intel {} +mod acpi; mod bzimage; mod cpuid; mod gdt; @@ -178,6 +179,7 @@ const CMDLINE_MAX_SIZE: u64 = KERNEL_START_OFFSET - CMDLINE_OFFSET; const X86_64_SERIAL_1_3_IRQ: u32 = 4; const X86_64_SERIAL_2_4_IRQ: u32 = 3; const X86_64_IRQ_BASE: u32 = 5; +const ACPI_HI_RSDP_WINDOW_BASE: u64 = 0x000E0000; fn configure_system( guest_mem: &GuestMemory, @@ -252,6 +254,10 @@ fn configure_system( guest_mem .write_obj_at_addr(params, zero_page_addr) .map_err(|_| Error::ZeroPageSetup)?; + + let rsdp_addr = acpi::create_acpi_tables(guest_mem, num_cpus, 9); + params.acpi_rsdp_addr = rsdp_addr.0; + Ok(()) } @@ -750,7 +756,7 @@ impl X8664arch { .insert( pm.clone(), devices::acpi::ACPIPM_RESOURCE_BASE, - devices::acpi::ACPIPM_RESOURCE_LEN, + devices::acpi::ACPIPM_RESOURCE_LEN as u64, false, ) .unwrap(); diff --git a/x86_64/src/mptable.rs b/x86_64/src/mptable.rs index 8b754bd..9aded3f 100644 --- a/x86_64/src/mptable.rs +++ b/x86_64/src/mptable.rs @@ -77,8 +77,10 @@ const MPC_OEM: [c_char; 8] = char_array!(c_char; 'C', 'R', 'O', 'S', 'V', 'M', ' 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 BUS_TYPE_PCI: [u8; 6] = char_array!(u8; 'P', 'C', 'I', ' ', ' ', ' '); -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 +// 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; const APIC_VERSION: u8 = 0x14; const CPU_STEPPING: u32 = 0x600; const CPU_FEATURE_APIC: u32 = 0x200; |