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/src/acpi.rs61
-rw-r--r--x86_64/src/lib.rs17
-rw-r--r--x86_64/src/mptable.rs3
3 files changed, 50 insertions, 31 deletions
diff --git a/x86_64/src/acpi.rs b/x86_64/src/acpi.rs
index c1d92ee..e6fc15a 100644
--- a/x86_64/src/acpi.rs
+++ b/x86_64/src/acpi.rs
@@ -8,6 +8,8 @@ use sys_util::{GuestAddress, GuestMemory};
 pub struct ACPIDevResource {
     pub amls: Vec<u8>,
     pub pm_iobase: u64,
+    /// Additional system descriptor tables.
+    pub sdts: Vec<SDT>,
 }
 
 #[repr(C)]
@@ -102,17 +104,35 @@ pub fn create_acpi_tables(
     num_cpus: u8,
     sci_irq: u32,
     acpi_dev_resource: ACPIDevResource,
-) -> GuestAddress {
+) -> Option<GuestAddress> {
     // RSDP is at the HI RSDP WINDOW
     let rsdp_offset = GuestAddress(super::ACPI_HI_RSDP_WINDOW_BASE);
+    let mut offset = rsdp_offset.checked_add(RSDP::len() as u64)?;
     let mut tables: Vec<u64> = Vec::new();
+    let mut dsdt_offset: Option<GuestAddress> = None;
+
+    // User supplied System Description Tables, e.g. SSDT.
+    for sdt in acpi_dev_resource.sdts.iter() {
+        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);
+        }
+        offset = offset.checked_add(sdt.len() as u64)?;
+    }
 
     // DSDT
-    let dsdt = create_dsdt_table(acpi_dev_resource.amls);
-    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");
+    let dsdt_offset = match dsdt_offset {
+        Some(dsdt_offset) => dsdt_offset,
+        None => {
+            let dsdt_offset = offset;
+            let dsdt = create_dsdt_table(acpi_dev_resource.amls);
+            guest_mem.write_at_addr(dsdt.as_slice(), offset).ok()?;
+            offset = offset.checked_add(dsdt.len() as u64)?;
+            dsdt_offset
+        }
+    };
 
     // FACP aka FADT
     // Revision 6 of the ACPI FADT table is 276 bytes long
@@ -160,11 +180,9 @@ pub fn create_acpi_tables(
 
     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);
+    guest_mem.write_at_addr(facp.as_slice(), offset).ok()?;
+    tables.push(offset.0);
+    offset = offset.checked_add(facp.len() as u64)?;
 
     // MADT
     let mut madt = SDT::new(
@@ -198,11 +216,9 @@ pub fn create_acpi_tables(
         ..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);
+    guest_mem.write_at_addr(madt.as_slice(), offset).ok()?;
+    tables.push(offset.0);
+    offset = offset.checked_add(madt.len() as u64)?;
 
     // XSDT
     let mut xsdt = SDT::new(
@@ -217,16 +233,11 @@ pub fn create_acpi_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");
+    guest_mem.write_at_addr(xsdt.as_slice(), offset).ok()?;
 
     // RSDP
-    let rsdp = RSDP::new(*b"CROSVM", xsdt_offset.0);
-    guest_mem
-        .write_at_addr(rsdp.as_slice(), rsdp_offset)
-        .expect("Error writing RSDP");
+    let rsdp = RSDP::new(*b"CROSVM", offset.0);
+    guest_mem.write_at_addr(rsdp.as_slice(), rsdp_offset).ok()?;
 
-    rsdp_offset
+    Some(rsdp_offset)
 }
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index b4c4aa7..9714638 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -55,6 +55,7 @@ use std::sync::Arc;
 
 use crate::bootparam::boot_params;
 use acpi_tables::aml::Aml;
+use acpi_tables::sdt::SDT;
 use arch::{
     get_serial_cmdline, GetSerialCmdlineError, RunnableLinuxVm, SerialHardware, SerialParameters,
     VmComponents, VmImage,
@@ -283,9 +284,11 @@ fn configure_system(
         .write_obj_at_addr(params, zero_page_addr)
         .map_err(|_| Error::ZeroPageSetup)?;
 
-    let rsdp_addr =
-        acpi::create_acpi_tables(guest_mem, num_cpus, X86_64_SCI_IRQ, acpi_dev_resource);
-    params.acpi_rsdp_addr = rsdp_addr.0;
+    if let Some(rsdp_addr) =
+        acpi::create_acpi_tables(guest_mem, num_cpus, X86_64_SCI_IRQ, acpi_dev_resource)
+    {
+        params.acpi_rsdp_addr = rsdp_addr.0;
+    }
 
     Ok(())
 }
@@ -442,6 +445,7 @@ impl arch::LinuxArch for X8664arch {
             &mut io_bus,
             &mut resources,
             suspend_evt.try_clone().map_err(Error::CloneEventFd)?,
+            components.acpi_sdts,
         )?;
 
         let ramoops_region = match components.pstore {
@@ -853,6 +857,7 @@ impl X8664arch {
         io_bus: &mut devices::Bus,
         resources: &mut SystemAllocator,
         suspend_evt: EventFd,
+        sdts: Vec<SDT>,
     ) -> Result<acpi::ACPIDevResource> {
         // The AML data for the acpi devices
         let mut amls = Vec::new();
@@ -883,7 +888,11 @@ impl X8664arch {
             .unwrap();
         io_bus.notify_on_resume(pm);
 
-        Ok(acpi::ACPIDevResource { amls, pm_iobase })
+        Ok(acpi::ACPIDevResource {
+            amls,
+            pm_iobase,
+            sdts,
+        })
     }
 
     /// Sets up the serial devices for this platform. Returns the serial port number and serial
diff --git a/x86_64/src/mptable.rs b/x86_64/src/mptable.rs
index 218f561..de489f2 100644
--- a/x86_64/src/mptable.rs
+++ b/x86_64/src/mptable.rs
@@ -10,7 +10,6 @@ use std::slice;
 
 use libc::c_char;
 
-use data_model::VolatileMemory;
 use devices::{PciAddress, PciInterruptPin};
 use sys_util::{GuestAddress, GuestMemory};
 
@@ -140,7 +139,7 @@ pub fn setup_mptable(
         return Err(Error::AddressOverflow);
     }
 
-    mem.get_slice(base_mp.0, mp_size as u64)
+    mem.get_slice_at_addr(base_mp, mp_size)
         .map_err(|_| Error::Clear)?
         .write_bytes(0);