acpi: Don't pass most of host MADT to guest
Most of the MADT describes hardware that isn't passed through to the
guest. Instead of passing that information to the guest, use a MADT
generated by crosvm. However, we do want to pass through the irq
override structures, so append those to the generated MADT.
BUG=none
TEST=boot kindred and observe 2 cores in the CrOS guest
Change-Id: Ia7279578f2eab6be1092817e3c2700905c10dd05
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2908281
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: David Stevens <stevensd@chromium.org>
Reviewed-by: Tomasz Jeznach <tjeznach@chromium.org>
diff --git a/x86_64/src/acpi.rs b/x86_64/src/acpi.rs
index 592ca4d..36effbb 100644
--- a/x86_64/src/acpi.rs
+++ b/x86_64/src/acpi.rs
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use acpi_tables::{facs::FACS, rsdp::RSDP, sdt::SDT};
+use base::error;
use data_model::DataInit;
use vm_memory::{GuestAddress, GuestMemory};
@@ -68,9 +69,13 @@
const MADT_REVISION: u8 = 5;
// MADT fields offset
const MADT_FIELD_LAPIC_ADDR: usize = 36;
+// MADT structure offsets
+const MADT_STRUCTURE_TYPE: usize = 0;
+const MADT_STRUCTURE_LEN: usize = 1;
// MADT types
const MADT_TYPE_LOCAL_APIC: u8 = 0;
const MADT_TYPE_IO_APIC: u8 = 1;
+const MADT_TYPE_INTERRUPT_SOURCE_OVERRIDE: u8 = 2;
// MADT flags
const MADT_ENABLED: u32 = 1;
// XSDT
@@ -167,7 +172,7 @@
let mut dsdt_offset: Option<GuestAddress> = None;
let mut tables: Vec<u64> = Vec::new();
let mut facp: Option<SDT> = None;
- let mut has_madt = false;
+ let mut host_madt: Option<SDT> = None;
// User supplied System Description Tables, e.g. SSDT.
for sdt in acpi_dev_resource.sdts.iter() {
@@ -175,15 +180,16 @@
facp = Some(sdt.clone());
continue;
}
+ if sdt.is_signature(b"APIC") {
+ host_madt = Some(sdt.clone());
+ continue;
+ }
guest_mem.write_at_addr(sdt.as_slice(), offset).ok()?;
if sdt.is_signature(b"DSDT") {
dsdt_offset = Some(offset);
} else {
tables.push(offset.0);
}
- if sdt.is_signature(b"APIC") {
- has_madt = true;
- }
offset = next_offset(offset, sdt.len() as u64)?;
}
@@ -218,45 +224,58 @@
tables.push(offset.0);
offset = next_offset(offset, facp.len() as u64)?;
- // MADT if not provided.
- if !has_madt {
- // 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,
- );
+ // 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()
- });
-
- guest_mem.write_at_addr(madt.as_slice(), offset).ok()?;
- tables.push(offset.0);
- offset = next_offset(offset, madt.len() as u64)?;
+ 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()
+ });
+
+ if let Some(host_madt) = host_madt {
+ let mut idx = MADT_LEN as usize;
+ while idx + MADT_STRUCTURE_LEN < host_madt.len() {
+ let struct_type = host_madt.as_slice()[idx + MADT_STRUCTURE_TYPE];
+ let struct_len = host_madt.as_slice()[idx + MADT_STRUCTURE_LEN] as usize;
+ if struct_type == MADT_TYPE_INTERRUPT_SOURCE_OVERRIDE {
+ if idx + struct_len <= host_madt.len() {
+ madt.append_slice(&host_madt.as_slice()[idx..(idx + struct_len)]);
+ } else {
+ error!("Malformed host MADT");
+ }
+ }
+ idx += struct_len;
+ }
+ }
+
+ guest_mem.write_at_addr(madt.as_slice(), offset).ok()?;
+ tables.push(offset.0);
+ offset = next_offset(offset, madt.len() as u64)?;
+
// XSDT
let mut xsdt = SDT::new(
*b"XSDT",