mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
acpi: support user provided ACPI SDTs.
Enable support for user provided ACPI tables with supplementary system description. Argument --acpi-table shall point to exsting file or pseudo-file with valid ACPI table content. BUG=None TEST=boot Linux kernel with generated SSDT tables. Change-Id: I8eac21da070dcc325884ed888cc7bcb01bc086ce Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2212501 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: Tomasz Jeznach <tjeznach@chromium.org> Commit-Queue: Tomasz Jeznach <tjeznach@chromium.org>
This commit is contained in:
parent
2705264dc6
commit
4264464153
9 changed files with 103 additions and 29 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -30,6 +30,7 @@ dependencies = [
|
|||
name = "arch"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"acpi_tables 0.1.0",
|
||||
"devices 0.1.0",
|
||||
"io_jail 0.1.0",
|
||||
"kernel_cmdline 0.1.0",
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{ErrorKind, Read, Result};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use data_model::DataInit;
|
||||
|
||||
/// SDT represents for System Description Table. The structure SDT is a
|
||||
|
@ -54,6 +58,23 @@ impl SDT {
|
|||
sdt
|
||||
}
|
||||
|
||||
/// Set up the ACPI table from file content. Verify file checksum.
|
||||
pub fn from_file(path: &PathBuf) -> Result<Self> {
|
||||
let mut file = File::open(path)?;
|
||||
let mut data = Vec::new();
|
||||
file.read_to_end(&mut data)?;
|
||||
let checksum = super::generate_checksum(data.as_slice());
|
||||
if checksum == 0 {
|
||||
Ok(SDT { data })
|
||||
} else {
|
||||
Err(ErrorKind::InvalidData.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_signature(&self, signature: &[u8; 4]) -> bool {
|
||||
self.data[0..4] == *signature
|
||||
}
|
||||
|
||||
fn update_checksum(&mut self) {
|
||||
self.data[CHECKSUM_OFFSET] = 0;
|
||||
let checksum = super::generate_checksum(self.data.as_slice());
|
||||
|
|
|
@ -5,6 +5,7 @@ authors = ["The Chromium OS Authors"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables" }
|
||||
devices = { path = "../devices" }
|
||||
io_jail = { path = "../io_jail" }
|
||||
kernel_cmdline = { path = "../kernel_cmdline" }
|
||||
|
|
|
@ -16,6 +16,7 @@ use std::os::unix::io::AsRawFd;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use acpi_tables::sdt::SDT;
|
||||
use devices::split_irqchip_common::GsiRelay;
|
||||
use devices::virtio::VirtioDevice;
|
||||
use devices::{
|
||||
|
@ -57,6 +58,7 @@ pub struct VmComponents {
|
|||
pub initrd_image: Option<File>,
|
||||
pub extra_kernel_params: Vec<String>,
|
||||
pub wayland_dmabuf: bool,
|
||||
pub acpi_sdts: Vec<SDT>,
|
||||
}
|
||||
|
||||
/// Holds the elements needed to run a Linux VM. Created by `build_vm`.
|
||||
|
|
|
@ -204,6 +204,7 @@ pub struct Config {
|
|||
pub vfio: Vec<PathBuf>,
|
||||
pub video_dec: bool,
|
||||
pub video_enc: bool,
|
||||
pub acpi_tables: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -254,6 +255,7 @@ impl Default for Config {
|
|||
vfio: Vec::new(),
|
||||
video_dec: false,
|
||||
video_enc: false,
|
||||
acpi_tables: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ use std::time::Duration;
|
|||
|
||||
use libc::{self, c_int, gid_t, uid_t};
|
||||
|
||||
use acpi_tables::sdt::SDT;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
use devices::virtio::EventDevice;
|
||||
use devices::virtio::{self, Console, VirtioDevice};
|
||||
|
@ -109,6 +111,7 @@ pub enum Error {
|
|||
LoadKernel(Box<dyn StdError>),
|
||||
MemoryTooLarge,
|
||||
NetDeviceNew(virtio::NetError),
|
||||
OpenAcpiTable(PathBuf, io::Error),
|
||||
OpenAndroidFstab(PathBuf, io::Error),
|
||||
OpenBios(PathBuf, io::Error),
|
||||
OpenInitrd(PathBuf, io::Error),
|
||||
|
@ -196,6 +199,7 @@ impl Display for Error {
|
|||
LoadKernel(e) => write!(f, "failed to load kernel: {}", e),
|
||||
MemoryTooLarge => write!(f, "requested memory size too large"),
|
||||
NetDeviceNew(e) => write!(f, "failed to set up virtio networking: {}", e),
|
||||
OpenAcpiTable(p, e) => write!(f, "failed to open ACPI file {}: {}", p.display(), e),
|
||||
OpenAndroidFstab(p, e) => write!(
|
||||
f,
|
||||
"failed to open android fstab file {}: {}",
|
||||
|
@ -1712,6 +1716,11 @@ pub fn run_config(cfg: Config) -> Result<()> {
|
|||
initrd_image,
|
||||
extra_kernel_params: cfg.params.clone(),
|
||||
wayland_dmabuf: cfg.wayland_dmabuf,
|
||||
acpi_sdts: cfg
|
||||
.acpi_tables
|
||||
.iter()
|
||||
.map(|path| SDT::from_file(path).map_err(|e| Error::OpenAcpiTable(path.clone(), e)))
|
||||
.collect::<Result<Vec<SDT>>>()?,
|
||||
};
|
||||
|
||||
let control_server_socket = match &cfg.socket_path {
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -1232,6 +1232,23 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
|
|||
"video-encoder" => {
|
||||
cfg.video_enc = true;
|
||||
}
|
||||
"acpi-table" => {
|
||||
let acpi_table = PathBuf::from(value.unwrap());
|
||||
if !acpi_table.exists() {
|
||||
return Err(argument::Error::InvalidValue {
|
||||
value: value.unwrap().to_owned(),
|
||||
expected: String::from("the acpi-table path does not exist"),
|
||||
});
|
||||
}
|
||||
if !acpi_table.is_file() {
|
||||
return Err(argument::Error::InvalidValue {
|
||||
value: value.unwrap().to_owned(),
|
||||
expected: String::from("the acpi-table path should be a file"),
|
||||
});
|
||||
}
|
||||
|
||||
cfg.acpi_tables.push(acpi_table);
|
||||
}
|
||||
|
||||
"help" => return Err(argument::Error::PrintHelp),
|
||||
_ => unreachable!(),
|
||||
|
@ -1406,6 +1423,7 @@ writeback=BOOL - Indicates whether the VM can use writeback caching (default: fa
|
|||
Argument::flag("video-decoder", "(EXPERIMENTAL) enable virtio-video decoder device"),
|
||||
#[cfg(feature = "video-encoder")]
|
||||
Argument::flag("video-encoder", "(EXPERIMENTAL) enable virtio-video encoder device"),
|
||||
Argument::value("acpi-table", "PATH", "Path to user provided ACPI table"),
|
||||
Argument::short_flag('h', "help", "Print help message.")];
|
||||
|
||||
let mut cfg = Config::default();
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue