summary refs log tree commit diff
path: root/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'x86_64')
-rw-r--r--x86_64/Cargo.toml1
-rw-r--r--x86_64/src/acpi.rs212
-rw-r--r--x86_64/src/bootparam.rs3
-rw-r--r--x86_64/src/lib.rs8
-rw-r--r--x86_64/src/mptable.rs6
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;