Merge 19 commits from origin/main (2022-03-10, cq-depend)
ee60fe49 crosvm: Change cargo resolver to 1 to fix issues with chromeos and b* builds
4d88ee98 Upstream data_model
cd75771e x86_64: acpi: always use virtual reset register
3fbf6c21 acpi: support GPE injection in command line
eb16dd51 acpi: support vGPE
6ca0323c acpi: support fixed power button event in command line
072c103b acpi: support fixed power button in vPM1
8f833c1f x86_64: acpi: always use vPM1 registers
80e6d5bf acpi: refactor PM1 virtualization
90922be6 crosvm: Enable plugin feature in CI builds
fb1df154 crosvm: Fix running plugins integration tests
5586ff50 linux: punch holes in guest memory for file mappings
de4d729c linux: allow file-backed mappings outside of MMIO regions
808bb0f5 resources: return overlapping Alloc in allocate_at
578e7cce base: remove wildcard and export specific sys_util symbols
449dd6b7 Don't add ramoops parameters except addr and size
4a3341ce crosvm: vvu: proxy: Handle sibling disconnect
bed40ad5 crosvm: migrate to Rust 2021 edition
6fd89263 crosvm: pci: prefer to/from le_bytes instead of manual byte manipulation
https://chromium.googlesource.com/chromiumos/platform/crosvm/+log/3e0a93a1e1fbd9e53c6d1dab94f9e219eb4d9f2a..ee60fe491fe15a1d8f5c7336175fab6284ca7f04
BUG=b:188011323
BUG=b:194136484
BUG=b:199383670
BUG=b:218891911
BUG=b:223855233,b:223821596
TEST=CQ
Cq-Depend: chromium:3491214
Change-Id: I29f1cca23bfacb60f9b58790e5c0b30217b54c80
diff --git a/Cargo.toml b/Cargo.toml
index 39c1ab6..16d39de 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,8 +2,10 @@
name = "crosvm"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
default-run = "crosvm"
+# b:223855233
+resolver = "1"
[lib]
path = "src/crosvm.rs"
@@ -102,12 +104,6 @@
"virgl_renderer",
"x",
]
-all-linux-armhf = [
- "composite-disk",
- "default",
- "gdb",
- "tpm",
- ]
audio = ["devices/audio"]
audio_cras = ["devices/audio_cras"]
chromeos = ["base/chromeos", "audio_cras", "devices/chromeos"]
@@ -119,6 +115,14 @@
gfxstream = ["devices/gfxstream"]
gpu = ["devices/gpu"]
libvda = ["devices/libvda"]
+linux-armhf = [
+ "composite-disk",
+ "default",
+ "gdb",
+ "tpm",
+ ]
+linux-x86_64 = ["all-linux", "plugin"]
+linux-aarch64 = ["all-linux"]
plugin = ["protos/plugin", "crosvm_plugin", "kvm", "kvm_sys", "protobuf"]
power-monitor-powerd = ["arch/power-monitor-powerd"]
tpm = ["devices/tpm"]
diff --git a/aarch64/Cargo.toml b/aarch64/Cargo.toml
index 7ad86c2..3fb0c23 100644
--- a/aarch64/Cargo.toml
+++ b/aarch64/Cargo.toml
@@ -2,7 +2,7 @@
name = "aarch64"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
arch = { path = "../arch" }
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index 170227a..39a0e00 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -482,6 +482,7 @@
rt_cpus: components.rt_cpus,
delay_rt: components.delay_rt,
bat_control: None,
+ pm: None,
resume_notify_devices: Vec::new(),
root_config: pci_root,
hotplug_bus: Vec::new(),
diff --git a/acpi_tables/Cargo.toml b/acpi_tables/Cargo.toml
index 9537960..c6d5917 100644
--- a/acpi_tables/Cargo.toml
+++ b/acpi_tables/Cargo.toml
@@ -2,7 +2,7 @@
name = "acpi_tables"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../common/data_model" }
diff --git a/acpi_tables/src/sdt.rs b/acpi_tables/src/sdt.rs
index 50e7442..bda2630 100644
--- a/acpi_tables/src/sdt.rs
+++ b/acpi_tables/src/sdt.rs
@@ -96,13 +96,23 @@
self.write(LENGTH_OFFSET, self.data.len() as u32);
}
+ /// Read a value at the given offset
+ pub fn read<T: DataInit + Default>(&self, offset: usize) -> T {
+ let value_len = std::mem::size_of::<T>();
+ *T::from_slice(
+ self.as_slice()
+ .get(offset..offset + value_len)
+ .unwrap_or(T::default().as_slice()),
+ )
+ .unwrap()
+ }
+
/// 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>();
if (offset + value_len) > self.data.len() {
return;
}
-
self.data[offset..offset + value_len].copy_from_slice(value.as_slice());
self.update_checksum();
}
diff --git a/arch/Cargo.toml b/arch/Cargo.toml
index 62167d2..3706fa8 100644
--- a/arch/Cargo.toml
+++ b/arch/Cargo.toml
@@ -2,7 +2,7 @@
name = "arch"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
power-monitor-powerd = ["power_monitor/powerd"]
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 930abf2..afe259b 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -29,7 +29,7 @@
use resources::{MmioType, SystemAllocator};
use sync::Mutex;
use thiserror::Error;
-use vm_control::{BatControl, BatteryType};
+use vm_control::{BatControl, BatteryType, PmResource};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
@@ -123,6 +123,7 @@
pub bat_control: Option<BatControl>,
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
pub gdb: Option<(u32, Tube)>,
+ pub pm: Option<Arc<Mutex<dyn PmResource>>>,
/// Devices to be notified before the system resumes from the S3 suspended state.
pub resume_notify_devices: Vec<Arc<Mutex<dyn BusResumeDevice>>>,
pub root_config: Arc<Mutex<PciRoot>>,
@@ -692,7 +693,7 @@
create_monitor,
)
.map_err(DeviceRegistrationError::RegisterBattery)?;
- Aml::to_aml_bytes(&goldfish_bat, amls);
+ goldfish_bat.to_aml_bytes(amls);
match battery_jail.as_ref() {
Some(jail) => {
diff --git a/arch/src/pstore.rs b/arch/src/pstore.rs
index bf90974..a914801 100644
--- a/arch/src/pstore.rs
+++ b/arch/src/pstore.rs
@@ -84,9 +84,6 @@
let ramoops_opts = [
("mem_address", ramoops_region.address),
("mem_size", ramoops_region.size as u64),
- ("console_size", (ramoops_region.size / 4) as u64),
- ("record_size", (ramoops_region.size / 4) as u64),
- ("dump_oops", 1_u64),
];
for (name, val) in &ramoops_opts {
cmdline.insert_str(format!("ramoops.{}={:#x}", name, val))?;
diff --git a/bit_field/Cargo.toml b/bit_field/Cargo.toml
index ac8846c..540412f 100644
--- a/bit_field/Cargo.toml
+++ b/bit_field/Cargo.toml
@@ -2,7 +2,7 @@
name = "bit_field"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
bit_field_derive = { path = "bit_field_derive" }
diff --git a/bit_field/bit_field_derive/Cargo.toml b/bit_field/bit_field_derive/Cargo.toml
index 4642b93..dddf7b4 100644
--- a/bit_field/bit_field_derive/Cargo.toml
+++ b/bit_field/bit_field_derive/Cargo.toml
@@ -2,7 +2,7 @@
name = "bit_field_derive"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
proc-macro2 = "^1"
diff --git a/common/assertions/Cargo.toml b/common/assertions/Cargo.toml
index 60b1c5e..6608f09 100644
--- a/common/assertions/Cargo.toml
+++ b/common/assertions/Cargo.toml
@@ -2,7 +2,7 @@
name = "assertions"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["src/**/*", "Cargo.toml"]
[workspace]
diff --git a/common/audio_streams/Cargo.toml b/common/audio_streams/Cargo.toml
index e014a6a..960dc4e 100644
--- a/common/audio_streams/Cargo.toml
+++ b/common/audio_streams/Cargo.toml
@@ -2,7 +2,7 @@
name = "audio_streams"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
path = "src/audio_streams.rs"
diff --git a/common/balloon_control/Cargo.toml b/common/balloon_control/Cargo.toml
index 32384b1..11b8acf 100644
--- a/common/balloon_control/Cargo.toml
+++ b/common/balloon_control/Cargo.toml
@@ -2,7 +2,7 @@
name = "balloon_control"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
serde = { version = "1", features = [ "derive" ] }
diff --git a/common/base/Cargo.toml b/common/base/Cargo.toml
index ca94518..3a57599 100644
--- a/common/base/Cargo.toml
+++ b/common/base/Cargo.toml
@@ -2,7 +2,7 @@
name = "base"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
chromeos = ["sys_util/chromeos"]
diff --git a/common/base/src/lib.rs b/common/base/src/lib.rs
index ac341ae..7be4ff5 100644
--- a/common/base/src/lib.rs
+++ b/common/base/src/lib.rs
@@ -2,7 +2,54 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-pub use sys_util::*;
+pub use sys_util::chown;
+pub use sys_util::drop_capabilities;
+pub use sys_util::handle_eintr_errno;
+pub use sys_util::iov_max;
+pub use sys_util::kernel_has_memfd;
+pub use sys_util::pipe;
+pub use sys_util::read_raw_stdin;
+pub use sys_util::syscall;
+pub use sys_util::syslog;
+pub use sys_util::EventFd;
+pub use sys_util::Fd;
+pub use sys_util::SignalFd;
+pub use sys_util::Terminal;
+pub use sys_util::TimerFd;
+pub use sys_util::UnsyncMarker;
+pub use sys_util::{add_fd_flags, clear_fd_flags};
+pub use sys_util::{
+ block_signal, clear_signal, get_blocked_signals, register_rt_signal_handler, signal,
+ unblock_signal, Killable, SIGRTMIN,
+};
+pub use sys_util::{
+ clone_descriptor, get_max_open_files, safe_descriptor_from_path, validate_raw_fd,
+ with_as_descriptor, with_raw_descriptor, AsRawDescriptor, Descriptor, FromRawDescriptor,
+ IntoRawDescriptor, RawDescriptor, SafeDescriptor, INVALID_DESCRIPTOR,
+};
+pub use sys_util::{debug, error, info, warn};
+pub use sys_util::{
+ enable_core_scheduling, get_cpu_affinity, set_cpu_affinity, set_rt_prio_limit,
+ set_rt_round_robin,
+};
+pub use sys_util::{errno_result, Error, Result};
+pub use sys_util::{flock, FlockOperation};
+pub use sys_util::{get_filesystem_type, open_file, FileFlags, PunchHole, WriteZeroes};
+pub use sys_util::{getegid, geteuid};
+pub use sys_util::{getpid, gettid, kill_process_group, reap_child};
+pub use sys_util::{ioctl_io_nr, ioctl_ior_nr, ioctl_iow_nr, ioctl_iowr_nr};
+pub use sys_util::{
+ net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener},
+ ScmSocket, UnlinkUnixListener,
+};
+pub use sys_util::{pagesize, round_up_to_page_size};
+pub use sys_util::{Clock, FakeClock};
+pub use sys_util::{EpollContext, EpollEvents};
+pub use sys_util::{ExternalMapping, ExternalMappingError, ExternalMappingResult};
+pub use sys_util::{
+ LayoutAllocation, MappedRegion, MemfdSeals, MemoryMappingArena, MmapError, Protection,
+};
+pub use sys_util::{PollToken, WatchingEvents};
mod async_types;
mod event;
diff --git a/common/base/src/tube.rs b/common/base/src/tube.rs
index 82c2ad5..934360d 100644
--- a/common/base/src/tube.rs
+++ b/common/base/src/tube.rs
@@ -8,7 +8,7 @@
use std::os::unix::prelude::{AsRawFd, RawFd};
use std::time::Duration;
-use crate::{net::UnixSeqpacket, FromRawDescriptor, SafeDescriptor, ScmSocket, UnsyncMarker};
+use crate::{FromRawDescriptor, SafeDescriptor, ScmSocket, UnixSeqpacket, UnsyncMarker};
use cros_async::{Executor, IntoAsync, IoSourceExt};
use remain::sorted;
diff --git a/common/cros-fuzz/Cargo.toml b/common/cros-fuzz/Cargo.toml
index e91baf2..c304d95 100644
--- a/common/cros-fuzz/Cargo.toml
+++ b/common/cros-fuzz/Cargo.toml
@@ -2,7 +2,7 @@
name = "cros_fuzz"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["Cargo.toml", "src/*.rs"]
[dependencies]
diff --git a/common/cros_async/Cargo.toml b/common/cros_async/Cargo.toml
index d8ee886..009dbbf 100644
--- a/common/cros_async/Cargo.toml
+++ b/common/cros_async/Cargo.toml
@@ -2,7 +2,7 @@
name = "cros_async"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
async-trait = "0.1.36"
diff --git a/common/cros_asyncv2/Cargo.toml b/common/cros_asyncv2/Cargo.toml
index 468ed90..0dac52b 100644
--- a/common/cros_asyncv2/Cargo.toml
+++ b/common/cros_asyncv2/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "cros_async"
version = "0.2.0"
-edition = "2018"
+edition = "2021"
[features]
uring = ["io-uring"]
diff --git a/common/data_model/Cargo.toml b/common/data_model/Cargo.toml
index 4401e0e..d3e3f3e 100644
--- a/common/data_model/Cargo.toml
+++ b/common/data_model/Cargo.toml
@@ -2,14 +2,21 @@
name = "data_model"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["src/**/*", "Cargo.toml"]
[dependencies]
assertions = { path = "../assertions" } # provided by ebuild
+cfg-if = "1.0.0"
libc = "*"
remain = "0.2"
serde = { version = "1", features = ["derive"] }
thiserror = "1.0.20"
+[target.'cfg(windows)'.dependencies]
+winapi = { version = "*", features = ["everything", "std", "impl-default"] }
+
+[target.'cfg(unix)'.dependencies]
+libc = "*"
+
[workspace]
diff --git a/common/data_model/src/lib.rs b/common/data_model/src/lib.rs
index 708bed3..4585b19 100644
--- a/common/data_model/src/lib.rs
+++ b/common/data_model/src/lib.rs
@@ -187,4 +187,4 @@
pub use flexible_array::{vec_with_array_field, FlexibleArray, FlexibleArrayWrapper};
mod sys;
-pub use sys::IoBufMut;
+pub use sys::{create_iobuf, IoBuf, IoBufMut};
diff --git a/common/data_model/src/sys.rs b/common/data_model/src/sys.rs
index 0099e06..2bf1722 100644
--- a/common/data_model/src/sys.rs
+++ b/common/data_model/src/sys.rs
@@ -1,134 +1,16 @@
-// Copyright 2020 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+//
+//! A wrapper module for platform dependent code.
-use std::ffi::c_void;
-use std::fmt::{self, Debug};
-use std::marker::PhantomData;
-use std::slice;
-
-use libc::iovec;
-
-/// This type is essentialy `std::io::IoBufMut`, and guaranteed to be ABI-compatible with
-/// `libc::iovec`; however, it does NOT automatically deref to `&mut [u8]`, which is critical
-/// because it can point to guest memory. (Guest memory is implicitly mutably borrowed by the
-/// guest, so another mutable borrow would violate Rust assumptions about references.)
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct IoBufMut<'a> {
- iov: iovec,
- phantom: PhantomData<&'a mut [u8]>,
-}
-
-impl<'a> IoBufMut<'a> {
- pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
- // Safe because buf's memory is of the supplied length, and
- // guaranteed to exist for the lifetime of the returned value.
- unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
- }
-
- /// Creates a `IoBufMut` from a pointer and a length.
- ///
- /// # Safety
- ///
- /// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
- /// and should live for the entire duration of lifetime `'a`.
- pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
- IoBufMut {
- iov: iovec {
- iov_base: addr as *mut c_void,
- iov_len: len,
- },
- phantom: PhantomData,
- }
- }
-
- /// Advance the internal position of the buffer.
- ///
- /// Panics if `count > self.len()`.
- pub fn advance(&mut self, count: usize) {
- assert!(count <= self.len());
-
- self.iov.iov_len -= count;
- // Safe because we've checked that `count <= self.len()` so both the starting and resulting
- // pointer are within the bounds of the allocation.
- self.iov.iov_base = unsafe { self.iov.iov_base.add(count) };
- }
-
- /// Shorten the length of the buffer.
- ///
- /// Has no effect if `len > self.len()`.
- pub fn truncate(&mut self, len: usize) {
- if len < self.len() {
- self.iov.iov_len = len;
- }
- }
-
- #[inline]
- pub fn len(&self) -> usize {
- self.iov.iov_len as usize
- }
-
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.iov.iov_len == 0
- }
-
- /// Gets a const pointer to this slice's memory.
- #[inline]
- pub fn as_ptr(&self) -> *const u8 {
- self.iov.iov_base as *const u8
- }
-
- /// Gets a mutable pointer to this slice's memory.
- #[inline]
- pub fn as_mut_ptr(&self) -> *mut u8 {
- self.iov.iov_base as *mut u8
- }
-
- /// Converts a slice of `IoBufMut`s into a slice of `iovec`s.
- #[allow(clippy::wrong_self_convention)]
- #[inline]
- pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [iovec] {
- // Safe because `IoBufMut` is ABI-compatible with `iovec`.
- unsafe { slice::from_raw_parts(iovs.as_ptr() as *const libc::iovec, iovs.len()) }
- }
-}
-
-impl<'a> AsRef<libc::iovec> for IoBufMut<'a> {
- fn as_ref(&self) -> &libc::iovec {
- &self.iov
- }
-}
-
-impl<'a> AsMut<libc::iovec> for IoBufMut<'a> {
- fn as_mut(&mut self) -> &mut libc::iovec {
- &mut self.iov
- }
-}
-
-// It's safe to implement Send + Sync for this type for the same reason that `std::io::IoBufMut`
-// is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send
-// + Sync. There's nothing wrong with sending a pointer between threads and de-referencing the
-// pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.
-unsafe impl<'a> Send for IoBufMut<'a> {}
-unsafe impl<'a> Sync for IoBufMut<'a> {}
-
-struct DebugIovec(iovec);
-impl Debug for DebugIovec {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("iovec")
- .field("iov_base", &self.0.iov_base)
- .field("iov_len", &self.0.iov_len)
- .finish()
- }
-}
-
-impl<'a> Debug for IoBufMut<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("IoBufMut")
- .field("iov", &DebugIovec(self.iov))
- .field("phantom", &self.phantom)
- .finish()
- }
+cfg_if::cfg_if! {
+ if #[cfg(unix)] {
+ mod unix;
+ pub use unix::*;
+ } else if #[cfg(windows)] {
+ mod windows;
+ pub use windows::*;
+ } else {
+ compile_error!("Unsupported platform");
+ }
}
diff --git a/common/data_model/src/sys/unix.rs b/common/data_model/src/sys/unix.rs
new file mode 100644
index 0000000..312668c
--- /dev/null
+++ b/common/data_model/src/sys/unix.rs
@@ -0,0 +1,158 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::c_void;
+use std::fmt::{self, Debug};
+use std::marker::PhantomData;
+use std::slice;
+
+use libc::iovec;
+
+/// Cross platform binary compatible iovec.
+pub type IoBuf = iovec;
+
+/// Cross platform stub to create a platform specific IoBuf.
+pub fn create_iobuf(addr: *mut u8, len: usize) -> IoBuf {
+ iovec {
+ iov_base: addr as *mut c_void,
+ iov_len: len,
+ }
+}
+
+/// This type is essentialy `std::io::IoBufMut`, and guaranteed to be ABI-compatible with
+/// `libc::iovec`; however, it does NOT automatically deref to `&mut [u8]`, which is critical
+/// because it can point to guest memory. (Guest memory is implicitly mutably borrowed by the
+/// guest, so another mutable borrow would violate Rust assumptions about references.)
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct IoBufMut<'a> {
+ iov: iovec,
+ phantom: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoBufMut<'a> {
+ pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
+ // Safe because buf's memory is of the supplied length, and
+ // guaranteed to exist for the lifetime of the returned value.
+ unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
+ }
+
+ /// Creates a `IoBufMut` from a pointer and a length.
+ ///
+ /// # Safety
+ ///
+ /// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
+ /// and should live for the entire duration of lifetime `'a`.
+ pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
+ IoBufMut {
+ iov: iovec {
+ iov_base: addr as *mut c_void,
+ iov_len: len,
+ },
+ phantom: PhantomData,
+ }
+ }
+
+ /// Creates a `IoBufMut` from an IoBuf.
+ ///
+ /// # Safety
+ ///
+ /// In order to use this method safely, `iobuf` must be valid for reads and writes through its
+ /// length and should live for the entire duration of lifetime `'a`.
+ pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {
+ IoBufMut {
+ iov: iobuf,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Advance the internal position of the buffer.
+ ///
+ /// Panics if `count > self.len()`.
+ pub fn advance(&mut self, count: usize) {
+ assert!(count <= self.len());
+
+ self.iov.iov_len -= count;
+ // Safe because we've checked that `count <= self.len()` so both the starting and resulting
+ // pointer are within the bounds of the allocation.
+ self.iov.iov_base = unsafe { self.iov.iov_base.add(count) };
+ }
+
+ /// Shorten the length of the buffer.
+ ///
+ /// Has no effect if `len > self.len()`.
+ pub fn truncate(&mut self, len: usize) {
+ if len < self.len() {
+ self.iov.iov_len = len;
+ }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.iov.iov_len as usize
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.iov.iov_len == 0
+ }
+
+ /// Gets a const pointer to this slice's memory.
+ #[inline]
+ pub fn as_ptr(&self) -> *const u8 {
+ self.iov.iov_base as *const u8
+ }
+
+ /// Gets a mutable pointer to this slice's memory.
+ #[inline]
+ pub fn as_mut_ptr(&self) -> *mut u8 {
+ self.iov.iov_base as *mut u8
+ }
+
+ /// Converts a slice of `IoBufMut`s into a slice of `iovec`s.
+ #[allow(clippy::wrong_self_convention)]
+ #[inline]
+ pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [iovec] {
+ // Safe because `IoBufMut` is ABI-compatible with `iovec`.
+ unsafe { slice::from_raw_parts(iovs.as_ptr() as *const libc::iovec, iovs.len()) }
+ }
+}
+
+impl<'a> AsRef<libc::iovec> for IoBufMut<'a> {
+ fn as_ref(&self) -> &libc::iovec {
+ &self.iov
+ }
+}
+
+impl<'a> AsMut<libc::iovec> for IoBufMut<'a> {
+ fn as_mut(&mut self) -> &mut libc::iovec {
+ &mut self.iov
+ }
+}
+
+// It's safe to implement Send + Sync for this type for the same reason that `std::io::IoBufMut`
+// is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send
+// + Sync. There's nothing wrong with sending a pointer between threads and de-referencing the
+// pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.
+unsafe impl<'a> Send for IoBufMut<'a> {}
+unsafe impl<'a> Sync for IoBufMut<'a> {}
+
+struct DebugIovec(iovec);
+impl Debug for DebugIovec {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("iovec")
+ .field("iov_base", &self.0.iov_base)
+ .field("iov_len", &self.0.iov_len)
+ .finish()
+ }
+}
+
+impl<'a> Debug for IoBufMut<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("IoBufMut")
+ .field("iov", &DebugIovec(self.iov))
+ .field("phantom", &self.phantom)
+ .finish()
+ }
+}
diff --git a/common/data_model/src/sys/windows.rs b/common/data_model/src/sys/windows.rs
new file mode 100644
index 0000000..4e3ae83
--- /dev/null
+++ b/common/data_model/src/sys/windows.rs
@@ -0,0 +1,133 @@
+use std::fmt::{self, Debug};
+use std::marker::PhantomData;
+use std::slice;
+
+use winapi::shared::ws2def::WSABUF;
+
+/// Cross platform binary compatible iovec.
+pub type IoBuf = WSABUF;
+
+/// Cross platform stub to create a platform specific IoBuf.
+pub fn create_iobuf(addr: *mut u8, len: usize) -> IoBuf {
+ WSABUF {
+ buf: addr as *mut i8,
+ len: len as u32,
+ }
+}
+
+/// This type is essentialy `std::io::IoBufMut`, and guaranteed to be ABI-compatible with
+/// `WSABUF`; however, it does NOT automatically deref to `&mut [u8]`, which is critical
+/// because it can point to guest memory. (Guest memory is implicitly mutably borrowed by the
+/// guest, so another mutable borrow would violate Rust assumptions about references.)
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct IoBufMut<'a> {
+ buf: WSABUF,
+ phantom: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoBufMut<'a> {
+ pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
+ // Safe because buf's memory is of the supplied length, and
+ // guaranteed to exist for the lifetime of the returned value.
+ unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
+ }
+
+ /// Creates a `IoBufMut` from a pointer and a length.
+ ///
+ /// # Safety
+ ///
+ /// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
+ /// and should live for the entire duration of lifetime `'a`.
+ pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
+ IoBufMut {
+ buf: WSABUF {
+ buf: addr as *mut i8,
+ len: len as u32,
+ },
+ phantom: PhantomData,
+ }
+ }
+
+ /// Creates a `IoBufMut` from an IoBuf.
+ ///
+ /// # Safety
+ ///
+ /// In order to use this method safely, `iobuf` must be valid for reads and writes through its
+ /// length and should live for the entire duration of lifetime `'a`.
+ pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {
+ IoBufMut {
+ buf: iobuf,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Advance the internal position of the buffer.
+ ///
+ /// Panics if `count > self.len()`.
+ pub fn advance(&mut self, _count: usize) {
+ unimplemented!()
+ }
+
+ /// Shorten the length of the buffer.
+ ///
+ /// Has no effect if `len > self.len()`.
+ pub fn truncate(&mut self, _len: usize) {
+ unimplemented!()
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.buf.len as usize
+ }
+
+ /// Gets a const pointer to this slice's memory.
+ #[inline]
+ pub fn as_ptr(&self) -> *const u8 {
+ self.buf.buf as *const u8
+ }
+
+ /// Gets a mutable pointer to this slice's memory.
+ #[inline]
+ pub fn as_mut_ptr(&self) -> *mut u8 {
+ self.buf.buf as *mut u8
+ }
+
+ /// Converts a slice of `IoBufMut`s into a slice of `iovec`s.
+ #[inline]
+ pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [IoBuf] {
+ // Safe because `IoBufMut` is ABI-compatible with `WSABUF`.
+ unsafe { slice::from_raw_parts(iovs.as_ptr() as *const WSABUF, iovs.len()) }
+ }
+}
+
+impl<'a> AsRef<WSABUF> for IoBufMut<'a> {
+ fn as_ref(&self) -> &WSABUF {
+ &self.buf
+ }
+}
+
+impl<'a> AsMut<WSABUF> for IoBufMut<'a> {
+ fn as_mut(&mut self) -> &mut WSABUF {
+ &mut self.buf
+ }
+}
+
+struct DebugWSABUF(WSABUF);
+impl Debug for DebugWSABUF {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("WSABUF")
+ .field("buf", &self.0.buf)
+ .field("len", &self.0.len)
+ .finish()
+ }
+}
+
+impl<'a> Debug for IoBufMut<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("IoBufMut")
+ .field("buf", &DebugWSABUF(self.buf))
+ .field("phantom", &self.phantom)
+ .finish()
+ }
+}
diff --git a/common/io_uring/Cargo.toml b/common/io_uring/Cargo.toml
index d420641..47b3138 100644
--- a/common/io_uring/Cargo.toml
+++ b/common/io_uring/Cargo.toml
@@ -2,7 +2,7 @@
name = "io_uring"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../data_model" } # provided by ebuild
diff --git a/common/p9/Cargo.toml b/common/p9/Cargo.toml
index 90616f3..45c5d0d 100644
--- a/common/p9/Cargo.toml
+++ b/common/p9/Cargo.toml
@@ -2,7 +2,7 @@
name = "p9"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
libc = "*"
diff --git a/common/p9/fuzz/Cargo.toml b/common/p9/fuzz/Cargo.toml
index fe9af4a..76ccc60 100644
--- a/common/p9/fuzz/Cargo.toml
+++ b/common/p9/fuzz/Cargo.toml
@@ -2,7 +2,7 @@
name = "p9-fuzz"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
p9 = { path = "../" }
diff --git a/common/sync/Cargo.toml b/common/sync/Cargo.toml
index af38fd1..953d41b 100644
--- a/common/sync/Cargo.toml
+++ b/common/sync/Cargo.toml
@@ -2,7 +2,7 @@
name = "sync"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["src/**/*", "Cargo.toml"]
[workspace]
diff --git a/common/sys_util/Cargo.toml b/common/sys_util/Cargo.toml
index 2971468..933dbda 100644
--- a/common/sys_util/Cargo.toml
+++ b/common/sys_util/Cargo.toml
@@ -2,7 +2,7 @@
name = "sys_util"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["src/**/*", "Cargo.toml"]
[dependencies]
diff --git a/common/sys_util/src/signal.rs b/common/sys_util/src/signal.rs
index 97fa64b..3dba86e 100644
--- a/common/sys_util/src/signal.rs
+++ b/common/sys_util/src/signal.rs
@@ -549,19 +549,12 @@
/// Treat some errno's as Ok(()).
macro_rules! ok_if {
- ($result:expr, $($errno:pat)|+) => {{
- let res = $result;
- match res {
- Ok(_) => Ok(()),
- Err(err) => {
- if matches!(err.errno(), $($errno)|+) {
- Ok(())
- } else {
- Err(err)
- }
+ ($result:expr, $errno:pat) => {{
+ match $result {
+ Err(err) if !matches!(err.errno(), $errno) => Err(err),
+ _ => Ok(()),
}
- }
- }}
+ }};
}
/// Terminates and reaps a child process. If the child process is a group leader, its children will
diff --git a/common/sys_util_core/Cargo.toml b/common/sys_util_core/Cargo.toml
index 2bf2cac..2546a51 100644
--- a/common/sys_util_core/Cargo.toml
+++ b/common/sys_util_core/Cargo.toml
@@ -2,7 +2,7 @@
name = "sys_util_core"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["src/**/*", "Cargo.toml"]
[dependencies]
diff --git a/common/sys_util_core/poll_token_derive/Cargo.toml b/common/sys_util_core/poll_token_derive/Cargo.toml
index 0b4d41c..6954015 100644
--- a/common/sys_util_core/poll_token_derive/Cargo.toml
+++ b/common/sys_util_core/poll_token_derive/Cargo.toml
@@ -2,7 +2,7 @@
name = "poll_token_derive"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["*.rs", "Cargo.toml"]
[lib]
diff --git a/crosvm-fuzz/Cargo.toml b/crosvm-fuzz/Cargo.toml
index e7f8e8b..0b54611 100644
--- a/crosvm-fuzz/Cargo.toml
+++ b/crosvm-fuzz/Cargo.toml
@@ -2,7 +2,7 @@
name = "crosvm-fuzz"
version = "0.0.1"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
cros_fuzz = "*"
diff --git a/crosvm_control/Cargo.toml b/crosvm_control/Cargo.toml
index 4554344..7f97143 100644
--- a/crosvm_control/Cargo.toml
+++ b/crosvm_control/Cargo.toml
@@ -2,7 +2,7 @@
name = "crosvm_control"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
crate-type = ["cdylib"]
diff --git a/crosvm_plugin/Cargo.toml b/crosvm_plugin/Cargo.toml
index 8531cf6..d1a631b 100644
--- a/crosvm_plugin/Cargo.toml
+++ b/crosvm_plugin/Cargo.toml
@@ -2,7 +2,7 @@
name = "crosvm_plugin"
version = "0.17.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
stats = []
diff --git a/devices/Cargo.toml b/devices/Cargo.toml
index 10a6c91..b49572a 100644
--- a/devices/Cargo.toml
+++ b/devices/Cargo.toml
@@ -2,7 +2,7 @@
name = "devices"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
audio = []
diff --git a/devices/src/acpi.rs b/devices/src/acpi.rs
index 8160057..e6e1c65 100644
--- a/devices/src/acpi.rs
+++ b/devices/src/acpi.rs
@@ -5,51 +5,145 @@
use crate::{BusAccessInfo, BusDevice, BusResumeDevice};
use acpi_tables::{aml, aml::Aml};
use base::{error, warn, Event};
+use vm_control::PmResource;
/// ACPI PM resource for handling OS suspend/resume request
+#[allow(dead_code)]
pub struct ACPIPMResource {
+ sci_evt: Event,
suspend_evt: Event,
exit_evt: Event,
pm1_status: u16,
pm1_enable: u16,
pm1_control: u16,
- sleep_control: u8,
- sleep_status: u8,
+ gpe0_status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
+ gpe0_enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
}
impl ACPIPMResource {
/// Constructs ACPI Power Management Resouce.
- pub fn new(suspend_evt: Event, exit_evt: Event) -> ACPIPMResource {
+ #[allow(dead_code)]
+ pub fn new(sci_evt: Event, suspend_evt: Event, exit_evt: Event) -> ACPIPMResource {
ACPIPMResource {
+ sci_evt,
suspend_evt,
exit_evt,
pm1_status: 0,
pm1_enable: 0,
pm1_control: 0,
- sleep_control: 0,
- sleep_status: 0,
+ gpe0_status: Default::default(),
+ gpe0_enable: Default::default(),
+ }
+ }
+
+ fn pm_sci(&self) {
+ if self.pm1_status
+ & self.pm1_enable
+ & (BITMASK_PM1EN_GBL_EN
+ | BITMASK_PM1EN_PWRBTN_EN
+ | BITMASK_PM1EN_SLPBTN_EN
+ | BITMASK_PM1EN_RTC_EN)
+ != 0
+ {
+ if let Err(e) = self.sci_evt.write(1) {
+ error!("ACPIPM: failed to trigger sci event: {}", e);
+ }
+ }
+ }
+
+ fn gpe_sci(&self) {
+ for i in 0..self.gpe0_status.len() {
+ if self.gpe0_status[i] & self.gpe0_enable[i] != 0 {
+ if let Err(e) = self.sci_evt.write(1) {
+ error!("ACPIPM: failed to trigger sci event: {}", e);
+ }
+ return;
+ }
}
}
}
/// 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;
+pub const ACPIPM_RESOURCE_GPE0_BLK_LEN: u8 = 64;
+pub const ACPIPM_RESOURCE_LEN: u8 = ACPIPM_RESOURCE_EVENTBLK_LEN + 4 + ACPIPM_RESOURCE_GPE0_BLK_LEN;
/// ACPI PM register value definitions
-const PM1_STATUS: u16 = 0;
-const PM1_ENABLE: u16 = 2;
-const PM1_CONTROL: u16 = 4;
-const SLEEP_CONTROL: u16 = 6;
-const SLEEP_STATUS: u16 = 7;
-const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
-const BITMASK_SLEEPCNT_SLEEP_ENABLE: u8 = 0x20;
-const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
-const BITMASK_SLEEPCNT_WAKE_STATUS: u8 = 0x80;
+/// 4.8.4.1.1 PM1 Status Registers, ACPI Spec Version 6.4
+/// Register Location: <PM1a_EVT_BLK / PM1b_EVT_BLK> System I/O or Memory Space (defined in FADT)
+/// Size: PM1_EVT_LEN / 2 (defined in FADT)
+const PM1_STATUS: u16 = 0;
+
+/// 4.8.4.1.2 PM1Enable Registers, ACPI Spec Version 6.4
+/// Register Location: <<PM1a_EVT_BLK / PM1b_EVT_BLK> + PM1_EVT_LEN / 2 System I/O or Memory Space
+/// (defined in FADT)
+/// Size: PM1_EVT_LEN / 2 (defined in FADT)
+const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
+
+/// 4.8.4.2.1 PM1 Control Registers, ACPI Spec Version 6.4
+/// Register Location: <PM1a_CNT_BLK / PM1b_CNT_BLK> System I/O or Memory Space (defined in FADT)
+/// Size: PM1_CNT_LEN (defined in FADT)
+const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
+
+/// 4.8.5.1 General-Purpose Event Register Blocks, ACPI Spec Version 6.4
+/// - Each register block contains two registers: an enable and a status register.
+/// - Each register block is 32-bit aligned.
+/// - Each register in the block is accessed as a byte.
+
+/// 4.8.5.1.1 General-Purpose Event 0 Register Block, ACPI Spec Version 6.4
+/// This register block consists of two registers: The GPE0_STS and the GPE0_EN registers. Each
+/// register’s length is defined to be half the length of the GPE0 register block, and is described
+/// in the ACPI FADT’s GPE0_BLK and GPE0_BLK_LEN operators.
+
+/// 4.8.5.1.1.1 General-Purpose Event 0 Status Register, ACPI Spec Version 6.4
+/// Register Location: <GPE0_STS> System I/O or System Memory Space (defined in FADT)
+/// Size: GPE0_BLK_LEN/2 (defined in FADT)
+const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; // ensure alignment
+
+/// 4.8.5.1.1.2 General-Purpose Event 0 Enable Register, ACPI Spec Version 6.4
+/// Register Location: <GPE0_EN> System I/O or System Memory Space (defined in FADT)
+/// Size: GPE0_BLK_LEN/2 (defined in FADT)
+const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
+
+const BITMASK_PM1STS_PWRBTN_STS: u16 = 1 << 8;
+const BITMASK_PM1EN_GBL_EN: u16 = 1 << 5;
+const BITMASK_PM1EN_PWRBTN_EN: u16 = 1 << 8;
+const BITMASK_PM1EN_SLPBTN_EN: u16 = 1 << 9;
+const BITMASK_PM1EN_RTC_EN: u16 = 1 << 10;
+const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
+const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
+
+#[cfg(not(feature = "direct"))]
const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
-const SLEEP_TYPE_S5: u16 = 0;
+#[cfg(not(feature = "direct"))]
+const SLEEP_TYPE_S1: u16 = 1 << 10;
+#[cfg(not(feature = "direct"))]
+const SLEEP_TYPE_S5: u16 = 0 << 10;
+
+impl PmResource for ACPIPMResource {
+ fn pwrbtn_evt(&mut self) {
+ self.pm1_status |= BITMASK_PM1STS_PWRBTN_STS;
+ self.pm_sci();
+ }
+
+ fn gpe_evt(&mut self, gpe: u32) {
+ let byte = gpe as usize / 8;
+ if byte >= self.gpe0_status.len() {
+ error!("gpe_evt: GPE register {} does not exist", byte);
+ return;
+ }
+ self.gpe0_status[byte] |= 1 << (gpe % 8);
+ self.gpe_sci();
+ }
+}
+
+const PM1_STATUS_LAST: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
+const PM1_ENABLE_LAST: u16 = PM1_ENABLE + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
+const PM1_CONTROL_LAST: u16 = PM1_CONTROL + ACPIPM_RESOURCE_CONTROLBLK_LEN as u16 - 1;
+const GPE0_STATUS_LAST: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
+const GPE0_ENABLE_LAST: u16 = GPE0_ENABLE + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
impl BusDevice for ACPIPMResource {
fn debug_label(&self) -> String {
@@ -57,69 +151,156 @@
}
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
- let val = match info.offset as u16 {
- PM1_STATUS => self.pm1_status,
- PM1_ENABLE => self.pm1_enable,
- PM1_CONTROL => self.pm1_control,
- SLEEP_CONTROL => self.sleep_control as u16,
- SLEEP_STATUS => self.sleep_status as u16,
+ match info.offset as u16 {
+ // Accesses to the PM1 registers are done through byte or word accesses
+ PM1_STATUS..=PM1_STATUS_LAST => {
+ if data.len() > std::mem::size_of::<u16>()
+ || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad read size: {}", data.len());
+ return;
+ }
+ let offset = (info.offset - PM1_STATUS as u64) as usize;
+ data.copy_from_slice(&self.pm1_status.to_ne_bytes()[offset..offset + data.len()]);
+ }
+ PM1_ENABLE..=PM1_ENABLE_LAST => {
+ if data.len() > std::mem::size_of::<u16>()
+ || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad read size: {}", data.len());
+ return;
+ }
+ let offset = (info.offset - PM1_ENABLE as u64) as usize;
+ data.copy_from_slice(&self.pm1_enable.to_ne_bytes()[offset..offset + data.len()]);
+ }
+ PM1_CONTROL..=PM1_CONTROL_LAST => {
+ if data.len() > std::mem::size_of::<u16>()
+ || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad read size: {}", data.len());
+ return;
+ }
+ let offset = (info.offset - PM1_CONTROL as u64) as usize;
+ data.copy_from_slice(&self.pm1_control.to_ne_bytes()[offset..offset + data.len()]);
+ }
+ // OSPM accesses GPE registers through byte accesses (regardless of their length)
+ GPE0_STATUS..=GPE0_STATUS_LAST => {
+ if data.len() > std::mem::size_of::<u8>()
+ || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad read size: {}", data.len());
+ return;
+ }
+ data[0] = self.gpe0_status[(info.offset - GPE0_STATUS as u64) as usize];
+ }
+ GPE0_ENABLE..=GPE0_ENABLE_LAST => {
+ if data.len() > std::mem::size_of::<u8>()
+ || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad read size: {}", data.len());
+ return;
+ }
+ data[0] = self.gpe0_enable[(info.offset - GPE0_ENABLE as u64) as usize];
+ }
_ => {
warn!("ACPIPM: Bad read from {}", info);
- return;
- }
- };
-
- let val_arr = val.to_ne_bytes();
- for i in 0..std::mem::size_of::<u16>() {
- if i < data.len() {
- data[i] = val_arr[i];
}
}
}
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
- let max_bytes = std::mem::size_of::<u16>();
-
- // only allow maximum max_bytes to write
- if data.len() > max_bytes {
- warn!("ACPIPM: bad write size: {}", data.len());
- return;
- }
-
- let mut val_arr = u16::to_ne_bytes(0u16);
- for i in 0..std::mem::size_of::<u16>() {
- if i < data.len() {
- val_arr[i] = data[i];
- }
- }
- let val = u16::from_ne_bytes(val_arr);
-
match info.offset as u16 {
- PM1_STATUS => self.pm1_status &= !val,
- PM1_ENABLE => self.pm1_enable = val,
- PM1_CONTROL => {
- if (val & BITMASK_PM1CNT_SLEEP_ENABLE) == BITMASK_PM1CNT_SLEEP_ENABLE {
- if val & BITMASK_PM1CNT_SLEEP_TYPE == SLEEP_TYPE_S5 {
- if let Err(e) = self.exit_evt.write(1) {
- error!("ACPIPM: failed to trigger exit event: {}", e);
+ // Accesses to the PM1 registers are done through byte or word accesses
+ PM1_STATUS..=PM1_STATUS_LAST => {
+ if data.len() > std::mem::size_of::<u16>()
+ || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad write size: {}", data.len());
+ return;
+ }
+ let offset = (info.offset - PM1_STATUS as u64) as usize;
+ let mut v = self.pm1_status.to_ne_bytes();
+ for (i, j) in (offset..offset + data.len()).enumerate() {
+ v[j] &= !data[i];
+ }
+ self.pm1_status = u16::from_ne_bytes(v);
+ }
+ PM1_ENABLE..=PM1_ENABLE_LAST => {
+ if data.len() > std::mem::size_of::<u16>()
+ || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad write size: {}", data.len());
+ return;
+ }
+ let offset = (info.offset - PM1_ENABLE as u64) as usize;
+ let mut v = self.pm1_enable.to_ne_bytes();
+ for (i, j) in (offset..offset + data.len()).enumerate() {
+ v[j] = data[i];
+ }
+ self.pm1_enable = u16::from_ne_bytes(v);
+ self.pm_sci(); // TODO take care of spurious interrupts
+ }
+ PM1_CONTROL..=PM1_CONTROL_LAST => {
+ if data.len() > std::mem::size_of::<u16>()
+ || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad write size: {}", data.len());
+ return;
+ }
+ let offset = (info.offset - PM1_CONTROL as u64) as usize;
+ let mut v = self.pm1_control.to_ne_bytes();
+ for (i, j) in (offset..offset + data.len()).enumerate() {
+ v[j] = data[i];
+ }
+ let val = u16::from_ne_bytes(v);
+
+ // SLP_EN is a write-only bit and reads to it always return a zero
+ if (val & BITMASK_PM1CNT_SLEEP_ENABLE) != 0 {
+ // only support S5 in direct mode
+ #[cfg(feature = "direct")]
+ if let Err(e) = self.exit_evt.write(1) {
+ error!("ACPIPM: failed to trigger exit event: {}", e);
+ }
+ #[cfg(not(feature = "direct"))]
+ match val & BITMASK_PM1CNT_SLEEP_TYPE {
+ SLEEP_TYPE_S1 => {
+ if let Err(e) = self.suspend_evt.write(1) {
+ error!("ACPIPM: failed to trigger suspend event: {}", e);
+ }
}
- } else if let Err(e) = self.suspend_evt.write(1) {
- error!("ACPIPM: failed to trigger suspend event: {}", e);
+ SLEEP_TYPE_S5 => {
+ if let Err(e) = self.exit_evt.write(1) {
+ error!("ACPIPM: failed to trigger exit event: {}", e);
+ }
+ }
+ _ => error!(
+ "ACPIPM: unknown SLP_TYP written: {}",
+ (val & BITMASK_PM1CNT_SLEEP_TYPE) >> 10
+ ),
}
}
self.pm1_control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
}
- SLEEP_CONTROL => {
- let sleep_control = val as u8;
- if (sleep_control & BITMASK_SLEEPCNT_SLEEP_ENABLE) == BITMASK_SLEEPCNT_SLEEP_ENABLE
+ // OSPM accesses GPE registers through byte accesses (regardless of their length)
+ GPE0_STATUS..=GPE0_STATUS_LAST => {
+ if data.len() > std::mem::size_of::<u8>()
+ || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
{
- if let Err(e) = self.suspend_evt.write(1) {
- error!("ACPIPM: failed to trigger suspend event: {}", e);
- }
+ warn!("ACPIPM: bad write size: {}", data.len());
+ return;
}
- self.sleep_control = sleep_control as u8 & !BITMASK_SLEEPCNT_SLEEP_ENABLE;
+ self.gpe0_status[(info.offset - GPE0_STATUS as u64) as usize] &= !data[0];
}
- SLEEP_STATUS => self.sleep_status &= !val as u8,
+ GPE0_ENABLE..=GPE0_ENABLE_LAST => {
+ if data.len() > std::mem::size_of::<u8>()
+ || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
+ {
+ warn!("ACPIPM: bad write size: {}", data.len());
+ return;
+ }
+ self.gpe0_enable[(info.offset - GPE0_ENABLE as u64) as usize] = data[0];
+ self.gpe_sci();
+ }
_ => {
warn!("ACPIPM: Bad write to {}", info);
}
@@ -129,11 +310,7 @@
impl BusResumeDevice for ACPIPMResource {
fn resume_imminent(&mut self) {
- let val = self.pm1_status;
- self.pm1_status = val | BITMASK_PM1CNT_WAKE_STATUS;
-
- let val = self.sleep_status;
- self.sleep_status = val | BITMASK_SLEEPCNT_WAKE_STATUS;
+ self.pm1_status |= BITMASK_PM1CNT_WAKE_STATUS;
}
}
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
index d7e3829..0989eb2 100644
--- a/devices/src/pci/pci_root.rs
+++ b/devices/src/pci/pci_root.rs
@@ -456,10 +456,7 @@
.lock()
.virtual_config_space_read(address, register)
};
- data[0] = value as u8;
- data[1] = (value >> (1 * 8)) as u8;
- data[2] = (value >> (2 * 8)) as u8;
- data[3] = (value >> (3 * 8)) as u8;
+ data[0..4].copy_from_slice(&value.to_le_bytes()[..]);
}
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
@@ -472,10 +469,8 @@
);
return;
}
- let value = (data[0] as u32)
- | ((data[1] as u32) << (1 * 8))
- | ((data[2] as u32) << (2 * 8))
- | ((data[3] as u32) << (3 * 8));
+ // Unwrap is safe as we verified length above
+ let value = u32::from_le_bytes(data.try_into().unwrap());
let (address, register) =
PciAddress::from_config_address(info.offset as u32, self.register_bit_num);
self.pci_root
diff --git a/devices/src/virtio/snd/vios_backend/shm_vios.rs b/devices/src/virtio/snd/vios_backend/shm_vios.rs
index aeace18..349781f 100644
--- a/devices/src/virtio/snd/vios_backend/shm_vios.rs
+++ b/devices/src/virtio/snd/vios_backend/shm_vios.rs
@@ -6,9 +6,9 @@
use crate::virtio::snd::layout::*;
use base::{
- error, net::UnixSeqpacket, AsRawDescriptor, Error as BaseError, Event, FromRawDescriptor,
- IntoRawDescriptor, MemoryMapping, MemoryMappingBuilder, MmapError, PollToken, SafeDescriptor,
- ScmSocket, WaitContext,
+ error, AsRawDescriptor, Error as BaseError, Event, FromRawDescriptor, IntoRawDescriptor,
+ MemoryMapping, MemoryMappingBuilder, MmapError, PollToken, SafeDescriptor, ScmSocket,
+ UnixSeqpacket, WaitContext,
};
use data_model::{DataInit, VolatileMemory, VolatileMemoryError, VolatileSlice};
diff --git a/devices/src/virtio/vhost/user/device/gpu.rs b/devices/src/virtio/vhost/user/device/gpu.rs
index 4a5405d..37da959 100644
--- a/devices/src/virtio/vhost/user/device/gpu.rs
+++ b/devices/src/virtio/vhost/user/device/gpu.rs
@@ -8,9 +8,8 @@
use argh::FromArgs;
use async_task::Task;
use base::{
- clone_descriptor, error,
- net::{UnixSeqpacketListener, UnlinkUnixSeqpacketListener},
- warn, Event, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor, TimerFd, Tube,
+ clone_descriptor, error, warn, Event, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor,
+ TimerFd, Tube, UnixSeqpacketListener, UnlinkUnixSeqpacketListener,
};
use cros_async::{AsyncWrapper, EventAsync, Executor, IoSourceExt, TimerAsync};
use futures::{
diff --git a/devices/src/virtio/vhost/user/device/wl.rs b/devices/src/virtio/vhost/user/device/wl.rs
index 3997850..ac34e85 100644
--- a/devices/src/virtio/vhost/user/device/wl.rs
+++ b/devices/src/virtio/vhost/user/device/wl.rs
@@ -13,9 +13,8 @@
use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{
- clone_descriptor, error,
- net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener},
- warn, Event, FromRawDescriptor, SafeDescriptor, Tube,
+ clone_descriptor, error, warn, Event, FromRawDescriptor, SafeDescriptor, Tube, UnixSeqpacket,
+ UnixSeqpacketListener, UnlinkUnixSeqpacketListener,
};
use cros_async::{AsyncWrapper, EventAsync, Executor, IoSourceExt};
use futures::future::{AbortHandle, Abortable};
diff --git a/devices/src/virtio/vhost/user/proxy.rs b/devices/src/virtio/vhost/user/proxy.rs
index aeeba07..c4fda6d 100644
--- a/devices/src/virtio/vhost/user/proxy.rs
+++ b/devices/src/virtio/vhost/user/proxy.rs
@@ -16,8 +16,8 @@
use std::thread;
use base::{
- error, info, AsRawDescriptor, Event, EventType, FromRawDescriptor, IntoRawDescriptor,
- PollToken, RawDescriptor, SafeDescriptor, Tube, TubeError, WaitContext,
+ error, AsRawDescriptor, Event, EventType, FromRawDescriptor, IntoRawDescriptor, PollToken,
+ RawDescriptor, SafeDescriptor, Tube, TubeError, WaitContext,
};
use data_model::{DataInit, Le32};
use libc::{recv, MSG_DONTWAIT, MSG_PEEK};
@@ -186,6 +186,9 @@
/// There are no more available descriptors to receive into.
#[error("no rx descriptors available")]
RxDescriptorsExhausted,
+ /// Sibling is disconnected.
+ #[error("sibling disconnected")]
+ SiblingDisconnected,
/// Failed to receive a memory mapping request from the main process.
#[error("receiving mapping request from tube failed: {0}")]
TubeReceiveFailure(TubeError),
@@ -395,6 +398,9 @@
.map_err(Error::WaitContextDisableSiblingVmSocket)?;
sibling_socket_polling_enabled = false;
}
+ // TODO(b/216407443): Handle sibling disconnection. The sibling sends
+ // 0-length data the proxy device forwards it to the guest so that the
+ // VVU backend can get notified that the connection is closed.
Err(e) => return Err(e),
}
}
@@ -461,102 +467,95 @@
// - Parse the Vhost-user sibling message. If it's not an action type message
// then copy the message as is to the Rx buffer and forward it to the
// device backend.
- let mut exhausted_queue = false;
+ //
// Peek if any data is left on the Vhost-user sibling socket. If no, then
// nothing to forwad to the device backend.
- while self.is_sibling_data_available() {
- if let Some(desc) = self.rx_queue.peek(&self.mem) {
- // To successfully receive attached file descriptors, we need to
- // receive messages and corresponding attached file descriptors in
- // this way:
- // - receive messsage header and optional attached files.
- // - receive optional message body and payload according size field
- // in message header.
- // - forward it to the device backend.
- let (hdr, files) = self
- .slave_req_helper
- .as_mut()
- .recv_header()
- .map_err(Error::ReadSiblingHeader)?;
- check_attached_files(&hdr, &files)?;
- let buf = self.get_sibling_msg_data(&hdr)?;
+ while self.is_sibling_data_available()? {
+ let desc = self
+ .rx_queue
+ .peek(&self.mem)
+ .ok_or(Error::RxDescriptorsExhausted)?;
+ // To successfully receive attached file descriptors, we need to
+ // receive messages and corresponding attached file descriptors in
+ // this way:
+ // - receive messsage header and optional attached files.
+ // - receive optional message body and payload according size field
+ // in message header.
+ // - forward it to the device backend.
+ let (hdr, files) = self
+ .slave_req_helper
+ .as_mut()
+ .recv_header()
+ .map_err(Error::ReadSiblingHeader)?;
+ check_attached_files(&hdr, &files)?;
+ let buf = self.get_sibling_msg_data(&hdr)?;
- let index = desc.index;
- let bytes_written = {
- if is_action_request(&hdr) {
- // TODO(abhishekbh): Implement action messages.
- let res = match hdr.get_code() {
- MasterReq::SET_MEM_TABLE => {
- // Map the sibling memory in this process and forward the sibling
- // memory info to the slave. Only if the mapping succeeds send info
- // along to the slave, else send a failed Ack back to the master.
- self.set_mem_table(&hdr, &buf, files)
- }
- MasterReq::SET_VRING_CALL => self.set_vring_call(&hdr, &buf, files),
- MasterReq::SET_VRING_KICK => {
- self.set_vring_kick(wait_ctx, &hdr, &buf, files)
- }
- _ => {
- unimplemented!("unimplemented action message:{:?}", hdr.get_code());
- }
- };
-
- // If the "action" in response to the action messages
- // failed then no bytes have been written to the virt
- // queue. Else, the action is done. Now forward the
- // message to the virt queue and return how many bytes
- // were written.
- match res {
- Ok(()) => self.forward_msg_to_device(desc, &hdr, &buf),
- Err(e) => Err(e),
+ let index = desc.index;
+ let bytes_written = {
+ if is_action_request(&hdr) {
+ // TODO(abhishekbh): Implement action messages.
+ let res = match hdr.get_code() {
+ MasterReq::SET_MEM_TABLE => {
+ // Map the sibling memory in this process and forward the
+ // sibling memory info to the slave. Only if the mapping
+ // succeeds send info along to the slave, else send a failed
+ // Ack back to the master.
+ self.set_mem_table(&hdr, &buf, files)
}
- } else {
- // If no special processing required. Forward this message as is
- // to the device backend.
- self.forward_msg_to_device(desc, &hdr, &buf)
- }
- };
-
- // If some bytes were written to the virt queue, now it's time
- // to add a used buffer and notify the guest. Else if there was
- // an error of any sort, we notify the sibling by sending an ACK
- // with failure.
- match bytes_written {
- Ok(bytes_written) => {
- // The driver is able to deal with a descriptor with 0 bytes written.
- self.rx_queue.pop_peeked(&self.mem);
- self.rx_queue.add_used(&self.mem, index, bytes_written);
- if !self.rx_queue.trigger_interrupt(&self.mem, &self.interrupt) {
- // This interrupt should always be injected. We'd rather fail fast
- // if there is an error.
- panic!("failed to send interrupt");
+ MasterReq::SET_VRING_CALL => self.set_vring_call(&hdr, &buf, files),
+ MasterReq::SET_VRING_KICK => {
+ self.set_vring_kick(wait_ctx, &hdr, &buf, files)
}
+ _ => {
+ unimplemented!("unimplemented action message:{:?}", hdr.get_code());
+ }
+ };
+
+ // If the "action" in response to the action messages
+ // failed then no bytes have been written to the virt
+ // queue. Else, the action is done. Now forward the
+ // message to the virt queue and return how many bytes
+ // were written.
+ match res {
+ Ok(()) => self.forward_msg_to_device(desc, &hdr, &buf),
+ Err(e) => Err(e),
}
- Err(e) => {
- error!("failed to forward message to the device: {}", e);
- self.slave_req_helper
- .send_ack_message(&hdr, false)
- .map_err(Error::FailedAck)?;
+ } else {
+ // If no special processing required. Forward this message as is
+ // to the device backend.
+ self.forward_msg_to_device(desc, &hdr, &buf)
+ }
+ };
+
+ // If some bytes were written to the virt queue, now it's time
+ // to add a used buffer and notify the guest. Else if there was
+ // an error of any sort, we notify the sibling by sending an ACK
+ // with failure.
+ match bytes_written {
+ Ok(bytes_written) => {
+ // The driver is able to deal with a descriptor with 0 bytes written.
+ self.rx_queue.pop_peeked(&self.mem);
+ self.rx_queue.add_used(&self.mem, index, bytes_written);
+ if !self.rx_queue.trigger_interrupt(&self.mem, &self.interrupt) {
+ // This interrupt should always be injected. We'd rather fail
+ // fast if there is an error.
+ panic!("failed to send interrupt");
}
}
- } else {
- // No buffer left to fill up. No point processing any data
- // from the Vhost-user sibling.
- exhausted_queue = true;
- break;
+ Err(e) => {
+ error!("failed to forward message to the device: {}", e);
+ self.slave_req_helper
+ .send_ack_message(&hdr, false)
+ .map_err(Error::FailedAck)?;
+ }
}
}
- if exhausted_queue {
- Err(Error::RxDescriptorsExhausted)
- } else {
- info!("no more data available on the sibling socket");
- Ok(())
- }
+ Ok(())
}
- // Returns true iff any data is available on the sibling socket.
- fn is_sibling_data_available(&self) -> bool {
+ // Returns the sibling connection status.
+ fn is_sibling_data_available(&self) -> Result<bool> {
// Peek if any data is left on the Vhost-user sibling socket. If no, then
// nothing to forwad to the device backend.
let mut peek_buf = [0; 1];
@@ -571,9 +570,16 @@
)
};
- // TODO(abhishekbh): Should we log on < 0 ?. Peek should
- // succeed.
- peek_ret > 0
+ match peek_ret {
+ 0 => Err(Error::SiblingDisconnected),
+ ret if ret < 0 => match base::Error::last() {
+ // EAGAIN means that no data is available. Any other error means that the sibling
+ // has disconnected.
+ e if e.errno() == libc::EAGAIN => Ok(false),
+ _ => Err(Error::SiblingDisconnected),
+ },
+ _ => Ok(true),
+ }
}
// Returns any data attached to a Vhost-user sibling message.
@@ -1183,7 +1189,10 @@
};
let rx_queue_evt = activate_params.queue_evts.remove(0);
let tx_queue_evt = activate_params.queue_evts.remove(0);
- let _ = worker.run(rx_queue_evt, tx_queue_evt, main_thread_tube, kill_evt);
+ if let Err(e) = worker.run(rx_queue_evt, tx_queue_evt, main_thread_tube, kill_evt) {
+ // TODO(b/216407443): Handle sibling reconnect events.
+ error!("worker thread exited: {}", e);
+ }
Ok(worker)
});
diff --git a/disk/Cargo.toml b/disk/Cargo.toml
index f3bbf14..5dff7ff 100644
--- a/disk/Cargo.toml
+++ b/disk/Cargo.toml
@@ -2,7 +2,7 @@
name = "disk"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
path = "src/disk.rs"
diff --git a/fuse/Cargo.toml b/fuse/Cargo.toml
index 3cbc6bd..7e4bfc9 100644
--- a/fuse/Cargo.toml
+++ b/fuse/Cargo.toml
@@ -2,7 +2,7 @@
name = "fuse"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
path = "src/lib.rs"
diff --git a/gpu_display/Cargo.toml b/gpu_display/Cargo.toml
index d5aa36d..84e1fc0 100644
--- a/gpu_display/Cargo.toml
+++ b/gpu_display/Cargo.toml
@@ -2,7 +2,7 @@
name = "gpu_display"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
x = []
diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml
index eea6f26..1bff265 100644
--- a/hypervisor/Cargo.toml
+++ b/hypervisor/Cargo.toml
@@ -2,7 +2,7 @@
name = "hypervisor"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
bit_field = { path = "../bit_field" }
diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml
index f250cfb..7da71c1 100644
--- a/integration_tests/Cargo.toml
+++ b/integration_tests/Cargo.toml
@@ -2,7 +2,7 @@
name = "integration_tests"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dev-dependencies]
tempfile = "3"
diff --git a/kernel_cmdline/Cargo.toml b/kernel_cmdline/Cargo.toml
index bf2a5d6..aacbe05 100644
--- a/kernel_cmdline/Cargo.toml
+++ b/kernel_cmdline/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "kernel_cmdline"
version = "0.1.0"
-edition = "2018"
+edition = "2021"
[dependencies]
libc = "*"
diff --git a/kernel_loader/Cargo.toml b/kernel_loader/Cargo.toml
index 9fd1e8c..b57b4d9 100644
--- a/kernel_loader/Cargo.toml
+++ b/kernel_loader/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "kernel_loader"
version = "0.1.0"
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../common/data_model" }
diff --git a/kvm/Cargo.toml b/kvm/Cargo.toml
index 525e73a..7bdfd17 100644
--- a/kvm/Cargo.toml
+++ b/kvm/Cargo.toml
@@ -2,7 +2,7 @@
name = "kvm"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../common/data_model" }
diff --git a/kvm_sys/Cargo.toml b/kvm_sys/Cargo.toml
index 0649785..dbac907 100644
--- a/kvm_sys/Cargo.toml
+++ b/kvm_sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "kvm_sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../common/data_model" }
diff --git a/libcras_stub/Cargo.toml b/libcras_stub/Cargo.toml
index 7d40cf2..4b0961c 100644
--- a/libcras_stub/Cargo.toml
+++ b/libcras_stub/Cargo.toml
@@ -2,7 +2,7 @@
name = "libcras"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
path = "src/libcras.rs"
diff --git a/libvda/Cargo.toml b/libvda/Cargo.toml
index 7de282c..551d558 100644
--- a/libvda/Cargo.toml
+++ b/libvda/Cargo.toml
@@ -2,7 +2,7 @@
name = "libvda"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
links = "vda"
[dependencies]
diff --git a/linux_input_sys/Cargo.toml b/linux_input_sys/Cargo.toml
index a8181d0..7d57c84 100644
--- a/linux_input_sys/Cargo.toml
+++ b/linux_input_sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "linux_input_sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../common/data_model" }
diff --git a/net_sys/Cargo.toml b/net_sys/Cargo.toml
index 53e3b1a..cd7c095 100644
--- a/net_sys/Cargo.toml
+++ b/net_sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "net_sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
base = { path = "../common/base" }
diff --git a/net_util/Cargo.toml b/net_util/Cargo.toml
index 8dfe1df..951d0e0 100644
--- a/net_util/Cargo.toml
+++ b/net_util/Cargo.toml
@@ -2,7 +2,7 @@
name = "net_util"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
libc = "*"
diff --git a/power_monitor/Cargo.toml b/power_monitor/Cargo.toml
index e16362c..c7fe4e0 100644
--- a/power_monitor/Cargo.toml
+++ b/power_monitor/Cargo.toml
@@ -2,7 +2,7 @@
name = "power_monitor"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
powerd = ["dbus", "protobuf", "protoc-rust"]
diff --git a/protos/Cargo.toml b/protos/Cargo.toml
index d4286e6..736d755 100644
--- a/protos/Cargo.toml
+++ b/protos/Cargo.toml
@@ -2,7 +2,7 @@
name = "protos"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
plugin = ["kvm_sys"]
diff --git a/qcow_utils/Cargo.toml b/qcow_utils/Cargo.toml
index 840bb18..28ade45 100644
--- a/qcow_utils/Cargo.toml
+++ b/qcow_utils/Cargo.toml
@@ -2,7 +2,7 @@
name = "qcow_utils"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
path = "src/qcow_utils.rs"
diff --git a/resources/Cargo.toml b/resources/Cargo.toml
index f5c7219..6cb4e0d 100644
--- a/resources/Cargo.toml
+++ b/resources/Cargo.toml
@@ -2,7 +2,7 @@
name = "resources"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
libc = "*"
diff --git a/resources/src/address_allocator.rs b/resources/src/address_allocator.rs
index ffb5152..12fc6c5 100644
--- a/resources/src/address_allocator.rs
+++ b/resources/src/address_allocator.rs
@@ -195,8 +195,8 @@
/// Allocates a range of addresses from the managed region with an optional tag
/// and required location. Allocation alignment is not enforced.
- /// Returns OutOfSpace if requested range is not available (e.g. already allocated
- /// with a different alloc tag).
+ /// Returns OutOfSpace if requested range is not available or ExistingAlloc if the requested
+ /// range overlaps an existing allocation.
pub fn allocate_at(&mut self, start: u64, size: u64, alloc: Alloc, tag: String) -> Result<()> {
if self.allocs.contains_key(&alloc) {
return Err(Error::ExistingAlloc(alloc));
@@ -224,7 +224,13 @@
Ok(())
}
- None => Err(Error::OutOfSpace),
+ None => {
+ if let Some(existing_alloc) = self.find_overlapping(start, size) {
+ Err(Error::ExistingAlloc(existing_alloc))
+ } else {
+ Err(Error::OutOfSpace)
+ }
+ }
}
}
@@ -237,19 +243,29 @@
/// Release a allocation contains the value.
pub fn release_containing(&mut self, value: u64) -> Result<()> {
- let mut alloc = None;
- for (key, val) in self.allocs.iter() {
- if value >= val.0 && value < val.0 + val.1 {
- alloc = Some(*key);
- break;
- }
+ if let Some(alloc) = self.find_overlapping(value, 1) {
+ self.release(alloc)
+ } else {
+ Err(Error::OutOfSpace)
+ }
+ }
+
+ // Find an existing allocation that overlaps the region defined by `address` and `size`. If more
+ // than one allocation overlaps the given region, any of them may be returned, since the HashMap
+ // iterator is not ordered in any particular way.
+ fn find_overlapping(&self, start: u64, size: u64) -> Option<Alloc> {
+ if size == 0 {
+ return None;
}
- if let Some(key) = alloc {
- return self.release(key);
- }
-
- Err(Error::OutOfSpace)
+ let end = start.saturating_add(size - 1);
+ self.allocs
+ .iter()
+ .find(|(_, &(alloc_start, alloc_size, _))| {
+ let alloc_end = alloc_start + alloc_size;
+ start < alloc_end && end >= alloc_start
+ })
+ .map(|(&alloc, _)| alloc)
}
/// Returns allocation associated with `alloc`, or None if no such allocation exists.
@@ -506,7 +522,8 @@
#[test]
fn allocate_and_split_allocate_at() {
- let mut pool = AddressAllocator::new(0x1000, 0x1000, Some(0x100), None).unwrap();
+ let mut pool = AddressAllocator::new(0x1000, 0x1000, Some(1), None).unwrap();
+ // 0x1200..0x1a00
assert_eq!(
pool.allocate_at(0x1200, 0x800, Alloc::Anon(0), String::from("bar0")),
Ok(())
@@ -515,14 +532,41 @@
pool.allocate(0x800, Alloc::Anon(1), String::from("bar1")),
Err(Error::OutOfSpace)
);
+ // 0x600..0x2000
assert_eq!(
pool.allocate(0x600, Alloc::Anon(2), String::from("bar2")),
Ok(0x1a00)
);
+ // 0x1000..0x1200
assert_eq!(
pool.allocate(0x200, Alloc::Anon(3), String::from("bar3")),
Ok(0x1000)
);
+ // 0x1b00..0x1c00 (overlaps with 0x600..0x2000)
+ assert_eq!(
+ pool.allocate_at(0x1b00, 0x100, Alloc::Anon(4), String::from("bar4")),
+ Err(Error::ExistingAlloc(Alloc::Anon(2)))
+ );
+ // 0x1fff..0x2000 (overlaps with 0x600..0x2000)
+ assert_eq!(
+ pool.allocate_at(0x1fff, 1, Alloc::Anon(5), String::from("bar5")),
+ Err(Error::ExistingAlloc(Alloc::Anon(2)))
+ );
+ // 0x1200..0x1201 (overlaps with 0x1200..0x1a00)
+ assert_eq!(
+ pool.allocate_at(0x1200, 1, Alloc::Anon(6), String::from("bar6")),
+ Err(Error::ExistingAlloc(Alloc::Anon(0)))
+ );
+ // 0x11ff..0x1200 (overlaps with 0x1000..0x1200)
+ assert_eq!(
+ pool.allocate_at(0x11ff, 1, Alloc::Anon(7), String::from("bar7")),
+ Err(Error::ExistingAlloc(Alloc::Anon(3)))
+ );
+ // 0x1100..0x1300 (overlaps with 0x1000..0x1200 and 0x1200..0x1a00)
+ match pool.allocate_at(0x1100, 0x200, Alloc::Anon(8), String::from("bar8")) {
+ Err(Error::ExistingAlloc(Alloc::Anon(0) | Alloc::Anon(3))) => {}
+ x => panic!("unexpected result {:?}", x),
+ }
}
#[test]
diff --git a/rutabaga_gfx/Cargo.toml b/rutabaga_gfx/Cargo.toml
index 46d56bb..bb02eac 100644
--- a/rutabaga_gfx/Cargo.toml
+++ b/rutabaga_gfx/Cargo.toml
@@ -2,7 +2,7 @@
name = "rutabaga_gfx"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
gfxstream = []
diff --git a/rutabaga_gfx/ffi/Cargo.toml b/rutabaga_gfx/ffi/Cargo.toml
index 9e10616..3926c4a 100644
--- a/rutabaga_gfx/ffi/Cargo.toml
+++ b/rutabaga_gfx/ffi/Cargo.toml
@@ -2,7 +2,7 @@
name = "rutabaga_gfx_ffi"
version = "0.1.0"
authors = ["The Chromium OS Authors + Android Open Source Project"]
-edition = "2018"
+edition = "2021"
[lib]
name = "rutabaga_gfx_ffi"
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/Cargo.toml b/rutabaga_gfx/src/rutabaga_gralloc/Cargo.toml
index 1ab814c..a541c9c 100644
--- a/rutabaga_gfx/src/rutabaga_gralloc/Cargo.toml
+++ b/rutabaga_gfx/src/rutabaga_gralloc/Cargo.toml
@@ -2,7 +2,7 @@
name = "gpu_buffer"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
data_model = { path = "../data_model" }
diff --git a/src/linux/mod.rs b/src/linux/mod.rs
index 568fd85..039d2fd 100644
--- a/src/linux/mod.rs
+++ b/src/linux/mod.rs
@@ -3,7 +3,7 @@
// found in the LICENSE file.
use std::cmp::{max, Reverse};
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryInto;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
@@ -27,8 +27,8 @@
use acpi_tables::sdt::SDT;
use anyhow::{anyhow, bail, Context, Result};
-use base::net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener};
use base::*;
+use base::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener};
use devices::serial_device::SerialHardware;
use devices::vfio::{VfioCommonSetup, VfioCommonTrait};
use devices::virtio::memory_mapper::MemoryMapperTrait;
@@ -55,7 +55,7 @@
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use crate::gdb::{gdb_thread, GdbStub};
-use crate::{Config, Executable, SharedDir, SharedDirKind, VfioType};
+use crate::{Config, Executable, FileBackedMappingParameters, SharedDir, SharedDirKind, VfioType};
use arch::{
self, LinuxArch, RunnableLinuxVm, VcpuAffinity, VirtioDeviceStub, VmComponents, VmImage,
};
@@ -640,15 +640,19 @@
.build()
.context("failed to map backing file for file-backed mapping")?;
- resources
- .mmio_allocator_any()
- .allocate_at(
- mapping.address,
- mapping.size,
- Alloc::FileBacked(mapping.address),
- "file-backed mapping".to_owned(),
- )
- .context("failed to allocate guest address for file-backed mapping")?;
+ match resources.mmio_allocator_any().allocate_at(
+ mapping.address,
+ mapping.size,
+ Alloc::FileBacked(mapping.address),
+ "file-backed mapping".to_owned(),
+ ) {
+ // OutOfSpace just means that this mapping is not in the MMIO regions at all, so don't
+ // consider it an error.
+ // TODO(b/222769529): Reserve this region in a global memory address space allocator once
+ // we have that so nothing else can accidentally overlap with it.
+ Ok(()) | Err(resources::Error::OutOfSpace) => {}
+ e => e.context("failed to allocate guest address for file-backed mapping")?,
+ }
vm.add_memory_region(
GuestAddress(mapping.address),
@@ -871,11 +875,58 @@
GuestPanic,
}
+// Remove ranges in `guest_mem_layout` that overlap with ranges in `file_backed_mappings`.
+// Returns the updated guest memory layout.
+fn punch_holes_in_guest_mem_layout_for_mappings(
+ guest_mem_layout: Vec<(GuestAddress, u64)>,
+ file_backed_mappings: &[FileBackedMappingParameters],
+) -> Vec<(GuestAddress, u64)> {
+ // Create a set containing (start, end) pairs with exclusive end (end = start + size; the byte
+ // at end is not included in the range).
+ let mut layout_set = BTreeSet::new();
+ for (addr, size) in &guest_mem_layout {
+ layout_set.insert((addr.offset(), addr.offset() + size));
+ }
+
+ for mapping in file_backed_mappings {
+ let mapping_start = mapping.address;
+ let mapping_end = mapping_start + mapping.size;
+
+ // Repeatedly split overlapping guest memory regions until no overlaps remain.
+ while let Some((range_start, range_end)) = layout_set
+ .iter()
+ .find(|&&(range_start, range_end)| {
+ mapping_start < range_end && mapping_end > range_start
+ })
+ .cloned()
+ {
+ layout_set.remove(&(range_start, range_end));
+
+ if range_start < mapping_start {
+ layout_set.insert((range_start, mapping_start));
+ }
+ if range_end > mapping_end {
+ layout_set.insert((mapping_end, range_end));
+ }
+ }
+ }
+
+ // Build the final guest memory layout from the modified layout_set.
+ layout_set
+ .iter()
+ .map(|(start, end)| (GuestAddress(*start), end - start))
+ .collect()
+}
+
pub fn run_config(cfg: Config) -> Result<ExitState> {
let components = setup_vm_components(&cfg)?;
let guest_mem_layout =
Arch::guest_memory_layout(&components).context("failed to create guest memory layout")?;
+
+ let guest_mem_layout =
+ punch_holes_in_guest_mem_layout_for_mappings(guest_mem_layout, &cfg.file_backed_mappings);
+
let guest_mem = GuestMemory::new(&guest_mem_layout).context("failed to create guest memory")?;
let mut mem_policy = MemoryPolicy::empty();
if components.hugepages {
@@ -1805,6 +1856,7 @@
balloon_host_tube.as_ref(),
&mut balloon_stats_id,
disk_host_tubes,
+ &mut linux.pm,
#[cfg(feature = "usb")]
Some(&usb_control_tube),
#[cfg(not(feature = "usb"))]
@@ -2035,3 +2087,161 @@
Ok(exit_state)
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // Create a file-backed mapping parameters struct with the given `address` and `size` and other
+ // parameters set to default values.
+ fn test_file_backed_mapping(address: u64, size: u64) -> FileBackedMappingParameters {
+ FileBackedMappingParameters {
+ address,
+ size,
+ path: PathBuf::new(),
+ offset: 0,
+ writable: false,
+ sync: false,
+ }
+ }
+
+ #[test]
+ fn guest_mem_file_backed_mappings_overlap() {
+ // Base case: no file mappings; output layout should be identical.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[]
+ ),
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ]
+ );
+
+ // File mapping that does not overlap guest memory.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0xD000_0000, 0x1000)]
+ ),
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ]
+ );
+
+ // File mapping at the start of the low address space region.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0, 0x2000)]
+ ),
+ vec![
+ (GuestAddress(0x2000), 0xD000_0000 - 0x2000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ]
+ );
+
+ // File mapping at the end of the low address space region.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0xD000_0000 - 0x2000, 0x2000)]
+ ),
+ vec![
+ (GuestAddress(0), 0xD000_0000 - 0x2000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ]
+ );
+
+ // File mapping fully contained within the middle of the low address space region.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0x1000, 0x2000)]
+ ),
+ vec![
+ (GuestAddress(0), 0x1000),
+ (GuestAddress(0x3000), 0xD000_0000 - 0x3000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ]
+ );
+
+ // File mapping at the start of the high address space region.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0x1_0000_0000, 0x2000)]
+ ),
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_2000), 0x8_0000 - 0x2000),
+ ]
+ );
+
+ // File mapping at the end of the high address space region.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0x1_0008_0000 - 0x2000, 0x2000)]
+ ),
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000 - 0x2000),
+ ]
+ );
+
+ // File mapping fully contained within the middle of the high address space region.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0x1_0000_1000, 0x2000)]
+ ),
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x1000),
+ (GuestAddress(0x1_0000_3000), 0x8_0000 - 0x3000),
+ ]
+ );
+
+ // File mapping overlapping two guest memory regions.
+ assert_eq!(
+ punch_holes_in_guest_mem_layout_for_mappings(
+ vec![
+ (GuestAddress(0), 0xD000_0000),
+ (GuestAddress(0x1_0000_0000), 0x8_0000),
+ ],
+ &[test_file_backed_mapping(0xA000_0000, 0x60002000)]
+ ),
+ vec![
+ (GuestAddress(0), 0xA000_0000),
+ (GuestAddress(0x1_0000_2000), 0x8_0000 - 0x2000),
+ ]
+ );
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 30a7bba..edab4b2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2583,7 +2583,7 @@
See --disk for valid options."),
Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."),
Argument::value("pmem-device", "PATH", "Path to a disk image."),
- Argument::value("pstore", "path=PATH,size=SIZE", "Path to pstore buffer backend file follewed by size."),
+ Argument::value("pstore", "path=PATH,size=SIZE", "Path to pstore buffer backend file followed by size."),
Argument::value("host_ip",
"IP",
"IP address to assign to host tap interface."),
@@ -2881,6 +2881,36 @@
vms_request(&VmRequest::Resume, socket_path)
}
+fn powerbtn_vms(mut args: std::env::Args) -> std::result::Result<(), ()> {
+ if args.len() == 0 {
+ print_help("crosvm powerbtn", "VM_SOCKET...", &[]);
+ println!("Triggers a power button event in the crosvm instance listening on each `VM_SOCKET` given.");
+ return Err(());
+ }
+ let socket_path = &args.next().unwrap();
+ let socket_path = Path::new(&socket_path);
+ vms_request(&VmRequest::Powerbtn, socket_path)
+}
+
+fn inject_gpe(mut args: std::env::Args) -> std::result::Result<(), ()> {
+ if args.len() < 2 {
+ print_help("crosvm gpe", "GPE# VM_SOCKET...", &[]);
+ println!("Injects a general-purpose event (GPE#) into the crosvm instance listening on each `VM_SOCKET` given.");
+ return Err(());
+ }
+ let gpe = match args.next().unwrap().parse::<u32>() {
+ Ok(n) => n,
+ Err(_) => {
+ error!("Failed to parse GPE#");
+ return Err(());
+ }
+ };
+
+ let socket_path = &args.next().unwrap();
+ let socket_path = Path::new(&socket_path);
+ vms_request(&VmRequest::Gpe(gpe), socket_path)
+}
+
fn balloon_vms(mut args: std::env::Args) -> std::result::Result<(), ()> {
if args.len() < 2 {
print_help("crosvm balloon", "SIZE VM_SOCKET...", &[]);
@@ -3393,6 +3423,8 @@
println!(" run - Start a new crosvm instance.");
println!(" stop - Stops crosvm instances via their control sockets.");
println!(" suspend - Suspends the crosvm instance.");
+ println!(" powerbtn - Triggers a power button event in the crosvm instance.");
+ println!(" gpe - Injects a general-purpose event into the crosvm instance.");
println!(" usb - Manage attached virtual USB devices.");
println!(" version - Show package version.");
println!(" vfio - add/remove host vfio pci device into guest.");
@@ -3448,6 +3480,8 @@
"resume" => resume_vms(args),
"stop" => stop_vms(args),
"suspend" => suspend_vms(args),
+ "powerbtn" => powerbtn_vms(args),
+ "gpe" => inject_gpe(args),
"usb" => modify_usb(args),
"version" => pkg_version(),
"vfio" => modify_vfio(args),
diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs
index 9d135b9..ef5eea5 100644
--- a/src/plugin/vcpu.rs
+++ b/src/plugin/vcpu.rs
@@ -725,8 +725,10 @@
{
Err(SysError::new(EINVAL))
} else {
- let mut cap: kvm_enable_cap = Default::default();
- cap.cap = capability;
+ let cap = kvm_enable_cap {
+ cap: capability,
+ ..Default::default()
+ };
// Safe because the allowed capabilities don't take pointer arguments.
unsafe { vcpu.kvm_enable_cap(&cap) }
}
diff --git a/system_api_stub/Cargo.toml b/system_api_stub/Cargo.toml
index d5a8ec1..764a68c 100644
--- a/system_api_stub/Cargo.toml
+++ b/system_api_stub/Cargo.toml
@@ -2,7 +2,7 @@
name = "system_api"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[lib]
path = "src/system_api.rs"
diff --git a/tests/plugins.rs b/tests/plugins.rs
index 8992045..1cbb2fd 100644
--- a/tests/plugins.rs
+++ b/tests/plugins.rs
@@ -62,11 +62,11 @@
.arg(&out_bin)
.arg("-L") // Path of shared object to link to.
.arg(&libcrosvm_plugin_dir)
- .arg("-lcrosvm_plugin")
.arg("-Wl,-rpath") // Search for shared object in the same path when exec'd.
.arg(&libcrosvm_plugin_dir)
.args(&["-Wl,-rpath", "."]) // Also check current directory in case of sandboxing.
.args(&["-xc", "-"]) // Read source code from piped stdin.
+ .arg("-lcrosvm_plugin")
.stdin(Stdio::piped())
.spawn()
.expect("failed to spawn compiler");
@@ -262,6 +262,8 @@
test_plugin(include_str!("plugin_supported_cpuid.c"));
}
+// b:223675792
+#[ignore]
#[test]
fn test_enable_cap() {
test_plugin(include_str!("plugin_enable_cap.c"));
diff --git a/third_party/vmm_vhost/Cargo.toml b/third_party/vmm_vhost/Cargo.toml
index 4bb822a..9f29a38 100644
--- a/third_party/vmm_vhost/Cargo.toml
+++ b/third_party/vmm_vhost/Cargo.toml
@@ -8,7 +8,7 @@
documentation = "https://docs.rs/vhost"
readme = "README.md"
license = "Apache-2.0 or BSD-3-Clause"
-edition = "2018"
+edition = "2021"
[features]
default = []
diff --git a/tools/dev_container b/tools/dev_container
index 0128508..67a9cfe 100755
--- a/tools/dev_container
+++ b/tools/dev_container
@@ -55,6 +55,8 @@
"--device /dev/vhost-vsock",
# Use tmpfs in the container for faster performance.
"--mount type=tmpfs,destination=/tmp",
+ # For plugin process jail
+ "--mount type=tmpfs,destination=/var/empty",
f"gcr.io/crosvm-packages/crosvm_dev:{IMAGE_VERSION}",
]
diff --git a/tools/impl/test_config.py b/tools/impl/test_config.py
index b2d5229..acaba07 100755
--- a/tools/impl/test_config.py
+++ b/tools/impl/test_config.py
@@ -41,6 +41,7 @@
CRATE_OPTIONS: dict[str, list[TestOption]] = {
"cros_async": [TestOption.LARGE],
"crosvm_plugin": [TestOption.DO_NOT_BUILD_AARCH64, TestOption.DO_NOT_BUILD_ARMHF],
+ "crosvm": [TestOption.SINGLE_THREADED],
"devices": [
TestOption.SINGLE_THREADED,
TestOption.LARGE,
@@ -75,16 +76,15 @@
}
BUILD_FEATURES: dict[str, str] = {
- "x86_64": "all-linux",
- "aarch64": "all-linux",
- "armhf": "all-linux-armhf",
+ "x86_64": "linux-x86_64",
+ "aarch64": "linux-aarch64",
+ "armhf": "linux-armhf",
}
elif os.name == "nt":
CRATE_OPTIONS: dict[str, list[TestOption]] = {
"aarch64": [TestOption.DO_NOT_BUILD],
"acpi_tables": [TestOption.DO_NOT_BUILD],
"arch": [TestOption.DO_NOT_BUILD],
- "assertions": [TestOption.DO_NOT_BUILD],
"audio_streams": [TestOption.DO_NOT_BUILD],
"balloon_control": [],
"base": [TestOption.DO_NOT_BUILD],
@@ -97,7 +97,6 @@
"crosvm_plugin": [TestOption.DO_NOT_BUILD],
"crosvm-fuzz": [TestOption.DO_NOT_BUILD],
"crosvm": [TestOption.DO_NOT_BUILD],
- "data_model": [TestOption.DO_NOT_BUILD],
"devices": [TestOption.DO_NOT_BUILD],
"disk": [TestOption.DO_NOT_BUILD],
"ffi": [TestOption.DO_NOT_BUILD],
diff --git a/tpm2-sys/Cargo.toml b/tpm2-sys/Cargo.toml
index 89dd491..59cfe2c 100644
--- a/tpm2-sys/Cargo.toml
+++ b/tpm2-sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "tpm2-sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
links = "tpm2"
[build-dependencies]
diff --git a/tpm2/Cargo.toml b/tpm2/Cargo.toml
index 56ee5fb..705be84 100644
--- a/tpm2/Cargo.toml
+++ b/tpm2/Cargo.toml
@@ -2,7 +2,7 @@
name = "tpm2"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
tpm2-sys = { path = "../tpm2-sys" }
diff --git a/usb_sys/Cargo.toml b/usb_sys/Cargo.toml
index 74f7b92..e74193a 100644
--- a/usb_sys/Cargo.toml
+++ b/usb_sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "usb_sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
base = { path = "../common/base" }
diff --git a/usb_util/Cargo.toml b/usb_util/Cargo.toml
index a52b7dc..f161565 100644
--- a/usb_util/Cargo.toml
+++ b/usb_util/Cargo.toml
@@ -2,7 +2,7 @@
name = "usb_util"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
assertions = { path = "../common/assertions" }
diff --git a/vfio_sys/Cargo.toml b/vfio_sys/Cargo.toml
index 856703e..782f1b2 100644
--- a/vfio_sys/Cargo.toml
+++ b/vfio_sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "vfio_sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
base = { path = "../common/base" }
diff --git a/vhost/Cargo.toml b/vhost/Cargo.toml
index 2f7adea..09403e4 100644
--- a/vhost/Cargo.toml
+++ b/vhost/Cargo.toml
@@ -2,7 +2,7 @@
name = "vhost"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
assertions = { path = "../common/assertions" }
diff --git a/virtio_sys/Cargo.toml b/virtio_sys/Cargo.toml
index b90929b..61460a0 100644
--- a/virtio_sys/Cargo.toml
+++ b/virtio_sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "virtio_sys"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[dependencies]
base = { path = "../common/base" }
diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml
index 12fdbbf..9f8b286 100644
--- a/vm_control/Cargo.toml
+++ b/vm_control/Cargo.toml
@@ -2,7 +2,7 @@
name = "vm_control"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
gdb = ["gdbstub_arch"]
diff --git a/vm_control/src/client.rs b/vm_control/src/client.rs
index 51c8661..863b843 100644
--- a/vm_control/src/client.rs
+++ b/vm_control/src/client.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::*;
-use base::{info, net::UnixSeqpacket, validate_raw_descriptor, RawDescriptor, Tube};
+use base::{info, validate_raw_descriptor, RawDescriptor, Tube, UnixSeqpacket};
use remain::sorted;
use thiserror::Error;
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 86b9493..4a21a0b 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -107,6 +107,11 @@
}
}
+pub trait PmResource {
+ fn pwrbtn_evt(&mut self) {}
+ fn gpe_evt(&mut self, _gpe: u32) {}
+}
+
/// The maximum number of devices that can be listed in one `UsbControlCommand`.
///
/// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not
@@ -879,10 +884,14 @@
pub enum VmRequest {
/// Break the VM's run loop and exit.
Exit,
+ /// Trigger a power button event in the guest.
+ Powerbtn,
/// Suspend the VM's VCPUs until resume.
Suspend,
/// Resume the VM's VCPUs that were previously suspended.
Resume,
+ /// Inject a general-purpose event.
+ Gpe(u32),
/// Make the VM's RT VCPU real-time.
MakeRT,
/// Command for balloon driver.
@@ -963,6 +972,7 @@
balloon_host_tube: Option<&Tube>,
balloon_stats_id: &mut u64,
disk_host_tubes: &[Tube],
+ pm: &mut Option<Arc<Mutex<dyn PmResource>>>,
usb_control_tube: Option<&Tube>,
bat_control: &mut Option<BatControl>,
vcpu_handles: &[(JoinHandle<()>, mpsc::Sender<VcpuControl>)],
@@ -972,6 +982,15 @@
*run_mode = Some(VmRunMode::Exiting);
VmResponse::Ok
}
+ VmRequest::Powerbtn => {
+ if pm.is_some() {
+ pm.as_ref().unwrap().lock().pwrbtn_evt();
+ VmResponse::Ok
+ } else {
+ error!("{:#?} not supported", *self);
+ VmResponse::Err(SysError::new(ENOTSUP))
+ }
+ }
VmRequest::Suspend => {
*run_mode = Some(VmRunMode::Suspending);
VmResponse::Ok
@@ -980,6 +999,15 @@
*run_mode = Some(VmRunMode::Running);
VmResponse::Ok
}
+ VmRequest::Gpe(gpe) => {
+ if pm.is_some() {
+ pm.as_ref().unwrap().lock().gpe_evt(gpe);
+ VmResponse::Ok
+ } else {
+ error!("{:#?} not supported", *self);
+ VmResponse::Err(SysError::new(ENOTSUP))
+ }
+ }
VmRequest::MakeRT => {
for (handle, channel) in vcpu_handles {
if let Err(e) = channel.send(VcpuControl::MakeRT) {
diff --git a/vm_memory/Cargo.toml b/vm_memory/Cargo.toml
index d79df95..f9fc9d2 100644
--- a/vm_memory/Cargo.toml
+++ b/vm_memory/Cargo.toml
@@ -2,7 +2,7 @@
name = "vm_memory"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
include = ["src/**/*", "Cargo.toml"]
[dependencies]
diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml
index 2e8ecd2..2d17645 100644
--- a/x86_64/Cargo.toml
+++ b/x86_64/Cargo.toml
@@ -2,7 +2,7 @@
name = "x86_64"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
-edition = "2018"
+edition = "2021"
[features]
gdb = ["gdbstub_arch", "arch/gdb"]
diff --git a/x86_64/src/acpi.rs b/x86_64/src/acpi.rs
index 613646c..2a52621 100644
--- a/x86_64/src/acpi.rs
+++ b/x86_64/src/acpi.rs
@@ -7,14 +7,17 @@
use acpi_tables::{facs::FACS, rsdp::RSDP, sdt::SDT};
use arch::VcpuAffinity;
-use base::error;
+use base::{error, warn};
use data_model::DataInit;
-use devices::{PciAddress, PciInterruptPin};
+use devices::{ACPIPMResource, PciAddress, PciInterruptPin};
+use std::sync::Arc;
+use sync::Mutex;
use vm_memory::{GuestAddress, GuestMemory};
pub struct AcpiDevResource {
pub amls: Vec<u8>,
pub pm_iobase: u64,
+ pub pm: Arc<Mutex<ACPIPMResource>>,
/// Additional system descriptor tables.
pub sdts: Vec<SDT>,
}
@@ -105,18 +108,34 @@
// FADT fields offset
const FADT_FIELD_FACS_ADDR32: usize = 36;
const FADT_FIELD_DSDT_ADDR32: usize = 40;
-const FADT_FIELD_SCI_INTERRUPT: usize = 46;
+pub const FADT_FIELD_SCI_INTERRUPT: usize = 46;
const FADT_FIELD_SMI_COMMAND: usize = 48;
const FADT_FIELD_PM1A_EVENT_BLK_ADDR: usize = 56;
+const FADT_FIELD_PM1B_EVENT_BLK_ADDR: usize = 60;
const FADT_FIELD_PM1A_CONTROL_BLK_ADDR: usize = 64;
+const FADT_FIELD_PM1B_CONTROL_BLK_ADDR: usize = 68;
+const FADT_FIELD_PM2_CONTROL_BLK_ADDR: usize = 72;
+const FADT_FIELD_GPE0_BLK_ADDR: usize = 80;
+const FADT_FIELD_GPE1_BLK_ADDR: usize = 84;
const FADT_FIELD_PM1A_EVENT_BLK_LEN: usize = 88;
const FADT_FIELD_PM1A_CONTROL_BLK_LEN: usize = 89;
+const FADT_FIELD_PM2_CONTROL_BLK_LEN: usize = 90;
+const FADT_FIELD_GPE0_BLK_LEN: usize = 92;
+const FADT_FIELD_GPE1_BLK_LEN: usize = 93;
+const FADT_FIELD_GPE1_BASE: usize = 94;
const FADT_FIELD_FLAGS: usize = 112;
const FADT_FIELD_RESET_REGISTER: usize = 116;
const FADT_FIELD_RESET_VALUE: usize = 128;
const FADT_FIELD_MINOR_REVISION: usize = 131;
const FADT_FIELD_FACS_ADDR: usize = 132;
const FADT_FIELD_DSDT_ADDR: usize = 140;
+const FADT_FIELD_X_PM1A_EVENT_BLK_ADDR: usize = 148;
+const FADT_FIELD_X_PM1B_EVENT_BLK_ADDR: usize = 160;
+const FADT_FIELD_X_PM1A_CONTROL_BLK_ADDR: usize = 172;
+const FADT_FIELD_X_PM1B_CONTROL_BLK_ADDR: usize = 184;
+const FADT_FIELD_X_PM2_CONTROL_BLK_ADDR: usize = 196;
+const FADT_FIELD_X_GPE0_BLK_ADDR: usize = 220;
+const FADT_FIELD_X_GPE1_BLK_ADDR: usize = 232;
const FADT_FIELD_HYPERVISOR_ID: usize = 268;
// MADT
const MADT_LEN: u32 = 44;
@@ -152,7 +171,7 @@
const MCFG_FIELD_START_BUS_NUMBER: usize = 54;
const MCFG_FIELD_END_BUS_NUMBER: usize = 55;
-fn create_dsdt_table(amls: Vec<u8>) -> SDT {
+fn create_dsdt_table(amls: &[u8]) -> SDT {
let mut dsdt = SDT::new(
*b"DSDT",
acpi_tables::HEADER_LEN,
@@ -163,19 +182,13 @@
);
if !amls.is_empty() {
- dsdt.append_slice(amls.as_slice());
+ dsdt.append_slice(amls);
}
dsdt
}
-fn create_facp_table(
- sci_irq: u16,
- pm_iobase: u32,
- reset_port: u32,
- reset_value: u8,
- force_s2idle: bool,
-) -> SDT {
+fn create_facp_table(sci_irq: u16, force_s2idle: bool) -> SDT {
let mut facp = SDT::new(
*b"FACP",
FADT_LEN,
@@ -185,8 +198,7 @@
OEM_REVISION,
);
- let mut fadt_flags: u32 = FADT_POWER_BUTTON | FADT_SLEEP_BUTTON | // mask POWER and SLEEP BUTTON
- FADT_RESET_REGISTER; // indicate we support FADT RESET_REG
+ let mut fadt_flags: u32 = FADT_SLEEP_BUTTON; // mask SLEEP BUTTON
if force_s2idle {
fadt_flags |= FADT_LOW_POWER_S2IDLE;
@@ -197,28 +209,142 @@
// SCI Interrupt
facp.write(FADT_FIELD_SCI_INTERRUPT, sci_irq);
+ facp.write(FADT_FIELD_MINOR_REVISION, FADT_MINOR_REVISION); // FADT minor version
+ facp.write(FADT_FIELD_HYPERVISOR_ID, *b"CROSVM"); // Hypervisor Vendor Identity
+
+ facp
+}
+
+// Write virtualized FADT fields
+fn write_facp_overrides(
+ facp: &mut SDT,
+ facs_offset: GuestAddress,
+ dsdt_offset: GuestAddress,
+ pm_iobase: u32,
+ reset_port: u32,
+ reset_value: u8,
+) {
+ let fadt_flags: u32 = facp.read(FADT_FIELD_FLAGS);
+ // indicate we support FADT RESET_REG
+ facp.write(FADT_FIELD_FLAGS, fadt_flags | FADT_RESET_REGISTER);
+
+ facp.write(FADT_FIELD_SMI_COMMAND, 0u32);
+ facp.write(FADT_FIELD_FACS_ADDR32, 0u32);
+ facp.write(FADT_FIELD_DSDT_ADDR32, 0u32);
+ facp.write(FADT_FIELD_FACS_ADDR, facs_offset.0 as u64);
+ facp.write(FADT_FIELD_DSDT_ADDR, dsdt_offset.0 as u64);
+
// PM1A Event Block Address
facp.write(FADT_FIELD_PM1A_EVENT_BLK_ADDR, pm_iobase);
+ // PM1B Event Block Address (not supported)
+ facp.write(FADT_FIELD_PM1B_EVENT_BLK_ADDR, 0u32);
+
// PM1A Control Block Address
facp.write(
FADT_FIELD_PM1A_CONTROL_BLK_ADDR,
pm_iobase + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32,
);
+ // PM1B Control Block Address (not supported)
+ facp.write(FADT_FIELD_PM1B_CONTROL_BLK_ADDR, 0u32);
+
+ // PM2 Control Block Address (not supported)
+ facp.write(FADT_FIELD_PM2_CONTROL_BLK_ADDR, 0u32);
+
+ // GPE0 Block Address
+ facp.write(
+ FADT_FIELD_GPE0_BLK_ADDR,
+ pm_iobase + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32 + 4,
+ );
+
+ // GPE1 Block Address (not supported)
+ facp.write(FADT_FIELD_GPE1_BLK_ADDR, 0u32);
+
// PM1 Event Block Length
facp.write(
FADT_FIELD_PM1A_EVENT_BLK_LEN,
- devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u8,
+ devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN,
);
// PM1 Control Block Length
facp.write(
FADT_FIELD_PM1A_CONTROL_BLK_LEN,
- devices::acpi::ACPIPM_RESOURCE_CONTROLBLK_LEN as u8,
+ devices::acpi::ACPIPM_RESOURCE_CONTROLBLK_LEN,
);
- // Reset register.
+ // PM2 Control Block Length (not supported)
+ facp.write(FADT_FIELD_PM2_CONTROL_BLK_LEN, 0u8);
+
+ // GPE0 Block Length
+ facp.write(
+ FADT_FIELD_GPE0_BLK_LEN,
+ devices::acpi::ACPIPM_RESOURCE_GPE0_BLK_LEN,
+ );
+
+ // GPE1 Block Length (not supported)
+ facp.write(FADT_FIELD_GPE1_BLK_LEN, 0u8);
+
+ // GPE1 Base (not supported)
+ facp.write(FADT_FIELD_GPE1_BASE, 0u8);
+
+ // PM1A Extended Event Block Address (not supported)
+ facp.write(
+ FADT_FIELD_X_PM1A_EVENT_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // PM1B Extended Event Block Address (not supported)
+ facp.write(
+ FADT_FIELD_X_PM1B_EVENT_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // PM1A Extended Control Block Address (not supported)
+ facp.write(
+ FADT_FIELD_X_PM1A_CONTROL_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // PM1B Extended Control Block Address (not supported)
+ facp.write(
+ FADT_FIELD_X_PM1B_CONTROL_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // PM2 Extended Control Block Address (not supported)
+ facp.write(
+ FADT_FIELD_X_PM2_CONTROL_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // GPE0 Extended Address (not supported)
+ facp.write(
+ FADT_FIELD_X_GPE0_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // GPE1 Extended Address (not supported)
+ facp.write(
+ FADT_FIELD_X_GPE1_BLK_ADDR,
+ GenericAddress {
+ ..Default::default()
+ },
+ );
+
+ // Reset register
facp.write(
FADT_FIELD_RESET_REGISTER,
GenericAddress {
@@ -230,11 +356,6 @@
},
);
facp.write(FADT_FIELD_RESET_VALUE, reset_value);
-
- facp.write(FADT_FIELD_MINOR_REVISION, FADT_MINOR_REVISION); // FADT minor version
- facp.write(FADT_FIELD_HYPERVISOR_ID, *b"CROSVM"); // Hypervisor Vendor Identity
-
- facp
}
fn next_offset(offset: GuestAddress, len: u64) -> Option<GuestAddress> {
@@ -363,7 +484,7 @@
sci_irq: u32,
reset_port: u32,
reset_value: u8,
- acpi_dev_resource: AcpiDevResource,
+ acpi_dev_resource: &AcpiDevResource,
host_cpus: Option<VcpuAffinity>,
apic_ids: &mut Vec<usize>,
pci_irqs: &[(PciAddress, u32, PciInterruptPin)],
@@ -408,7 +529,7 @@
Some(dsdt_offset) => dsdt_offset,
None => {
let dsdt_offset = offset;
- let dsdt = create_dsdt_table(acpi_dev_resource.amls);
+ let dsdt = create_dsdt_table(&acpi_dev_resource.amls);
guest_mem.write_at_addr(dsdt.as_slice(), offset).ok()?;
offset = next_offset(offset, dsdt.len() as u64)?;
dsdt_offset
@@ -416,23 +537,28 @@
};
// FACP aka FADT
- let pm_iobase = acpi_dev_resource.pm_iobase as u32;
- let mut facp = facp.unwrap_or_else(|| {
- create_facp_table(
- sci_irq as u16,
- pm_iobase,
- reset_port,
- reset_value,
- force_s2idle,
- )
- });
+ let mut facp = facp.map_or_else(
+ || create_facp_table(sci_irq as u16, force_s2idle),
+ |facp| {
+ let fadt_flags: u32 = facp.read(FADT_FIELD_FLAGS);
+ if fadt_flags & FADT_POWER_BUTTON != 0 {
+ warn!(
+ "Control Method Power Button is not supported. FADT flags = 0x{:x}",
+ fadt_flags
+ );
+ }
+ facp
+ },
+ );
- // Crosvm FACP overrides.
- facp.write(FADT_FIELD_SMI_COMMAND, 0u32);
- facp.write(FADT_FIELD_FACS_ADDR32, 0u32);
- facp.write(FADT_FIELD_DSDT_ADDR32, 0u32);
- facp.write(FADT_FIELD_FACS_ADDR, facs_offset.0 as u64);
- facp.write(FADT_FIELD_DSDT_ADDR, dsdt_offset.0 as u64);
+ write_facp_overrides(
+ &mut facp,
+ facs_offset,
+ dsdt_offset,
+ acpi_dev_resource.pm_iobase as u32,
+ reset_port,
+ reset_value,
+ );
guest_mem.write_at_addr(facp.as_slice(), offset).ok()?;
tables.push(offset.0);
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index 3aa7f0e..20a9916 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -56,7 +56,7 @@
use acpi_tables::sdt::SDT;
use acpi_tables::{aml, aml::Aml};
use arch::{get_serial_cmdline, GetSerialCmdlineError, RunnableLinuxVm, VmComponents, VmImage};
-use base::Event;
+use base::{warn, Event};
use devices::serial_device::{SerialHardware, SerialParameters};
use devices::{
BusDeviceObj, BusResumeDevice, IrqChip, IrqChipX86_64, PciAddress, PciConfigIo, PciConfigMmio,
@@ -453,6 +453,24 @@
let tss_addr = GuestAddress(TSS_ADDR);
vm.set_tss_addr(tss_addr).map_err(Error::SetTssAddr)?;
+ // Use IRQ info in ACPI if provided by the user.
+ let mut noirq = true;
+ let mut mptable = true;
+ let mut sci_irq = X86_64_SCI_IRQ;
+
+ for sdt in components.acpi_sdts.iter() {
+ if sdt.is_signature(b"DSDT") || sdt.is_signature(b"APIC") {
+ noirq = false;
+ } else if sdt.is_signature(b"FACP") {
+ mptable = false;
+ let sci_irq_fadt: u16 = sdt.read(acpi::FADT_FIELD_SCI_INTERRUPT);
+ sci_irq = sci_irq_fadt.into();
+ if !system_allocator.reserve_irq(sci_irq) {
+ warn!("sci irq {} already reserved.", sci_irq);
+ }
+ }
+ }
+
let mmio_bus = Arc::new(devices::Bus::new());
let io_bus = Arc::new(devices::Bus::new());
@@ -532,18 +550,13 @@
exit_evt.try_clone().map_err(Error::CloneEvent)?,
components.acpi_sdts,
irq_chip.as_irq_chip_mut(),
+ sci_irq,
battery,
&mmio_bus,
max_bus,
&mut resume_notify_devices,
)?;
- // Use IRQ info in ACPI if provided by the user.
- let noirq = !acpi_dev_resource
- .sdts
- .iter()
- .any(|sdt| sdt.is_signature(b"DSDT") || sdt.is_signature(b"APIC"));
-
irq_chip
.finalize_devices(system_allocator, &io_bus, &mmio_bus)
.map_err(Error::RegisterIrqfd)?;
@@ -556,8 +569,11 @@
// If another guest does need a way to pass these tables down to it's BIOS, this approach
// should be rethought.
- // Note that this puts the mptable at 0x9FC00 in guest physical memory.
- mptable::setup_mptable(&mem, vcpu_count as u8, &pci_irqs).map_err(Error::SetupMptable)?;
+ if mptable {
+ // Note that this puts the mptable at 0x9FC00 in guest physical memory.
+ mptable::setup_mptable(&mem, vcpu_count as u8, &pci_irqs)
+ .map_err(Error::SetupMptable)?;
+ }
smbios::setup_smbios(&mem, components.dmi_path).map_err(Error::SetupSmbios)?;
let host_cpus = if components.host_cpu_topology {
@@ -570,10 +586,10 @@
acpi::create_acpi_tables(
&mem,
vcpu_count as u8,
- X86_64_SCI_IRQ,
+ sci_irq,
0xcf9,
6, // RST_CPU|SYS_RST
- acpi_dev_resource,
+ &acpi_dev_resource,
host_cpus,
kvm_vcpu_ids,
&pci_irqs,
@@ -646,6 +662,7 @@
bat_control,
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
gdb: components.gdb,
+ pm: Some(acpi_dev_resource.pm),
root_config: pci,
hotplug_bus: Vec::new(),
})
@@ -1266,6 +1283,7 @@
exit_evt: Event,
sdts: Vec<SDT>,
irq_chip: &mut dyn IrqChip,
+ sci_irq: u32,
battery: (&Option<BatteryType>, Option<Minijail>),
mmio_bus: &devices::Bus,
max_bus: u8,
@@ -1281,17 +1299,21 @@
devices::acpi::ACPIPM_RESOURCE_LEN as u64,
pm_alloc,
"ACPIPM".to_string(),
- devices::acpi::ACPIPM_RESOURCE_LEN as u64,
+ 4, // must be 32-bit aligned
)
.map_err(Error::AllocateIOResouce)?,
None => 0x600,
};
let pcie_vcfg = aml::Name::new("VCFG".into(), &Self::get_pcie_vcfg_mmio_base(mem));
- Aml::to_aml_bytes(&pcie_vcfg, &mut amls);
+ pcie_vcfg.to_aml_bytes(&mut amls);
- let pmresource = devices::ACPIPMResource::new(suspend_evt, exit_evt);
- Aml::to_aml_bytes(&pmresource, &mut amls);
+ let pm_sci_evt = Event::new().map_err(Error::CreateEvent)?;
+ irq_chip
+ .register_irq_event(sci_irq, &pm_sci_evt, None)
+ .map_err(Error::RegisterIrqfd)?;
+ let pmresource = devices::ACPIPMResource::new(pm_sci_evt, suspend_evt, exit_evt);
+ pmresource.to_aml_bytes(&mut amls);
let mut pci_dsdt_inner_data: Vec<&dyn aml::Aml> = Vec::new();
let hid = aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A08"));
@@ -1340,18 +1362,13 @@
devices::acpi::ACPIPM_RESOURCE_LEN as u64,
)
.unwrap();
- resume_notify_devices.push(pm);
+ resume_notify_devices.push(pm.clone());
let bat_control = if let Some(battery_type) = battery.0 {
match battery_type {
BatteryType::Goldfish => {
let control_tube = arch::add_goldfish_battery(
- &mut amls,
- battery.1,
- mmio_bus,
- irq_chip,
- X86_64_SCI_IRQ,
- resources,
+ &mut amls, battery.1, mmio_bus, irq_chip, sci_irq, resources,
)
.map_err(Error::CreateBatDevices)?;
Some(BatControl {
@@ -1368,6 +1385,7 @@
acpi::AcpiDevResource {
amls,
pm_iobase,
+ pm,
sdts,
},
bat_control,
diff --git a/x86_64/src/test_integration.rs b/x86_64/src/test_integration.rs
index b19f92d..90eec51 100644
--- a/x86_64/src/test_integration.rs
+++ b/x86_64/src/test_integration.rs
@@ -193,6 +193,7 @@
exit_evt.try_clone().expect("unable to clone exit_evt"),
Default::default(),
&mut irq_chip,
+ X86_64_SCI_IRQ,
(&None, None),
&mmio_bus,
max_bus,
@@ -221,7 +222,7 @@
X86_64_SCI_IRQ,
0xcf9,
6,
- acpi_dev_resource.0,
+ &acpi_dev_resource.0,
None,
&mut apic_ids,
&pci_irqs,