diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | acpi_tables/src/sdt.rs | 5 | ||||
-rw-r--r-- | devices/Cargo.toml | 1 | ||||
-rw-r--r-- | devices/src/acpi.rs | 15 | ||||
-rw-r--r-- | x86_64/src/acpi.rs | 41 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 60 |
6 files changed, 93 insertions, 30 deletions
diff --git a/Cargo.lock b/Cargo.lock index 41843ee..88a1881 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,6 +167,7 @@ dependencies = [ name = "devices" version = "0.1.0" dependencies = [ + "acpi_tables 0.1.0", "audio_streams 0.1.0", "bit_field 0.1.0", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/acpi_tables/src/sdt.rs b/acpi_tables/src/sdt.rs index e8a9ea2..0ea61a0 100644 --- a/acpi_tables/src/sdt.rs +++ b/acpi_tables/src/sdt.rs @@ -69,6 +69,11 @@ impl SDT { self.write(LENGTH_OFFSET, self.data.len() as u32); } + pub fn append_slice(&mut self, value: &[u8]) { + self.data.extend_from_slice(value); + self.write(LENGTH_OFFSET, self.data.len() as u32); + } + /// Write a value at the given offset pub fn write<T: DataInit>(&mut self, offset: usize, value: T) { let value_len = std::mem::size_of::<T>(); diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 629f29b..0ffab50 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -12,6 +12,7 @@ x = ["gpu_display/x"] gfxstream = ["gpu"] [dependencies] +acpi_tables = {path = "../acpi_tables" } audio_streams = "*" bit_field = { path = "../bit_field" } bitflags = "1" diff --git a/devices/src/acpi.rs b/devices/src/acpi.rs index 990a782..1cfab35 100644 --- a/devices/src/acpi.rs +++ b/devices/src/acpi.rs @@ -3,6 +3,7 @@ // found in the LICENSE file. use crate::{BusDevice, BusResumeDevice}; +use acpi_tables::{aml, aml::Aml}; use sys_util::{error, warn, EventFd}; /// ACPI PM resource for handling OS suspend/resume request @@ -29,8 +30,7 @@ impl ACPIPMResource { } } -/// the ACPI PM register's base and length. -pub const ACPIPM_RESOURCE_BASE: u64 = 0x600; +/// the ACPI PM register length. pub const ACPIPM_RESOURCE_LEN: u8 = 8; pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4; pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2; @@ -127,3 +127,14 @@ impl BusResumeDevice for ACPIPMResource { self.sleep_status = val | BITMASK_SLEEPCNT_WAKE_STATUS; } } + +impl Aml for ACPIPMResource { + fn to_aml_bytes(&self, bytes: &mut Vec<u8>) { + // S1 + aml::Name::new( + "_S1_".into(), + &aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]), + ) + .to_aml_bytes(bytes); + } +} diff --git a/x86_64/src/acpi.rs b/x86_64/src/acpi.rs index 14b21a7..c1d92ee 100644 --- a/x86_64/src/acpi.rs +++ b/x86_64/src/acpi.rs @@ -5,6 +5,11 @@ use acpi_tables::{rsdp::RSDP, sdt::SDT}; use data_model::DataInit; use sys_util::{GuestAddress, GuestMemory}; +pub struct ACPIDevResource { + pub amls: Vec<u8>, + pub pm_iobase: u64, +} + #[repr(C)] #[derive(Clone, Copy, Default)] struct LocalAPIC { @@ -65,21 +70,7 @@ const MADT_ENABLED: u32 = 1; // XSDT const XSDT_REVISION: u8 = 1; -fn create_dsdt_table() -> SDT { - // The hex tables in this file are generated from the ASL below with: - // "iasl -tc <dsdt.asl>" - // Below is the tables represents by the pm_dsdt_data - // Name (_S1, Package (0x04) // _S1_: S1 System State - // { - // One, - // One, - // Zero, - // Zero - // }) - let pm_dsdt_data = [ - 0x08u8, 0x5F, 0x53, 0x31, 0x5f, 0x12, 0x06, 0x04, 0x01, 0x01, 0x00, 0x00, - ]; - +fn create_dsdt_table(amls: Vec<u8>) -> SDT { let mut dsdt = SDT::new( *b"DSDT", acpi_tables::HEADER_LEN, @@ -88,7 +79,10 @@ fn create_dsdt_table() -> SDT { *b"CROSVMDT", OEM_REVISION, ); - dsdt.append(pm_dsdt_data); + + if amls.len() != 0 { + dsdt.append_slice(amls.as_slice()); + } dsdt } @@ -102,13 +96,19 @@ fn create_dsdt_table() -> SDT { /// * `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 { +/// * `acpi_dev_resource` - resouces needed by the ACPI devices for creating tables +pub fn create_acpi_tables( + guest_mem: &GuestMemory, + num_cpus: u8, + sci_irq: u32, + acpi_dev_resource: ACPIDevResource, +) -> 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 = create_dsdt_table(); + 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) @@ -134,14 +134,13 @@ pub fn create_acpi_tables(guest_mem: &GuestMemory, num_cpus: u8, sci_irq: u32) - // PM1A Event Block Address facp.write( FADT_FIELD_PM1A_EVENT_BLK_ADDR, - devices::acpi::ACPIPM_RESOURCE_BASE as u32, + acpi_dev_resource.pm_iobase 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, + acpi_dev_resource.pm_iobase as u32 + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32, ); // PM1 Event Block Length diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index a6a02bc..b4c4aa7 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -54,6 +54,7 @@ use std::mem; use std::sync::Arc; use crate::bootparam::boot_params; +use acpi_tables::aml::Aml; use arch::{ get_serial_cmdline, GetSerialCmdlineError, RunnableLinuxVm, SerialHardware, SerialParameters, VmComponents, VmImage, @@ -74,6 +75,7 @@ use vm_control::VmIrqRequestSocket; #[sorted] #[derive(Debug)] pub enum Error { + AllocateIOResouce(resources::Error), AllocateIrq, CloneEventFd(sys_util::Error), Cmdline(kernel_cmdline::Error), @@ -124,6 +126,7 @@ impl Display for Error { #[sorted] match self { + AllocateIOResouce(e) => write!(f, "error allocating IO resource: {}", e), AllocateIrq => write!(f, "error allocating a single irq"), CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e), Cmdline(e) => write!(f, "the given kernel command line was invalid: {}", e), @@ -216,6 +219,7 @@ fn configure_system( setup_data: Option<GuestAddress>, initrd: Option<(GuestAddress, usize)>, mut params: boot_params, + acpi_dev_resource: acpi::ACPIDevResource, ) -> Result<()> { const EBDA_START: u64 = 0x0009fc00; const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; @@ -279,7 +283,8 @@ 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); + 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; Ok(()) @@ -423,7 +428,6 @@ impl arch::LinuxArch for X8664arch { exit_evt.try_clone().map_err(Error::CloneEventFd)?, Some(pci_bus.clone()), components.memory_size, - suspend_evt.try_clone().map_err(Error::CloneEventFd)?, )?; Self::setup_serial_devices( @@ -434,6 +438,12 @@ impl arch::LinuxArch for X8664arch { serial_jail, )?; + let acpi_dev_resource = Self::setup_acpi_devices( + &mut io_bus, + &mut resources, + suspend_evt.try_clone().map_err(Error::CloneEventFd)?, + )?; + let ramoops_region = match components.pstore { Some(pstore) => Some( arch::pstore::create_memory_region(&mut vm, &mut resources, &pstore) @@ -506,6 +516,7 @@ impl arch::LinuxArch for X8664arch { components.android_fstab, kernel_end, params, + acpi_dev_resource, )?; } } @@ -592,6 +603,7 @@ impl X8664arch { android_fstab: Option<File>, kernel_end: u64, params: boot_params, + acpi_dev_resource: acpi::ACPIDevResource, ) -> Result<()> { kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline) .map_err(Error::LoadCmdline)?; @@ -653,6 +665,7 @@ impl X8664arch { setup_data, initrd, params, + acpi_dev_resource, )?; Ok(()) } @@ -754,14 +767,12 @@ impl X8664arch { /// * - `gsi_relay`: only valid for split IRQ chip (i.e. userspace PIT/PIC/IOAPIC) /// * - `exit_evt` - the event fd object which should receive exit events /// * - `mem_size` - the size in bytes of physical ram for the guest - /// * - `suspend_evt` - the event fd object which used to suspend the vm fn setup_io_bus( _vm: &mut Vm, gsi_relay: &mut Option<GsiRelay>, exit_evt: EventFd, pci: Option<Arc<Mutex<devices::PciConfigIo>>>, mem_size: u64, - suspend_evt: EventFd, ) -> Result<devices::Bus> { struct NoDevice; impl devices::BusDevice for NoDevice { @@ -826,18 +837,53 @@ impl X8664arch { .unwrap(); } - let pm = Arc::new(Mutex::new(devices::ACPIPMResource::new(suspend_evt))); + Ok(io_bus) + } + + /// Sets up the acpi devices for this platform and + /// return the resources which is used to set the ACPI tables. + /// + /// # Arguments + /// + /// * - `io_bus` the I/O bus to add the devices to + /// * - `resources` the SystemAllocator to allocate IO and MMIO for acpi + /// devices. + /// * - `suspend_evt` - the event fd object which used to suspend the vm + fn setup_acpi_devices( + io_bus: &mut devices::Bus, + resources: &mut SystemAllocator, + suspend_evt: EventFd, + ) -> Result<acpi::ACPIDevResource> { + // The AML data for the acpi devices + let mut amls = Vec::new(); + + let pm_alloc = resources.get_anon_alloc(); + let pm_iobase = match resources.io_allocator() { + Some(io) => io + .allocate_with_align( + devices::acpi::ACPIPM_RESOURCE_LEN as u64, + pm_alloc, + "ACPIPM".to_string(), + devices::acpi::ACPIPM_RESOURCE_LEN as u64, + ) + .map_err(Error::AllocateIOResouce)?, + None => 0x600, + }; + + let pmresource = devices::ACPIPMResource::new(suspend_evt); + Aml::to_aml_bytes(&pmresource, &mut amls); + let pm = Arc::new(Mutex::new(pmresource)); io_bus .insert( pm.clone(), - devices::acpi::ACPIPM_RESOURCE_BASE, + pm_iobase as u64, devices::acpi::ACPIPM_RESOURCE_LEN as u64, false, ) .unwrap(); io_bus.notify_on_resume(pm); - Ok(io_bus) + Ok(acpi::ACPIDevResource { amls, pm_iobase }) } /// Sets up the serial devices for this platform. Returns the serial port number and serial |