summary refs log tree commit diff
path: root/x86_64
diff options
context:
space:
mode:
authorChuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com>2020-02-27 13:58:26 +0800
committerCommit Bot <commit-bot@chromium.org>2020-02-28 00:11:19 +0000
commit020fbf04c2ac112f34b87306b5fbb75e7a02a81a (patch)
tree127111f64edbb95d7a2b6deceb414dfd24b8db39 /x86_64
parent46d61ba80df1ccf8364d9589170b3a7bff1268ee (diff)
downloadcrosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.tar
crosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.tar.gz
crosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.tar.bz2
crosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.tar.lz
crosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.tar.xz
crosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.tar.zst
crosvm-020fbf04c2ac112f34b87306b5fbb75e7a02a81a.zip
x86_64: generate ACPI tables
Add acpi_rsdp_addr in boot_params to allow crosvm to pass
a physicall address of RSDP to the Linux guest kernel, so
that the linux guest kernel can parse the constructed ACPI
tables and enable the ACPI.

Although there is ACPI tables but as we still have "acpi=off"
in command line parameter, there is still no ACPI in guest kernel.

The ACPI construction refers to the implementation of the
Cloud-hypervisor commit:
- arch: x86_64: Generate basic ACPI tables

BUG=chromium:1018674
TEST=None

Change-Id: Ibcb2ae98c43da8ef8c07a07eda9213f61570d14c
Signed-off-by: Chuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2035351
Reviewed-by: Tomasz Jeznach <tjeznach@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Tomasz Jeznach <tjeznach@chromium.org>
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;