diff options
author | Chuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com> | 2020-04-27 16:32:13 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-11 13:43:59 +0000 |
commit | 6db9f9f58a095ee9a70c8edb6563aaf7027cb278 (patch) | |
tree | 283b384f5bb40f1a16ebf1ee3a7304f71601b499 | |
parent | e1f8d9187d3f16e31d0c1304030ad412cf43b2bf (diff) | |
download | crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.tar crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.tar.gz crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.tar.bz2 crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.tar.lz crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.tar.xz crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.tar.zst crosvm-6db9f9f58a095ee9a70c8edb6563aaf7027cb278.zip |
acpi: refactor the ACPI PM device
Add the AML support to generate the S1 table instead of hard coding. Also use the IO allocater to allocate the IO resouce for ACPI PM. BUG=None TEST=boot crosvm by command "crosvm run -s crosvm.sock -m 4096 --cpus 4 --rwdisk rootfs.img -p "root=/dev/vda rootfstype=ext4" vmlinux". Check the S1 capability by "#echo standby > /sys/power/state" from guest side. Linux guest is suspended. And resume linux guest by "#crosvm resume crosvm.sock" from host side. Change-Id: I75b484c44db05f98d49557ba694a1531b57871c1 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2119571 Reviewed-by: Tomasz Jeznach <tjeznach@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Chuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com>
-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 |