Snap for 8458224 from d4ae2f4185ff51482812702abe8fb5ba61c3d7d7 to tm-qpr1-release
Change-Id: Ib7dc26f4cf395c8feeacb1d252887342d38e9591
diff --git a/.cargo/config.toml b/.cargo/config.toml
index 0261860..98133d5 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -42,3 +42,6 @@
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
+
+[target.x86_64-pc-windows-gnu]
+runner = "wine64"
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index bae315f..d8c7505 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -208,7 +208,8 @@
- `kernel_loader` - Loads elf64 kernel files to a slice of memory.
- `kvm_sys` - Low-level (mostly) auto-generated structures and constants for using KVM.
- `kvm` - Unsafe, low-level wrapper code for using `kvm_sys`.
-- `libvda` - Safe wrapper of [libvda], a Chrome OS HW-accelerated video decoding/encoding library.
+- `media/libvda` - Safe wrapper of [libvda], a Chrome OS HW-accelerated video decoding/encoding
+ library.
- `net_sys` - Low-level (mostly) auto-generated structures and constants for creating TUN/TAP
devices.
- `net_util` - Wrapper for creating TUN/TAP devices.
diff --git a/Android.bp b/Android.bp
index 3be0b8e..6e0097f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -53,6 +53,7 @@
"libaudio_streams",
"libbase_rust",
"libbit_field",
+ "libcfg_if",
"libcrosvm",
"libdata_model",
"libdevices",
@@ -152,12 +153,14 @@
"libaudio_streams",
"libbase_rust",
"libbit_field",
+ "libcfg_if",
"libdata_model",
"libdevices",
"libdisk",
"libhypervisor",
"libkernel_cmdline",
"libkernel_loader",
+ "liblazy_static",
"liblibc",
"liblibcras",
"libminijail_rust",
@@ -238,6 +241,7 @@
"libaudio_streams",
"libbase_rust",
"libbit_field",
+ "libcfg_if",
"libcrosvm",
"libdata_model",
"libdevices",
@@ -245,6 +249,7 @@
"libhypervisor",
"libkernel_cmdline",
"libkernel_loader",
+ "liblazy_static",
"liblibc",
"liblibcras",
"libminijail_rust",
@@ -320,6 +325,7 @@
"libaudio_streams",
"libbase_rust",
"libbit_field",
+ "libcfg_if",
"libdata_model",
"libdevices",
"libdisk",
diff --git a/Cargo.toml b/Cargo.toml
index faedaf1..3a3742b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -67,8 +67,8 @@
"kvm",
"kvm_sys",
"libcras_stub",
- "libvda",
"linux_input_sys",
+ "media/libvda",
"net_sys",
"net_util",
"power_monitor",
@@ -118,6 +118,7 @@
"virgl_renderer",
"x",
]
+win64 = []
audio = ["devices/audio"]
audio_cras = ["devices/audio_cras"]
chromeos = ["base/chromeos", "audio_cras", "devices/chromeos"]
@@ -138,7 +139,9 @@
linux-x86_64 = ["all-linux", "plugin"]
linux-aarch64 = ["all-linux"]
plugin = ["protos/plugin", "crosvm_plugin", "kvm", "kvm_sys", "protobuf"]
+plugin-render-server = []
power-monitor-powerd = ["arch/power-monitor-powerd"]
+slirp = ["devices/slirp"]
tpm = ["devices/tpm"]
usb = ["devices/usb"]
video-decoder = ["devices/video-decoder"]
@@ -155,6 +158,7 @@
audio_streams = "*"
base = { path = "base" }
bit_field = { path = "bit_field" }
+cfg-if = "1.0.0"
crosvm_plugin = { path = "crosvm_plugin", optional = true }
data_model = "*"
devices = { path = "devices" }
@@ -197,6 +201,7 @@
[dev-dependencies]
base = { path = "base" }
+lazy_static = "*"
[patch.crates-io]
assertions = { path = "common/assertions" }
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs
index 09a81ff..1f3347f 100644
--- a/aarch64/src/fdt.rs
+++ b/aarch64/src/fdt.rs
@@ -9,7 +9,7 @@
use arch::fdt::{Error, FdtWriter, Result};
use arch::SERIAL_ADDR;
use devices::{PciAddress, PciInterruptPin};
-use hypervisor::PsciVersion;
+use hypervisor::{PsciVersion, PSCI_0_2, PSCI_1_0};
use vm_memory::{GuestAddress, GuestMemory};
// This is the start of DRAM in the physical address space.
@@ -223,15 +223,29 @@
Ok(())
}
-fn create_psci_node(fdt: &mut FdtWriter, version: &PsciVersion) -> Result<()> {
- let mut compatible = vec![format!("arm,psci-{}.{}", version.major, version.minor)];
- if version.major == 1 {
- // Put `psci-0.2` as well because PSCI 1.0 is compatible with PSCI 0.2.
- compatible.push(format!("arm,psci-0.2"))
- };
+fn psci_compatible(version: &PsciVersion) -> Vec<&str> {
+ // The PSCI kernel driver only supports compatible strings for the following
+ // backward-compatible versions.
+ let supported = [(PSCI_1_0, "arm,psci-1.0"), (PSCI_0_2, "arm,psci-0.2")];
+ let mut compatible: Vec<_> = supported
+ .iter()
+ .filter(|&(v, _)| *version >= *v)
+ .map(|&(_, c)| c)
+ .collect();
+
+ // The PSCI kernel driver also supports PSCI v0.1, which is NOT forward-compatible.
+ if compatible.is_empty() {
+ compatible = vec!["arm,psci"];
+ }
+
+ compatible
+}
+
+fn create_psci_node(fdt: &mut FdtWriter, version: &PsciVersion) -> Result<()> {
+ let compatible = psci_compatible(version);
let psci_node = fdt.begin_node("psci")?;
- fdt.property_string_list("compatible", compatible)?;
+ fdt.property_string_list("compatible", &compatible)?;
// Only support aarch64 guest
fdt.property_string("method", "hvc")?;
fdt.end_node(psci_node)?;
@@ -500,3 +514,51 @@
}
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn psci_compatible_v0_1() {
+ assert_eq!(
+ psci_compatible(&PsciVersion::new(0, 1).unwrap()),
+ vec!["arm,psci"]
+ );
+ }
+
+ #[test]
+ fn psci_compatible_v0_2() {
+ assert_eq!(
+ psci_compatible(&PsciVersion::new(0, 2).unwrap()),
+ vec!["arm,psci-0.2"]
+ );
+ }
+
+ #[test]
+ fn psci_compatible_v0_5() {
+ // Only the 0.2 version supported by the kernel should be added.
+ assert_eq!(
+ psci_compatible(&PsciVersion::new(0, 5).unwrap()),
+ vec!["arm,psci-0.2"]
+ );
+ }
+
+ #[test]
+ fn psci_compatible_v1_0() {
+ // Both 1.0 and 0.2 should be listed, in that order.
+ assert_eq!(
+ psci_compatible(&PsciVersion::new(1, 0).unwrap()),
+ vec!["arm,psci-1.0", "arm,psci-0.2"]
+ );
+ }
+
+ #[test]
+ fn psci_compatible_v1_5() {
+ // Only the 1.0 and 0.2 versions supported by the kernel should be listed.
+ assert_eq!(
+ psci_compatible(&PsciVersion::new(1, 5).unwrap()),
+ vec!["arm,psci-1.0", "arm,psci-0.2"]
+ );
+ }
+}
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index 98bf5ba..0d9130f 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -377,23 +377,23 @@
Self::add_arch_devs(irq_chip.as_irq_chip_mut(), &mmio_bus)?;
- let com_evt_1_3 = Event::new().map_err(Error::CreateEvent)?;
- let com_evt_2_4 = Event::new().map_err(Error::CreateEvent)?;
+ let com_evt_1_3 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
+ let com_evt_2_4 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
arch::add_serial_devices(
components.protected_vm,
&mmio_bus,
- &com_evt_1_3,
- &com_evt_2_4,
+ &com_evt_1_3.get_trigger(),
+ &com_evt_2_4.get_trigger(),
serial_parameters,
serial_jail,
)
.map_err(Error::CreateSerialDevices)?;
irq_chip
- .register_irq_event(AARCH64_SERIAL_1_3_IRQ, &com_evt_1_3, None)
+ .register_edge_irq_event(AARCH64_SERIAL_1_3_IRQ, &com_evt_1_3)
.map_err(Error::RegisterIrqfd)?;
irq_chip
- .register_irq_event(AARCH64_SERIAL_2_4_IRQ, &com_evt_2_4, None)
+ .register_edge_irq_event(AARCH64_SERIAL_2_4_IRQ, &com_evt_2_4)
.map_err(Error::RegisterIrqfd)?;
mmio_bus
@@ -556,9 +556,9 @@
/// * `irq_chip` - The IRQ chip to add irqs to.
/// * `bus` - The bus to add devices to.
fn add_arch_devs(irq_chip: &mut dyn IrqChip, bus: &Bus) -> Result<()> {
- let rtc_evt = Event::new().map_err(Error::CreateEvent)?;
+ let rtc_evt = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
irq_chip
- .register_irq_event(AARCH64_RTC_IRQ, &rtc_evt, None)
+ .register_edge_irq_event(AARCH64_RTC_IRQ, &rtc_evt)
.map_err(Error::RegisterIrqfd)?;
let rtc = Arc::new(Mutex::new(devices::pl030::Pl030::new(rtc_evt)));
diff --git a/acpi_tables/src/aml.rs b/acpi_tables/src/aml.rs
index 7caa43a..6365d22 100644
--- a/acpi_tables/src/aml.rs
+++ b/acpi_tables/src/aml.rs
@@ -1636,13 +1636,13 @@
#[test]
fn test_pkg_length() {
- assert_eq!(create_pkg_length(&[0u8; 62].to_vec(), true), vec![63]);
+ assert_eq!(create_pkg_length(&[0u8; 62], true), vec![63]);
assert_eq!(
- create_pkg_length(&[0u8; 64].to_vec(), true),
+ create_pkg_length(&[0u8; 64], true),
vec![1 << 6 | (66 & 0xf), 66 >> 4]
);
assert_eq!(
- create_pkg_length(&[0u8; 4096].to_vec(), true),
+ create_pkg_length(&[0u8; 4096], true),
vec![
2 << 6 | (4099 & 0xf) as u8,
(4099 >> 4) as u8,
diff --git a/acpi_tables/src/sdt.rs b/acpi_tables/src/sdt.rs
index bda2630..e1f0f23 100644
--- a/acpi_tables/src/sdt.rs
+++ b/acpi_tables/src/sdt.rs
@@ -156,7 +156,7 @@
}
// Read it back and verify.
- let actual_sdt = SDT::from_file(&temp_file.path().to_path_buf())?;
+ let actual_sdt = SDT::from_file(temp_file.path())?;
assert!(actual_sdt.is_signature(b"TEST"));
assert_eq!(actual_sdt.as_slice(), expected_sdt.as_slice());
Ok(())
diff --git a/arch/src/fdt.rs b/arch/src/fdt.rs
index d060586..bbb2e43 100644
--- a/arch/src/fdt.rs
+++ b/arch/src/fdt.rs
@@ -259,9 +259,9 @@
}
/// Write a stringlist property.
- pub fn property_string_list(&mut self, name: &str, values: Vec<String>) -> Result<()> {
+ pub fn property_string_list(&mut self, name: &str, values: &[&str]) -> Result<()> {
let mut bytes = Vec::new();
- for s in values {
+ for &s in values {
let cstr = CString::new(s).map_err(|_| Error::InvalidString)?;
bytes.extend_from_slice(cstr.to_bytes_with_nul());
}
@@ -513,8 +513,7 @@
fdt.property_u32("u32", 0x12345678).unwrap();
fdt.property_u64("u64", 0x1234567887654321).unwrap();
fdt.property_string("str", "hello").unwrap();
- fdt.property_string_list("strlst", vec!["hi".into(), "bye".into()])
- .unwrap();
+ fdt.property_string_list("strlst", &["hi", "bye"]).unwrap();
fdt.property_array_u32("arru32", &[0x12345678, 0xAABBCCDD])
.unwrap();
fdt.property_array_u64("arru64", &[0x1234567887654321])
@@ -709,8 +708,8 @@
#[test]
fn invalid_prop_string_list_value_nul() {
let mut fdt = FdtWriter::new(&[]);
- let strs = vec!["test".into(), "abc\0def".into()];
- fdt.property_string_list("mystr", strs)
+ let strs = ["test", "abc\0def"];
+ fdt.property_string_list("mystr", &strs)
.expect_err("stringlist property value with embedded NUL");
}
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index a8561ad..a92d2d4 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -339,6 +339,9 @@
/// Failed to register irq event with VM.
#[error("failed to register irq event to VM: {0}")]
RegisterIrqfd(base::Error),
+ /// Could not setup VFIO platform IRQ for the device.
+ #[error("Setting up VFIO platform IRQ: {0}")]
+ SetupVfioPlatformIrq(anyhow::Error),
}
/// Config a PCI device for used by this vm.
@@ -364,16 +367,15 @@
.map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
// Do not suggest INTx for hot-plug devices.
- let intx_event = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
- let intx_resample = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
+ let intx_event = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
- if let Some((gsi, _pin)) = device.assign_irq(&intx_event, &intx_resample, None) {
+ if let Some((gsi, _pin)) = device.assign_irq(&intx_event, None) {
resources.reserve_irq(gsi);
linux
.irq_chip
.as_irq_chip_mut()
- .register_irq_event(gsi, &intx_event, Some(&intx_resample))
+ .register_level_irq_event(gsi, &intx_event)
.map_err(DeviceRegistrationError::RegisterIrqfd)?;
}
@@ -447,23 +449,31 @@
.get_platform_irqs()
.map_err(DeviceRegistrationError::AllocateIrqResource)?;
for irq in irqs.into_iter() {
- let irqfd = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
- keep_rds.push(irqfd.as_raw_descriptor());
- let irq_resample_fd = if device.irq_is_automask(&irq) {
- let evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
- keep_rds.push(evt.as_raw_descriptor());
- Some(evt)
- } else {
- None
- };
-
let irq_num = resources
.allocate_irq()
.ok_or(DeviceRegistrationError::AllocateIrq)?;
- irq_chip
- .register_irq_event(irq_num, &irqfd, irq_resample_fd.as_ref())
- .map_err(DeviceRegistrationError::RegisterIrqfd)?;
- device.assign_platform_irq(irqfd, irq_resample_fd, irq.index);
+
+ if device.irq_is_automask(&irq) {
+ let irq_evt =
+ devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
+ irq_chip
+ .register_level_irq_event(irq_num, &irq_evt)
+ .map_err(DeviceRegistrationError::RegisterIrqfd)?;
+ device
+ .assign_level_platform_irq(&irq_evt, irq.index)
+ .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
+ keep_rds.extend(irq_evt.as_raw_descriptors());
+ } else {
+ let irq_evt =
+ devices::IrqEdgeEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
+ irq_chip
+ .register_edge_irq_event(irq_num, &irq_evt)
+ .map_err(DeviceRegistrationError::RegisterIrqfd)?;
+ device
+ .assign_edge_platform_irq(&irq_evt, irq.index)
+ .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
+ keep_rds.extend(irq_evt.as_raw_descriptors());
+ }
}
let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
@@ -583,16 +593,16 @@
irq
};
- let intx_event = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
- let intx_resample = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
+ let intx_event =
+ devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
- if let Some((gsi, pin)) = device.assign_irq(&intx_event, &intx_resample, Some(irq_num)) {
+ if let Some((gsi, pin)) = device.assign_irq(&intx_event, Some(irq_num)) {
// reserve INTx if needed and non-default.
if gsi != irq_num {
resources.reserve_irq(gsi);
};
irq_chip
- .register_irq_event(gsi, &intx_event, Some(&intx_resample))
+ .register_level_irq_event(gsi, &intx_event)
.map_err(DeviceRegistrationError::RegisterIrqfd)?;
pci_irqs.push((device_addrs[dev_idx], gsi, pin));
@@ -673,11 +683,10 @@
)
.map_err(DeviceRegistrationError::AllocateIoResource)?;
- let irq_evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
- let irq_resample_evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
+ let irq_evt = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
irq_chip
- .register_irq_event(irq_num, &irq_evt, Some(&irq_resample_evt))
+ .register_level_irq_event(irq_num, &irq_evt)
.map_err(DeviceRegistrationError::RegisterIrqfd)?;
let (control_tube, response_tube) =
@@ -690,15 +699,9 @@
#[cfg(not(feature = "power-monitor-powerd"))]
let create_monitor = None;
- let goldfish_bat = devices::GoldfishBattery::new(
- mmio_base,
- irq_num,
- irq_evt,
- irq_resample_evt,
- response_tube,
- create_monitor,
- )
- .map_err(DeviceRegistrationError::RegisterBattery)?;
+ let goldfish_bat =
+ devices::GoldfishBattery::new(mmio_base, irq_num, irq_evt, response_tube, create_monitor)
+ .map_err(DeviceRegistrationError::RegisterBattery)?;
goldfish_bat.to_aml_bytes(amls);
match battery_jail.as_ref() {
diff --git a/base/src/common/alloc.rs b/base/src/alloc.rs
similarity index 99%
rename from base/src/common/alloc.rs
rename to base/src/alloc.rs
index 7f237f1..9cb6a55 100644
--- a/base/src/common/alloc.rs
+++ b/base/src/alloc.rs
@@ -18,7 +18,7 @@
/// ```
/// use std::alloc::Layout;
/// use std::mem;
-/// use crate::common::LayoutAllocation;
+/// use crate::LayoutAllocation;
///
/// #[repr(C)]
/// struct Header {
diff --git a/base/src/common/mod.rs b/base/src/common/mod.rs
deleted file mode 100644
index 461e04e..0000000
--- a/base/src/common/mod.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2022 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.
-
-//! Small system utility modules for usage by other higher level system
-//! utility modules like sys_util(on unix/linux) and win_sys_util(on windows).
-//!
-//! Crates other than sys_util and win_sys_util should not depend directly on
-//! sys_util_core.
-//!
-//! sys_util_core contains system utilities that are strictly platform/os
-//! independent. Platform dependent, conditionally compiled, code should
-//! not be added to sys_util_core.
-//!
-
-mod alloc;
-mod errno;
-mod external_mapping;
-mod scoped_event_macro;
-
-pub use alloc::LayoutAllocation;
-pub use errno::{errno_result, Error, Result};
-pub use external_mapping::{Error as ExternalMappingError, Result as ExternalMappingResult, *};
-pub use scoped_event_macro::*;
diff --git a/base/src/descriptor.rs b/base/src/descriptor.rs
new file mode 100644
index 0000000..0b840ea
--- /dev/null
+++ b/base/src/descriptor.rs
@@ -0,0 +1,130 @@
+// Copyright 2022 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 crate::{PollToken, RawDescriptor};
+use serde::{Deserialize, Serialize};
+use std::{
+ fs::File,
+ mem::{self, ManuallyDrop},
+};
+
+/// Wraps a RawDescriptor and safely closes it when self falls out of scope.
+#[derive(Serialize, Deserialize, Debug, Eq)]
+#[serde(transparent)]
+pub struct SafeDescriptor {
+ #[serde(with = "super::with_raw_descriptor")]
+ pub(crate) descriptor: RawDescriptor,
+}
+
+/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
+pub trait IntoRawDescriptor {
+ fn into_raw_descriptor(self) -> RawDescriptor;
+}
+
+/// Trait for returning the underlying raw descriptor, without giving up ownership of the
+/// descriptor.
+pub trait AsRawDescriptor {
+ fn as_raw_descriptor(&self) -> RawDescriptor;
+}
+
+/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
+pub trait AsRawDescriptors {
+ fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
+}
+
+pub trait FromRawDescriptor {
+ /// # Safety
+ /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
+ /// `from_raw_descriptor`
+ unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
+}
+
+impl AsRawDescriptor for SafeDescriptor {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.descriptor
+ }
+}
+
+impl<T> AsRawDescriptors for T
+where
+ T: AsRawDescriptor,
+{
+ fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
+ vec![self.as_raw_descriptor()]
+ }
+}
+
+impl IntoRawDescriptor for SafeDescriptor {
+ fn into_raw_descriptor(self) -> RawDescriptor {
+ let descriptor = self.descriptor;
+ mem::forget(self);
+ descriptor
+ }
+}
+
+impl FromRawDescriptor for SafeDescriptor {
+ unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
+ SafeDescriptor { descriptor }
+ }
+}
+
+impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
+ type Error = std::io::Error;
+
+ /// Clones the underlying descriptor (handle), internally creating a new descriptor.
+ ///
+ /// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this
+ /// function on IO completion ports, sockets, or pseudo-handles (except those from
+ /// GetCurrentProcess or GetCurrentThread). See
+ /// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
+ /// for further details.
+ ///
+ /// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some
+ /// adjustments to smooth those edges.
+ fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
+ // Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
+ //
+ // Note that we are cloning the underlying raw descriptor since we have no guarantee of
+ // its existence after this function returns.
+ let rd_as_safe_desc = ManuallyDrop::new(unsafe {
+ SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
+ });
+
+ // We have to clone rd because we have no guarantee ownership was transferred (rd is
+ // borrowed).
+ rd_as_safe_desc
+ .try_clone()
+ .map_err(|e| Self::Error::from_raw_os_error(e.errno()))
+ }
+}
+
+impl From<File> for SafeDescriptor {
+ fn from(f: File) -> SafeDescriptor {
+ // Safe because we own the File at this point.
+ unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
+ }
+}
+
+/// For use cases where a simple wrapper around a RawDescriptor is needed.
+/// This is a simply a wrapper and does not manage the lifetime of the descriptor.
+/// Most usages should prefer SafeDescriptor or using a RawDescriptor directly
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(transparent)]
+pub struct Descriptor(pub RawDescriptor);
+impl AsRawDescriptor for Descriptor {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.0
+ }
+}
+
+/// Implement token for implementations that wish to use this struct as such
+impl PollToken for Descriptor {
+ fn as_raw_token(&self) -> u64 {
+ self.0 as u64
+ }
+
+ fn from_raw_token(data: u64) -> Self {
+ Descriptor(data as RawDescriptor)
+ }
+}
diff --git a/base/src/windows/descriptor_reflection.rs b/base/src/descriptor_reflection.rs
similarity index 98%
rename from base/src/windows/descriptor_reflection.rs
rename to base/src/descriptor_reflection.rs
index bf7cff1..4aa7e11 100644
--- a/base/src/windows/descriptor_reflection.rs
+++ b/base/src/descriptor_reflection.rs
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// 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.
@@ -64,7 +64,8 @@
ser, Deserialize, Deserializer, Serialize, Serializer,
};
-use super::{RawDescriptor, SafeDescriptor};
+use super::RawDescriptor;
+use crate::descriptor::SafeDescriptor;
thread_local! {
static DESCRIPTOR_DST: RefCell<Option<Vec<RawDescriptor>>> = Default::default();
@@ -339,7 +340,8 @@
/// }
/// ```
pub mod with_raw_descriptor {
- use super::super::{IntoRawDescriptor, RawDescriptor};
+ use super::super::RawDescriptor;
+ use crate::descriptor::IntoRawDescriptor;
use serde::Deserializer;
pub use super::serialize_descriptor as serialize;
@@ -369,7 +371,7 @@
/// }
/// ```
pub mod with_as_descriptor {
- use super::super::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor};
+ use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor};
use serde::{Deserializer, Serializer};
pub fn serialize<S: Serializer>(
diff --git a/base/src/common/errno.rs b/base/src/errno.rs
similarity index 100%
rename from base/src/common/errno.rs
rename to base/src/errno.rs
diff --git a/base/src/event.rs b/base/src/event.rs
index b69c187..f3f7ac7 100644
--- a/base/src/event.rs
+++ b/base/src/event.rs
@@ -12,11 +12,9 @@
use serde::{Deserialize, Serialize};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor};
pub use crate::platform::EventReadResult;
-use crate::{
- generate_scoped_event, platform::EventFd, AsRawDescriptor, FromRawDescriptor,
- IntoRawDescriptor, RawDescriptor, Result,
-};
+use crate::{generate_scoped_event, platform::EventFd, RawDescriptor, Result};
/// See [EventFd](crate::platform::EventFd) for struct- and method-level
/// documentation.
diff --git a/base/src/common/external_mapping.rs b/base/src/external_mapping.rs
similarity index 100%
rename from base/src/common/external_mapping.rs
rename to base/src/external_mapping.rs
diff --git a/base/src/ioctl.rs b/base/src/ioctl.rs
index d5a91fc..995a6ea 100644
--- a/base/src/ioctl.rs
+++ b/base/src/ioctl.rs
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::{AsRawDescriptor, IoctlNr};
+use crate::descriptor::AsRawDescriptor;
+use crate::IoctlNr;
use std::os::raw::{c_int, c_ulong, c_void};
/// Run an ioctl with no arguments.
diff --git a/base/src/lib.rs b/base/src/lib.rs
index 2e98780..7de1230 100644
--- a/base/src/lib.rs
+++ b/base/src/lib.rs
@@ -2,7 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-pub mod common;
+mod alloc;
+pub mod descriptor;
+pub mod descriptor_reflection;
+mod errno;
+pub mod external_mapping;
+pub mod scoped_event_macro;
+mod tube;
#[cfg(unix)]
pub mod unix;
@@ -10,8 +16,10 @@
#[cfg(windows)]
pub mod windows;
-mod tube;
-
+pub use alloc::LayoutAllocation;
+pub use errno::{errno_result, Error, Result};
+pub use external_mapping::{Error as ExternalMappingError, Result as ExternalMappingResult, *};
+pub use scoped_event_macro::*;
pub use tube::{Error as TubeError, RecvTube, Result as TubeResult, SendTube, Tube};
cfg_if::cfg_if! {
@@ -42,36 +50,14 @@
pub use wait_context::{EventToken, EventType, TriggeredEvent, WaitContext};
} else if #[cfg(windows)] {
pub use windows as platform;
+ pub use tube::{set_duplicate_handle_tube, set_alias_pid, DuplicateHandleTube};
} else {
compile_error!("Unsupported platform");
}
}
+pub use crate::descriptor::{
+ AsRawDescriptor, AsRawDescriptors, Descriptor, FromRawDescriptor, IntoRawDescriptor,
+ SafeDescriptor,
+};
pub use platform::*;
-
-/// Wraps an AsRawDescriptor in the simple Descriptor struct, which
-/// has AsRawFd methods for interfacing with sys_util
-pub fn wrap_descriptor(descriptor: &dyn AsRawDescriptor) -> Descriptor {
- Descriptor(descriptor.as_raw_descriptor())
-}
-
-/// Verifies that |raw_descriptor| is actually owned by this process and duplicates it
-/// to ensure that we have a unique handle to it.
-#[cfg(unix)]
-pub fn validate_raw_descriptor(raw_descriptor: RawDescriptor) -> Result<RawDescriptor> {
- validate_raw_fd(raw_descriptor)
-}
-
-/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
-pub trait AsRawDescriptors {
- fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
-}
-
-impl<T> AsRawDescriptors for T
-where
- T: AsRawDescriptor,
-{
- fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
- vec![self.as_raw_descriptor()]
- }
-}
diff --git a/base/src/mmap.rs b/base/src/mmap.rs
index 3599b70..8f9c0ce 100644
--- a/base/src/mmap.rs
+++ b/base/src/mmap.rs
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+use crate::descriptor::AsRawDescriptor;
use crate::{
- platform::MemoryMapping as SysUtilMmap, wrap_descriptor, AsRawDescriptor, MappedRegion,
- MemoryMappingArena, MmapError, Protection, SharedMemory,
+ platform::MemoryMapping as SysUtilMmap, MappedRegion, MemoryMappingArena, MmapError,
+ Protection, SharedMemory,
};
use data_model::{volatile_memory::*, DataInit};
use std::fs::File;
@@ -49,8 +50,7 @@
src: &dyn AsRawDescriptor,
count: usize,
) -> Result<()> {
- self.mapping
- .read_to_memory(mem_offset, &wrap_descriptor(src), count)
+ self.mapping.read_to_memory(mem_offset, src, count)
}
pub fn write_from_memory(
@@ -59,8 +59,7 @@
dst: &dyn AsRawDescriptor,
count: usize,
) -> Result<()> {
- self.mapping
- .write_from_memory(mem_offset, &wrap_descriptor(dst), count)
+ self.mapping.write_from_memory(mem_offset, dst, count)
}
}
@@ -170,7 +169,7 @@
}
Some(descriptor) => {
MemoryMappingBuilder::wrap(SysUtilMmap::from_fd_offset_protection_populate(
- &wrap_descriptor(descriptor),
+ descriptor,
self.size,
self.offset.unwrap_or(0),
self.protection.unwrap_or_else(Protection::read_write),
@@ -203,7 +202,7 @@
Some(descriptor) => {
MemoryMappingBuilder::wrap(SysUtilMmap::from_fd_offset_protection_fixed(
addr,
- &wrap_descriptor(descriptor),
+ descriptor,
self.size,
self.offset.unwrap_or(0),
self.protection.unwrap_or_else(Protection::read_write),
diff --git a/base/src/notifiers.rs b/base/src/notifiers.rs
index b01cd2f..9988b69 100644
--- a/base/src/notifiers.rs
+++ b/base/src/notifiers.rs
@@ -5,7 +5,7 @@
#[cfg(unix)]
use std::os::unix::net::UnixStream;
-use crate::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
pub trait ReadNotifier {
/// Gets a descriptor that can be used in EventContext to wait for events to be available (e.g.
diff --git a/base/src/common/scoped_event_macro.rs b/base/src/scoped_event_macro.rs
similarity index 100%
rename from base/src/common/scoped_event_macro.rs
rename to base/src/scoped_event_macro.rs
diff --git a/base/src/shm.rs b/base/src/shm.rs
index 55f1468..33f0a5f 100644
--- a/base/src/shm.rs
+++ b/base/src/shm.rs
@@ -2,10 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::{
- AsRawDescriptor, Error, FromRawDescriptor, IntoRawDescriptor, MemfdSeals, RawDescriptor,
- Result, SafeDescriptor,
-};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
+use crate::{Error, MemfdSeals, RawDescriptor, Result};
#[cfg(unix)]
use std::os::unix::io::RawFd;
use std::{
diff --git a/base/src/timer.rs b/base/src/timer.rs
index 1f9b3c0..0912120 100644
--- a/base/src/timer.rs
+++ b/base/src/timer.rs
@@ -2,9 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::{
- AsRawDescriptor, FakeClock, FromRawDescriptor, IntoRawDescriptor, RawDescriptor, Result,
-};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor};
+use crate::{FakeClock, RawDescriptor, Result};
use crate::platform::{FakeTimerFd, TimerFd};
use std::{
@@ -43,10 +42,6 @@
self.0.wait().map(|_| ())
}
- pub fn is_armed(&self) -> Result<bool> {
- self.0.is_armed()
- }
-
pub fn clear(&mut self) -> Result<()> {
self.0.clear()
}
diff --git a/base/src/unix/descriptor.rs b/base/src/unix/descriptor.rs
index ba20b46..6fa6fb0 100644
--- a/base/src/unix/descriptor.rs
+++ b/base/src/unix/descriptor.rs
@@ -6,8 +6,6 @@
convert::TryFrom,
fs::File,
io::{Stderr, Stdin, Stdout},
- mem,
- mem::ManuallyDrop,
net::UdpSocket,
ops::Drop,
os::unix::{
@@ -16,36 +14,19 @@
},
};
-use serde::{Deserialize, Serialize};
-
use super::{
errno_result,
net::{UnixSeqpacket, UnlinkUnixSeqpacketListener},
- PollToken, Result,
+ Result,
+};
+use crate::descriptor::{
+ AsRawDescriptor, Descriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor,
};
pub type RawDescriptor = RawFd;
pub const INVALID_DESCRIPTOR: RawDescriptor = -1;
-/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
-pub trait IntoRawDescriptor {
- fn into_raw_descriptor(self) -> RawDescriptor;
-}
-
-/// Trait for returning the underlying raw descriptor, without giving up ownership of the
-/// descriptor.
-pub trait AsRawDescriptor {
- fn as_raw_descriptor(&self) -> RawDescriptor;
-}
-
-pub trait FromRawDescriptor {
- /// # Safety
- /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
- /// `from_raw_descriptor`
- unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
-}
-
/// Clones `descriptor`, returning a new `RawDescriptor` that refers to the same open file
/// description as `descriptor`. The cloned descriptor will have the `FD_CLOEXEC` flag set but will
/// not share any other file descriptor flags with `descriptor`.
@@ -66,12 +47,27 @@
}
}
-/// Wraps a RawDescriptor and safely closes it when self falls out of scope.
-#[derive(Serialize, Deserialize, Debug, Eq)]
-#[serde(transparent)]
-pub struct SafeDescriptor {
- #[serde(with = "super::with_raw_descriptor")]
- descriptor: RawDescriptor,
+/// Clears CLOEXEC flag on descriptor
+pub fn clear_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()> {
+ clear_fd_cloexec(&fd_owner.as_raw_descriptor())
+}
+
+/// Clears CLOEXEC flag on fd
+fn clear_fd_cloexec<A: AsRawFd>(fd_owner: &A) -> Result<()> {
+ let fd = fd_owner.as_raw_fd();
+ // Safe because fd is read only.
+ let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
+ if flags == -1 {
+ return errno_result();
+ }
+
+ let masked_flags = flags & !libc::FD_CLOEXEC;
+ // Safe because this has no side effect(s) on the current process.
+ if masked_flags != flags && unsafe { libc::fcntl(fd, libc::F_SETFD, masked_flags) } == -1 {
+ errno_result()
+ } else {
+ Ok(())
+ }
}
const KCMP_FILE: u32 = 0;
@@ -107,26 +103,6 @@
}
}
-impl AsRawDescriptor for SafeDescriptor {
- fn as_raw_descriptor(&self) -> RawDescriptor {
- self.descriptor
- }
-}
-
-impl IntoRawDescriptor for SafeDescriptor {
- fn into_raw_descriptor(self) -> RawDescriptor {
- let descriptor = self.descriptor;
- mem::forget(self);
- descriptor
- }
-}
-
-impl FromRawDescriptor for SafeDescriptor {
- unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
- SafeDescriptor { descriptor }
- }
-}
-
impl AsRawFd for SafeDescriptor {
fn as_raw_fd(&self) -> RawFd {
self.as_raw_descriptor()
@@ -143,27 +119,6 @@
}
}
-impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
- type Error = std::io::Error;
-
- /// Clones the underlying descriptor (handle), internally creating a new descriptor.
- fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
- // Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
- //
- // Note that we are cloning the underlying raw descriptor since we have no guarantee of
- // its existence after this function returns.
- let rd_as_safe_desc = ManuallyDrop::new(unsafe {
- SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
- });
-
- // We have to clone rd because we have no guarantee ownership was transferred (rd is
- // borrowed).
- rd_as_safe_desc
- .try_clone()
- .map_err(|e| Self::Error::from_raw_os_error(e.errno()))
- }
-}
-
impl SafeDescriptor {
/// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
/// share the same underlying count within the kernel.
@@ -185,13 +140,6 @@
}
}
-impl From<File> for SafeDescriptor {
- fn from(f: File) -> SafeDescriptor {
- // Safe because we own the File at this point.
- unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
- }
-}
-
impl From<SafeDescriptor> for UnixStream {
fn from(s: SafeDescriptor) -> Self {
// Safe because we own the SafeDescriptor at this point.
@@ -206,18 +154,6 @@
}
}
-/// For use cases where a simple wrapper around a RawDescriptor is needed.
-/// This is a simply a wrapper and does not manage the lifetime of the descriptor.
-/// Most usages should prefer SafeDescriptor or using a RawDescriptor directly
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
-#[repr(transparent)]
-pub struct Descriptor(pub RawDescriptor);
-impl AsRawDescriptor for Descriptor {
- fn as_raw_descriptor(&self) -> RawDescriptor {
- self.0
- }
-}
-
// AsRawFd for interoperability with interfaces that require it. Within crosvm,
// always use AsRawDescriptor when possible.
impl AsRawFd for Descriptor {
@@ -226,17 +162,6 @@
}
}
-/// Implement token for implementations that wish to use this struct as such
-impl PollToken for Descriptor {
- fn as_raw_token(&self) -> u64 {
- self.0 as u64
- }
-
- fn from_raw_token(data: u64) -> Self {
- Descriptor(data as RawDescriptor)
- }
-}
-
macro_rules! AsRawDescriptor {
($name:ident) => {
impl AsRawDescriptor for $name {
diff --git a/base/src/unix/descriptor_reflection.rs b/base/src/unix/descriptor_reflection.rs
deleted file mode 100644
index f05f541..0000000
--- a/base/src/unix/descriptor_reflection.rs
+++ /dev/null
@@ -1,543 +0,0 @@
-// 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.
-
-//! Provides infrastructure for de/serializing descriptors embedded in Rust data structures.
-//!
-//! # Example
-//!
-//! ```
-//! use serde_json::to_string;
-//! use crate::platform::{
-//! FileSerdeWrapper, FromRawDescriptor, SafeDescriptor, SerializeDescriptors,
-//! deserialize_with_descriptors,
-//! };
-//! use tempfile::tempfile;
-//!
-//! let tmp_f = tempfile().unwrap();
-//!
-//! // Uses a simple wrapper to serialize a File because we can't implement Serialize for File.
-//! let data = FileSerdeWrapper(tmp_f);
-//!
-//! // Wraps Serialize types to collect side channel descriptors as Serialize is called.
-//! let data_wrapper = SerializeDescriptors::new(&data);
-//!
-//! // Use the wrapper with any serializer to serialize data is normal, grabbing descriptors
-//! // as the data structures are serialized by the serializer.
-//! let out_json = serde_json::to_string(&data_wrapper).expect("failed to serialize");
-//!
-//! // If data_wrapper contains any side channel descriptor refs
-//! // (it contains tmp_f in this case), we can retrieve the actual descriptors
-//! // from the side channel using into_descriptors().
-//! let out_descriptors = data_wrapper.into_descriptors();
-//!
-//! // When sending out_json over some transport, also send out_descriptors.
-//!
-//! // For this example, we aren't really transporting data across the process, but we do need to
-//! // convert the descriptor type.
-//! let mut safe_descriptors = out_descriptors
-//! .iter()
-//! .map(|&v| Some(unsafe { SafeDescriptor::from_raw_descriptor(v) }))
-//! .collect();
-//! std::mem::forget(data); // Prevent double drop of tmp_f.
-//!
-//! // The deserialize_with_descriptors function is used give the descriptor deserializers access
-//! // to side channel descriptors.
-//! let res: FileSerdeWrapper =
-//! deserialize_with_descriptors(|| serde_json::from_str(&out_json), &mut safe_descriptors)
-//! .expect("failed to deserialize");
-//! ```
-
-use std::{
- cell::{Cell, RefCell},
- convert::TryInto,
- fmt,
- fs::File,
- ops::{Deref, DerefMut},
- panic::{catch_unwind, resume_unwind, AssertUnwindSafe},
-};
-
-use serde::{
- de::{
- Error, Visitor, {self},
- },
- ser, Deserialize, Deserializer, Serialize, Serializer,
-};
-
-use super::{RawDescriptor, SafeDescriptor};
-
-thread_local! {
- static DESCRIPTOR_DST: RefCell<Option<Vec<RawDescriptor>>> = Default::default();
-}
-
-/// Initializes the thread local storage for descriptor serialization. Fails if it was already
-/// initialized without an intervening `take_descriptor_dst` on this thread.
-fn init_descriptor_dst() -> Result<(), &'static str> {
- DESCRIPTOR_DST.with(|d| {
- let mut descriptors = d.borrow_mut();
- if descriptors.is_some() {
- return Err(
- "attempt to initialize descriptor destination that was already initialized",
- );
- }
- *descriptors = Some(Default::default());
- Ok(())
- })
-}
-
-/// Takes the thread local storage for descriptor serialization. Fails if there wasn't a prior call
-/// to `init_descriptor_dst` on this thread.
-fn take_descriptor_dst() -> Result<Vec<RawDescriptor>, &'static str> {
- match DESCRIPTOR_DST.with(|d| d.replace(None)) {
- Some(d) => Ok(d),
- None => Err("attempt to take descriptor destination before it was initialized"),
- }
-}
-
-/// Pushes a descriptor on the thread local destination of descriptors, returning the index in which
-/// the descriptor was pushed.
-//
-/// Returns Err if the thread local destination was not already initialized.
-fn push_descriptor(rd: RawDescriptor) -> Result<usize, &'static str> {
- DESCRIPTOR_DST.with(|d| {
- d.borrow_mut()
- .as_mut()
- .ok_or("attempt to serialize descriptor without descriptor destination")
- .map(|descriptors| {
- let index = descriptors.len();
- descriptors.push(rd);
- index
- })
- })
-}
-
-/// Serializes a descriptor for later retrieval in a parent `SerializeDescriptors` struct.
-///
-/// If there is no parent `SerializeDescriptors` being serialized, this will return an error.
-///
-/// For convenience, it is recommended to use the `with_raw_descriptor` module in a `#[serde(with =
-/// "...")]` attribute which will make use of this function.
-pub fn serialize_descriptor<S: Serializer>(
- rd: &RawDescriptor,
- se: S,
-) -> std::result::Result<S::Ok, S::Error> {
- let index = push_descriptor(*rd).map_err(ser::Error::custom)?;
- se.serialize_u32(
- index
- .try_into()
- .map_err(|_| ser::Error::custom("attempt to serialize too many descriptors at once"))?,
- )
-}
-
-/// Wrapper for a `Serialize` value which will capture any descriptors exported by the value when
-/// given to an ordinary `Serializer`.
-///
-/// This is the corresponding type to use for serialization before using
-/// `deserialize_with_descriptors`.
-///
-/// # Examples
-///
-/// ```
-/// use serde_json::to_string;
-/// use crate::platform::{FileSerdeWrapper, SerializeDescriptors};
-/// use tempfile::tempfile;
-///
-/// let tmp_f = tempfile().unwrap();
-/// let data = FileSerdeWrapper(tmp_f);
-/// let data_wrapper = SerializeDescriptors::new(&data);
-///
-/// // Serializes `v` as normal...
-/// let out_json = serde_json::to_string(&data_wrapper).expect("failed to serialize");
-/// // If `serialize_descriptor` was called, we can capture the descriptors from here.
-/// let out_descriptors = data_wrapper.into_descriptors();
-/// ```
-pub struct SerializeDescriptors<'a, T: Serialize>(&'a T, Cell<Vec<RawDescriptor>>);
-
-impl<'a, T: Serialize> SerializeDescriptors<'a, T> {
- pub fn new(inner: &'a T) -> Self {
- Self(inner, Default::default())
- }
-
- pub fn into_descriptors(self) -> Vec<RawDescriptor> {
- self.1.into_inner()
- }
-}
-
-impl<'a, T: Serialize> Serialize for SerializeDescriptors<'a, T> {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- init_descriptor_dst().map_err(ser::Error::custom)?;
-
- // catch_unwind is used to ensure that init_descriptor_dst is always balanced with a call to
- // take_descriptor_dst afterwards.
- let res = catch_unwind(AssertUnwindSafe(|| self.0.serialize(serializer)));
- self.1.set(take_descriptor_dst().unwrap());
- match res {
- Ok(r) => r,
- Err(e) => resume_unwind(e),
- }
- }
-}
-
-thread_local! {
- static DESCRIPTOR_SRC: RefCell<Option<Vec<Option<SafeDescriptor>>>> = Default::default();
-}
-
-/// Sets the thread local storage of descriptors for deserialization. Fails if this was already
-/// called without a call to `take_descriptor_src` on this thread.
-///
-/// This is given as a collection of `Option` so that unused descriptors can be returned.
-fn set_descriptor_src(descriptors: Vec<Option<SafeDescriptor>>) -> Result<(), &'static str> {
- DESCRIPTOR_SRC.with(|d| {
- let mut src = d.borrow_mut();
- if src.is_some() {
- return Err("attempt to set descriptor source that was already set");
- }
- *src = Some(descriptors);
- Ok(())
- })
-}
-
-/// Takes the thread local storage of descriptors for deserialization. Fails if the storage was
-/// already taken or never set with `set_descriptor_src`.
-///
-/// If deserialization was done, the descriptors will mostly come back as `None` unless some of them
-/// were unused.
-fn take_descriptor_src() -> Result<Vec<Option<SafeDescriptor>>, &'static str> {
- DESCRIPTOR_SRC.with(|d| {
- d.replace(None)
- .ok_or("attempt to take descriptor source which was never set")
- })
-}
-
-/// Takes a descriptor at the given index from the thread local source of descriptors.
-//
-/// Returns None if the thread local source was not already initialized.
-fn take_descriptor(index: usize) -> Result<SafeDescriptor, &'static str> {
- DESCRIPTOR_SRC.with(|d| {
- d.borrow_mut()
- .as_mut()
- .ok_or("attempt to deserialize descriptor without descriptor source")?
- .get_mut(index)
- .ok_or("attempt to deserialize out of bounds descriptor")?
- .take()
- .ok_or("attempt to deserialize descriptor that was already taken")
- })
-}
-
-/// Deserializes a descriptor provided via `deserialize_with_descriptors`.
-///
-/// If `deserialize_with_descriptors` is not in the call chain, this will return an error.
-///
-/// For convenience, it is recommended to use the `with_raw_descriptor` module in a `#[serde(with =
-/// "...")]` attribute which will make use of this function.
-pub fn deserialize_descriptor<'de, D>(de: D) -> std::result::Result<SafeDescriptor, D::Error>
-where
- D: Deserializer<'de>,
-{
- struct DescriptorVisitor;
-
- impl<'de> Visitor<'de> for DescriptorVisitor {
- type Value = u32;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("an integer which fits into a u32")
- }
-
- fn visit_u8<E: de::Error>(self, value: u8) -> Result<Self::Value, E> {
- Ok(value as _)
- }
-
- fn visit_u16<E: de::Error>(self, value: u16) -> Result<Self::Value, E> {
- Ok(value as _)
- }
-
- fn visit_u32<E: de::Error>(self, value: u32) -> Result<Self::Value, E> {
- Ok(value)
- }
-
- fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
-
- fn visit_u128<E: de::Error>(self, value: u128) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
-
- fn visit_i8<E: de::Error>(self, value: i8) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
-
- fn visit_i16<E: de::Error>(self, value: i16) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
-
- fn visit_i32<E: de::Error>(self, value: i32) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
-
- fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
-
- fn visit_i128<E: de::Error>(self, value: i128) -> Result<Self::Value, E> {
- value.try_into().map_err(E::custom)
- }
- }
-
- let index = de.deserialize_u32(DescriptorVisitor)? as usize;
- take_descriptor(index).map_err(D::Error::custom)
-}
-
-/// Allows the use of any serde deserializer within a closure while providing access to the a set of
-/// descriptors for use in `deserialize_descriptor`.
-///
-/// This is the corresponding call to use deserialize after using `SerializeDescriptors`.
-///
-/// If `deserialize_with_descriptors` is called anywhere within the given closure, it return an
-/// error.
-pub fn deserialize_with_descriptors<F, T, E>(
- f: F,
- descriptors: &mut Vec<Option<SafeDescriptor>>,
-) -> Result<T, E>
-where
- F: FnOnce() -> Result<T, E>,
- E: de::Error,
-{
- let swap_descriptors = std::mem::take(descriptors);
- set_descriptor_src(swap_descriptors).map_err(E::custom)?;
-
- // catch_unwind is used to ensure that set_descriptor_src is always balanced with a call to
- // take_descriptor_src afterwards.
- let res = catch_unwind(AssertUnwindSafe(f));
-
- // unwrap is used because set_descriptor_src is always called before this, so it should never
- // panic.
- *descriptors = take_descriptor_src().unwrap();
-
- match res {
- Ok(r) => r,
- Err(e) => resume_unwind(e),
- }
-}
-
-/// Module that exports `serialize`/`deserialize` functions for use with `#[serde(with = "...")]`
-/// attribute. It only works with fields with `RawDescriptor` type.
-///
-/// # Examples
-///
-/// ```
-/// use serde::{Deserialize, Serialize};
-/// use crate::platform::RawDescriptor;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct RawContainer {
-/// #[serde(with = "crate::platform::with_raw_descriptor")]
-/// rd: RawDescriptor,
-/// }
-/// ```
-pub mod with_raw_descriptor {
- use super::super::{IntoRawDescriptor, RawDescriptor};
- use serde::Deserializer;
-
- pub use super::serialize_descriptor as serialize;
-
- pub fn deserialize<'de, D>(de: D) -> std::result::Result<RawDescriptor, D::Error>
- where
- D: Deserializer<'de>,
- {
- super::deserialize_descriptor(de).map(IntoRawDescriptor::into_raw_descriptor)
- }
-}
-
-/// Module that exports `serialize`/`deserialize` functions for use with `#[serde(with = "...")]`
-/// attribute.
-///
-/// # Examples
-///
-/// ```
-/// use std::fs::File;
-/// use serde::{Deserialize, Serialize};
-/// use crate::platform::RawDescriptor;
-///
-/// #[derive(Serialize, Deserialize)]
-/// struct FileContainer {
-/// #[serde(with = "crate::platform::with_as_descriptor")]
-/// file: File,
-/// }
-/// ```
-pub mod with_as_descriptor {
- use super::super::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor};
- use serde::{Deserializer, Serializer};
-
- pub fn serialize<S: Serializer>(
- rd: &dyn AsRawDescriptor,
- se: S,
- ) -> std::result::Result<S::Ok, S::Error> {
- super::serialize_descriptor(&rd.as_raw_descriptor(), se)
- }
-
- pub fn deserialize<'de, D, T>(de: D) -> std::result::Result<T, D::Error>
- where
- D: Deserializer<'de>,
- T: FromRawDescriptor,
- {
- super::deserialize_descriptor(de)
- .map(IntoRawDescriptor::into_raw_descriptor)
- .map(|rd| unsafe { T::from_raw_descriptor(rd) })
- }
-}
-
-/// A simple wrapper around `File` that implements `Serialize`/`Deserialize`, which is useful when
-/// the `#[serde(with = "with_as_descriptor")]` trait is infeasible, such as for a field with type
-/// `Option<File>`.
-#[derive(Serialize, Deserialize)]
-#[serde(transparent)]
-pub struct FileSerdeWrapper(#[serde(with = "with_as_descriptor")] pub File);
-
-impl fmt::Debug for FileSerdeWrapper {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl From<File> for FileSerdeWrapper {
- fn from(file: File) -> Self {
- FileSerdeWrapper(file)
- }
-}
-
-impl From<FileSerdeWrapper> for File {
- fn from(f: FileSerdeWrapper) -> File {
- f.0
- }
-}
-
-impl Deref for FileSerdeWrapper {
- type Target = File;
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl DerefMut for FileSerdeWrapper {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::super::{
- deserialize_with_descriptors, with_as_descriptor, with_raw_descriptor, FileSerdeWrapper,
- FromRawDescriptor, RawDescriptor, SafeDescriptor, SerializeDescriptors,
- };
-
- use std::{collections::HashMap, fs::File, mem::ManuallyDrop, os::unix::io::AsRawFd};
-
- use serde::{de::DeserializeOwned, Deserialize, Serialize};
- use tempfile::tempfile;
-
- fn deserialize<T: DeserializeOwned>(json: &str, descriptors: &[RawDescriptor]) -> T {
- let mut safe_descriptors = descriptors
- .iter()
- .map(|&v| Some(unsafe { SafeDescriptor::from_raw_descriptor(v) }))
- .collect();
-
- let res =
- deserialize_with_descriptors(|| serde_json::from_str(json), &mut safe_descriptors)
- .unwrap();
-
- assert!(safe_descriptors.iter().all(|v| v.is_none()));
-
- res
- }
-
- #[test]
- fn raw() {
- #[derive(Serialize, Deserialize, PartialEq, Debug)]
- struct RawContainer {
- #[serde(with = "with_raw_descriptor")]
- rd: RawDescriptor,
- }
- // Specifically chosen to not overlap a real descriptor to avoid having to allocate any
- // descriptors for this test.
- let fake_rd = 5_123_457_i32;
- let v = RawContainer { rd: fake_rd };
- let v_serialize = SerializeDescriptors::new(&v);
- let json = serde_json::to_string(&v_serialize).unwrap();
- let descriptors = v_serialize.into_descriptors();
- let res = deserialize(&json, &descriptors);
- assert_eq!(v, res);
- }
-
- #[test]
- fn file() {
- #[derive(Serialize, Deserialize)]
- struct FileContainer {
- #[serde(with = "with_as_descriptor")]
- file: File,
- }
-
- let v = FileContainer {
- file: tempfile().unwrap(),
- };
- let v_serialize = SerializeDescriptors::new(&v);
- let json = serde_json::to_string(&v_serialize).unwrap();
- let descriptors = v_serialize.into_descriptors();
- let v = ManuallyDrop::new(v);
- let res: FileContainer = deserialize(&json, &descriptors);
- assert_eq!(v.file.as_raw_fd(), res.file.as_raw_fd());
- }
-
- #[test]
- fn option() {
- #[derive(Serialize, Deserialize)]
- struct TestOption {
- a: Option<FileSerdeWrapper>,
- b: Option<FileSerdeWrapper>,
- }
-
- let v = TestOption {
- a: None,
- b: Some(tempfile().unwrap().into()),
- };
- let v_serialize = SerializeDescriptors::new(&v);
- let json = serde_json::to_string(&v_serialize).unwrap();
- let descriptors = v_serialize.into_descriptors();
- let v = ManuallyDrop::new(v);
- let res: TestOption = deserialize(&json, &descriptors);
- assert!(res.a.is_none());
- assert!(res.b.is_some());
- assert_eq!(
- v.b.as_ref().unwrap().as_raw_fd(),
- res.b.unwrap().as_raw_fd()
- );
- }
-
- #[test]
- fn map() {
- let mut v: HashMap<String, FileSerdeWrapper> = HashMap::new();
- v.insert("a".into(), tempfile().unwrap().into());
- v.insert("b".into(), tempfile().unwrap().into());
- v.insert("c".into(), tempfile().unwrap().into());
- let v_serialize = SerializeDescriptors::new(&v);
- let json = serde_json::to_string(&v_serialize).unwrap();
- let descriptors = v_serialize.into_descriptors();
- // Prevent the files in `v` from dropping while allowing the HashMap itself to drop. It is
- // done this way to prevent a double close of the files (which should reside in `res`)
- // without triggering the leak sanitizer on `v`'s HashMap heap memory.
- let v: HashMap<_, _> = v
- .into_iter()
- .map(|(k, v)| (k, ManuallyDrop::new(v)))
- .collect();
- let res: HashMap<String, FileSerdeWrapper> = deserialize(&json, &descriptors);
-
- assert_eq!(v.len(), res.len());
- for (k, v) in v.iter() {
- assert_eq!(res.get(k).unwrap().as_raw_fd(), v.as_raw_fd());
- }
- }
-}
diff --git a/base/src/unix/eventfd.rs b/base/src/unix/eventfd.rs
index 0dc861b..84080ac 100644
--- a/base/src/unix/eventfd.rs
+++ b/base/src/unix/eventfd.rs
@@ -13,10 +13,8 @@
use libc::{c_void, eventfd, read, write, POLLIN};
use serde::{Deserialize, Serialize};
-use super::{
- duration_to_timespec, errno_result, AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor,
- RawDescriptor, Result, SafeDescriptor,
-};
+use super::{duration_to_timespec, errno_result, RawDescriptor, Result};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
use crate::generate_scoped_event;
/// A safe wrapper around a Linux eventfd (man 2 eventfd).
diff --git a/base/src/unix/fork.rs b/base/src/unix/fork.rs
deleted file mode 100644
index 3c103a8..0000000
--- a/base/src/unix/fork.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2017 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::{fs, io, path::Path, process, result};
-
-use libc::{c_long, pid_t, syscall, SYS_clone, CLONE_NEWPID, CLONE_NEWUSER, SIGCHLD};
-use remain::sorted;
-use thiserror::Error;
-
-use super::errno_result;
-
-/// Controls what namespace `clone_process` will have. See NAMESPACES(7).
-#[repr(u32)]
-pub enum CloneNamespace {
- /// The new process will inherit the namespace from the old process.
- Inherit = 0,
- /// The new process with be in a new user and PID namespace.
- NewUserPid = CLONE_NEWUSER as u32 | CLONE_NEWPID as u32,
-}
-
-#[sorted]
-#[derive(Error, Debug)]
-pub enum CloneError {
- /// There was an error trying to iterate this process's threads.
- #[error("error iterating this process's threads")]
- IterateTasks(io::Error),
- /// There are multiple threads running. The `usize` indicates how many threads.
- #[error("multiple threads are already running")]
- Multithreaded(usize),
- /// There was an error while cloning.
- #[error("error while cloning")]
- Sys(super::Error),
-}
-
-unsafe fn do_clone(flags: i32) -> super::Result<pid_t> {
- // Forking is unsafe, this function must be unsafe as there is no way to guarantee safety
- // without more context about the state of the program.
- let pid = syscall(SYS_clone as c_long, flags | SIGCHLD as i32, 0);
- if pid < 0 {
- errno_result()
- } else {
- Ok(pid as pid_t)
- }
-}
-
-fn count_dir_entries<P: AsRef<Path>>(path: P) -> io::Result<usize> {
- Ok(fs::read_dir(path)?.count())
-}
-
-/// Clones this process and calls a closure in the new process.
-///
-/// After `post_clone_cb` returns or panics, the new process exits. Similar to how a `fork` syscall
-/// works, the new process is the same as the current process with the exception of the namespace
-/// controlled with the `ns` argument.
-///
-/// # Arguments
-/// * `ns` - What namespace the new process will have (see NAMESPACES(7)).
-/// * `post_clone_cb` - Callback to run in the new process
-pub fn clone_process<F>(ns: CloneNamespace, post_clone_cb: F) -> result::Result<pid_t, CloneError>
-where
- F: FnOnce(),
-{
- match count_dir_entries("/proc/self/task") {
- Ok(1) => {}
- Ok(thread_count) => {
- // Test cfg gets a free pass on this because tests generally have multiple independent
- // test threads going.
- let _ = thread_count;
- #[cfg(not(test))]
- return Err(CloneError::Multithreaded(thread_count));
- }
- Err(e) => return Err(CloneError::IterateTasks(e)),
- }
- // Forking is considered unsafe in mutlithreaded programs, but we just checked for other threads
- // in this process. We also only allow valid flags from CloneNamespace and check the return
- // result for errors. We also never let the cloned process return from this function.
- let ret = unsafe { do_clone(ns as i32) }.map_err(CloneError::Sys)?;
- if ret == 0 {
- struct ExitGuard;
- impl Drop for ExitGuard {
- fn drop(&mut self) {
- process::exit(101);
- }
- }
- // Prevents a panic in post_clone_cb from bypassing the process::exit.
- #[allow(unused_variables)]
- let exit_guard = ExitGuard {};
- post_clone_cb();
- // ! Never returns
- process::exit(0);
- }
-
- Ok(ret)
-}
-
-#[cfg(test)]
-mod tests {
- use super::{
- super::{getpid, EventFd},
- *,
- };
-
- fn wait_process(pid: libc::pid_t) -> super::super::Result<libc::c_int> {
- let mut status: libc::c_int = 0;
- unsafe {
- if libc::waitpid(pid, &mut status as *mut libc::c_int, 0) < 0 {
- errno_result()
- } else {
- Ok(libc::WEXITSTATUS(status))
- }
- }
- }
-
- #[test]
- fn pid_diff() {
- let evt_fd = EventFd::new().expect("failed to create EventFd");
- let evt_fd_fork = evt_fd.try_clone().expect("failed to clone EventFd");
- let pid = getpid();
- clone_process(CloneNamespace::Inherit, || {
- // checks that this is a genuine fork with a new PID
- if pid != getpid() {
- evt_fd_fork.write(1).unwrap()
- } else {
- evt_fd_fork.write(2).unwrap()
- }
- })
- .expect("failed to clone");
- assert_eq!(evt_fd.read(), Ok(1));
- }
-
- // This test can deadlock occasionally when running in the builders VM. It
- // is disabled for now.
- // TODO(b/179924844): Investigate the issue and re-enable
- #[test]
- #[ignore]
- fn panic_safe() {
- let pid = getpid();
- assert_ne!(pid, 0);
-
- let clone_pid = clone_process(CloneNamespace::Inherit, || {
- panic!();
- })
- .expect("failed to clone");
-
- // This should never happen;
- if pid != getpid() {
- process::exit(2);
- }
-
- let status = wait_process(clone_pid).expect("wait_process failed");
- assert!(status == 101 || status == 0);
- }
-}
diff --git a/base/src/unix/mmap.rs b/base/src/unix/mmap.rs
index 06316ef..5fc3063 100644
--- a/base/src/unix/mmap.rs
+++ b/base/src/unix/mmap.rs
@@ -9,11 +9,11 @@
cmp::min,
io,
mem::size_of,
- os::unix::io::AsRawFd,
ptr::{copy_nonoverlapping, null_mut, read_unaligned, write_unaligned},
};
-use crate::common::ExternalMapping;
+use crate::external_mapping::ExternalMapping;
+use crate::AsRawDescriptor;
use libc::{
c_int, c_void, read, write, {self},
};
@@ -137,7 +137,7 @@
&mut self,
_offset: usize,
_size: usize,
- _fd: &dyn AsRawFd,
+ _fd: &dyn AsRawDescriptor,
_fd_offset: u64,
_prot: Protection,
) -> Result<()> {
@@ -233,11 +233,15 @@
/// # Arguments
/// * `fd` - File descriptor to mmap from.
/// * `size` - Size of memory region in bytes.
- pub fn from_fd(fd: &dyn AsRawFd, size: usize) -> Result<MemoryMapping> {
+ pub fn from_fd(fd: &dyn AsRawDescriptor, size: usize) -> Result<MemoryMapping> {
MemoryMapping::from_fd_offset(fd, size, 0)
}
- pub fn from_fd_offset(fd: &dyn AsRawFd, size: usize, offset: u64) -> Result<MemoryMapping> {
+ pub fn from_fd_offset(
+ fd: &dyn AsRawDescriptor,
+ size: usize,
+ offset: u64,
+ ) -> Result<MemoryMapping> {
MemoryMapping::from_fd_offset_protection(fd, size, offset, Protection::read_write())
}
@@ -250,7 +254,7 @@
/// * `flags` - flags passed directly to mmap.
/// * `prot` - Protection (e.g. readable/writable) of the memory region.
fn from_fd_offset_flags(
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
size: usize,
offset: u64,
flags: c_int,
@@ -271,7 +275,7 @@
/// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
/// * `prot` - Protection (e.g. readable/writable) of the memory region.
pub fn from_fd_offset_protection(
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
size: usize,
offset: u64,
prot: Protection,
@@ -286,7 +290,7 @@
/// * `size` - Size of memory region in bytes.
/// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
pub fn from_fd_offset_protection_populate(
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
size: usize,
offset: u64,
prot: Protection,
@@ -342,7 +346,7 @@
/// present at `(addr..addr+size)`.
pub unsafe fn from_fd_offset_protection_fixed(
addr: *mut u8,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
size: usize,
offset: u64,
prot: Protection,
@@ -363,7 +367,7 @@
size: usize,
prot: c_int,
flags: c_int,
- fd: Option<(&dyn AsRawFd, u64)>,
+ fd: Option<(&dyn AsRawDescriptor, u64)>,
) -> Result<MemoryMapping> {
let mut flags = flags;
// If addr is provided, set the FIXED flag, and validate addr alignment
@@ -383,7 +387,7 @@
if offset > libc::off_t::max_value() as u64 {
return Err(Error::InvalidOffset);
}
- (fd.as_raw_fd(), offset as libc::off_t)
+ (fd.as_raw_descriptor(), offset as libc::off_t)
}
None => (-1, 0),
};
@@ -584,7 +588,7 @@
pub fn read_to_memory(
&self,
mut mem_offset: usize,
- src: &dyn AsRawFd,
+ src: &dyn AsRawDescriptor,
mut count: usize,
) -> Result<()> {
self.range_end(mem_offset, count)
@@ -594,7 +598,7 @@
// read call.
match unsafe {
read(
- src.as_raw_fd(),
+ src.as_raw_descriptor(),
self.as_ptr().add(mem_offset) as *mut c_void,
count,
)
@@ -643,7 +647,7 @@
pub fn write_from_memory(
&self,
mut mem_offset: usize,
- dst: &dyn AsRawFd,
+ dst: &dyn AsRawDescriptor,
mut count: usize,
) -> Result<()> {
self.range_end(mem_offset, count)
@@ -653,7 +657,7 @@
// write call.
match unsafe {
write(
- dst.as_raw_fd(),
+ dst.as_raw_descriptor(),
self.as_ptr().add(mem_offset) as *const c_void,
count,
)
@@ -808,7 +812,7 @@
/// * `offset` - Page aligned offset into the arena in bytes.
/// * `size` - Size of memory region in bytes.
/// * `fd` - File descriptor to mmap from.
- pub fn add_fd(&mut self, offset: usize, size: usize, fd: &dyn AsRawFd) -> Result<()> {
+ pub fn add_fd(&mut self, offset: usize, size: usize, fd: &dyn AsRawDescriptor) -> Result<()> {
self.add_fd_offset(offset, size, fd, 0)
}
@@ -824,7 +828,7 @@
&mut self,
offset: usize,
size: usize,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
fd_offset: u64,
) -> Result<()> {
self.add_fd_offset_protection(offset, size, fd, fd_offset, Protection::read_write())
@@ -844,7 +848,7 @@
&mut self,
offset: usize,
size: usize,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
fd_offset: u64,
prot: Protection,
) -> Result<()> {
@@ -858,7 +862,7 @@
offset: usize,
size: usize,
prot: Protection,
- fd: Option<(&dyn AsRawFd, u64)>,
+ fd: Option<(&dyn AsRawDescriptor, u64)>,
) -> Result<()> {
// Ensure offset is page-aligned
if offset % pagesize() != 0 {
@@ -911,7 +915,7 @@
&mut self,
offset: usize,
size: usize,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
fd_offset: u64,
prot: Protection,
) -> Result<()> {
@@ -947,7 +951,8 @@
#[cfg(test)]
mod tests {
- use super::{super::Descriptor, *};
+ use super::*;
+ use crate::descriptor::Descriptor;
use data_model::{VolatileMemory, VolatileMemoryError};
use tempfile::tempfile;
diff --git a/base/src/unix/mod.rs b/base/src/unix/mod.rs
index def9f7d..16576e0 100644
--- a/base/src/unix/mod.rs
+++ b/base/src/unix/mod.rs
@@ -27,11 +27,9 @@
mod capabilities;
mod clock;
mod descriptor;
-mod descriptor_reflection;
mod eventfd;
mod file_flags;
pub mod file_traits;
-mod fork;
mod get_filesystem_type;
mod mmap;
pub mod net;
@@ -52,8 +50,12 @@
pub mod vsock;
mod write_zeroes;
+pub use crate::descriptor_reflection::{
+ deserialize_with_descriptors, with_as_descriptor, with_raw_descriptor, FileSerdeWrapper,
+ SerializeDescriptors,
+};
pub use crate::{
- common::{Error, Result, *},
+ errno::{Error, Result, *},
generate_scoped_event,
};
pub use acpi_event::*;
@@ -61,13 +63,8 @@
pub use capabilities::drop_capabilities;
pub use clock::{Clock, FakeClock};
pub use descriptor::*;
-pub use descriptor_reflection::{
- deserialize_with_descriptors, with_as_descriptor, with_raw_descriptor, FileSerdeWrapper,
- SerializeDescriptors,
-};
pub use eventfd::*;
pub use file_flags::*;
-pub use fork::*;
pub use get_filesystem_type::*;
pub use ioctl::*;
pub use mmap::*;
@@ -84,6 +81,7 @@
pub use terminal::*;
pub use timerfd::*;
+use crate::descriptor::{FromRawDescriptor, SafeDescriptor};
pub use file_traits::{
AsRawFds, FileAllocate, FileGetLen, FileReadWriteAtVolatile, FileReadWriteVolatile, FileSetLen,
FileSync,
@@ -486,6 +484,12 @@
}
}
+/// Verifies that |raw_descriptor| is actually owned by this process and duplicates it
+/// to ensure that we have a unique handle to it.
+pub fn validate_raw_descriptor(raw_descriptor: RawDescriptor) -> Result<RawDescriptor> {
+ validate_raw_fd(raw_descriptor)
+}
+
/// Verifies that |raw_fd| is actually owned by this process and duplicates it to ensure that
/// we have a unique handle to it.
pub fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> {
diff --git a/base/src/unix/net.rs b/base/src/unix/net.rs
index 8705ccd..11cb4b6 100644
--- a/base/src/unix/net.rs
+++ b/base/src/unix/net.rs
@@ -30,8 +30,9 @@
use super::{
sock_ctrl_msg::{ScmSocket, SCM_SOCKET_MAX_FD_COUNT},
- AsRawDescriptor, Error, FromRawDescriptor, IntoRawDescriptor, RawDescriptor,
+ Error, RawDescriptor,
};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor};
/// Assist in handling both IP version 4 and IP version 6.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
diff --git a/base/src/unix/netlink.rs b/base/src/unix/netlink.rs
index 194b3c6..297f255 100644
--- a/base/src/unix/netlink.rs
+++ b/base/src/unix/netlink.rs
@@ -7,12 +7,10 @@
use data_model::DataInit;
use libc::EINVAL;
-use crate::common::LayoutAllocation;
+use crate::alloc::LayoutAllocation;
-use super::{
- errno_result, getpid, AsRawDescriptor, Error, FromRawDescriptor, RawDescriptor, Result,
- SafeDescriptor,
-};
+use super::{errno_result, getpid, Error, RawDescriptor, Result};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, SafeDescriptor};
macro_rules! debug_pr {
// By default debugs are suppressed, to enabled them replace macro body with:
diff --git a/base/src/unix/poll.rs b/base/src/unix/poll.rs
index d8a4457..5e7e947 100644
--- a/base/src/unix/poll.rs
+++ b/base/src/unix/poll.rs
@@ -8,7 +8,6 @@
fs::File,
i32, i64,
marker::PhantomData,
- os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
ptr::null_mut,
slice, thread,
time::Duration,
@@ -20,6 +19,7 @@
};
use super::{errno_result, Result};
+use crate::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, RawDescriptor};
const POLL_CONTEXT_MAX_EVENTS: usize = 16;
@@ -305,7 +305,7 @@
return errno_result();
}
Ok(EpollContext {
- epoll_ctx: unsafe { File::from_raw_fd(epoll_fd) },
+ epoll_ctx: unsafe { File::from_raw_descriptor(epoll_fd) },
tokens: PhantomData,
})
}
@@ -315,7 +315,7 @@
///
/// This is equivalent to calling `new` followed by `add_many`. If there is an error, this will
/// return the error instead of the new context.
- pub fn build_with(fd_tokens: &[(&dyn AsRawFd, T)]) -> Result<EpollContext<T>> {
+ pub fn build_with(fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<EpollContext<T>> {
let ctx = EpollContext::new()?;
ctx.add_many(fd_tokens)?;
Ok(ctx)
@@ -326,7 +326,7 @@
/// This is equivalent to calling `add` with each `fd` and `token`. If there are any errors,
/// this method will stop adding `fd`s and return the first error, leaving this context in a
/// undefined state.
- pub fn add_many(&self, fd_tokens: &[(&dyn AsRawFd, T)]) -> Result<()> {
+ pub fn add_many(&self, fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<()> {
for (fd, token) in fd_tokens {
self.add(*fd, T::from_raw_token(token.as_raw_token()))?;
}
@@ -339,7 +339,7 @@
/// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
/// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
/// FD number) added to this context, events will not be reported by `wait` anymore.
- pub fn add(&self, fd: &dyn AsRawFd, token: T) -> Result<()> {
+ pub fn add(&self, fd: &dyn AsRawDescriptor, token: T) -> Result<()> {
self.add_fd_with_events(fd, WatchingEvents::empty().set_read(), token)
}
@@ -351,7 +351,7 @@
/// FD number) added to this context, events will not be reported by `wait` anymore.
pub fn add_fd_with_events(
&self,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
events: WatchingEvents,
token: T,
) -> Result<()> {
@@ -363,9 +363,9 @@
// structure. Then we check the return value.
let ret = unsafe {
epoll_ctl(
- self.epoll_ctx.as_raw_fd(),
+ self.epoll_ctx.as_raw_descriptor(),
EPOLL_CTL_ADD,
- fd.as_raw_fd(),
+ fd.as_raw_descriptor(),
&mut evt,
)
};
@@ -377,7 +377,7 @@
/// If `fd` was previously added to this context, the watched events will be replaced with
/// `events` and the token associated with it will be replaced with the given `token`.
- pub fn modify(&self, fd: &dyn AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
+ pub fn modify(&self, fd: &dyn AsRawDescriptor, events: WatchingEvents, token: T) -> Result<()> {
let mut evt = epoll_event {
events: events.0,
u64: token.as_raw_token(),
@@ -386,9 +386,9 @@
// structure. Then we check the return value.
let ret = unsafe {
epoll_ctl(
- self.epoll_ctx.as_raw_fd(),
+ self.epoll_ctx.as_raw_descriptor(),
EPOLL_CTL_MOD,
- fd.as_raw_fd(),
+ fd.as_raw_descriptor(),
&mut evt,
)
};
@@ -404,14 +404,14 @@
/// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`.
/// Failure to do so will cause the `wait` method to always return immediately, causing ~100%
/// CPU load.
- pub fn delete(&self, fd: &dyn AsRawFd) -> Result<()> {
+ pub fn delete(&self, fd: &dyn AsRawDescriptor) -> Result<()> {
// Safe because we give a valid epoll FD and FD to stop watching. Then we check the return
// value.
let ret = unsafe {
epoll_ctl(
- self.epoll_ctx.as_raw_fd(),
+ self.epoll_ctx.as_raw_descriptor(),
EPOLL_CTL_DEL,
- fd.as_raw_fd(),
+ fd.as_raw_descriptor(),
null_mut(),
)
};
@@ -462,7 +462,7 @@
// pointer, which we trust the kernel to fill in properly.
unsafe {
handle_eintr_errno!(epoll_wait(
- self.epoll_ctx.as_raw_fd(),
+ self.epoll_ctx.as_raw_descriptor(),
&mut epoll_events[0],
max_events,
timeout_millis
@@ -482,15 +482,15 @@
}
}
-impl<T: PollToken> AsRawFd for EpollContext<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.epoll_ctx.as_raw_fd()
+impl<T: PollToken> AsRawDescriptor for EpollContext<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.epoll_ctx.as_raw_descriptor()
}
}
-impl<T: PollToken> IntoRawFd for EpollContext<T> {
- fn into_raw_fd(self) -> RawFd {
- self.epoll_ctx.into_raw_fd()
+impl<T: PollToken> IntoRawDescriptor for EpollContext<T> {
+ fn into_raw_descriptor(self) -> RawDescriptor {
+ self.epoll_ctx.into_raw_descriptor()
}
}
@@ -547,7 +547,7 @@
///
/// This is equivalent to calling `new` followed by `add_many`. If there is an error, this will
/// return the error instead of the new context.
- pub fn build_with(fd_tokens: &[(&dyn AsRawFd, T)]) -> Result<PollContext<T>> {
+ pub fn build_with(fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<PollContext<T>> {
let ctx = PollContext::new()?;
ctx.add_many(fd_tokens)?;
Ok(ctx)
@@ -558,7 +558,7 @@
/// This is equivalent to calling `add` with each `fd` and `token`. If there are any errors,
/// this method will stop adding `fd`s and return the first error, leaving this context in a
/// undefined state.
- pub fn add_many(&self, fd_tokens: &[(&dyn AsRawFd, T)]) -> Result<()> {
+ pub fn add_many(&self, fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<()> {
for (fd, token) in fd_tokens {
self.add(*fd, T::from_raw_token(token.as_raw_token()))?;
}
@@ -571,7 +571,7 @@
/// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
/// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
/// FD number) added to this context, events will not be reported by `wait` anymore.
- pub fn add(&self, fd: &dyn AsRawFd, token: T) -> Result<()> {
+ pub fn add(&self, fd: &dyn AsRawDescriptor, token: T) -> Result<()> {
self.add_fd_with_events(fd, WatchingEvents::empty().set_read(), token)
}
@@ -583,7 +583,7 @@
/// FD number) added to this context, events will not be reported by `wait` anymore.
pub fn add_fd_with_events(
&self,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
events: WatchingEvents,
token: T,
) -> Result<()> {
@@ -595,7 +595,7 @@
/// If `fd` was previously added to this context, the watched events will be replaced with
/// `events` and the token associated with it will be replaced with the given `token`.
- pub fn modify(&self, fd: &dyn AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
+ pub fn modify(&self, fd: &dyn AsRawDescriptor, events: WatchingEvents, token: T) -> Result<()> {
self.epoll_ctx.modify(fd, events, token)
}
@@ -605,7 +605,7 @@
/// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`.
/// Failure to do so will cause the `wait` method to always return immediately, causing ~100%
/// CPU load.
- pub fn delete(&self, fd: &dyn AsRawFd) -> Result<()> {
+ pub fn delete(&self, fd: &dyn AsRawDescriptor) -> Result<()> {
self.epoll_ctx.delete(fd)?;
self.hangups.set(0);
self.max_hangups.set(self.max_hangups.get() - 1);
@@ -677,15 +677,15 @@
}
}
-impl<T: PollToken> AsRawFd for PollContext<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.epoll_ctx.as_raw_fd()
+impl<T: PollToken> AsRawDescriptor for PollContext<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.epoll_ctx.as_raw_descriptor()
}
}
-impl<T: PollToken> IntoRawFd for PollContext<T> {
- fn into_raw_fd(self) -> RawFd {
- self.epoll_ctx.into_raw_fd()
+impl<T: PollToken> IntoRawDescriptor for PollContext<T> {
+ fn into_raw_descriptor(self) -> RawDescriptor {
+ self.epoll_ctx.into_raw_descriptor()
}
}
diff --git a/base/src/unix/shm.rs b/base/src/unix/shm.rs
index 1b96018..5640a20 100644
--- a/base/src/unix/shm.rs
+++ b/base/src/unix/shm.rs
@@ -19,6 +19,7 @@
use serde::{Deserialize, Serialize};
use super::{errno_result, Error, Result};
+use crate::{AsRawDescriptor, RawDescriptor};
/// A shared memory file descriptor and its size.
#[derive(Serialize, Deserialize)]
@@ -289,6 +290,12 @@
}
}
+impl AsRawDescriptor for SharedMemory {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.fd.as_raw_descriptor()
+ }
+}
+
impl From<SharedMemory> for File {
fn from(s: SharedMemory) -> File {
s.fd
diff --git a/base/src/unix/signalfd.rs b/base/src/unix/signalfd.rs
index c14c7b4..2d2ef90 100644
--- a/base/src/unix/signalfd.rs
+++ b/base/src/unix/signalfd.rs
@@ -16,7 +16,8 @@
use remain::sorted;
use thiserror::Error;
-use super::{signal, AsRawDescriptor, Error as ErrnoError, RawDescriptor};
+use super::{signal, Error as ErrnoError, RawDescriptor};
+use crate::descriptor::AsRawDescriptor;
#[sorted]
#[derive(Error, Debug)]
diff --git a/base/src/unix/timerfd.rs b/base/src/unix/timerfd.rs
index a09e80a..b6cb935 100644
--- a/base/src/unix/timerfd.rs
+++ b/base/src/unix/timerfd.rs
@@ -12,10 +12,7 @@
};
use sync::Mutex;
-use libc::{
- clock_getres, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC,
- {self},
-};
+use libc::{self, clock_getres, timerfd_create, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC};
use super::{errno_result, EventFd, FakeClock, Result};
@@ -92,20 +89,6 @@
Ok(count)
}
- /// Returns `true` if the timer is currently armed.
- pub fn is_armed(&self) -> Result<bool> {
- // Safe because we are zero-initializing a struct with only primitive member fields.
- let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
-
- // Safe because timerfd_gettime is trusted to only modify `spec`.
- let ret = unsafe { timerfd_gettime(self.as_raw_fd(), &mut spec) };
- if ret < 0 {
- return errno_result();
- }
-
- Ok(spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
- }
-
/// Disarms the timer.
pub fn clear(&self) -> Result<()> {
// Safe because we are zero-initializing a struct with only primitive member fields.
@@ -215,11 +198,6 @@
}
}
- /// Returns `true` if the timer is currently armed.
- pub fn is_armed(&self) -> Result<bool> {
- Ok(self.deadline_ns.is_some())
- }
-
/// Disarms the timer.
pub fn clear(&mut self) -> Result<()> {
self.deadline_ns = None;
@@ -256,14 +234,11 @@
#[test]
fn one_shot() {
let tfd = TimerFd::new().expect("failed to create timerfd");
- assert!(!tfd.is_armed().unwrap());
let dur = Duration::from_millis(200);
let now = Instant::now();
tfd.reset(dur, None).expect("failed to arm timer");
- assert!(tfd.is_armed().unwrap());
-
let count = tfd.wait().expect("unable to wait for timer");
assert_eq!(count, 1);
@@ -288,12 +263,10 @@
fn fake_one_shot() {
let clock = Arc::new(Mutex::new(FakeClock::new()));
let mut tfd = FakeTimerFd::new(clock.clone());
- assert!(!tfd.is_armed().unwrap());
let dur = Duration::from_nanos(200);
tfd.reset(dur, None).expect("failed to arm timer");
- assert!(tfd.is_armed().unwrap());
clock.lock().add_ns(200);
let count = tfd.wait().expect("unable to wait for timer");
diff --git a/base/src/unix/tube.rs b/base/src/unix/tube.rs
index beddafa..9583dde 100644
--- a/base/src/unix/tube.rs
+++ b/base/src/unix/tube.rs
@@ -9,11 +9,11 @@
time::Duration,
};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, SafeDescriptor};
use crate::{
platform::{deserialize_with_descriptors, SerializeDescriptors},
tube::{Error, RecvTube, Result, SendTube},
- AsRawDescriptor, FromRawDescriptor, RawDescriptor, ReadNotifier, SafeDescriptor, ScmSocket,
- UnixSeqpacket, UnsyncMarker,
+ RawDescriptor, ReadNotifier, ScmSocket, UnixSeqpacket, UnsyncMarker,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
diff --git a/base/src/wait_context.rs b/base/src/wait_context.rs
index 3a83c7e..ed03e4c 100644
--- a/base/src/wait_context.rs
+++ b/base/src/wait_context.rs
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::{os::unix::io::AsRawFd, time::Duration};
+use std::time::Duration;
+use crate::descriptor::AsRawDescriptor;
use crate::{
platform::{PollContext, PollToken, WatchingEvents},
- wrap_descriptor, AsRawDescriptor, RawDescriptor, Result,
+ RawDescriptor, Result,
};
use smallvec::SmallVec;
@@ -89,11 +90,8 @@
event_type: EventType,
token: T,
) -> Result<()> {
- self.0.add_fd_with_events(
- &wrap_descriptor(descriptor),
- convert_to_watching_events(event_type),
- token,
- )
+ self.0
+ .add_fd_with_events(descriptor, convert_to_watching_events(event_type), token)
}
/// Adds multiple triggers to the WaitContext.
@@ -112,17 +110,14 @@
event_type: EventType,
token: T,
) -> Result<()> {
- self.0.modify(
- &wrap_descriptor(descriptor),
- convert_to_watching_events(event_type),
- token,
- )
+ self.0
+ .modify(descriptor, convert_to_watching_events(event_type), token)
}
/// Removes the given handle from triggers registered in the WaitContext if
/// present.
pub fn delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {
- self.0.delete(&wrap_descriptor(descriptor))
+ self.0.delete(descriptor)
}
/// Waits for one or more of the registered triggers to become signaled.
@@ -147,7 +142,7 @@
impl<T: PollToken> AsRawDescriptor for WaitContext<T> {
fn as_raw_descriptor(&self) -> RawDescriptor {
- self.0.as_raw_fd()
+ self.0.as_raw_descriptor()
}
}
diff --git a/base/src/windows/clock.rs b/base/src/windows/clock.rs
index 4693b34..2d8d0ab 100644
--- a/base/src/windows/clock.rs
+++ b/base/src/windows/clock.rs
@@ -7,7 +7,8 @@
use std::time::{Duration, Instant};
-use super::{AsRawDescriptor, Event};
+use super::Event;
+use crate::descriptor::AsRawDescriptor;
#[derive(Debug, Copy, Clone)]
pub struct Clock(Instant);
diff --git a/base/src/windows/descriptor.rs b/base/src/windows/descriptor.rs
index 1b096df..2fa29af 100644
--- a/base/src/windows/descriptor.rs
+++ b/base/src/windows/descriptor.rs
@@ -2,22 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use super::{PollToken, Result};
+use super::Result;
use std::{
convert::TryFrom,
fs::File,
io::{Stderr, Stdin, Stdout},
- mem,
ops::Drop,
};
-use serde::{Deserialize, Serialize};
-
-// Windows imports
+use crate::descriptor::{
+ AsRawDescriptor, Descriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor,
+};
use std::{
ffi::CString,
marker::{Send, Sync},
- mem::{ManuallyDrop, MaybeUninit},
+ mem::MaybeUninit,
os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
sync::Once,
};
@@ -34,32 +33,6 @@
pub const INVALID_DESCRIPTOR: RawDescriptor = INVALID_HANDLE_VALUE;
-/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
-pub trait IntoRawDescriptor {
- fn into_raw_descriptor(self) -> RawDescriptor;
-}
-
-/// Trait for returning the underlying raw descriptor, without giving up ownership of the
-/// descriptor.
-pub trait AsRawDescriptor {
- fn as_raw_descriptor(&self) -> RawDescriptor;
-}
-
-pub trait FromRawDescriptor {
- /// # Safety
- /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
- /// `from_raw_descriptor`
- unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
-}
-
-/// Wraps a RawDescriptor and safely closes it when self falls out of scope.
-#[derive(Serialize, Deserialize, Debug, Eq)]
-#[serde(transparent)]
-pub struct SafeDescriptor {
- #[serde(with = "super::with_raw_descriptor")]
- descriptor: RawDescriptor,
-}
-
impl PartialEq for SafeDescriptor {
fn eq(&self, other: &Self) -> bool {
return compare_object_handles(self.descriptor, other.as_raw_descriptor());
@@ -72,26 +45,6 @@
}
}
-impl AsRawDescriptor for SafeDescriptor {
- fn as_raw_descriptor(&self) -> RawDescriptor {
- self.descriptor
- }
-}
-
-impl IntoRawDescriptor for SafeDescriptor {
- fn into_raw_descriptor(self) -> RawDescriptor {
- let descriptor = self.descriptor;
- mem::forget(self);
- descriptor
- }
-}
-
-impl FromRawDescriptor for SafeDescriptor {
- unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
- SafeDescriptor { descriptor }
- }
-}
-
impl AsRawHandle for SafeDescriptor {
fn as_raw_handle(&self) -> RawHandle {
self.as_raw_descriptor()
@@ -140,36 +93,6 @@
}
}
-impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
- type Error = std::io::Error;
-
- /// Clones the underlying descriptor (handle), internally creating a new descriptor.
- ///
- /// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this
- /// function on IO completion ports, sockets, or pseudo-handles (except those from
- /// GetCurrentProcess or GetCurrentThread). See
- /// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
- /// for further details.
- ///
- /// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some
- /// adjustments to smooth those edges.
- fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
- // Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
- //
- // Note that we are cloning the underlying raw descriptor since we have no guarantee of
- // its existence after this function returns.
- let rd_as_safe_desc = ManuallyDrop::new(unsafe {
- SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
- });
-
- // We have to clone rd because we have no guarantee ownership was transferred (rd is
- // borrowed).
- rd_as_safe_desc
- .try_clone()
- .map_err(|e| Self::Error::from_raw_os_error(e.errno()))
- }
-}
-
impl SafeDescriptor {
/// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
/// share the same underlying count within the kernel.
@@ -187,35 +110,6 @@
unsafe impl Send for SafeDescriptor {}
unsafe impl Sync for SafeDescriptor {}
-impl From<File> for SafeDescriptor {
- fn from(f: File) -> SafeDescriptor {
- // Safe because we own the File at this point.
- unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
- }
-}
-
-/// For use cases where a simple wrapper around a RawDescriptor is needed.
-/// This is a simply a wrapper and does not manage the lifetime of the descriptor.
-/// Most usages should prefer SafeDescriptor or using a RawDescriptor directly
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
-#[repr(transparent)]
-pub struct Descriptor(pub RawDescriptor);
-impl AsRawDescriptor for Descriptor {
- fn as_raw_descriptor(&self) -> RawDescriptor {
- self.0
- }
-}
-
-impl PollToken for Descriptor {
- fn as_raw_token(&self) -> u64 {
- self.0 as u64
- }
-
- fn from_raw_token(data: u64) -> Self {
- Descriptor(data as RawDescriptor)
- }
-}
-
// On Windows, RawHandles are represented by raw pointers but are opaque to the
// userspace and cannot be derefenced by rust code, and are therefore safe to
// send between threads.
@@ -267,7 +161,8 @@
#[test]
#[allow(clippy::eq_op)]
fn clone_equality() {
- use super::{Event, IntoRawDescriptor};
+ use super::Event;
+ use crate::descriptor::IntoRawDescriptor;
let evt = Event::new().unwrap();
let descriptor = unsafe { SafeDescriptor::from_raw_descriptor(evt.into_raw_descriptor()) };
diff --git a/base/src/windows/eventfd.rs b/base/src/windows/eventfd.rs
index 1d79698..b286668 100644
--- a/base/src/windows/eventfd.rs
+++ b/base/src/windows/eventfd.rs
@@ -10,10 +10,8 @@
use libc::{c_void, eventfd, read, write, POLLIN};
use serde::{Deserialize, Serialize};
-use crate::{
- duration_to_timespec, errno_result, AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor,
- RawDescriptor, Result, SafeDescriptor,
-};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
+use crate::{duration_to_timespec, errno_result, RawDescriptor, Result};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
/// A safe wrapper around a Linux eventfd (man 2 eventfd).
diff --git a/base/src/windows/events.rs b/base/src/windows/events.rs
index 9ef922a..dda0ba8 100644
--- a/base/src/windows/events.rs
+++ b/base/src/windows/events.rs
@@ -4,7 +4,8 @@
use std::{clone::Clone, default::Default, marker::Copy};
-use super::{AsRawDescriptor, PollToken, RawDescriptor};
+use super::{PollToken, RawDescriptor};
+use crate::descriptor::AsRawDescriptor;
#[path = "win/wait.rs"]
mod wait;
diff --git a/base/src/windows/file_traits.rs b/base/src/windows/file_traits.rs
index 24b52ef..e9b9302 100644
--- a/base/src/windows/file_traits.rs
+++ b/base/src/windows/file_traits.rs
@@ -3,7 +3,8 @@
// found in the LICENSE file.
pub use super::win::file_traits::*;
-use super::{AsRawDescriptor, RawDescriptor};
+use super::RawDescriptor;
+use crate::descriptor::AsRawDescriptor;
use std::{
fs::File,
diff --git a/base/src/windows/ioctl.rs b/base/src/windows/ioctl.rs
index 09d0e18..869f804 100644
--- a/base/src/windows/ioctl.rs
+++ b/base/src/windows/ioctl.rs
@@ -6,7 +6,7 @@
use std::os::raw::*;
-use super::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
/// Raw macro to declare the expression that calculates an ioctl number
#[macro_export]
diff --git a/base/src/windows/mmap.rs b/base/src/windows/mmap.rs
index 08ac6ce..fbce506 100644
--- a/base/src/windows/mmap.rs
+++ b/base/src/windows/mmap.rs
@@ -14,7 +14,9 @@
use libc::{c_int, c_uint, c_void};
-use super::{AsRawDescriptor, Descriptor, ExternalMapping, RawDescriptor};
+use super::RawDescriptor;
+use crate::descriptor::{AsRawDescriptor, Descriptor};
+use crate::external_mapping::ExternalMapping;
#[path = "win/mmap.rs"]
mod mmap_platform;
diff --git a/base/src/windows/mod.rs b/base/src/windows/mod.rs
index e3b5bee..09148e8 100644
--- a/base/src/windows/mod.rs
+++ b/base/src/windows/mod.rs
@@ -18,7 +18,6 @@
#[path = "win/console.rs"]
mod console;
mod descriptor;
-mod descriptor_reflection;
#[path = "win/event.rs"]
mod event;
mod events;
@@ -44,15 +43,15 @@
mod write_zeroes;
-pub use crate::common::{Error, Result, *};
+pub use crate::descriptor_reflection::{
+ deserialize_with_descriptors, with_as_descriptor, with_raw_descriptor, FileSerdeWrapper,
+ SerializeDescriptors,
+};
+pub use crate::errno::{Error, Result, *};
pub use base_poll_token_derive::*;
pub use clock::{Clock, FakeClock};
pub use console::*;
pub use descriptor::*;
-pub use descriptor_reflection::{
- deserialize_with_descriptors, with_as_descriptor, with_raw_descriptor, FileSerdeWrapper,
- SerializeDescriptors,
-};
pub use event::*;
pub use events::*;
pub use get_filesystem_type::*;
diff --git a/base/src/windows/notifiers.rs b/base/src/windows/notifiers.rs
index 3ab4640..71dbdfa 100644
--- a/base/src/windows/notifiers.rs
+++ b/base/src/windows/notifiers.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 super::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
pub trait ReadNotifier {
/// Gets a descriptor that can be used in EventContext to wait for events to be available (e.g.
diff --git a/base/src/windows/shm.rs b/base/src/windows/shm.rs
index 801e348..d944832 100644
--- a/base/src/windows/shm.rs
+++ b/base/src/windows/shm.rs
@@ -4,9 +4,8 @@
use std::ffi::CString;
-use super::{
- AsRawDescriptor, IntoRawDescriptor, MemoryMapping, RawDescriptor, Result, SafeDescriptor,
-};
+use super::{MemoryMapping, RawDescriptor, Result};
+use crate::descriptor::{AsRawDescriptor, IntoRawDescriptor, SafeDescriptor};
use libc::EINVAL;
use std::io::{
Error, ErrorKind, Read, Seek, SeekFrom, Write, {self},
diff --git a/base/src/windows/stream_channel.rs b/base/src/windows/stream_channel.rs
index 4ec139a..5b142b5 100644
--- a/base/src/windows/stream_channel.rs
+++ b/base/src/windows/stream_channel.rs
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use super::{AsRawDescriptor, RawDescriptor};
+use super::RawDescriptor;
+use crate::descriptor::AsRawDescriptor;
use std::io;
#[path = "win/stream_channel.rs"]
mod stream_channel;
diff --git a/base/src/windows/syslog.rs b/base/src/windows/syslog.rs
index c146539..eb54575 100644
--- a/base/src/windows/syslog.rs
+++ b/base/src/windows/syslog.rs
@@ -21,7 +21,8 @@
//! ```
pub use super::win::syslog::PlatformSyslog;
-use super::{AsRawDescriptor, RawDescriptor};
+use super::RawDescriptor;
+use crate::descriptor::AsRawDescriptor;
use crate::{syslog_lock, CHRONO_TIMESTAMP_FIXED_FMT};
use serde::{Deserialize, Serialize};
use std::{
diff --git a/base/src/windows/timer.rs b/base/src/windows/timer.rs
index 312f8c5..a20c931 100644
--- a/base/src/windows/timer.rs
+++ b/base/src/windows/timer.rs
@@ -8,10 +8,8 @@
};
use sync::Mutex;
-use super::{
- AsRawDescriptor, Event, EventReadResult, FakeClock, FromRawDescriptor, IntoRawDescriptor,
- RawDescriptor, Result, SafeDescriptor,
-};
+use super::{Event, EventReadResult, FakeClock, RawDescriptor, Result};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
#[path = "win/timer.rs"]
mod timer_platform;
@@ -153,11 +151,6 @@
}
}
- /// Returns `true` if the timer is currently armed.
- pub fn is_armed(&self) -> Result<bool> {
- Ok(self.deadline_ns.is_some())
- }
-
/// Disarms the timer.
pub fn clear(&mut self) -> Result<()> {
self.deadline_ns = None;
@@ -278,12 +271,10 @@
fn fake_one_shot() {
let clock = Arc::new(Mutex::new(FakeClock::new()));
let mut tfd = FakeTimer::new(clock.clone());
- assert_eq!(tfd.is_armed().unwrap(), false);
let dur = Duration::from_nanos(200);
tfd.reset(dur, None).expect("failed to arm timer");
- assert_eq!(tfd.is_armed().unwrap(), true);
clock.lock().add_ns(200);
let result = tfd.wait(None).expect("unable to wait for timer");
@@ -295,11 +286,9 @@
fn fake_one_shot_timeout() {
let clock = Arc::new(Mutex::new(FakeClock::new()));
let mut tfd = FakeTimer::new(clock.clone());
- assert_eq!(tfd.is_armed().unwrap(), false);
let dur = Duration::from_nanos(200);
tfd.reset(dur, None).expect("failed to arm timer");
- assert_eq!(tfd.is_armed().unwrap(), true);
clock.lock().add_ns(100);
let result = tfd
diff --git a/base/src/windows/tube.rs b/base/src/windows/tube.rs
index e6e8189..3f59ffa 100644
--- a/base/src/windows/tube.rs
+++ b/base/src/windows/tube.rs
@@ -9,13 +9,11 @@
time::Duration,
};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, SafeDescriptor};
use crate::{
- platform::{
- deserialize_with_descriptors, AsRawDescriptor, RawDescriptor, SerializeDescriptors,
- },
+ platform::{deserialize_with_descriptors, RawDescriptor, SerializeDescriptors},
tube::{Error, RecvTube, Result, SendTube},
- BlockingMode, CloseNotifier, FramingMode, FromRawDescriptor, PollToken, ReadNotifier,
- SafeDescriptor, StreamChannel,
+ BlockingMode, CloseNotifier, FramingMode, PollToken, ReadNotifier, StreamChannel,
};
use data_model::DataInit;
use lazy_static::lazy_static;
@@ -139,7 +137,7 @@
}
pub fn recv<T: DeserializeOwned>(&self) -> Result<T> {
- deserialize_and_recv(|buf| (&*&self.socket).read(buf))
+ deserialize_and_recv(|buf| (&self.socket).read(buf))
}
/// NOTE: On Windows this will only succeed if called on a server pipe. See #pair
diff --git a/base/src/windows/win/console.rs b/base/src/windows/win/console.rs
index 9ea6f1d..7957c5d 100644
--- a/base/src/windows/win/console.rs
+++ b/base/src/windows/win/console.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 super::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
use std::io::{stdin, Error, Read, Result};
use winapi::{
shared::{minwindef::LPVOID, ntdef::NULL},
diff --git a/base/src/windows/win/event.rs b/base/src/windows/win/event.rs
index 77e7b98..c750000 100644
--- a/base/src/windows/win/event.rs
+++ b/base/src/windows/win/event.rs
@@ -29,10 +29,8 @@
},
};
-use super::{
- errno_result, AsRawDescriptor, Error, FromRawDescriptor, IntoRawDescriptor, RawDescriptor,
- Result, SafeDescriptor,
-};
+use super::{errno_result, Error, RawDescriptor, Result};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
/// A safe wrapper around Windows synchapi methods used to mimic Linux eventfd (man 2 eventfd).
/// Since the eventfd isn't using "EFD_SEMAPHORE", we don't need to keep count so we can just use
diff --git a/base/src/windows/win/file_util.rs b/base/src/windows/win/file_util.rs
index 7561ff8..eed42bb 100644
--- a/base/src/windows/win/file_util.rs
+++ b/base/src/windows/win/file_util.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 super::super::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
use std::{ffi::c_void, io};
pub use winapi::um::winioctl::FSCTL_SET_SPARSE;
diff --git a/base/src/windows/win/ioctl.rs b/base/src/windows/win/ioctl.rs
index 31e3530..5c04f56 100644
--- a/base/src/windows/win/ioctl.rs
+++ b/base/src/windows/win/ioctl.rs
@@ -6,7 +6,7 @@
use std::{mem::size_of, os::raw::*, ptr::null_mut};
-use super::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
pub use winapi::um::winioctl::{CTL_CODE, FILE_ANY_ACCESS, METHOD_BUFFERED};
use winapi::um::{errhandlingapi::GetLastError, ioapiset::DeviceIoControl};
diff --git a/base/src/windows/win/mmap.rs b/base/src/windows/win/mmap.rs
index 4770d7a..dbd4310 100644
--- a/base/src/windows/win/mmap.rs
+++ b/base/src/windows/win/mmap.rs
@@ -19,10 +19,8 @@
FlushViewOfFile, MapViewOfFile, MapViewOfFileEx, UnmapViewOfFile, FILE_MAP_READ, FILE_MAP_WRITE,
};
-use super::{
- super::{AsRawDescriptor, RawDescriptor},
- Error, MappedRegion, MemoryMapping, Protection, Result,
-};
+use super::{super::RawDescriptor, Error, MappedRegion, MemoryMapping, Protection, Result};
+use crate::descriptor::AsRawDescriptor;
use crate::warn;
pub(super) const PROT_NONE: c_uint = 0;
@@ -304,9 +302,10 @@
#[cfg(test)]
mod tests {
use super::{
- super::super::{pagesize, FromRawDescriptor, SharedMemory},
+ super::super::{pagesize, SharedMemory},
*,
};
+ use crate::descriptor::FromRawDescriptor;
use data_model::{VolatileMemory, VolatileMemoryError};
use std::ptr;
use winapi::shared::winerror;
diff --git a/base/src/windows/win/mod.rs b/base/src/windows/win/mod.rs
index 080b184..1fcd891 100644
--- a/base/src/windows/win/mod.rs
+++ b/base/src/windows/win/mod.rs
@@ -14,9 +14,8 @@
mod file_util;
pub use file_util::*;
-use super::{
- errno_result, pid_t, AsRawDescriptor, Error, FromRawDescriptor, Result, SafeDescriptor,
-};
+use super::{errno_result, pid_t, Error, Result};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, SafeDescriptor};
use serde::{Deserialize, Serialize};
use std::{
fs::{File, OpenOptions},
diff --git a/base/src/windows/win/named_pipes.rs b/base/src/windows/win/named_pipes.rs
index 02bd33f..57bd679 100644
--- a/base/src/windows/win/named_pipes.rs
+++ b/base/src/windows/win/named_pipes.rs
@@ -14,9 +14,8 @@
sync::atomic::{AtomicUsize, Ordering},
};
-use super::{
- AsRawDescriptor, Event, FromRawDescriptor, IntoRawDescriptor, RawDescriptor, SafeDescriptor,
-};
+use super::{Event, RawDescriptor};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
use serde::{Deserialize, Serialize};
use win_util::{SecurityAttributes, SelfRelativeSecurityDescriptor};
use winapi::{
diff --git a/base/src/windows/win/punch_hole.rs b/base/src/windows/win/punch_hole.rs
index 3cc3f91..654f5f4 100644
--- a/base/src/windows/win/punch_hole.rs
+++ b/base/src/windows/win/punch_hole.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 super::super::AsRawDescriptor;
+use crate::descriptor::AsRawDescriptor;
use std::io::{
Error, {self},
};
diff --git a/base/src/windows/win/shm.rs b/base/src/windows/win/shm.rs
index c9d41f1..b4cfb1b 100644
--- a/base/src/windows/win/shm.rs
+++ b/base/src/windows/win/shm.rs
@@ -6,10 +6,8 @@
use win_util::create_file_mapping;
use winapi::um::winnt::PAGE_EXECUTE_READWRITE;
-use super::super::{
- shm::SharedMemory, AsRawDescriptor, FromRawDescriptor, MemoryMapping, MmapError, Result,
- SafeDescriptor,
-};
+use super::super::{shm::SharedMemory, MemoryMapping, MmapError, Result};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, SafeDescriptor};
impl SharedMemory {
/// Creates a new shared memory file mapping with zero size.
diff --git a/base/src/windows/win/stream_channel.rs b/base/src/windows/win/stream_channel.rs
index f675219..49b3f30 100644
--- a/base/src/windows/win/stream_channel.rs
+++ b/base/src/windows/win/stream_channel.rs
@@ -7,8 +7,9 @@
PipeConnection, {self},
},
stream_channel::{BlockingMode, FramingMode},
- AsRawDescriptor, CloseNotifier, Event, MultiProcessMutex, RawDescriptor, ReadNotifier, Result,
+ CloseNotifier, Event, MultiProcessMutex, RawDescriptor, ReadNotifier, Result,
};
+use crate::descriptor::AsRawDescriptor;
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use std::{cell::RefCell, io, sync::Arc};
use sync::Mutex;
@@ -451,7 +452,7 @@
let writer = std::thread::spawn(move || {
let buf = [0u8; 100];
for _ in 0..NUM_OPS {
- writer.write(&buf).unwrap();
+ assert_eq!(writer.write(&buf).unwrap(), buf.len());
}
writer
});
diff --git a/base/src/windows/win/timer.rs b/base/src/windows/win/timer.rs
index 62807ab..24d3d2d 100644
--- a/base/src/windows/win/timer.rs
+++ b/base/src/windows/win/timer.rs
@@ -18,12 +18,10 @@
};
use super::{
- super::{
- errno_result, win::nt_query_timer_resolution, AsRawDescriptor, FromRawDescriptor, Result,
- SafeDescriptor,
- },
+ super::{errno_result, win::nt_query_timer_resolution, Result},
Timer, WaitResult,
};
+use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, SafeDescriptor};
impl AsRawHandle for Timer {
fn as_raw_handle(&self) -> RawHandle {
diff --git a/base/src/windows/win/wait.rs b/base/src/windows/win/wait.rs
index 5a601d8..892cda3 100644
--- a/base/src/windows/win/wait.rs
+++ b/base/src/windows/win/wait.rs
@@ -19,9 +19,9 @@
};
use super::super::{
- errno_result, AsRawDescriptor, Descriptor, Error, Event, EventTrigger, EventType, PollToken,
- Result, TriggeredEvent,
+ errno_result, Error, Event, EventTrigger, EventType, PollToken, Result, TriggeredEvent,
};
+use crate::descriptor::{AsRawDescriptor, Descriptor};
use crate::error;
// MAXIMUM_WAIT_OBJECTS = 64
pub const MAXIMUM_WAIT_OBJECTS: usize = winapi::um::winnt::MAXIMUM_WAIT_OBJECTS as usize;
diff --git a/ci/kokoro/build-merge-into-chromeos.sh b/ci/kokoro/build-merge-into-chromeos.sh
index 9ecc36e..2e84c68 100755
--- a/ci/kokoro/build-merge-into-chromeos.sh
+++ b/ci/kokoro/build-merge-into-chromeos.sh
@@ -207,9 +207,6 @@
echo "Not enough commits to merge."
fi
- # Rebase to integrate cherry-picks. Always resolve conflicts with content from origin/main.
- git rebase --rebase-merges -X theirs
-
upload_with_retries
echo "Abandoning previous dry runs"
diff --git a/ci/kokoro/windows/crosvm_build.bat b/ci/kokoro/windows/crosvm_build.bat
index 01c1691..942e477 100644
--- a/ci/kokoro/windows/crosvm_build.bat
+++ b/ci/kokoro/windows/crosvm_build.bat
@@ -41,8 +41,14 @@
echo [%TIME%] Python version:
py --version
+py -m pip install argh --user
+
+echo [%TIME%] Calling crosvm\tools\clippy
+py .\tools\clippy
+if %ERRORLEVEL% neq 0 ( exit /b %ERRORLEVEL% )
+
echo [%TIME%] Calling crosvm\build_test.py
-py ./tools\impl/test_runner.py --arch x86_64 -v
+py ./tools\impl/test_runner.py --arch win64 -v
if %ERRORLEVEL% neq 0 ( exit /b %ERRORLEVEL% )
exit /b %ERRORLEVEL%
diff --git a/common/cros_async/src/timer.rs b/common/cros_async/src/timer.rs
index f9624e0..2bc3ebd 100644
--- a/common/cros_async/src/timer.rs
+++ b/common/cros_async/src/timer.rs
@@ -69,14 +69,11 @@
async fn this_test(ex: &URingExecutor) {
let tfd = TimerFd::new().expect("failed to create timerfd");
- assert_eq!(tfd.is_armed().unwrap(), false);
let dur = Duration::from_millis(200);
let now = Instant::now();
tfd.reset(dur, None).expect("failed to arm timer");
- assert_eq!(tfd.is_armed().unwrap(), true);
-
let t = TimerAsync::new_uring(tfd, ex).unwrap();
let count = t.next_val().await.expect("unable to wait for timer");
@@ -92,14 +89,11 @@
fn one_shot_fd() {
async fn this_test(ex: &FdExecutor) {
let tfd = TimerFd::new().expect("failed to create timerfd");
- assert_eq!(tfd.is_armed().unwrap(), false);
let dur = Duration::from_millis(200);
let now = Instant::now();
tfd.reset(dur, None).expect("failed to arm timer");
- assert_eq!(tfd.is_armed().unwrap(), true);
-
let t = TimerAsync::new_poll(tfd, ex).unwrap();
let count = t.next_val().await.expect("unable to wait for timer");
diff --git a/common/p9/src/server/tests.rs b/common/p9/src/server/tests.rs
index a273429..c910706 100644
--- a/common/p9/src/server/tests.rs
+++ b/common/p9/src/server/tests.rs
@@ -105,6 +105,8 @@
impl<'a> DirEntry<'a> {
// Creates `self` in the path given by `dir`.
+ // TODO(b/228627457): clippy is warning about the `Cow` below, but it is necessary
+ #[allow(clippy::ptr_arg)]
fn create(&self, dir: &mut Cow<Path>) {
match *self {
DirEntry::File { name, content } => {
diff --git a/common/sys_util/src/fork.rs b/common/sys_util/src/fork.rs
deleted file mode 100644
index 3c103a8..0000000
--- a/common/sys_util/src/fork.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2017 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::{fs, io, path::Path, process, result};
-
-use libc::{c_long, pid_t, syscall, SYS_clone, CLONE_NEWPID, CLONE_NEWUSER, SIGCHLD};
-use remain::sorted;
-use thiserror::Error;
-
-use super::errno_result;
-
-/// Controls what namespace `clone_process` will have. See NAMESPACES(7).
-#[repr(u32)]
-pub enum CloneNamespace {
- /// The new process will inherit the namespace from the old process.
- Inherit = 0,
- /// The new process with be in a new user and PID namespace.
- NewUserPid = CLONE_NEWUSER as u32 | CLONE_NEWPID as u32,
-}
-
-#[sorted]
-#[derive(Error, Debug)]
-pub enum CloneError {
- /// There was an error trying to iterate this process's threads.
- #[error("error iterating this process's threads")]
- IterateTasks(io::Error),
- /// There are multiple threads running. The `usize` indicates how many threads.
- #[error("multiple threads are already running")]
- Multithreaded(usize),
- /// There was an error while cloning.
- #[error("error while cloning")]
- Sys(super::Error),
-}
-
-unsafe fn do_clone(flags: i32) -> super::Result<pid_t> {
- // Forking is unsafe, this function must be unsafe as there is no way to guarantee safety
- // without more context about the state of the program.
- let pid = syscall(SYS_clone as c_long, flags | SIGCHLD as i32, 0);
- if pid < 0 {
- errno_result()
- } else {
- Ok(pid as pid_t)
- }
-}
-
-fn count_dir_entries<P: AsRef<Path>>(path: P) -> io::Result<usize> {
- Ok(fs::read_dir(path)?.count())
-}
-
-/// Clones this process and calls a closure in the new process.
-///
-/// After `post_clone_cb` returns or panics, the new process exits. Similar to how a `fork` syscall
-/// works, the new process is the same as the current process with the exception of the namespace
-/// controlled with the `ns` argument.
-///
-/// # Arguments
-/// * `ns` - What namespace the new process will have (see NAMESPACES(7)).
-/// * `post_clone_cb` - Callback to run in the new process
-pub fn clone_process<F>(ns: CloneNamespace, post_clone_cb: F) -> result::Result<pid_t, CloneError>
-where
- F: FnOnce(),
-{
- match count_dir_entries("/proc/self/task") {
- Ok(1) => {}
- Ok(thread_count) => {
- // Test cfg gets a free pass on this because tests generally have multiple independent
- // test threads going.
- let _ = thread_count;
- #[cfg(not(test))]
- return Err(CloneError::Multithreaded(thread_count));
- }
- Err(e) => return Err(CloneError::IterateTasks(e)),
- }
- // Forking is considered unsafe in mutlithreaded programs, but we just checked for other threads
- // in this process. We also only allow valid flags from CloneNamespace and check the return
- // result for errors. We also never let the cloned process return from this function.
- let ret = unsafe { do_clone(ns as i32) }.map_err(CloneError::Sys)?;
- if ret == 0 {
- struct ExitGuard;
- impl Drop for ExitGuard {
- fn drop(&mut self) {
- process::exit(101);
- }
- }
- // Prevents a panic in post_clone_cb from bypassing the process::exit.
- #[allow(unused_variables)]
- let exit_guard = ExitGuard {};
- post_clone_cb();
- // ! Never returns
- process::exit(0);
- }
-
- Ok(ret)
-}
-
-#[cfg(test)]
-mod tests {
- use super::{
- super::{getpid, EventFd},
- *,
- };
-
- fn wait_process(pid: libc::pid_t) -> super::super::Result<libc::c_int> {
- let mut status: libc::c_int = 0;
- unsafe {
- if libc::waitpid(pid, &mut status as *mut libc::c_int, 0) < 0 {
- errno_result()
- } else {
- Ok(libc::WEXITSTATUS(status))
- }
- }
- }
-
- #[test]
- fn pid_diff() {
- let evt_fd = EventFd::new().expect("failed to create EventFd");
- let evt_fd_fork = evt_fd.try_clone().expect("failed to clone EventFd");
- let pid = getpid();
- clone_process(CloneNamespace::Inherit, || {
- // checks that this is a genuine fork with a new PID
- if pid != getpid() {
- evt_fd_fork.write(1).unwrap()
- } else {
- evt_fd_fork.write(2).unwrap()
- }
- })
- .expect("failed to clone");
- assert_eq!(evt_fd.read(), Ok(1));
- }
-
- // This test can deadlock occasionally when running in the builders VM. It
- // is disabled for now.
- // TODO(b/179924844): Investigate the issue and re-enable
- #[test]
- #[ignore]
- fn panic_safe() {
- let pid = getpid();
- assert_ne!(pid, 0);
-
- let clone_pid = clone_process(CloneNamespace::Inherit, || {
- panic!();
- })
- .expect("failed to clone");
-
- // This should never happen;
- if pid != getpid() {
- process::exit(2);
- }
-
- let status = wait_process(clone_pid).expect("wait_process failed");
- assert!(status == 101 || status == 0);
- }
-}
diff --git a/common/sys_util/src/lib.rs b/common/sys_util/src/lib.rs
index 7877e39..3f2841e 100644
--- a/common/sys_util/src/lib.rs
+++ b/common/sys_util/src/lib.rs
@@ -31,7 +31,6 @@
mod eventfd;
mod file_flags;
pub mod file_traits;
-mod fork;
mod get_filesystem_type;
mod mmap;
pub mod net;
@@ -63,7 +62,6 @@
};
pub use eventfd::*;
pub use file_flags::*;
-pub use fork::*;
pub use get_filesystem_type::*;
pub use ioctl::*;
pub use mmap::*;
diff --git a/common/sys_util/src/timerfd.rs b/common/sys_util/src/timerfd.rs
index a09e80a..b6cb935 100644
--- a/common/sys_util/src/timerfd.rs
+++ b/common/sys_util/src/timerfd.rs
@@ -12,10 +12,7 @@
};
use sync::Mutex;
-use libc::{
- clock_getres, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC,
- {self},
-};
+use libc::{self, clock_getres, timerfd_create, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC};
use super::{errno_result, EventFd, FakeClock, Result};
@@ -92,20 +89,6 @@
Ok(count)
}
- /// Returns `true` if the timer is currently armed.
- pub fn is_armed(&self) -> Result<bool> {
- // Safe because we are zero-initializing a struct with only primitive member fields.
- let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
-
- // Safe because timerfd_gettime is trusted to only modify `spec`.
- let ret = unsafe { timerfd_gettime(self.as_raw_fd(), &mut spec) };
- if ret < 0 {
- return errno_result();
- }
-
- Ok(spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
- }
-
/// Disarms the timer.
pub fn clear(&self) -> Result<()> {
// Safe because we are zero-initializing a struct with only primitive member fields.
@@ -215,11 +198,6 @@
}
}
- /// Returns `true` if the timer is currently armed.
- pub fn is_armed(&self) -> Result<bool> {
- Ok(self.deadline_ns.is_some())
- }
-
/// Disarms the timer.
pub fn clear(&mut self) -> Result<()> {
self.deadline_ns = None;
@@ -256,14 +234,11 @@
#[test]
fn one_shot() {
let tfd = TimerFd::new().expect("failed to create timerfd");
- assert!(!tfd.is_armed().unwrap());
let dur = Duration::from_millis(200);
let now = Instant::now();
tfd.reset(dur, None).expect("failed to arm timer");
- assert!(tfd.is_armed().unwrap());
-
let count = tfd.wait().expect("unable to wait for timer");
assert_eq!(count, 1);
@@ -288,12 +263,10 @@
fn fake_one_shot() {
let clock = Arc::new(Mutex::new(FakeClock::new()));
let mut tfd = FakeTimerFd::new(clock.clone());
- assert!(!tfd.is_armed().unwrap());
let dur = Duration::from_nanos(200);
tfd.reset(dur, None).expect("failed to arm timer");
- assert!(tfd.is_armed().unwrap());
clock.lock().add_ns(200);
let count = tfd.wait().expect("unable to wait for timer");
diff --git a/cros_async/Android.bp b/cros_async/Android.bp
index 0ace215..3ea2351 100644
--- a/cros_async/Android.bp
+++ b/cros_async/Android.bp
@@ -16,7 +16,7 @@
host_supported: true,
crate_name: "cros_async",
cargo_env_compat: true,
- cargo_pkg_version: "0.1.0",
+ cargo_pkg_version: "0.1.1",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
@@ -57,7 +57,7 @@
host_supported: true,
crate_name: "cros_async",
cargo_env_compat: true,
- cargo_pkg_version: "0.1.0",
+ cargo_pkg_version: "0.1.1",
srcs: ["src/lib.rs"],
edition: "2021",
rustlibs: [
diff --git a/cros_async/Cargo.toml b/cros_async/Cargo.toml
index 57ee805..b081b74 100644
--- a/cros_async/Cargo.toml
+++ b/cros_async/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cros_async"
-version = "0.1.0"
+version = "0.1.1"
authors = ["The Chromium OS Authors"]
edition = "2021"
diff --git a/cros_async/src/timer.rs b/cros_async/src/timer.rs
index 52df705..6ce3ff7 100644
--- a/cros_async/src/timer.rs
+++ b/cros_async/src/timer.rs
@@ -69,14 +69,11 @@
async fn this_test(ex: &URingExecutor) {
let tfd = TimerFd::new().expect("failed to create timerfd");
- assert_eq!(tfd.is_armed().unwrap(), false);
let dur = Duration::from_millis(200);
let now = Instant::now();
tfd.reset(dur, None).expect("failed to arm timer");
- assert_eq!(tfd.is_armed().unwrap(), true);
-
let t = TimerAsync::new_uring(tfd, ex).unwrap();
let count = t.next_val().await.expect("unable to wait for timer");
@@ -92,14 +89,11 @@
fn one_shot_fd() {
async fn this_test(ex: &FdExecutor) {
let tfd = TimerFd::new().expect("failed to create timerfd");
- assert_eq!(tfd.is_armed().unwrap(), false);
let dur = Duration::from_millis(200);
let now = Instant::now();
tfd.reset(dur, None).expect("failed to arm timer");
- assert_eq!(tfd.is_armed().unwrap(), true);
-
let t = TimerAsync::new_poll(tfd, ex).unwrap();
let count = t.next_val().await.expect("unable to wait for timer");
diff --git a/crosvm-fuzz/block_fuzzer.rs b/crosvm-fuzz/block_fuzzer.rs
index b944d1f..de0f798 100644
--- a/crosvm-fuzz/block_fuzzer.rs
+++ b/crosvm-fuzz/block_fuzzer.rs
@@ -12,6 +12,7 @@
use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::{base_features, Block, Interrupt, Queue, VirtioDevice};
+use devices::IrqLevelEvent;
use hypervisor::ProtectionType;
use vm_memory::{GuestAddress, GuestMemory};
@@ -87,8 +88,7 @@
mem,
Interrupt::new(
Arc::new(AtomicUsize::new(0)),
- Event::new().unwrap(),
- Event::new().unwrap(),
+ IrqLevelEvent::new().unwrap(),
None, // msix_config
0xFFFF, // VIRTIO_MSI_NO_VECTOR
),
diff --git a/crosvm_control/src/lib.rs b/crosvm_control/src/lib.rs
index ca2ffa8..3721596 100644
--- a/crosvm_control/src/lib.rs
+++ b/crosvm_control/src/lib.rs
@@ -294,8 +294,7 @@
impl From<&BalloonStats> for BalloonStatsFfi {
fn from(other: &BalloonStats) -> Self {
- let convert =
- |x: Option<u64>| -> i64 { x.map(|y| y.try_into().ok()).flatten().unwrap_or(-1) };
+ let convert = |x: Option<u64>| -> i64 { x.and_then(|y| y.try_into().ok()).unwrap_or(-1) };
Self {
swap_in: convert(other.swap_in),
swap_out: convert(other.swap_out),
diff --git a/crosvm_plugin/crosvm.h b/crosvm_plugin/crosvm.h
index d1bea2a..e18e9f8 100644
--- a/crosvm_plugin/crosvm.h
+++ b/crosvm_plugin/crosvm.h
@@ -175,6 +175,11 @@
#endif
/*
+ * Gets fd for the gpu server.
+ */
+int crosvm_get_render_server_fd(void);
+
+/*
* Gets the network configuration.
*/
int crosvm_net_get_config(struct crosvm*, struct crosvm_net_config*);
diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs
index 2378ee9..4a07450 100644
--- a/crosvm_plugin/src/lib.rs
+++ b/crosvm_plugin/src/lib.rs
@@ -63,6 +63,11 @@
const CROSVM_VCPU_EVENT_KIND_HYPERV_HCALL: u32 = 3;
const CROSVM_VCPU_EVENT_KIND_HYPERV_SYNIC: u32 = 4;
+pub const CROSVM_GPU_SERVER_FD_ENV: &str = "CROSVM_GPU_SERVER_FD";
+pub const CROSVM_SOCKET_ENV: &str = "CROSVM_SOCKET";
+#[cfg(feature = "stats")]
+pub const CROSVM_STATS_ENV: &str = "CROSVM_STATS";
+
#[repr(C)]
#[derive(Copy, Clone)]
pub struct crosvm_net_config {
@@ -236,7 +241,7 @@
#[cfg(feature = "stats")]
fn printstats() {
// Unsafe due to racy access - OK for stats
- if std::env::var("CROSVM_STATS").is_ok() {
+ if std::env::var(CROSVM_STATS_ENV).is_ok() {
unsafe {
stats::STATS.print();
}
@@ -514,8 +519,7 @@
entry.irq_id = route.irq_id;
match route.kind {
CROSVM_IRQ_ROUTE_IRQCHIP => {
- let irqchip: &mut MainRequest_SetIrqRouting_Route_Irqchip;
- irqchip = entry.mut_irqchip();
+ let irqchip: &mut MainRequest_SetIrqRouting_Route_Irqchip = entry.mut_irqchip();
// Safe because route.kind indicates which union field is valid.
irqchip.irqchip = unsafe { route.route.irqchip }.irqchip;
irqchip.pin = unsafe { route.route.irqchip }.pin;
@@ -1364,9 +1368,22 @@
}
#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_render_server_fd() -> c_int {
+ let fd = match env::var(CROSVM_GPU_SERVER_FD_ENV) {
+ Ok(v) => v,
+ _ => return -EINVAL,
+ };
+
+ match fd.parse() {
+ Ok(v) if v >= 0 => v,
+ _ => -EINVAL,
+ }
+}
+
+#[no_mangle]
pub unsafe extern "C" fn crosvm_connect(out: *mut *mut crosvm) -> c_int {
let _u = record(Stat::Connect);
- let socket_name = match env::var("CROSVM_SOCKET") {
+ let socket_name = match env::var(CROSVM_SOCKET_ENV) {
Ok(v) => v,
_ => return -ENOTCONN,
};
diff --git a/devices/Cargo.toml b/devices/Cargo.toml
index 9a8d3cf..35a56a4 100644
--- a/devices/Cargo.toml
+++ b/devices/Cargo.toml
@@ -18,6 +18,7 @@
x = ["gpu_display/x", "rutabaga_gfx/x"]
virgl_renderer = ["gpu", "rutabaga_gfx/virgl_renderer"]
gfxstream = ["gpu", "rutabaga_gfx/gfxstream"]
+slirp = []
[dependencies]
argh = "0.1.7"
@@ -41,7 +42,7 @@
kvm_sys = { path = "../kvm_sys" }
libc = "*"
libcras = { path = "../libcras_stub", optional = true }
-libvda = { path = "../libvda", optional = true }
+libvda = { path = "../media/libvda", optional = true }
linux_input_sys = { path = "../linux_input_sys" }
memoffset = { version = "0.6" }
minijail = { path = "../../minijail/rust/minijail" } # ignored by ebuild
diff --git a/devices/src/acpi.rs b/devices/src/acpi.rs
index b369312..be2b078 100644
--- a/devices/src/acpi.rs
+++ b/devices/src/acpi.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::{BusAccessInfo, BusDevice, BusResumeDevice};
+use crate::{BusAccessInfo, BusDevice, BusResumeDevice, IrqLevelEvent};
use acpi_tables::{aml, aml::Aml};
use base::{error, info, warn, Error as SysError, Event, PollToken, WaitContext};
use base::{AcpiNotifyEvent, NetlinkGenericSocket};
@@ -53,10 +53,11 @@
/// ACPI PM resource for handling OS suspend/resume request
#[allow(dead_code)]
pub struct ACPIPMResource {
- sci_evt: Event,
- sci_evt_resample: Event,
+ // This is SCI interrupt that will be raised in the VM.
+ sci_evt: IrqLevelEvent,
+ // This is the host SCI that is being handled by crosvm.
#[cfg(feature = "direct")]
- sci_direct_evt: Option<(Event, Event)>,
+ sci_direct_evt: Option<IrqLevelEvent>,
#[cfg(feature = "direct")]
direct_gpe: Vec<DirectGpe>,
kill_evt: Option<Event>,
@@ -73,9 +74,8 @@
/// `direct_gpe_info` - tuple of host SCI trigger and resample events, and list of direct GPEs
#[allow(dead_code)]
pub fn new(
- sci_evt: Event,
- sci_evt_resample: Event,
- #[cfg(feature = "direct")] direct_gpe_info: Option<(Event, Event, &[u32])>,
+ sci_evt: IrqLevelEvent,
+ #[cfg(feature = "direct")] direct_gpe_info: Option<(IrqLevelEvent, &[u32])>,
suspend_evt: Event,
exit_evt: Event,
) -> ACPIPMResource {
@@ -92,16 +92,15 @@
#[cfg(feature = "direct")]
let (sci_direct_evt, direct_gpe) = if let Some(info) = direct_gpe_info {
- let (trigger_evt, resample_evt, gpes) = info;
+ let (evt, gpes) = info;
let gpe_vec = gpes.iter().map(|gpe| DirectGpe::new(*gpe)).collect();
- (Some((trigger_evt, resample_evt)), gpe_vec)
+ (Some(evt), gpe_vec)
} else {
(None, Vec::new())
};
ACPIPMResource {
sci_evt,
- sci_evt_resample,
#[cfg(feature = "direct")]
sci_direct_evt,
#[cfg(feature = "direct")]
@@ -125,23 +124,12 @@
};
self.kill_evt = Some(self_kill_evt);
- let sci_resample = self
- .sci_evt_resample
- .try_clone()
- .expect("failed to clone event");
let sci_evt = self.sci_evt.try_clone().expect("failed to clone event");
let pm1 = self.pm1.clone();
let gpe0 = self.gpe0.clone();
#[cfg(feature = "direct")]
- let sci_direct_evt = if let Some((trigger, resample)) = &self.sci_direct_evt {
- Some((
- trigger.try_clone().expect("failed to clone event"),
- resample.try_clone().expect("failed to clone event"),
- ))
- } else {
- None
- };
+ let sci_direct_evt = self.sci_direct_evt.take();
#[cfg(feature = "direct")]
// Direct GPEs are forwarded via direct SCI forwarding,
@@ -155,9 +143,8 @@
.name("ACPI PM worker".to_string())
.spawn(move || {
if let Err(e) = run_worker(
- sci_resample,
- kill_evt,
sci_evt,
+ kill_evt,
pm1,
gpe0,
acpi_event_ignored_gpe,
@@ -176,13 +163,12 @@
}
fn run_worker(
- sci_resample: Event,
+ sci_evt: IrqLevelEvent,
kill_evt: Event,
- sci_evt: Event,
pm1: Arc<Mutex<Pm1Resource>>,
gpe0: Arc<Mutex<GpeResource>>,
acpi_event_ignored_gpe: Vec<u32>,
- #[cfg(feature = "direct")] sci_direct_evt: Option<(Event, Event)>,
+ #[cfg(feature = "direct")] sci_direct_evt: Option<IrqLevelEvent>,
) -> Result<(), ACPIPMError> {
// Get group id corresponding to acpi_mc_group of acpi_event family
let nl_groups: u32;
@@ -214,20 +200,20 @@
let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
(&acpi_event_sock, Token::AcpiEvent),
- (&sci_resample, Token::InterruptResample),
+ (sci_evt.get_resample(), Token::InterruptResample),
(&kill_evt, Token::Kill),
])
.map_err(ACPIPMError::CreateWaitContext)?;
#[cfg(feature = "direct")]
- if let Some((ref trigger, _)) = sci_direct_evt {
+ if let Some(ref evt) = sci_direct_evt {
wait_ctx
- .add(trigger, Token::InterruptTriggerDirect)
+ .add(evt.get_trigger(), Token::InterruptTriggerDirect)
.map_err(ACPIPMError::CreateWaitContext)?;
}
#[cfg(feature = "direct")]
- let mut pending_sci_direct_resample: Option<&Event> = None;
+ let mut pending_sci_direct: Option<&IrqLevelEvent> = None;
loop {
let events = wait_ctx.wait().map_err(ACPIPMError::WaitError)?;
@@ -243,11 +229,11 @@
);
}
Token::InterruptResample => {
- let _ = sci_resample.read();
+ sci_evt.clear_resample();
#[cfg(feature = "direct")]
- if let Some(resample) = pending_sci_direct_resample.take() {
- if let Err(e) = resample.write(1) {
+ if let Some(evt) = pending_sci_direct.take() {
+ if let Err(e) = evt.trigger_resample() {
error!("ACPIPM: failed to resample sci event: {}", e);
}
}
@@ -258,8 +244,8 @@
}
#[cfg(feature = "direct")]
Token::InterruptTriggerDirect => {
- if let Some((ref trigger, ref resample)) = sci_direct_evt {
- let _ = trigger.read();
+ if let Some(ref evt) = sci_direct_evt {
+ evt.clear_trigger();
for (gpe, devs) in &gpe0.lock().gpe_notify {
if DirectGpe::is_gpe_trigger(*gpe).unwrap_or(false) {
@@ -269,10 +255,10 @@
}
}
- if let Err(e) = sci_evt.write(1) {
+ if let Err(e) = sci_evt.trigger() {
error!("ACPIPM: failed to trigger sci event: {}", e);
}
- pending_sci_direct_resample = Some(resample);
+ pending_sci_direct = Some(evt);
}
}
Token::Kill => return Ok(()),
@@ -281,11 +267,11 @@
}
}
-fn acpi_event_gpe_class(
+fn acpi_event_handle_gpe(
gpe_number: u32,
_type: u32,
gpe0: &Arc<Mutex<GpeResource>>,
- sci_evt: &Event,
+ sci_evt: &IrqLevelEvent,
ignored_gpe: &[u32],
) {
// If gpe event, emulate GPE and trigger SCI
@@ -304,10 +290,10 @@
const ACPI_BUTTON_NOTIFY_STATUS: u32 = 0x80;
-fn acpi_event_pwrbtn_class(
+fn acpi_event_handle_power_button(
acpi_event: AcpiNotifyEvent,
pm1: &Arc<Mutex<Pm1Resource>>,
- sci_evt: &Event,
+ sci_evt: &IrqLevelEvent,
) {
// If received power button event, emulate PM/PWRBTN_STS and trigger SCI
if acpi_event._type == ACPI_BUTTON_NOTIFY_STATUS && acpi_event.bus_id.contains("LNXPWRBN") {
@@ -320,7 +306,13 @@
fn get_acpi_event_group() -> Option<u32> {
// Create netlink generic socket which will be used to query about given family name
- let netlink_ctrl_sock = NetlinkGenericSocket::new(0).unwrap();
+ let netlink_ctrl_sock = match NetlinkGenericSocket::new(0) {
+ Ok(sock) => sock,
+ Err(e) => {
+ error!("netlink generic socket creation error: {}", e);
+ return None;
+ }
+ };
let nlmsg_family_response = netlink_ctrl_sock
.family_name_query("acpi_event".to_string())
@@ -332,7 +324,7 @@
acpi_event_sock: &NetlinkGenericSocket,
gpe0: &Arc<Mutex<GpeResource>>,
pm1: &Arc<Mutex<Pm1Resource>>,
- sci_evt: &Event,
+ sci_evt: &IrqLevelEvent,
ignored_gpe: &[u32],
) {
let nl_msg = match acpi_event_sock.recv() {
@@ -353,7 +345,7 @@
};
match acpi_event.device_class.as_str() {
"gpe" => {
- acpi_event_gpe_class(
+ acpi_event_handle_gpe(
acpi_event.data,
acpi_event._type,
gpe0,
@@ -361,7 +353,7 @@
ignored_gpe,
);
}
- "button/power" => acpi_event_pwrbtn_class(acpi_event, pm1, sci_evt),
+ "button/power" => acpi_event_handle_power_button(acpi_event, pm1, sci_evt),
c => warn!("unknown acpi event {}", c),
};
}
@@ -380,7 +372,7 @@
}
impl Pm1Resource {
- fn trigger_sci(&self, sci_evt: &Event) {
+ fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
if self.status
& self.enable
& (BITMASK_PM1EN_GBL_EN
@@ -389,7 +381,7 @@
| BITMASK_PM1EN_RTC_EN)
!= 0
{
- if let Err(e) = sci_evt.write(1) {
+ if let Err(e) = sci_evt.trigger() {
error!("ACPIPM: failed to trigger sci event for pm1: {}", e);
}
}
@@ -397,7 +389,7 @@
}
impl GpeResource {
- fn trigger_sci(&self, sci_evt: &Event) {
+ fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
let mut trigger = false;
for i in 0..self.status.len() {
let gpes = self.status[i] & self.enable[i];
@@ -421,7 +413,7 @@
}
if trigger {
- if let Err(e) = sci_evt.write(1) {
+ if let Err(e) = sci_evt.trigger() {
error!("ACPIPM: failed to trigger sci event for gpe: {}", e);
}
}
diff --git a/devices/src/bat.rs b/devices/src/bat.rs
index b50c0cd..63add05 100644
--- a/devices/src/bat.rs
+++ b/devices/src/bat.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::{BusAccessInfo, BusDevice};
+use crate::{BusAccessInfo, BusDevice, IrqLevelEvent};
use acpi_tables::{aml, aml::Aml};
use base::{
error, warn, AsRawDescriptor, Descriptor, Event, PollToken, RawDescriptor, Tube, WaitContext,
@@ -93,8 +93,7 @@
state: Arc<Mutex<GoldfishBatteryState>>,
mmio_base: u32,
irq_num: u32,
- irq_evt: Event,
- irq_resample_evt: Event,
+ irq_evt: IrqLevelEvent,
activated: bool,
monitor_thread: Option<thread::JoinHandle<()>>,
kill_evt: Option<Event>,
@@ -136,8 +135,7 @@
fn command_monitor(
tube: Tube,
- irq_evt: Event,
- irq_resample_evt: Event,
+ irq_evt: IrqLevelEvent,
kill_evt: Event,
state: Arc<Mutex<GoldfishBatteryState>>,
create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
@@ -145,7 +143,7 @@
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&Descriptor(tube.as_raw_descriptor()), Token::Commands),
(
- &Descriptor(irq_resample_evt.as_raw_descriptor()),
+ &Descriptor(irq_evt.get_resample().as_raw_descriptor()),
Token::Resample,
),
(&Descriptor(kill_evt.as_raw_descriptor()), Token::Kill),
@@ -221,7 +219,7 @@
};
if inject_irq {
- let _ = irq_evt.write(1);
+ let _ = irq_evt.trigger();
}
if let Err(e) = tube.send(&BatControlResult::Ok) {
@@ -269,14 +267,14 @@
}
if inject_irq {
- let _ = irq_evt.write(1);
+ let _ = irq_evt.trigger();
}
}
Token::Resample => {
- let _ = irq_resample_evt.read();
+ irq_evt.clear_resample();
if state.lock().int_status() != 0 {
- let _ = irq_evt.write(1);
+ let _ = irq_evt.trigger();
}
}
@@ -294,13 +292,11 @@
/// which will be put into the ACPI DSDT.
/// * `irq_evt` - The interrupt event used to notify driver about
/// the battery properties changing.
- /// * `irq_resample_evt` - Resample interrupt event notified at EOI.
/// * `socket` - Battery control socket
pub fn new(
mmio_base: u64,
irq_num: u32,
- irq_evt: Event,
- irq_resample_evt: Event,
+ irq_evt: IrqLevelEvent,
tube: Tube,
create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
) -> Result<Self> {
@@ -326,7 +322,6 @@
mmio_base: mmio_base as u32,
irq_num,
irq_evt,
- irq_resample_evt,
activated: false,
monitor_thread: None,
kill_evt: None,
@@ -338,8 +333,8 @@
/// return the fds used by this device
pub fn keep_rds(&self) -> Vec<RawDescriptor> {
let mut rds = vec![
- self.irq_evt.as_raw_descriptor(),
- self.irq_resample_evt.as_raw_descriptor(),
+ self.irq_evt.get_trigger().as_raw_descriptor(),
+ self.irq_evt.get_resample().as_raw_descriptor(),
];
if let Some(tube) = &self.tube {
@@ -369,21 +364,13 @@
if let Some(tube) = self.tube.take() {
let irq_evt = self.irq_evt.try_clone().unwrap();
- let irq_resample_evt = self.irq_resample_evt.try_clone().unwrap();
let bat_state = self.state.clone();
let create_monitor_fn = self.create_power_monitor.take();
let monitor_result = thread::Builder::new()
.name(self.debug_label())
.spawn(move || {
- command_monitor(
- tube,
- irq_evt,
- irq_resample_evt,
- kill_evt,
- bat_state,
- create_monitor_fn,
- );
+ command_monitor(tube, irq_evt, kill_evt, bat_state, create_monitor_fn);
});
self.monitor_thread = match monitor_result {
diff --git a/devices/src/bus.rs b/devices/src/bus.rs
index 041da84..f93190f 100644
--- a/devices/src/bus.rs
+++ b/devices/src/bus.rs
@@ -70,6 +70,12 @@
pub trait BusDevice: Send {
/// Returns a label suitable for debug output.
fn debug_label(&self) -> String;
+
+ /// Returns a unique id per device type suitable for metrics gathering.
+ // TODO(225991065): Remove this default implementation when all of the crate is upstreamed.
+ fn device_id(&self) -> u32 {
+ 0
+ }
/// Reads at `offset` from this device
fn read(&mut self, offset: BusAccessInfo, data: &mut [u8]) {}
/// Writes at `offset` into this device
diff --git a/devices/src/direct_irq.rs b/devices/src/direct_irq.rs
index b4332e7..c120c7f 100644
--- a/devices/src/direct_irq.rs
+++ b/devices/src/direct_irq.rs
@@ -12,15 +12,23 @@
use thiserror::Error;
use vfio_sys::*;
+use crate::{IrqEdgeEvent, IrqLevelEvent};
+
#[sorted]
#[derive(Error, Debug)]
pub enum DirectIrqError {
+ #[error("failed to clone trigger event: {0}")]
+ CloneEvent(base::Error),
+ #[error("failed to clone resample event: {0}")]
+ CloneResampleEvent(base::Error),
#[error("failed to enable direct irq")]
Enable,
#[error("failed to enable gpe irq")]
EnableGpe,
#[error("failed to enable direct sci irq")]
EnableSci,
+ #[error("failed to enable wake irq")]
+ EnableWake,
#[error("failed to open /dev/plat-irq-forward: {0}")]
Open(io::Error),
}
@@ -33,8 +41,19 @@
}
impl DirectIrq {
- /// Create DirectIrq object to access hardware triggered interrupts.
- pub fn new(trigger: Event, resample: Option<Event>) -> Result<Self, DirectIrqError> {
+ fn new(trigger_evt: &Event, resample_evt: Option<&Event>) -> Result<Self, DirectIrqError> {
+ let trigger = trigger_evt
+ .try_clone()
+ .map_err(DirectIrqError::CloneEvent)?;
+ let resample = if let Some(event) = resample_evt {
+ Some(
+ event
+ .try_clone()
+ .map_err(DirectIrqError::CloneResampleEvent)?,
+ )
+ } else {
+ None
+ };
let dev = OpenOptions::new()
.read(true)
.write(true)
@@ -48,6 +67,16 @@
})
}
+ /// Create DirectIrq object to access hardware edge triggered interrupts.
+ pub fn new_edge(irq_evt: &IrqEdgeEvent) -> Result<Self, DirectIrqError> {
+ DirectIrq::new(irq_evt.get_trigger(), None)
+ }
+
+ /// Create DirectIrq object to access hardware level triggered interrupts.
+ pub fn new_level(irq_evt: &IrqLevelEvent) -> Result<Self, DirectIrqError> {
+ DirectIrq::new(irq_evt.get_trigger(), Some(irq_evt.get_resample()))
+ }
+
/// Enable hardware triggered interrupt handling.
///
/// Note: this feature is not part of VFIO, but provides
@@ -80,6 +109,10 @@
Ok(())
}
+ pub fn irq_wake_enable(&self, irq_num: u32) -> Result<(), DirectIrqError> {
+ self.plat_irq_wake_ioctl(irq_num, PLAT_IRQ_WAKE_ENABLE)
+ }
+
/// Enable hardware triggered SCI interrupt handling for GPE.
///
/// Note: sci_irq_prepare() itself does not enable SCI forwarding yet
@@ -133,6 +166,21 @@
}
}
+ fn plat_irq_wake_ioctl(&self, irq_num: u32, action: u32) -> Result<(), DirectIrqError> {
+ let mut irq_wake_set = vec_with_array_field::<plat_irq_wake_set, u32>(0);
+ irq_wake_set[0].argsz = (size_of::<plat_irq_wake_set>()) as u32;
+ irq_wake_set[0].action_flags = action;
+ irq_wake_set[0].irq_number_host = irq_num;
+
+ // Safe as we are the owner of plat_irq_wake_set and irq_wake_set which are valid value
+ let ret = unsafe { ioctl_with_ref(self, PLAT_IRQ_WAKE_SET(), &irq_wake_set[0]) };
+ if ret < 0 {
+ Err(DirectIrqError::EnableWake)
+ } else {
+ Ok(())
+ }
+ }
+
/// Enable hardware triggered GPE handling via SCI interrupt forwarding.
/// Note: requires sci_irq_prepare() to be called beforehand.
///
diff --git a/devices/src/irq_event.rs b/devices/src/irq_event.rs
new file mode 100644
index 0000000..2eb6500
--- /dev/null
+++ b/devices/src/irq_event.rs
@@ -0,0 +1,120 @@
+// Copyright 2022 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 base::{AsRawDescriptor, AsRawDescriptors, Event, RawDescriptor, Result};
+
+/// A structure suitable for implementing edge triggered interrupts in device backends.
+pub struct IrqEdgeEvent(Event);
+
+impl IrqEdgeEvent {
+ pub fn new() -> Result<IrqEdgeEvent> {
+ Event::new().map(IrqEdgeEvent)
+ }
+
+ pub fn try_clone(&self) -> Result<IrqEdgeEvent> {
+ self.0.try_clone().map(IrqEdgeEvent)
+ }
+
+ /// Creates an instance of IrqLevelEvent from an existing event.
+ pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
+ IrqEdgeEvent(trigger_evt)
+ }
+
+ pub fn get_trigger(&self) -> &Event {
+ &self.0
+ }
+
+ pub fn trigger(&self) -> Result<()> {
+ self.0.write(1)
+ }
+
+ pub fn clear_trigger(&self) {
+ let _ = self.0.read();
+ }
+}
+
+/// A structure suitable for implementing level triggered interrupts in device backends.
+pub struct IrqLevelEvent {
+ /// An event used by the device backend to signal hypervisor/VM about data or new unit
+ /// of work being available.
+ trigger_evt: Event,
+ /// An event used by the hypervisor to signal device backend that it completed processing
+ /// a unit of work and that device should re-raise `trigger_evt` if there is additional
+ /// work needs to be done.
+ resample_evt: Event,
+}
+
+impl IrqLevelEvent {
+ pub fn new() -> Result<IrqLevelEvent> {
+ let trigger_evt = Event::new()?;
+ let resample_evt = Event::new()?;
+ Ok(IrqLevelEvent {
+ trigger_evt,
+ resample_evt,
+ })
+ }
+
+ pub fn try_clone(&self) -> Result<IrqLevelEvent> {
+ let trigger_evt = self.trigger_evt.try_clone()?;
+ let resample_evt = self.resample_evt.try_clone()?;
+ Ok(IrqLevelEvent {
+ trigger_evt,
+ resample_evt,
+ })
+ }
+
+ /// Creates an instance of IrqLevelEvent from an existing pair of events.
+ pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
+ IrqLevelEvent {
+ trigger_evt,
+ resample_evt,
+ }
+ }
+
+ pub fn get_trigger(&self) -> &Event {
+ &self.trigger_evt
+ }
+
+ pub fn get_resample(&self) -> &Event {
+ &self.resample_evt
+ }
+
+ /// Allows backend to inject interrupt (typically into guest).
+ pub fn trigger(&self) -> Result<()> {
+ self.trigger_evt.write(1)
+ }
+
+ /// Allows code servicing interrupt to consume or clear the event.
+ pub fn clear_trigger(&self) {
+ let _ = self.trigger_evt.read();
+ }
+
+ /// Allows code servicing interrupt to signal that processing is done and that the backend
+ /// should go ahead and re-trigger it if there is more work needs to be done.
+ /// Note that typically resampling is signalled not by individual backends, but rather
+ /// by the code implementing interrupt controller.
+ pub fn trigger_resample(&self) -> Result<()> {
+ self.resample_evt.write(1)
+ }
+
+ /// Allows backend to consume or clear the resample event.
+ pub fn clear_resample(&self) {
+ let _ = self.resample_evt.read();
+ }
+}
+
+impl AsRawDescriptors for IrqEdgeEvent {
+ fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
+ vec![self.0.as_raw_descriptor()]
+ }
+}
+
+impl AsRawDescriptors for IrqLevelEvent {
+ fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
+ vec![
+ self.trigger_evt.as_raw_descriptor(),
+ self.resample_evt.as_raw_descriptor(),
+ ]
+ }
+}
diff --git a/devices/src/irqchip/ioapic.rs b/devices/src/irqchip/ioapic.rs
index 39b5f2f..aaf7d1c 100644
--- a/devices/src/irqchip/ioapic.rs
+++ b/devices/src/irqchip/ioapic.rs
@@ -397,7 +397,12 @@
evt.gsi
} else {
let event = Event::new().map_err(IoapicError::CreateEvent)?;
- let request = VmIrqRequest::AllocateOneMsi { irqfd: event };
+ let request = VmIrqRequest::AllocateOneMsi {
+ irqfd: event,
+ device_id: self.device_id(),
+ queue_id: index,
+ device_name: self.debug_label(),
+ };
self.irq_tube
.send(&request)
.map_err(IoapicError::AllocateOneMsiSend)?;
@@ -410,7 +415,7 @@
self.out_events[index] = Some(IrqEvent {
gsi,
event: match request {
- VmIrqRequest::AllocateOneMsi { irqfd } => irqfd,
+ VmIrqRequest::AllocateOneMsi { irqfd, .. } => irqfd,
_ => unreachable!(),
},
resample_event: None,
diff --git a/devices/src/irqchip/kvm/mod.rs b/devices/src/irqchip/kvm/mod.rs
index 1dd8bfd..9cf67bb 100644
--- a/devices/src/irqchip/kvm/mod.rs
+++ b/devices/src/irqchip/kvm/mod.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::Bus;
+use crate::{Bus, IrqEdgeEvent, IrqLevelEvent};
use base::{error, Error, Event, Result};
use hypervisor::kvm::KvmVcpu;
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
@@ -36,20 +36,37 @@
Ok(())
}
- /// Register an event that can trigger an interrupt for a particular GSI.
- fn register_irq_event(
+ /// Register an event with edge-trigger semantic that can trigger an interrupt
+ /// for a particular GSI.
+ fn register_edge_irq_event(
&mut self,
irq: u32,
- irq_event: &Event,
- resample_event: Option<&Event>,
+ irq_event: &IrqEdgeEvent,
) -> Result<Option<IrqEventIndex>> {
- self.vm.register_irqfd(irq, irq_event, resample_event)?;
+ self.vm.register_irqfd(irq, irq_event.get_trigger(), None)?;
Ok(None)
}
- /// Unregister an event for a particular GSI.
- fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()> {
- self.vm.unregister_irqfd(irq, irq_event)
+ /// Unregister an event with edge-trigger semantic for a particular GSI.
+ fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
+ self.vm.unregister_irqfd(irq, irq_event.get_trigger())
+ }
+
+ /// Register an event with level-trigger semantic that can trigger an interrupt
+ /// for a particular GSI.
+ fn register_level_irq_event(
+ &mut self,
+ irq: u32,
+ irq_event: &IrqLevelEvent,
+ ) -> Result<Option<IrqEventIndex>> {
+ self.vm
+ .register_irqfd(irq, irq_event.get_trigger(), Some(irq_event.get_resample()))?;
+ Ok(None)
+ }
+
+ /// Unregister an event with level-trigger semantic for a particular GSI.
+ fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
+ self.vm.unregister_irqfd(irq, irq_event.get_trigger())
}
/// Route an IRQ line to an interrupt controller, or to a particular MSI vector.
diff --git a/devices/src/irqchip/kvm/x86_64.rs b/devices/src/irqchip/kvm/x86_64.rs
index 3d13d39..e9bd145 100644
--- a/devices/src/irqchip/kvm/x86_64.rs
+++ b/devices/src/irqchip/kvm/x86_64.rs
@@ -24,7 +24,7 @@
Ioapic, IrqEvent, IrqEventIndex, Pic, VcpuRunState, IOAPIC_BASE_ADDRESS,
IOAPIC_MEM_LENGTH_BYTES,
};
-use crate::{Bus, IrqChip, IrqChipCap, IrqChipX86_64, Pit, PitError};
+use crate::{Bus, IrqChip, IrqChipCap, IrqChipX86_64, IrqEdgeEvent, IrqLevelEvent, Pit, PitError};
/// PIT tube 0 timer is connected to IRQ 0
const PIT_CHANNEL0_IRQ: u32 = 0;
@@ -197,18 +197,20 @@
) -> Result<Self> {
let ioapic_pins = ioapic_pins.unwrap_or(vm.get_ioapic_num_pins()?);
vm.enable_split_irqchip(ioapic_pins)?;
- let pit_evt = Event::new()?;
+ let pit_evt = IrqEdgeEvent::new()?;
let pit = Arc::new(Mutex::new(
- Pit::new(pit_evt.try_clone()?, Arc::new(Mutex::new(Clock::new()))).map_err(
- |e| match e {
- PitError::CloneEvent(err) => err,
- PitError::CreateEvent(err) => err,
- PitError::CreateWaitContext(err) => err,
- PitError::WaitError(err) => err,
- PitError::TimerCreateError(err) => err,
- PitError::SpawnThread(_) => Error::new(libc::EIO),
- },
- )?,
+ Pit::new(
+ pit_evt.get_trigger().try_clone()?,
+ Arc::new(Mutex::new(Clock::new())),
+ )
+ .map_err(|e| match e {
+ PitError::CloneEvent(err) => err,
+ PitError::CreateEvent(err) => err,
+ PitError::CreateWaitContext(err) => err,
+ PitError::WaitError(err) => err,
+ PitError::TimerCreateError(err) => err,
+ PitError::SpawnThread(_) => Error::new(libc::EIO),
+ })?,
));
let mut chip = KvmSplitIrqChip {
@@ -241,7 +243,7 @@
// Set the routes so they get sent to KVM
chip.set_irq_routes(&routes)?;
- chip.register_irq_event(PIT_CHANNEL0_IRQ, &pit_evt, None)?;
+ chip.register_edge_irq_event(PIT_CHANNEL0_IRQ, &pit_evt)?;
Ok(chip)
}
}
@@ -293,48 +295,6 @@
.get_external_interrupt()
.map(|vector| vector as u32)
}
-}
-
-/// Convenience function for determining whether or not two irq routes conflict.
-/// Returns true if they conflict.
-fn routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool {
- // They don't conflict if they have different GSIs.
- if route.gsi != other.gsi {
- return false;
- }
-
- // If they're both MSI with the same GSI then they conflict.
- if let (IrqSource::Msi { .. }, IrqSource::Msi { .. }) = (route.source, other.source) {
- return true;
- }
-
- // If the route chips match and they have the same GSI then they conflict.
- if let (
- IrqSource::Irqchip {
- chip: route_chip, ..
- },
- IrqSource::Irqchip {
- chip: other_chip, ..
- },
- ) = (route.source, other.source)
- {
- return route_chip == other_chip;
- }
-
- // Otherwise they do not conflict.
- false
-}
-
-/// This IrqChip only works with Kvm so we only implement it for KvmVcpu.
-impl IrqChip for KvmSplitIrqChip {
- /// Add a vcpu to the irq chip.
- fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()> {
- let vcpu: &KvmVcpu = vcpu
- .downcast_ref()
- .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
- self.vcpus.lock()[vcpu_id] = Some(vcpu.try_clone()?);
- Ok(())
- }
/// Register an event that can trigger an interrupt for a particular GSI.
fn register_irq_event(
@@ -381,6 +341,73 @@
self.vm.unregister_irqfd(irq, irq_event)
}
}
+}
+
+/// Convenience function for determining whether or not two irq routes conflict.
+/// Returns true if they conflict.
+fn routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool {
+ // They don't conflict if they have different GSIs.
+ if route.gsi != other.gsi {
+ return false;
+ }
+
+ // If they're both MSI with the same GSI then they conflict.
+ if let (IrqSource::Msi { .. }, IrqSource::Msi { .. }) = (route.source, other.source) {
+ return true;
+ }
+
+ // If the route chips match and they have the same GSI then they conflict.
+ if let (
+ IrqSource::Irqchip {
+ chip: route_chip, ..
+ },
+ IrqSource::Irqchip {
+ chip: other_chip, ..
+ },
+ ) = (route.source, other.source)
+ {
+ return route_chip == other_chip;
+ }
+
+ // Otherwise they do not conflict.
+ false
+}
+
+/// This IrqChip only works with Kvm so we only implement it for KvmVcpu.
+impl IrqChip for KvmSplitIrqChip {
+ /// Add a vcpu to the irq chip.
+ fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()> {
+ let vcpu: &KvmVcpu = vcpu
+ .downcast_ref()
+ .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
+ self.vcpus.lock()[vcpu_id] = Some(vcpu.try_clone()?);
+ Ok(())
+ }
+
+ /// Register an event that can trigger an interrupt for a particular GSI.
+ fn register_edge_irq_event(
+ &mut self,
+ irq: u32,
+ irq_event: &IrqEdgeEvent,
+ ) -> Result<Option<IrqEventIndex>> {
+ self.register_irq_event(irq, irq_event.get_trigger(), None)
+ }
+
+ fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
+ self.unregister_irq_event(irq, irq_event.get_trigger())
+ }
+
+ fn register_level_irq_event(
+ &mut self,
+ irq: u32,
+ irq_event: &IrqLevelEvent,
+ ) -> Result<Option<IrqEventIndex>> {
+ self.register_irq_event(irq, irq_event.get_trigger(), Some(irq_event.get_resample()))
+ }
+
+ fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
+ self.unregister_irq_event(irq, irq_event.get_trigger())
+ }
/// Route an IRQ line to an interrupt controller, or to a particular MSI vector.
fn route_irq(&mut self, route: IrqRoute) -> Result<()> {
@@ -905,8 +932,8 @@
assert_eq!(tokens[0].1, 0);
// register another irq event
- let evt = Event::new().expect("failed to create event");
- chip.register_irq_event(6, &evt, None)
+ let evt = IrqEdgeEvent::new().expect("failed to create event");
+ chip.register_edge_irq_event(6, &evt)
.expect("failed to register irq event");
let tokens = chip
@@ -917,7 +944,7 @@
assert_eq!(tokens.len(), 2);
assert_eq!(tokens[0].1, 0);
assert_eq!(tokens[1].1, 6);
- assert_eq!(tokens[1].2, evt);
+ assert_eq!(tokens[1].2, *evt.get_trigger());
}
#[test]
@@ -948,13 +975,11 @@
)
.expect("failed to create SystemAllocator");
- // setup an event and a resample event for irq line 1
- let evt = Event::new().expect("failed to create event");
- let resample_evt = Event::new().expect("failed to create event");
-
+ // Set up a level-triggered interrupt line 1
+ let evt = IrqLevelEvent::new().expect("failed to create event");
let evt_index = chip
- .register_irq_event(1, &evt, Some(&resample_evt))
- .expect("failed to register_irq_event")
+ .register_level_irq_event(1, &evt)
+ .expect("failed to register irq event")
.expect("register_irq_event should not return None");
// Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
@@ -989,7 +1014,7 @@
assert!(state.special_fully_nested_mode);
// Need to write to the irq event before servicing it
- evt.write(1).expect("failed to write to event");
+ evt.trigger().expect("failed to write to event");
// if we assert irq line one, and then get the resulting interrupt, an auto-eoi should
// occur and cause the resample_event to be written to
@@ -1005,6 +1030,8 @@
0x9
);
+ // Clone resample event because read_timeout() needs a mutable reference.
+ let resample_evt = evt.get_resample().try_clone().unwrap();
assert_eq!(
resample_evt
.read_timeout(std::time::Duration::from_secs(1))
diff --git a/devices/src/irqchip/mod.rs b/devices/src/irqchip/mod.rs
index 5eef968..90351eb 100644
--- a/devices/src/irqchip/mod.rs
+++ b/devices/src/irqchip/mod.rs
@@ -4,7 +4,7 @@
use std::marker::{Send, Sized};
-use crate::Bus;
+use crate::{Bus, IrqEdgeEvent, IrqLevelEvent};
use base::{Event, Result};
use hypervisor::{IrqRoute, MPState, Vcpu};
use resources::SystemAllocator;
@@ -61,16 +61,25 @@
/// Add a vcpu to the irq chip.
fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>;
- /// Register an event that can trigger an interrupt for a particular GSI.
- fn register_irq_event(
+ /// Register an event with edge-trigger semantic that can trigger an interrupt for a particular GSI.
+ fn register_edge_irq_event(
&mut self,
irq: u32,
- irq_event: &Event,
- resample_event: Option<&Event>,
+ irq_event: &IrqEdgeEvent,
) -> Result<Option<IrqEventIndex>>;
- /// Unregister an event for a particular GSI.
- fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>;
+ /// Unregister an event with edge-trigger semantic for a particular GSI.
+ fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>;
+
+ /// Register an event with level-trigger semantic that can trigger an interrupt for a particular GSI.
+ fn register_level_irq_event(
+ &mut self,
+ irq: u32,
+ irq_event: &IrqLevelEvent,
+ ) -> Result<Option<IrqEventIndex>>;
+
+ /// Unregister an event with level-trigger semantic for a particular GSI.
+ fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>;
/// Route an IRQ line to an interrupt controller, or to a particular MSI vector.
fn route_irq(&mut self, route: IrqRoute) -> Result<()>;
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 5d4888f..57fe6f9 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -11,6 +11,7 @@
#[cfg(feature = "direct")]
pub mod direct_irq;
mod i8042;
+mod irq_event;
pub mod irqchip;
mod pci;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
@@ -25,6 +26,8 @@
pub mod bat;
mod serial;
pub mod serial_device;
+#[cfg(feature = "tpm")]
+mod software_tpm;
mod sys;
#[cfg(feature = "usb")]
pub mod usb;
@@ -46,6 +49,7 @@
#[cfg(feature = "direct")]
pub use self::direct_irq::{DirectIrq, DirectIrqError};
pub use self::i8042::I8042Device;
+pub use self::irq_event::{IrqEdgeEvent, IrqLevelEvent};
pub use self::irqchip::*;
#[cfg(feature = "audio")]
pub use self::pci::{Ac97Backend, Ac97Dev, Ac97Parameters};
@@ -65,6 +69,8 @@
pub use self::serial_device::{
Error as SerialError, SerialDevice, SerialHardware, SerialParameters, SerialType,
};
+#[cfg(feature = "tpm")]
+pub use self::software_tpm::SoftwareTpm;
#[cfg(feature = "usb")]
pub use self::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
#[cfg(feature = "usb")]
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs
index ed53f6a..8a4fd0f 100644
--- a/devices/src/pci/ac97.rs
+++ b/devices/src/pci/ac97.rs
@@ -7,7 +7,7 @@
use std::str::FromStr;
use audio_streams::shm_streams::{NullShmStreamSource, ShmStreamSource};
-use base::{error, AsRawDescriptor, Event, RawDescriptor};
+use base::{error, AsRawDescriptor, RawDescriptor};
#[cfg(feature = "audio_cras")]
use libcras::{CrasClient, CrasClientType, CrasSocketType, CrasSysError};
use remain::sorted;
@@ -28,6 +28,7 @@
use crate::virtio::snd::vios_backend::Error as VioSError;
#[cfg(any(target_os = "linux", target_os = "android"))]
use crate::virtio::snd::vios_backend::VioSShmStreamSource;
+use crate::IrqLevelEvent;
// Use 82801AA because it's what qemu does.
const PCI_DEVICE_ID_INTEL_82801AA_5: u16 = 0x2415;
@@ -114,8 +115,7 @@
pci_address: Option<PciAddress>,
// The irq events are temporarily saved here. They need to be passed to the device after the
// jail forks. This happens when the bus is first written.
- irq_evt: Option<Event>,
- irq_resample_evt: Option<Event>,
+ irq_evt: Option<IrqLevelEvent>,
bus_master: Ac97BusMaster,
mixer: Ac97Mixer,
backend: Ac97Backend,
@@ -145,7 +145,6 @@
config_regs,
pci_address: None,
irq_evt: None,
- irq_resample_evt: None,
bus_master: Ac97BusMaster::new(mem, audio_server),
mixer: Ac97Mixer::new(),
backend,
@@ -304,12 +303,10 @@
fn assign_irq(
&mut self,
- irq_evt: &Event,
- irq_resample_evt: &Event,
+ irq_evt: &IrqLevelEvent,
irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
self.irq_evt = Some(irq_evt.try_clone().ok()?);
- self.irq_resample_evt = Some(irq_resample_evt.try_clone().ok()?);
let gsi = irq_num?;
let pin = self.pci_address.map_or(
PciInterruptPin::IntA,
@@ -404,10 +401,8 @@
rds.append(&mut server_fds);
}
if let Some(irq_evt) = &self.irq_evt {
- rds.push(irq_evt.as_raw_descriptor());
- }
- if let Some(irq_resample_evt) = &self.irq_resample_evt {
- rds.push(irq_resample_evt.as_raw_descriptor());
+ rds.push(irq_evt.get_trigger().as_raw_descriptor());
+ rds.push(irq_evt.get_resample().as_raw_descriptor());
}
rds
}
@@ -431,10 +426,8 @@
a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.write_mixer(addr - bar0, data),
a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => {
// Check if the irq needs to be passed to the device.
- if let (Some(irq_evt), Some(irq_resample_evt)) =
- (self.irq_evt.take(), self.irq_resample_evt.take())
- {
- self.bus_master.set_irq_event(irq_evt, irq_resample_evt);
+ if let Some(irq_evt) = self.irq_evt.take() {
+ self.bus_master.set_irq_event(irq_evt);
}
self.write_bus_master(addr - bar1, data)
}
diff --git a/devices/src/pci/ac97_bus_master.rs b/devices/src/pci/ac97_bus_master.rs
index dc9b3ef..f0350f2 100644
--- a/devices/src/pci/ac97_bus_master.rs
+++ b/devices/src/pci/ac97_bus_master.rs
@@ -15,7 +15,7 @@
};
use base::{
self, error, set_rt_prio_limit, set_rt_round_robin, warn, AsRawDescriptor, AsRawDescriptors,
- Event, FromRawDescriptor, RawDescriptor, SharedMemoryUnix,
+ FromRawDescriptor, RawDescriptor, SharedMemoryUnix,
};
use remain::sorted;
use sync::{Condvar, Mutex};
@@ -24,6 +24,7 @@
use crate::pci::ac97_mixer::Ac97Mixer;
use crate::pci::ac97_regs::*;
+use crate::IrqLevelEvent;
const INPUT_SAMPLE_RATE: u32 = 48000;
const DEVICE_INPUT_CHANNEL_COUNT: usize = 2;
@@ -39,7 +40,7 @@
glob_sta: u32,
// IRQ event - driven by the glob_sta register.
- irq_evt: Option<Event>,
+ irq_evt: Option<IrqLevelEvent>,
}
impl Ac97BusMasterRegs {
@@ -248,12 +249,12 @@
}
/// Provides the events needed to raise interrupts in the guest.
- pub fn set_irq_event(&mut self, irq_evt: Event, irq_resample_evt: Event) {
+ pub fn set_irq_event(&mut self, irq_evt: IrqLevelEvent) {
let thread_regs = self.regs.clone();
- self.regs.lock().irq_evt = Some(irq_evt);
+ self.regs.lock().irq_evt = Some(irq_evt.try_clone().expect("cloning irq_evt failed"));
self.irq_resample_thread = Some(thread::spawn(move || {
loop {
- if let Err(e) = irq_resample_evt.read() {
+ if let Err(e) = irq_evt.get_resample().read() {
error!(
"Failed to read the irq event from the resample thread: {}.",
e,
@@ -264,11 +265,9 @@
// Scope for the lock on thread_regs.
let regs = thread_regs.lock();
if regs.has_irq() {
- if let Some(irq_evt) = regs.irq_evt.as_ref() {
- if let Err(e) = irq_evt.write(1) {
- error!("Failed to set the irq from the resample thread: {}.", e);
- break;
- }
+ if let Err(e) = irq_evt.trigger() {
+ error!("Failed to set the irq from the resample thread: {}.", e);
+ break;
}
}
}
@@ -939,9 +938,9 @@
if interrupt_high {
regs.glob_sta |= int_mask;
- if let Some(irq_evt) = regs.irq_evt.as_ref() {
+ if let Some(ref irq_evt) = regs.irq_evt {
// Ignore write failure, nothing can be done about it from here.
- let _ = irq_evt.write(1);
+ let _ = irq_evt.trigger();
}
} else {
regs.glob_sta &= !int_mask;
diff --git a/devices/src/pci/coiommu.rs b/devices/src/pci/coiommu.rs
index abf8d4f..421eea5 100644
--- a/devices/src/pci/coiommu.rs
+++ b/devices/src/pci/coiommu.rs
@@ -33,6 +33,7 @@
use data_model::DataInit;
use hypervisor::Datamatch;
use resources::{Alloc, MmioType, SystemAllocator};
+use serde::{Deserialize, Serialize};
use sync::Mutex;
use thiserror::Error as ThisError;
@@ -84,7 +85,7 @@
const UNPIN_DEFAULT_INTERVAL: Duration = Duration::from_secs(60);
const UNPIN_GEN_DEFAULT_THRES: u64 = 10;
/// Holds the coiommu unpin policy
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum CoIommuUnpinPolicy {
Off,
Lru,
@@ -117,7 +118,7 @@
}
/// Holds the parameters for a coiommu device
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct CoIommuParameters {
pub unpin_policy: CoIommuUnpinPolicy,
pub unpin_interval: Duration,
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index f247e9d..fea98ec 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -58,3 +58,26 @@
pub const PCI_VENDOR_ID_INTEL: u16 = 0x8086;
pub const PCI_VENDOR_ID_REDHAT: u16 = 0x1b36;
+
+/// A wrapper structure for pci device and vendor id.
+#[derive(Copy, Clone)]
+pub struct PciId {
+ vendor_id: u16,
+ device_id: u16,
+}
+
+impl PciId {
+ pub fn new(vendor_id: u16, device_id: u16) -> Self {
+ Self {
+ vendor_id,
+ device_id,
+ }
+ }
+}
+
+impl From<PciId> for u32 {
+ fn from(pci_id: PciId) -> Self {
+ // vendor ID is the lower 16 bits and device id is the upper 16 bits
+ pci_id.vendor_id as u32 | (pci_id.device_id as u32) << 16
+ }
+}
diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs
index d5a4950..57a3b4c 100644
--- a/devices/src/pci/msix.rs
+++ b/devices/src/pci/msix.rs
@@ -18,6 +18,7 @@
pub const BITS_PER_PBA_ENTRY: usize = 64;
const FUNCTION_MASK_BIT: u16 = 0x4000;
const MSIX_ENABLE_BIT: u16 = 0x8000;
+const MSIX_TABLE_ENTRY_MASK_BIT: u32 = 0x1;
#[derive(Clone, Default)]
struct MsixTableEntry {
@@ -29,7 +30,7 @@
impl MsixTableEntry {
fn masked(&self) -> bool {
- self.vector_ctl & 0x1 == 0x1
+ self.vector_ctl & MSIX_TABLE_ENTRY_MASK_BIT == MSIX_TABLE_ENTRY_MASK_BIT
}
}
@@ -42,11 +43,13 @@
pub struct MsixConfig {
table_entries: Vec<MsixTableEntry>,
pba_entries: Vec<u64>,
- irq_vec: Vec<IrqfdGsi>,
+ irq_vec: Vec<Option<IrqfdGsi>>,
masked: bool,
enabled: bool,
msi_device_socket: Tube,
msix_num: u16,
+ pci_id: u32,
+ device_name: String,
}
#[sorted]
@@ -75,24 +78,32 @@
}
impl MsixConfig {
- pub fn new(msix_vectors: u16, vm_socket: Tube) -> Self {
+ pub fn new(msix_vectors: u16, vm_socket: Tube, pci_id: u32, device_name: String) -> Self {
assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
let mut table_entries: Vec<MsixTableEntry> = Vec::new();
table_entries.resize_with(msix_vectors as usize, Default::default);
+ table_entries
+ .iter_mut()
+ .for_each(|entry| entry.vector_ctl |= MSIX_TABLE_ENTRY_MASK_BIT);
let mut pba_entries: Vec<u64> = Vec::new();
let num_pba_entries: usize =
((msix_vectors as usize) + BITS_PER_PBA_ENTRY - 1) / BITS_PER_PBA_ENTRY;
pba_entries.resize_with(num_pba_entries, Default::default);
+ let mut irq_vec = Vec::new();
+ irq_vec.resize_with(msix_vectors.into(), || None::<IrqfdGsi>);
+
MsixConfig {
table_entries,
pba_entries,
- irq_vec: Vec::new(),
+ irq_vec,
masked: false,
enabled: false,
msi_device_socket: vm_socket,
msix_num: msix_vectors,
+ pci_id,
+ device_name,
}
}
@@ -155,7 +166,7 @@
self.enabled = (reg & MSIX_ENABLE_BIT) == MSIX_ENABLE_BIT;
if !old_enabled && self.enabled {
- if let Err(e) = self.msix_enable() {
+ if let Err(e) = self.msix_enable_all() {
error!("failed to enable MSI-X: {}", e);
self.enabled = false;
}
@@ -213,37 +224,55 @@
Ok(())
}
- fn msix_enable(&mut self) -> MsixResult<()> {
- self.irq_vec.clear();
- for i in 0..self.msix_num {
- let irqfd = Event::new().unwrap();
- let request = VmIrqRequest::AllocateOneMsi { irqfd };
- self.msi_device_socket
- .send(&request)
- .map_err(MsixError::AllocateOneMsiSend)?;
- let irq_num: u32;
- match self
- .msi_device_socket
- .recv()
- .map_err(MsixError::AllocateOneMsiRecv)?
- {
- VmIrqResponse::AllocateOneMsi { gsi } => irq_num = gsi,
- VmIrqResponse::Err(e) => return Err(MsixError::AllocateOneMsi(e)),
- _ => unreachable!(),
- }
- self.irq_vec.push(IrqfdGsi {
- irqfd: match request {
- VmIrqRequest::AllocateOneMsi { irqfd } => irqfd,
- _ => unreachable!(),
- },
- gsi: irq_num,
- });
-
- self.add_msi_route(i, irq_num)?;
+ // Enable MSI-X
+ fn msix_enable_all(&mut self) -> MsixResult<()> {
+ for index in 0..self.irq_vec.len() {
+ self.msix_enable_one(index)?;
}
Ok(())
}
+ // Use a new MSI-X vector
+ // Create a new eventfd and bind them to a new msi
+ fn msix_enable_one(&mut self, index: usize) -> MsixResult<()> {
+ if self.irq_vec[index].is_some()
+ || !self.enabled()
+ || self.masked()
+ || self.table_masked(index)
+ {
+ return Ok(());
+ }
+ let irqfd = Event::new().map_err(MsixError::AllocateOneMsi)?;
+ let request = VmIrqRequest::AllocateOneMsi {
+ irqfd,
+ device_id: self.pci_id,
+ queue_id: index as usize,
+ device_name: self.device_name.clone(),
+ };
+ self.msi_device_socket
+ .send(&request)
+ .map_err(MsixError::AllocateOneMsiSend)?;
+ let irq_num: u32 = match self
+ .msi_device_socket
+ .recv()
+ .map_err(MsixError::AllocateOneMsiRecv)?
+ {
+ VmIrqResponse::AllocateOneMsi { gsi } => gsi,
+ VmIrqResponse::Err(e) => return Err(MsixError::AllocateOneMsi(e)),
+ _ => unreachable!(),
+ };
+ self.irq_vec[index] = Some(IrqfdGsi {
+ irqfd: match request {
+ VmIrqRequest::AllocateOneMsi { irqfd, .. } => irqfd,
+ _ => unreachable!(),
+ },
+ gsi: irq_num,
+ });
+
+ self.add_msi_route(index as u16, irq_num)?;
+ Ok(())
+ }
+
/// Read MSI-X table
/// # Arguments
/// * 'offset' - the offset within the MSI-X Table
@@ -344,14 +373,31 @@
};
let new_entry = self.table_entries[index].clone();
+
+ // This MSI-X vector is enabled for the first time.
+ if self.enabled()
+ && !self.masked()
+ && self.irq_vec[index].is_none()
+ && old_entry.masked()
+ && !new_entry.masked()
+ {
+ if let Err(e) = self.msix_enable_one(index) {
+ error!("failed to enable MSI-X vector {}: {}", index, e);
+ self.table_entries[index].vector_ctl |= MSIX_TABLE_ENTRY_MASK_BIT;
+ }
+ return MsixStatus::EntryChanged(index);
+ }
+
if self.enabled()
&& (old_entry.msg_addr_lo != new_entry.msg_addr_lo
|| old_entry.msg_addr_hi != new_entry.msg_addr_hi
|| old_entry.msg_data != new_entry.msg_data)
{
- let irq_num = self.irq_vec[index].gsi;
- if let Err(e) = self.add_msi_route(index as u16, irq_num) {
- error!("add_msi_route failed: {}", e);
+ if let Some(irqfd_gsi) = &self.irq_vec[index] {
+ let irq_num = irqfd_gsi.gsi;
+ if let Err(e) = self.add_msi_route(index as u16, irq_num) {
+ error!("add_msi_route failed: {}", e);
+ }
}
}
@@ -449,7 +495,7 @@
}
fn inject_msix_and_clear_pba(&mut self, vector: usize) {
- if let Some(irq) = self.irq_vec.get(vector) {
+ if let Some(irq) = &self.irq_vec[vector] {
irq.irqfd.write(1).unwrap();
}
@@ -475,12 +521,12 @@
pub fn trigger(&mut self, vector: u16) {
if self.table_entries[vector as usize].masked() || self.masked() {
self.set_pba_bit(vector, true);
- } else if let Some(irq) = self.irq_vec.get(vector as usize) {
+ } else if let Some(irq) = self.irq_vec.get(vector as usize).unwrap_or(&None) {
irq.irqfd.write(1).unwrap();
}
}
- /// Return the raw fd of the MSI device socket
+ /// Return the raw descriptor of the MSI device socket
pub fn get_msi_socket(&self) -> RawDescriptor {
self.msi_device_socket.as_raw_descriptor()
}
@@ -490,7 +536,7 @@
/// # Arguments
/// * 'vector' - the index to the MSI-X table entry
pub fn get_irqfd(&self, vector: usize) -> Option<&Event> {
- match self.irq_vec.get(vector) {
+ match self.irq_vec.get(vector as usize).unwrap_or(&None) {
Some(irq) => Some(&irq.irqfd),
None => None,
}
@@ -498,14 +544,16 @@
pub fn destroy(&mut self) {
while let Some(irq) = self.irq_vec.pop() {
- let request = VmIrqRequest::ReleaseOneIrq {
- gsi: irq.gsi,
- irqfd: irq.irqfd,
- };
- if self.msi_device_socket.send(&request).is_err() {
- continue;
+ if let Some(irq) = irq {
+ let request = VmIrqRequest::ReleaseOneIrq {
+ gsi: irq.gsi,
+ irqfd: irq.irqfd,
+ };
+ if self.msi_device_socket.send(&request).is_err() {
+ continue;
+ }
+ let _ = self.msi_device_socket.recv::<VmIrqResponse>();
}
- let _ = self.msi_device_socket.recv::<VmIrqResponse>();
}
}
}
@@ -594,6 +642,7 @@
}
}
+ #[cfg(unix)]
pub fn msg_ctl(&self) -> MsixCtrl {
self.msg_ctl
}
diff --git a/devices/src/pci/pci_address.rs b/devices/src/pci/pci_address.rs
index ef4d9e7..e43b179 100644
--- a/devices/src/pci/pci_address.rs
+++ b/devices/src/pci/pci_address.rs
@@ -3,6 +3,7 @@
// found in the LICENSE file.
use std::fmt::{self, Display};
+use std::str::FromStr;
use remain::sorted;
use serde::{Deserialize, Serialize};
@@ -41,7 +42,50 @@
impl Display for PciAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:04x}:{:02x}.{:0x}", self.bus, self.dev, self.func)
+ let domain = 0;
+ write!(
+ f,
+ "{:04x}:{:02x}:{:02x}.{:0x}",
+ domain, self.bus, self.dev, self.func,
+ )
+ }
+}
+
+/// Construct PciAddress from string [domain:]bus:device.function.
+impl FromStr for PciAddress {
+ type Err = Error;
+
+ fn from_str(address: &str) -> std::result::Result<Self, Self::Err> {
+ let (dev_bus_domain, func) = address.rsplit_once('.').ok_or(Error::MissingDelimiter(
+ PciAddressComponent::Device,
+ PciAddressComponent::Function,
+ ))?;
+ let func = u32::from_str_radix(func, 16)
+ .map_err(|_| Error::InvalidHex(PciAddressComponent::Function))?;
+
+ let (bus_domain, dev) = dev_bus_domain
+ .rsplit_once(':')
+ .ok_or(Error::MissingDelimiter(
+ PciAddressComponent::Bus,
+ PciAddressComponent::Device,
+ ))?;
+ let dev = u32::from_str_radix(dev, 16)
+ .map_err(|_| Error::InvalidHex(PciAddressComponent::Device))?;
+
+ // Domain is optional; if unspecified, the rest of the string is the bus, and domain
+ // defaults to 0.
+ let (domain, bus) = bus_domain.rsplit_once(':').unwrap_or(("0", bus_domain));
+ let bus = u32::from_str_radix(bus, 16)
+ .map_err(|_| Error::InvalidHex(PciAddressComponent::Bus))?;
+
+ if domain.contains(':') {
+ return Err(Error::TooManyComponents);
+ }
+
+ let domain = u32::from_str_radix(domain, 16)
+ .map_err(|_| Error::InvalidHex(PciAddressComponent::Domain))?;
+
+ Self::new(domain, bus, dev, func)
}
}
@@ -92,40 +136,6 @@
(PciAddress { bus, dev, func }, register)
}
- /// Construct PciAddress from string [domain:]bus:device.function.
- pub fn from_string(address: &str) -> Result<Self> {
- let (dev_bus_domain, func) = address.rsplit_once('.').ok_or(Error::MissingDelimiter(
- PciAddressComponent::Device,
- PciAddressComponent::Function,
- ))?;
- let func = u32::from_str_radix(func, 16)
- .map_err(|_| Error::InvalidHex(PciAddressComponent::Function))?;
-
- let (bus_domain, dev) = dev_bus_domain
- .rsplit_once(':')
- .ok_or(Error::MissingDelimiter(
- PciAddressComponent::Bus,
- PciAddressComponent::Device,
- ))?;
- let dev = u32::from_str_radix(dev, 16)
- .map_err(|_| Error::InvalidHex(PciAddressComponent::Device))?;
-
- // Domain is optional; if unspecified, the rest of the string is the bus, and domain
- // defaults to 0.
- let (domain, bus) = bus_domain.rsplit_once(':').unwrap_or(("0", bus_domain));
- let bus = u32::from_str_radix(bus, 16)
- .map_err(|_| Error::InvalidHex(PciAddressComponent::Bus))?;
-
- if domain.contains(':') {
- return Err(Error::TooManyComponents);
- }
-
- let domain = u32::from_str_radix(domain, 16)
- .map_err(|_| Error::InvalidHex(PciAddressComponent::Domain))?;
-
- Self::new(domain, bus, dev, func)
- }
-
/// Encode PciAddress into CONFIG_ADDRESS value.
pub fn to_config_address(&self, register: usize, register_bits_num: usize) -> u32 {
let bus_offset = register_bits_num + Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM;
@@ -164,7 +174,7 @@
#[test]
fn from_string() {
assert_eq!(
- PciAddress::from_string("0000:00:00.0").unwrap(),
+ PciAddress::from_str("0000:00:00.0").unwrap(),
PciAddress {
bus: 0,
dev: 0,
@@ -172,7 +182,7 @@
}
);
assert_eq!(
- PciAddress::from_string("00:00.0").unwrap(),
+ PciAddress::from_str("00:00.0").unwrap(),
PciAddress {
bus: 0,
dev: 0,
@@ -180,7 +190,7 @@
}
);
assert_eq!(
- PciAddress::from_string("01:02.3").unwrap(),
+ PciAddress::from_str("01:02.3").unwrap(),
PciAddress {
bus: 1,
dev: 2,
@@ -188,7 +198,7 @@
}
);
assert_eq!(
- PciAddress::from_string("ff:1f.7").unwrap(),
+ PciAddress::from_str("ff:1f.7").unwrap(),
PciAddress {
bus: 0xff,
dev: 0x1f,
@@ -200,7 +210,7 @@
#[test]
fn from_string_missing_func_delim() {
assert_eq!(
- PciAddress::from_string("1").expect_err("parse should fail"),
+ PciAddress::from_str("1").expect_err("parse should fail"),
Error::MissingDelimiter(PciAddressComponent::Device, PciAddressComponent::Function)
);
}
@@ -208,7 +218,7 @@
#[test]
fn from_string_missing_dev_delim() {
assert_eq!(
- PciAddress::from_string("2.1").expect_err("parse should fail"),
+ PciAddress::from_str("2.1").expect_err("parse should fail"),
Error::MissingDelimiter(PciAddressComponent::Bus, PciAddressComponent::Device)
);
}
@@ -216,7 +226,7 @@
#[test]
fn from_string_extra_components() {
assert_eq!(
- PciAddress::from_string("0:0:0:0.0").expect_err("parse should fail"),
+ PciAddress::from_str("0:0:0:0.0").expect_err("parse should fail"),
Error::TooManyComponents
);
}
@@ -224,7 +234,7 @@
#[test]
fn from_string_invalid_func_hex() {
assert_eq!(
- PciAddress::from_string("0000:00:00.g").expect_err("parse should fail"),
+ PciAddress::from_str("0000:00:00.g").expect_err("parse should fail"),
Error::InvalidHex(PciAddressComponent::Function)
);
}
@@ -232,7 +242,7 @@
#[test]
fn from_string_invalid_func_range() {
assert_eq!(
- PciAddress::from_string("0000:00:00.8").expect_err("parse should fail"),
+ PciAddress::from_str("0000:00:00.8").expect_err("parse should fail"),
Error::ComponentOutOfRange(PciAddressComponent::Function)
);
}
@@ -240,7 +250,7 @@
#[test]
fn from_string_invalid_dev_hex() {
assert_eq!(
- PciAddress::from_string("0000:00:gg.0").expect_err("parse should fail"),
+ PciAddress::from_str("0000:00:gg.0").expect_err("parse should fail"),
Error::InvalidHex(PciAddressComponent::Device)
);
}
@@ -248,7 +258,7 @@
#[test]
fn from_string_invalid_dev_range() {
assert_eq!(
- PciAddress::from_string("0000:00:20.0").expect_err("parse should fail"),
+ PciAddress::from_str("0000:00:20.0").expect_err("parse should fail"),
Error::ComponentOutOfRange(PciAddressComponent::Device)
);
}
@@ -256,7 +266,7 @@
#[test]
fn from_string_invalid_bus_hex() {
assert_eq!(
- PciAddress::from_string("0000:gg:00.0").expect_err("parse should fail"),
+ PciAddress::from_str("0000:gg:00.0").expect_err("parse should fail"),
Error::InvalidHex(PciAddressComponent::Bus)
);
}
@@ -264,7 +274,7 @@
#[test]
fn from_string_invalid_bus_range() {
assert_eq!(
- PciAddress::from_string("0000:100:00.0").expect_err("parse should fail"),
+ PciAddress::from_str("0000:100:00.0").expect_err("parse should fail"),
Error::ComponentOutOfRange(PciAddressComponent::Bus)
);
}
@@ -272,7 +282,7 @@
#[test]
fn from_string_invalid_domain_hex() {
assert_eq!(
- PciAddress::from_string("gggg:00:00.0").expect_err("parse should fail"),
+ PciAddress::from_str("gggg:00:00.0").expect_err("parse should fail"),
Error::InvalidHex(PciAddressComponent::Domain)
);
}
@@ -280,8 +290,24 @@
#[test]
fn from_string_invalid_domain_range() {
assert_eq!(
- PciAddress::from_string("0001:00:00.0").expect_err("parse should fail"),
+ PciAddress::from_str("0001:00:00.0").expect_err("parse should fail"),
Error::ComponentOutOfRange(PciAddressComponent::Domain)
);
}
+
+ #[test]
+ fn format_simple() {
+ assert_eq!(
+ PciAddress::new(0, 1, 2, 3).unwrap().to_string(),
+ "0000:01:02.3"
+ );
+ }
+
+ #[test]
+ fn format_max() {
+ assert_eq!(
+ PciAddress::new(0, 0xff, 0x1f, 7).unwrap().to_string(),
+ "0000:ff:1f.7"
+ );
+ }
}
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs
index 439cf8d..ad9db69 100644
--- a/devices/src/pci/pci_configuration.rs
+++ b/devices/src/pci/pci_configuration.rs
@@ -15,12 +15,16 @@
// The number of 32bit registers in the config space, 256 bytes.
const NUM_CONFIGURATION_REGISTERS: usize = 64;
+pub const PCI_ID_REG: usize = 0;
pub const COMMAND_REG: usize = 1;
pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001;
pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
const STATUS_REG: usize = 1;
pub const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
+#[cfg(unix)]
pub const CLASS_REG: usize = 2;
+#[cfg(feature = "direct")]
+pub const CLASS_REG_REVISION_ID_OFFSET: usize = 0;
pub const HEADER_TYPE_REG: usize = 3;
pub const HEADER_TYPE_MULTIFUNCTION_MASK: u32 = 0x0080_0000;
pub const BAR0_REG: usize = 4;
@@ -33,6 +37,7 @@
pub const ROM_BAR_IDX: PciBarIndex = 6;
pub const ROM_BAR_REG: usize = 12;
pub const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
+#[cfg(unix)]
pub const PCI_CAP_NEXT_POINTER: usize = 0x1;
const FIRST_CAPABILITY_OFFSET: usize = 0x40;
pub const CAPABILITY_MAX_OFFSET: usize = 255;
@@ -49,7 +54,7 @@
/// Classes of PCI nodes.
#[allow(dead_code)]
-#[derive(Copy, Clone, enumn::N)]
+#[derive(Copy, Clone, enumn::N, Serialize, Deserialize)]
pub enum PciClassCode {
TooOld,
MassStorage,
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs
index 9983b44..06f3d24 100644
--- a/devices/src/pci/pci_device.rs
+++ b/devices/src/pci/pci_device.rs
@@ -14,13 +14,13 @@
use crate::bus::{BusDeviceObj, BusRange, BusType, ConfigWriteResult};
use crate::pci::pci_configuration::{
self, PciBarConfiguration, BAR0_REG, COMMAND_REG, COMMAND_REG_IO_SPACE_MASK,
- COMMAND_REG_MEMORY_SPACE_MASK, NUM_BAR_REGS, ROM_BAR_REG,
+ COMMAND_REG_MEMORY_SPACE_MASK, NUM_BAR_REGS, PCI_ID_REG, ROM_BAR_REG,
};
use crate::pci::{PciAddress, PciAddressError, PciInterruptPin};
use crate::virtio::ipc_memory_mapper::IpcMemoryMapper;
#[cfg(feature = "audio")]
use crate::virtio::snd::vios_backend::Error as VioSError;
-use crate::{BusAccessInfo, BusDevice};
+use crate::{BusAccessInfo, BusDevice, IrqLevelEvent};
#[sorted]
#[derive(Error, Debug)]
@@ -96,8 +96,7 @@
/// If legacy INTx is used, function shall return requested IRQ number and PCI INTx pin.
fn assign_irq(
&mut self,
- _irq_evt: &Event,
- _irq_resample_evt: &Event,
+ _irq_evt: &IrqLevelEvent,
_irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
None
@@ -199,6 +198,11 @@
PciDevice::debug_label(self)
}
+ fn device_id(&self) -> u32 {
+ // Use the PCI ID for PCI devices, which contains the PCI vendor ID and the PCI device ID
+ PciDevice::read_config_register(self, PCI_ID_REG)
+ }
+
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
self.read_bar(info.address, data)
}
@@ -363,11 +367,10 @@
}
fn assign_irq(
&mut self,
- irq_evt: &Event,
- irq_resample_evt: &Event,
+ irq_evt: &IrqLevelEvent,
irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
- (**self).assign_irq(irq_evt, irq_resample_evt, irq_num)
+ (**self).assign_irq(irq_evt, irq_num)
}
fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<BarRange>> {
(**self).allocate_io_bars(resources)
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
index 0989eb2..517964e 100644
--- a/devices/src/pci/pci_root.rs
+++ b/devices/src/pci/pci_root.rs
@@ -15,7 +15,7 @@
HEADER_TYPE_MULTIFUNCTION_MASK, HEADER_TYPE_REG,
};
use crate::pci::pci_device::{Error, PciDevice};
-use crate::pci::{PciAddress, PCI_VENDOR_ID_INTEL};
+use crate::pci::{PciAddress, PciId, PCI_VENDOR_ID_INTEL};
use crate::{Bus, BusAccessInfo, BusDevice, BusType};
use resources::SystemAllocator;
@@ -314,6 +314,10 @@
format!("pci config io-port 0x{:03x}", self.config_address)
}
+ fn device_id(&self) -> u32 {
+ PciId::new(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441).into()
+ }
+
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
// `offset` is relative to 0xcf8
let value = match info.offset {
@@ -387,6 +391,10 @@
"pci config mmio".to_owned()
}
+ fn device_id(&self) -> u32 {
+ PciId::new(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441).into()
+ }
+
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
// Only allow reads to the register boundary.
let start = info.offset as usize % 4;
@@ -440,6 +448,10 @@
"pci virtual config mmio".to_owned()
}
+ fn device_id(&self) -> u32 {
+ PciId::new(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441).into()
+ }
+
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
let value = if info.offset % 4 != 0 || data.len() != 4 {
error!(
diff --git a/devices/src/pci/pcie/pci_bridge.rs b/devices/src/pci/pcie/pci_bridge.rs
index 4da7582..9fe194b 100644
--- a/devices/src/pci/pcie/pci_bridge.rs
+++ b/devices/src/pci/pcie/pci_bridge.rs
@@ -12,11 +12,12 @@
PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PCI_VENDOR_ID_INTEL,
};
use crate::PciInterruptPin;
-use base::{warn, AsRawDescriptor, Event, RawDescriptor, Tube};
+use base::{warn, AsRawDescriptors, Event, RawDescriptor, Tube};
use hypervisor::Datamatch;
use resources::{Alloc, MmioType, SystemAllocator};
use crate::pci::pcie::pcie_device::PcieDevice;
+use crate::IrqLevelEvent;
const BR_MSIX_TABLE_OFFSET: u64 = 0x0;
const BR_MSIX_PBA_OFFSET: u64 = 0x100;
@@ -57,14 +58,18 @@
setting_bar: u8,
msix_config: Arc<Mutex<MsixConfig>>,
msix_cap_reg_idx: Option<usize>,
- interrupt_evt: Option<Event>,
- interrupt_resample_evt: Option<Event>,
+ interrupt_evt: Option<IrqLevelEvent>,
}
impl PciBridge {
pub fn new(device: Arc<Mutex<dyn PcieDevice>>, msi_device_tube: Tube) -> Self {
- let msix_config = Arc::new(Mutex::new(MsixConfig::new(1, msi_device_tube)));
let device_id = device.lock().get_device_id();
+ let msix_config = Arc::new(Mutex::new(MsixConfig::new(
+ 1,
+ msi_device_tube,
+ (PCI_VENDOR_ID_INTEL as u32) | (device_id as u32) << 16,
+ device.lock().debug_label(),
+ )));
let mut config = PciConfiguration::new(
PCI_VENDOR_ID_INTEL,
device_id,
@@ -98,7 +103,6 @@
msix_config,
msix_cap_reg_idx: None,
interrupt_evt: None,
- interrupt_resample_evt: None,
}
}
@@ -183,10 +187,7 @@
fn keep_rds(&self) -> Vec<RawDescriptor> {
let mut rds = Vec::new();
if let Some(interrupt_evt) = &self.interrupt_evt {
- rds.push(interrupt_evt.as_raw_descriptor());
- }
- if let Some(interrupt_resample_evt) = &self.interrupt_resample_evt {
- rds.push(interrupt_resample_evt.as_raw_descriptor());
+ rds.extend(interrupt_evt.as_raw_descriptors());
}
let descriptor = self.msix_config.lock().get_msi_socket();
rds.push(descriptor);
@@ -195,12 +196,10 @@
fn assign_irq(
&mut self,
- irq_evt: &Event,
- irq_resample_evt: &Event,
+ irq_evt: &IrqLevelEvent,
irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
self.interrupt_evt = Some(irq_evt.try_clone().ok()?);
- self.interrupt_resample_evt = Some(irq_resample_evt.try_clone().ok()?);
let msix_config_clone = self.msix_config.clone();
self.device.lock().clone_interrupt(msix_config_clone);
diff --git a/devices/src/pci/pcie/pcie_host.rs b/devices/src/pci/pcie/pcie_host.rs
index 7e94fe6..aae1ccb 100644
--- a/devices/src/pci/pcie/pcie_host.rs
+++ b/devices/src/pci/pcie/pcie_host.rs
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#[cfg(feature = "direct")]
+use std::fs::read_to_string;
use std::fs::{read, write, File, OpenOptions};
use std::os::unix::fs::FileExt;
use std::path::{Path, PathBuf};
@@ -9,6 +11,8 @@
use std::thread;
use anyhow::{anyhow, bail, Context, Result};
+#[cfg(feature = "direct")]
+use base::warn;
use base::{error, Tube};
use data_model::DataInit;
use sync::Mutex;
@@ -17,8 +21,10 @@
use crate::pci::{PciCapabilityID, PciClassCode};
use crate::pci::pci_configuration::{
- PciBridgeSubclass, CAPABILITY_LIST_HEAD_OFFSET, PCI_CAP_NEXT_POINTER,
+ PciBridgeSubclass, CAPABILITY_LIST_HEAD_OFFSET, HEADER_TYPE_REG, PCI_CAP_NEXT_POINTER,
};
+#[cfg(feature = "direct")]
+use crate::pci::pci_configuration::{CLASS_REG, CLASS_REG_REVISION_ID_OFFSET};
use crate::pci::pcie::pci_bridge::{
PciBridgeBusRange, BR_BUS_NUMBER_REG, BR_MEM_BASE_MASK, BR_MEM_BASE_SHIFT, BR_MEM_LIMIT_MASK,
@@ -214,6 +220,10 @@
hotplug_in_process: Arc<Mutex<bool>>,
hotplug_child_exist: Arc<Mutex<bool>>,
vm_socket: Arc<Mutex<Tube>>,
+ #[cfg(feature = "direct")]
+ sysfs_path: Option<PathBuf>,
+ #[cfg(feature = "direct")]
+ header_type_reg: Option<u32>,
}
impl PcieHostRootPort {
@@ -260,12 +270,36 @@
return Err(anyhow!("host {} isn't pcie root port", host_name));
}
+ #[cfg(feature = "direct")]
+ let (sysfs_path, header_type_reg) =
+ match PcieHostRootPort::coordinated_pm(host_sysfs_path, true) {
+ Ok(_) => {
+ // Cache the dword at offset 0x0c (cacheline size, latency timer,
+ // header type, BIST).
+ // When using the "direct" feature, this dword can be accessed for
+ // device power state. Directly accessing a device's physical PCI
+ // config space in D3cold state causes a hang. We treat the cacheline
+ // size, latency timer and header type field as immutable in the
+ // guest.
+ let reg: u32 = host_config.read_config((HEADER_TYPE_REG as u64) * 4);
+ (Some(host_sysfs_path.to_path_buf()), Some(reg))
+ }
+ Err(e) => {
+ warn!("coordinated_pm not supported: {}", e);
+ (None, None)
+ }
+ };
+
Ok(PcieHostRootPort {
host_config,
host_name,
hotplug_in_process: Arc::new(Mutex::new(false)),
hotplug_child_exist: Arc::new(Mutex::new(false)),
vm_socket: Arc::new(Mutex::new(socket)),
+ #[cfg(feature = "direct")]
+ sysfs_path,
+ #[cfg(feature = "direct")]
+ header_type_reg,
})
}
@@ -291,13 +325,40 @@
}
pub fn read_config(&self, reg_idx: usize, data: &mut u32) {
- if reg_idx == 3 {
- // device header type
- *data = self.host_config.read_config(0x0C);
+ if reg_idx == HEADER_TYPE_REG {
+ #[cfg(feature = "direct")]
+ if let Some(header_type_reg) = self.header_type_reg {
+ let mut v = header_type_reg.to_le_bytes();
+ // HACK
+ // Reads from the "BIST" register are interpreted as device
+ // PCI power state
+ v[3] = self.power_state().unwrap_or_else(|e| {
+ error!("Failed to get device power state: {}", e);
+ 5 // unknown state
+ });
+ *data = u32::from_le_bytes(v);
+ return;
+ }
+ *data = self.host_config.read_config((HEADER_TYPE_REG as u64) * 4)
}
}
- pub fn write_config(&mut self, _reg_idx: usize, _offset: u64, _data: &[u8]) {}
+ #[allow(unused_variables)]
+ pub fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
+ #[cfg(feature = "direct")]
+ if self.sysfs_path.is_some()
+ && reg_idx == CLASS_REG
+ && offset == CLASS_REG_REVISION_ID_OFFSET as u64
+ && data.len() == 1
+ {
+ // HACK
+ // Byte writes to the "Revision ID" register are interpreted as PM
+ // op calls
+ if let Err(e) = self.op_call(data[0]) {
+ error!("Failed to perform op call: {}", e);
+ }
+ }
+ }
pub fn get_bridge_window_size(&self) -> (u64, u64) {
let br_memory: u32 = self.host_config.read_config(BR_MEM_REG as u64 * 4);
@@ -356,4 +417,46 @@
pub fn hot_unplug(&mut self) {
*self.hotplug_child_exist.lock() = false;
}
+
+ #[cfg(feature = "direct")]
+ fn coordinated_pm(host_sysfs_path: &Path, enter: bool) -> Result<()> {
+ let path = Path::new(host_sysfs_path).join("power/coordinated");
+ write(&path, if enter { "enter\n" } else { "exit\n" })
+ .with_context(|| format!("Failed to write to {}", path.to_string_lossy()))
+ }
+
+ #[cfg(feature = "direct")]
+ fn power_state(&self) -> Result<u8> {
+ let path = Path::new(&self.sysfs_path.as_ref().unwrap()).join("power_state");
+ let state = read_to_string(&path)
+ .with_context(|| format!("Failed to read from {}", path.to_string_lossy()))?;
+ match state.as_str() {
+ "D0\n" => Ok(0),
+ "D1\n" => Ok(1),
+ "D2\n" => Ok(2),
+ "D3hot\n" => Ok(3),
+ "D3cold\n" => Ok(4),
+ "unknown\n" => Ok(5),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "invalid state",
+ ))?,
+ }
+ }
+
+ #[cfg(feature = "direct")]
+ fn op_call(&self, id: u8) -> Result<()> {
+ let path = Path::new(self.sysfs_path.as_ref().unwrap()).join("power/op_call");
+ write(&path, &[id])
+ .with_context(|| format!("Failed to write to {}", path.to_string_lossy()))
+ }
+}
+
+#[cfg(feature = "direct")]
+impl Drop for PcieHostRootPort {
+ fn drop(&mut self) {
+ if self.sysfs_path.is_some() {
+ let _ = PcieHostRootPort::coordinated_pm(self.sysfs_path.as_ref().unwrap(), false);
+ }
+ }
}
diff --git a/devices/src/pci/pcie/pcie_rp.rs b/devices/src/pci/pcie/pcie_rp.rs
index e5e4ea4..06f591e 100644
--- a/devices/src/pci/pcie/pcie_rp.rs
+++ b/devices/src/pci/pcie/pcie_rp.rs
@@ -1,6 +1,8 @@
// Copyright 2021 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::str::FromStr;
use std::sync::Arc;
use sync::Mutex;
@@ -310,7 +312,7 @@
if self.pci_address.is_none() {
match &self.pcie_host {
Some(host) => {
- let address = PciAddress::from_string(&host.host_name())
+ let address = PciAddress::from_str(&host.host_name())
.map_err(|e| PciDeviceError::PciAddressParseFailure(host.host_name(), e))?;
if resources.reserve_pci(
Alloc::PciBar {
diff --git a/devices/src/pci/pvpanic.rs b/devices/src/pci/pvpanic.rs
index 009d60f..7806186 100644
--- a/devices/src/pci/pvpanic.rs
+++ b/devices/src/pci/pvpanic.rs
@@ -9,6 +9,9 @@
//!
//! This implementation emulates pci interface for pvpanic virtual device.
+// TODO(218575411): Support pvpanic on windows crosvm.
+#![cfg_attr(windows, allow(dead_code))]
+
use std::fmt;
use base::RawDescriptor;
diff --git a/devices/src/pci/stub.rs b/devices/src/pci/stub.rs
index 3c0386e..08b1743 100644
--- a/devices/src/pci/stub.rs
+++ b/devices/src/pci/stub.rs
@@ -21,7 +21,9 @@
};
use crate::pci::pci_device::{PciDevice, Result};
use crate::pci::{PciAddress, PciDeviceError};
+use serde::{Deserialize, Serialize};
+#[derive(Serialize, Deserialize)]
pub struct StubPciParameters {
pub address: PciAddress,
pub vendor_id: u16,
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index 66fd428..ca9dc38 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -2,16 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#[cfg(feature = "direct")]
+use anyhow::Context;
use std::cmp::{max, min, Reverse};
use std::collections::{BTreeMap, BTreeSet};
use std::fs;
+#[cfg(feature = "direct")]
+use std::path::Path;
use std::path::PathBuf;
+use std::str::FromStr;
use std::sync::Arc;
use std::thread;
use std::u32;
+use sync::Mutex;
use base::{
- error, pagesize, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, Tube, WaitContext,
+ error, pagesize, warn, AsRawDescriptor, AsRawDescriptors, Event, PollToken, RawDescriptor,
+ Tube, WaitContext,
};
use hypervisor::{Datamatch, MemSlot};
@@ -24,19 +31,22 @@
};
use crate::pci::msix::{
- MsixConfig, BITS_PER_PBA_ENTRY, MSIX_PBA_ENTRIES_MODULO, MSIX_TABLE_ENTRIES_MODULO,
+ MsixConfig, MsixStatus, BITS_PER_PBA_ENTRY, MSIX_PBA_ENTRIES_MODULO, MSIX_TABLE_ENTRIES_MODULO,
};
+#[cfg(feature = "direct")]
+use crate::pci::pci_configuration::{CLASS_REG, CLASS_REG_REVISION_ID_OFFSET, HEADER_TYPE_REG};
use crate::pci::pci_device::{BarRange, Error as PciDeviceError, PciDevice};
use crate::pci::{
PciAddress, PciBarConfiguration, PciBarIndex, PciBarPrefetchable, PciBarRegionType,
- PciClassCode, PciInterruptPin,
+ PciClassCode, PciId, PciInterruptPin, PCI_VENDOR_ID_INTEL,
};
-use crate::vfio::{VfioDevice, VfioIrqType, VfioPciConfig};
+use crate::vfio::{VfioDevice, VfioError, VfioIrqType, VfioPciConfig};
+use crate::IrqLevelEvent;
const PCI_VENDOR_ID: u32 = 0x0;
-const INTEL_VENDOR_ID: u16 = 0x8086;
+const PCI_DEVICE_ID: u32 = 0x2;
const PCI_COMMAND: u32 = 0x4;
const PCI_COMMAND_MEMORY: u8 = 0x2;
const PCI_BASE_CLASS_CODE: u32 = 0x0B;
@@ -67,6 +77,7 @@
enum VfioMsiChange {
Disable,
Enable,
+ FunctionChanged,
}
struct VfioMsiCap {
@@ -79,10 +90,18 @@
vm_socket_irq: Tube,
irqfd: Option<Event>,
gsi: Option<u32>,
+ device_id: u32,
+ device_name: String,
}
impl VfioMsiCap {
- fn new(config: &VfioPciConfig, msi_cap_start: u32, vm_socket_irq: Tube) -> Self {
+ fn new(
+ config: &VfioPciConfig,
+ msi_cap_start: u32,
+ vm_socket_irq: Tube,
+ device_id: u32,
+ device_name: String,
+ ) -> Self {
let msi_ctl: u16 = config.read_config(msi_cap_start + PCI_MSI_FLAGS);
VfioMsiCap {
@@ -95,6 +114,8 @@
vm_socket_irq,
irqfd: None,
gsi: None,
+ device_id,
+ device_name,
}
}
@@ -205,12 +226,17 @@
},
};
- let request = VmIrqRequest::AllocateOneMsi { irqfd };
+ let request = VmIrqRequest::AllocateOneMsi {
+ irqfd,
+ device_id: self.device_id,
+ queue_id: 0,
+ device_name: self.device_name.clone(),
+ };
let request_result = self.vm_socket_irq.send(&request);
// Stash the irqfd in self immediately because we used take above.
self.irqfd = match request {
- VmIrqRequest::AllocateOneMsi { irqfd } => Some(irqfd),
+ VmIrqRequest::AllocateOneMsi { irqfd, .. } => Some(irqfd),
_ => unreachable!(),
};
@@ -269,10 +295,17 @@
pba_pci_bar: u32,
pba_offset: u64,
pba_size_bytes: u64,
+ msix_interrupt_evt: Vec<Event>,
}
impl VfioMsixCap {
- fn new(config: &VfioPciConfig, msix_cap_start: u32, vm_socket_irq: Tube) -> Self {
+ fn new(
+ config: &VfioPciConfig,
+ msix_cap_start: u32,
+ vm_socket_irq: Tube,
+ pci_id: u32,
+ device_name: String,
+ ) -> Self {
let msix_ctl: u16 = config.read_config(msix_cap_start + PCI_MSIX_FLAGS);
let table: u32 = config.read_config(msix_cap_start + PCI_MSIX_TABLE);
let table_pci_bar = table & PCI_MSIX_TABLE_BIR;
@@ -293,9 +326,12 @@
let pba_size_bytes = ((table_size + BITS_PER_PBA_ENTRY as u64 - 1)
/ BITS_PER_PBA_ENTRY as u64)
* MSIX_PBA_ENTRIES_MODULO;
-
+ let mut msix_interrupt_evt = Vec::new();
+ for _ in 0..table_size {
+ msix_interrupt_evt.push(Event::new().expect("failed to create msix interrupt"));
+ }
VfioMsixCap {
- config: MsixConfig::new(table_size as u16, vm_socket_irq),
+ config: MsixConfig::new(table_size as u16, vm_socket_irq, pci_id, device_name),
offset: msix_cap_start,
table_size: table_size as u16,
table_pci_bar,
@@ -304,6 +340,7 @@
pba_pci_bar,
pba_offset,
pba_size_bytes,
+ msix_interrupt_evt,
}
}
@@ -328,10 +365,13 @@
let new_enabled = self.config.enabled();
let new_masked = self.config.masked();
- if (!old_enabled && new_enabled) || (new_enabled && old_masked && !new_masked) {
+
+ if !old_enabled && new_enabled {
Some(VfioMsiChange::Enable)
- } else if (old_enabled && !new_enabled) || (new_enabled && !old_masked && new_masked) {
+ } else if old_enabled && !new_enabled {
Some(VfioMsiChange::Disable)
+ } else if new_enabled && old_masked != new_masked {
+ Some(VfioMsiChange::FunctionChanged)
} else {
None
}
@@ -356,9 +396,9 @@
self.config.read_msix_table(offset, data);
}
- fn write_table(&mut self, offset: u64, data: &[u8]) {
+ fn write_table(&mut self, offset: u64, data: &[u8]) -> MsixStatus {
let offset = offset - self.table_offset;
- self.config.write_msix_table(offset, data);
+ self.config.write_msix_table(offset, data)
}
fn is_msix_pba(&self, bar_index: u32, offset: u64) -> bool {
@@ -385,19 +425,46 @@
self.config.write_pba_entries(offset, data);
}
- fn get_msix_irqfds(&self) -> Option<Vec<&Event>> {
+ fn get_msix_irqfd(&self, index: usize) -> Option<&Event> {
+ let irqfd = self.config.get_irqfd(index);
+ if let Some(fd) = irqfd {
+ if self.msix_vector_masked(index) {
+ Some(&self.msix_interrupt_evt[index])
+ } else {
+ Some(fd)
+ }
+ } else {
+ None
+ }
+ }
+
+ fn get_msix_irqfds(&self) -> Vec<Option<&Event>> {
let mut irqfds = Vec::new();
for i in 0..self.table_size {
- let irqfd = self.config.get_irqfd(i as usize);
- if let Some(fd) = irqfd {
- irqfds.push(fd);
- } else {
- return None;
- }
+ irqfds.push(self.get_msix_irqfd(i as usize));
}
- Some(irqfds)
+ irqfds
+ }
+
+ fn table_size(&self) -> usize {
+ self.table_size.into()
+ }
+
+ fn clone_msix_evt(&self) -> Vec<Event> {
+ self.msix_interrupt_evt
+ .iter()
+ .map(|irq| irq.try_clone().unwrap())
+ .collect()
+ }
+
+ fn msix_vector_masked(&self, index: usize) -> bool {
+ !self.config.enabled() || self.config.masked() || self.config.table_masked(index)
+ }
+
+ fn trigger(&mut self, index: usize) {
+ self.config.trigger(index as u16);
}
fn destroy(&mut self) {
@@ -506,14 +573,16 @@
struct VfioPciWorker {
vm_socket: Tube,
name: String,
+ msix_cap: Option<Arc<Mutex<VfioMsixCap>>>,
}
impl VfioPciWorker {
- fn run(&mut self, req_irq_evt: Event, kill_evt: Event) {
+ fn run(&mut self, req_irq_evt: Event, kill_evt: Event, msix_evt: Vec<Event>) {
#[derive(PollToken)]
enum Token {
ReqIrq,
Kill,
+ MsixIrqi { index: usize },
}
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
@@ -531,6 +600,12 @@
}
};
+ for (index, msix_int) in msix_evt.iter().enumerate() {
+ wait_ctx
+ .add(msix_int, Token::MsixIrqi { index })
+ .expect("Failed to create vfio WaitContext for msix interrupt event")
+ }
+
'wait: loop {
let events = match wait_ctx.wait() {
Ok(v) => v,
@@ -542,6 +617,11 @@
for event in events.iter().filter(|e| e.is_readable) {
match event.token {
+ Token::MsixIrqi { index } => {
+ if let Some(msix_cap) = &self.msix_cap {
+ msix_cap.lock().trigger(index);
+ }
+ }
Token::ReqIrq => {
let mut sysfs_path = PathBuf::new();
sysfs_path.push("/sys/bus/pci/devices/");
@@ -576,18 +656,21 @@
hotplug_bus_number: Option<u8>, // hot plug device has bus number specified at device creation.
guest_address: Option<PciAddress>,
pci_address: Option<PciAddress>,
- interrupt_evt: Option<Event>,
- interrupt_resample_evt: Option<Event>,
+ interrupt_evt: Option<IrqLevelEvent>,
mmio_regions: Vec<PciBarConfiguration>,
io_regions: Vec<PciBarConfiguration>,
msi_cap: Option<VfioMsiCap>,
- msix_cap: Option<VfioMsixCap>,
+ msix_cap: Option<Arc<Mutex<VfioMsixCap>>>,
irq_type: Option<VfioIrqType>,
vm_socket_mem: Tube,
device_data: Option<DeviceData>,
kill_evt: Option<Event>,
worker_thread: Option<thread::JoinHandle<VfioPciWorker>>,
vm_socket_vm: Option<Tube>,
+ #[cfg(feature = "direct")]
+ sysfs_path: Option<PathBuf>,
+ #[cfg(feature = "direct")]
+ header_type_reg: Option<u32>,
mapped_mmio_bars: BTreeMap<PciBarIndex, (u64, Vec<MemSlot>)>,
}
@@ -595,6 +678,7 @@
impl VfioPciDevice {
/// Constructs a new Vfio Pci device for the give Vfio device
pub fn new(
+ #[cfg(feature = "direct")] sysfs_path: &Path,
device: VfioDevice,
hotplug_bus_number: Option<u8>,
guest_address: Option<PciAddress>,
@@ -608,28 +692,44 @@
let mut msi_socket = Some(vfio_device_socket_msi);
let mut msix_socket = Some(vfio_device_socket_msix);
let mut msi_cap: Option<VfioMsiCap> = None;
- let mut msix_cap: Option<VfioMsixCap> = None;
+ let mut msix_cap: Option<Arc<Mutex<VfioMsixCap>>> = None;
let mut cap_next: u32 = config.read_config::<u8>(PCI_CAPABILITY_LIST).into();
+ let vendor_id: u16 = config.read_config(PCI_VENDOR_ID);
+ let device_id: u16 = config.read_config(PCI_DEVICE_ID);
+
+ let pci_id = PciId::new(vendor_id, device_id);
+
while cap_next != 0 {
let cap_id: u8 = config.read_config(cap_next);
if cap_id == PCI_CAP_ID_MSI {
if let Some(msi_socket) = msi_socket.take() {
- msi_cap = Some(VfioMsiCap::new(&config, cap_next, msi_socket));
+ msi_cap = Some(VfioMsiCap::new(
+ &config,
+ cap_next,
+ msi_socket,
+ pci_id.into(),
+ dev.device_name().to_string(),
+ ));
}
} else if cap_id == PCI_CAP_ID_MSIX {
if let Some(msix_socket) = msix_socket.take() {
- msix_cap = Some(VfioMsixCap::new(&config, cap_next, msix_socket));
+ msix_cap = Some(Arc::new(Mutex::new(VfioMsixCap::new(
+ &config,
+ cap_next,
+ msix_socket,
+ pci_id.into(),
+ dev.device_name().to_string(),
+ ))));
}
}
let offset = cap_next + PCI_MSI_NEXT_POINTER;
cap_next = config.read_config::<u8>(offset).into();
}
- let vendor_id: u16 = config.read_config(PCI_VENDOR_ID);
let class_code: u8 = config.read_config(PCI_BASE_CLASS_CODE);
- let is_intel_gfx = vendor_id == INTEL_VENDOR_ID
+ let is_intel_gfx = vendor_id == PCI_VENDOR_ID_INTEL
&& class_code == PciClassCode::DisplayController.get_register_value();
let device_data = if is_intel_gfx {
Some(DeviceData::IntelGfxData {
@@ -639,6 +739,25 @@
None
};
+ #[cfg(feature = "direct")]
+ let (sysfs_path, header_type_reg) = match VfioPciDevice::coordinated_pm(sysfs_path, true) {
+ Ok(_) => {
+ // Cache the dword at offset 0x0c (cacheline size, latency timer,
+ // header type, BIST).
+ // When using the "direct" feature, this dword can be accessed for
+ // device power state. Directly accessing a device's physical PCI
+ // config space in D3cold state causes a hang. We treat the cacheline
+ // size, latency timer and header type field as immutable in the
+ // guest.
+ let reg: u32 = config.read_config((HEADER_TYPE_REG as u32) * 4);
+ (Some(sysfs_path.to_path_buf()), Some(reg))
+ }
+ Err(e) => {
+ warn!("coordinated_pm not supported: {}", e);
+ (None, None)
+ }
+ };
+
VfioPciDevice {
device: dev,
config,
@@ -646,7 +765,6 @@
guest_address,
pci_address: None,
interrupt_evt: None,
- interrupt_resample_evt: None,
mmio_regions: Vec::new(),
io_regions: Vec::new(),
msi_cap,
@@ -657,6 +775,10 @@
kill_evt: None,
worker_thread: None,
vm_socket_vm: vfio_device_socket_vm,
+ #[cfg(feature = "direct")]
+ sysfs_path,
+ #[cfg(feature = "direct")]
+ header_type_reg,
mapped_mmio_bars: BTreeMap::new(),
}
}
@@ -684,41 +806,35 @@
}
fn enable_intx(&mut self) {
- if self.interrupt_evt.is_none() || self.interrupt_resample_evt.is_none() {
- return;
- }
-
if let Some(ref interrupt_evt) = self.interrupt_evt {
- if let Err(e) = self
- .device
- .irq_enable(&[interrupt_evt], VFIO_PCI_INTX_IRQ_INDEX)
- {
+ if let Err(e) = self.device.irq_enable(
+ &[Some(interrupt_evt.get_trigger())],
+ VFIO_PCI_INTX_IRQ_INDEX,
+ 0,
+ ) {
error!("{} Intx enable failed: {}", self.debug_label(), e);
return;
}
- if let Some(ref irq_resample_evt) = self.interrupt_resample_evt {
- if let Err(e) = self.device.irq_mask(VFIO_PCI_INTX_IRQ_INDEX) {
- error!("{} Intx mask failed: {}", self.debug_label(), e);
- self.disable_intx();
- return;
- }
- if let Err(e) = self
- .device
- .resample_virq_enable(irq_resample_evt, VFIO_PCI_INTX_IRQ_INDEX)
- {
- error!("{} resample enable failed: {}", self.debug_label(), e);
- self.disable_intx();
- return;
- }
- if let Err(e) = self.device.irq_unmask(VFIO_PCI_INTX_IRQ_INDEX) {
- error!("{} Intx unmask failed: {}", self.debug_label(), e);
- self.disable_intx();
- return;
- }
+ if let Err(e) = self.device.irq_mask(VFIO_PCI_INTX_IRQ_INDEX) {
+ error!("{} Intx mask failed: {}", self.debug_label(), e);
+ self.disable_intx();
+ return;
}
+ if let Err(e) = self
+ .device
+ .resample_virq_enable(interrupt_evt.get_resample(), VFIO_PCI_INTX_IRQ_INDEX)
+ {
+ error!("{} resample enable failed: {}", self.debug_label(), e);
+ self.disable_intx();
+ return;
+ }
+ if let Err(e) = self.device.irq_unmask(VFIO_PCI_INTX_IRQ_INDEX) {
+ error!("{} Intx unmask failed: {}", self.debug_label(), e);
+ self.disable_intx();
+ return;
+ }
+ self.irq_type = Some(VfioIrqType::Intx);
}
-
- self.irq_type = Some(VfioIrqType::Intx);
}
fn disable_intx(&mut self) {
@@ -760,7 +876,10 @@
}
};
- if let Err(e) = self.device.irq_enable(&[irqfd], VFIO_PCI_MSI_IRQ_INDEX) {
+ if let Err(e) = self
+ .device
+ .irq_enable(&[Some(irqfd)], VFIO_PCI_MSI_IRQ_INDEX, 0)
+ {
error!("{} failed to enable msi: {}", self.debug_label(), e);
self.enable_intx();
return;
@@ -780,46 +899,94 @@
}
fn enable_msix(&mut self) {
- self.disable_irqs();
-
- let irqfds = match &self.msix_cap {
- Some(cap) => cap.get_msix_irqfds(),
- None => return,
- };
-
- if let Some(descriptors) = irqfds {
- if let Err(e) = self
- .device
- .irq_enable(&descriptors, VFIO_PCI_MSIX_IRQ_INDEX)
- {
- error!("{} failed to enable msix: {}", self.debug_label(), e);
- self.enable_intx();
- return;
- }
- } else {
- self.enable_intx();
+ if self.msix_cap.is_none() {
return;
}
+ self.disable_irqs();
+ let cap = self.msix_cap.as_ref().unwrap().lock();
+ let vector_in_use = cap.get_msix_irqfds().iter().any(|&irq| irq.is_some());
+
+ let mut failed = false;
+ if !vector_in_use {
+ // If there are no msix vectors currently in use, we explicitly assign a new eventfd
+ // to vector 0. Then we enable it and immediately disable it, so that vfio will
+ // activate physical device. If there are available msix vectors, just enable them
+ // instead.
+ let fd = Event::new().expect("failed to create event");
+ let table_size = cap.table_size();
+ let mut irqfds = vec![None; table_size];
+ irqfds[0] = Some(&fd);
+ for fd in irqfds.iter_mut().skip(1) {
+ *fd = None;
+ }
+ if let Err(e) = self.device.irq_enable(&irqfds, VFIO_PCI_MSIX_IRQ_INDEX, 0) {
+ error!("{} failed to enable msix: {}", self.debug_label(), e);
+ failed = true;
+ }
+ irqfds[0] = None;
+ if let Err(e) = self.device.irq_enable(&irqfds, VFIO_PCI_MSIX_IRQ_INDEX, 0) {
+ error!("{} failed to enable msix: {}", self.debug_label(), e);
+ failed = true;
+ }
+ } else {
+ let result = self
+ .device
+ .irq_enable(&cap.get_msix_irqfds(), VFIO_PCI_MSIX_IRQ_INDEX, 0);
+ if let Err(e) = result {
+ error!("{} failed to enable msix: {}", self.debug_label(), e);
+ failed = true;
+ }
+ }
+
+ std::mem::drop(cap);
+ if failed {
+ self.enable_intx();
+ return;
+ }
self.irq_type = Some(VfioIrqType::Msix);
}
fn disable_msix(&mut self) {
+ if self.msix_cap.is_none() {
+ return;
+ }
if let Err(e) = self.device.irq_disable(VFIO_PCI_MSIX_IRQ_INDEX) {
error!("{} failed to disable msix: {}", self.debug_label(), e);
return;
}
self.irq_type = None;
-
self.enable_intx();
}
+ fn msix_vectors_update(&self) -> Result<(), VfioError> {
+ if let Some(cap) = &self.msix_cap {
+ self.device
+ .irq_enable(&cap.lock().get_msix_irqfds(), VFIO_PCI_MSIX_IRQ_INDEX, 0)?;
+ }
+ Ok(())
+ }
+
+ fn msix_vector_update(&self, index: usize, irqfd: Option<&Event>) {
+ if let Err(e) = self
+ .device
+ .irq_enable(&[irqfd], VFIO_PCI_MSIX_IRQ_INDEX, index as u32)
+ {
+ error!(
+ "{} failed to update msix vector {}: {}",
+ self.debug_label(),
+ index,
+ e
+ );
+ }
+ }
+
fn add_bar_mmap_msix(
&self,
bar_index: u32,
bar_mmaps: Vec<vfio_region_sparse_mmap_area>,
) -> Vec<vfio_region_sparse_mmap_area> {
- let msix_cap = &self.msix_cap.as_ref().unwrap();
+ let msix_cap = &self.msix_cap.as_ref().unwrap().lock();
let mut msix_mmaps: Vec<(u64, u64)> = Vec::new();
if let Some(t) = msix_cap.get_msix_table(bar_index) {
@@ -983,8 +1150,8 @@
if let Some(msi) = self.msi_cap.as_mut() {
msi.destroy();
}
- if let Some(msix) = self.msix_cap.as_mut() {
- msix.destroy();
+ if let Some(msix) = &self.msix_cap {
+ msix.lock().destroy();
}
self.disable_bars_mmap();
self.device.close();
@@ -998,7 +1165,10 @@
let req_evt = match Event::new() {
Ok(evt) => {
- if let Err(e) = self.device.irq_enable(&[&evt], VFIO_PCI_REQ_IRQ_INDEX) {
+ if let Err(e) = self
+ .device
+ .irq_enable(&[Some(&evt)], VFIO_PCI_REQ_IRQ_INDEX, 0)
+ {
error!("{} enable req_irq failed: {}", self.debug_label(), e);
return;
}
@@ -1020,12 +1190,22 @@
};
self.kill_evt = Some(self_kill_evt);
+ let mut msix_evt = Vec::new();
+ if let Some(msix_cap) = &self.msix_cap {
+ msix_evt = msix_cap.lock().clone_msix_evt();
+ }
+
let name = self.device.device_name().to_string();
+ let msix_cap = self.msix_cap.clone();
let worker_result = thread::Builder::new()
.name("vfio_pci".to_string())
.spawn(move || {
- let mut worker = VfioPciWorker { vm_socket, name };
- worker.run(req_evt, kill_evt);
+ let mut worker = VfioPciWorker {
+ vm_socket,
+ name,
+ msix_cap,
+ };
+ worker.run(req_evt, kill_evt, msix_evt);
worker
});
@@ -1291,6 +1471,39 @@
}
Ok(ranges)
}
+
+ #[cfg(feature = "direct")]
+ fn coordinated_pm(sysfs_path: &Path, enter: bool) -> anyhow::Result<()> {
+ let path = Path::new(sysfs_path).join("power/coordinated");
+ fs::write(&path, if enter { "enter\n" } else { "exit\n" })
+ .with_context(|| format!("Failed to write to {}", path.to_string_lossy()))
+ }
+
+ #[cfg(feature = "direct")]
+ fn power_state(&self) -> anyhow::Result<u8> {
+ let path = Path::new(&self.sysfs_path.as_ref().unwrap()).join("power_state");
+ let state = fs::read_to_string(&path)
+ .with_context(|| format!("Failed to read from {}", path.to_string_lossy()))?;
+ match state.as_str() {
+ "D0\n" => Ok(0),
+ "D1\n" => Ok(1),
+ "D2\n" => Ok(2),
+ "D3hot\n" => Ok(3),
+ "D3cold\n" => Ok(4),
+ "unknown\n" => Ok(5),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "invalid state",
+ ))?,
+ }
+ }
+
+ #[cfg(feature = "direct")]
+ fn op_call(&self, id: u8) -> anyhow::Result<()> {
+ let path = Path::new(self.sysfs_path.as_ref().unwrap()).join("power/op_call");
+ fs::write(&path, &[id])
+ .with_context(|| format!("Failed to write to {}", path.to_string_lossy()))
+ }
}
impl PciDevice for VfioPciDevice {
@@ -1304,7 +1517,7 @@
) -> Result<PciAddress, PciDeviceError> {
if self.pci_address.is_none() {
let mut address = self.guest_address.unwrap_or(
- PciAddress::from_string(self.device.device_name()).map_err(|e| {
+ PciAddress::from_str(self.device.device_name()).map_err(|e| {
PciDeviceError::PciAddressParseFailure(self.device.device_name().clone(), e)
})?,
);
@@ -1334,25 +1547,21 @@
fn keep_rds(&self) -> Vec<RawDescriptor> {
let mut rds = self.device.keep_rds();
if let Some(ref interrupt_evt) = self.interrupt_evt {
- rds.push(interrupt_evt.as_raw_descriptor());
- }
- if let Some(ref interrupt_resample_evt) = self.interrupt_resample_evt {
- rds.push(interrupt_resample_evt.as_raw_descriptor());
+ rds.extend(interrupt_evt.as_raw_descriptors());
}
rds.push(self.vm_socket_mem.as_raw_descriptor());
if let Some(msi_cap) = &self.msi_cap {
rds.push(msi_cap.vm_socket_irq.as_raw_descriptor());
}
if let Some(msix_cap) = &self.msix_cap {
- rds.push(msix_cap.config.as_raw_descriptor());
+ rds.push(msix_cap.lock().config.as_raw_descriptor());
}
rds
}
fn assign_irq(
&mut self,
- irq_evt: &Event,
- irq_resample_evt: &Event,
+ irq_evt: &IrqLevelEvent,
_irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
// Is INTx configured?
@@ -1366,7 +1575,6 @@
// Keep event/resample event references.
self.interrupt_evt = Some(irq_evt.try_clone().ok()?);
- self.interrupt_resample_evt = Some(irq_resample_evt.try_clone().ok()?);
// enable INTX
self.enable_intx();
@@ -1424,7 +1632,7 @@
// Make intel gfx's opregion as mmio bar, and allocate a gpa for it
// then write this gpa into pci cfg register
if let Some((index, size)) = self.device.get_cap_type_info(
- VFIO_REGION_TYPE_PCI_VENDOR_TYPE | (INTEL_VENDOR_ID as u32),
+ VFIO_REGION_TYPE_PCI_VENDOR_TYPE | (PCI_VENDOR_ID_INTEL as u32),
VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION,
) {
let address = self
@@ -1491,8 +1699,22 @@
}
fn read_config_register(&self, reg_idx: usize) -> u32 {
- let reg: u32 = (reg_idx * 4) as u32;
+ #[cfg(feature = "direct")]
+ if reg_idx == HEADER_TYPE_REG {
+ if let Some(header_type_reg) = self.header_type_reg {
+ let mut v = header_type_reg.to_le_bytes();
+ // HACK
+ // Reads from the "BIST" register are interpreted as device
+ // PCI power state
+ v[3] = self.power_state().unwrap_or_else(|e| {
+ error!("Failed to get device power state: {}", e);
+ 5 // unknown state
+ });
+ return u32::from_le_bytes(v);
+ }
+ }
+ let reg: u32 = (reg_idx * 4) as u32;
let mut config: u32 = self.config.read_config(reg);
// Ignore IO bar
@@ -1504,6 +1726,7 @@
}
}
} else if let Some(msix_cap) = &self.msix_cap {
+ let msix_cap = msix_cap.lock();
if msix_cap.is_msix_control_reg(reg, 4) {
msix_cap.read_msix_control(&mut config);
}
@@ -1518,13 +1741,28 @@
}
fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
- let start = (reg_idx * 4) as u64 + offset;
-
// When guest write config register at the first time, start worker thread
if self.worker_thread.is_none() && self.vm_socket_vm.is_some() {
self.start_work_thread();
};
+ #[cfg(feature = "direct")]
+ if self.sysfs_path.is_some()
+ && reg_idx == CLASS_REG
+ && offset == CLASS_REG_REVISION_ID_OFFSET as u64
+ && data.len() == 1
+ {
+ // HACK
+ // Byte writes to the "Revision ID" register are interpreted as PM
+ // op calls
+ if let Err(e) = self.op_call(data[0]) {
+ error!("Failed to perform op call: {}", e);
+ }
+ return;
+ }
+
+ let start = (reg_idx * 4) as u64 + offset;
+
let mut msi_change: Option<VfioMsiChange> = None;
if let Some(msi_cap) = self.msi_cap.as_mut() {
if msi_cap.is_msi_reg(start, data.len()) {
@@ -1535,19 +1773,26 @@
match msi_change {
Some(VfioMsiChange::Enable) => self.enable_msi(),
Some(VfioMsiChange::Disable) => self.disable_msi(),
- None => (),
+ _ => (),
}
msi_change = None;
- if let Some(msix_cap) = self.msix_cap.as_mut() {
+ if let Some(msix_cap) = &self.msix_cap {
+ let mut msix_cap = msix_cap.lock();
if msix_cap.is_msix_control_reg(start as u32, data.len() as u32) {
msi_change = msix_cap.write_msix_control(data);
}
}
+
match msi_change {
Some(VfioMsiChange::Enable) => self.enable_msix(),
Some(VfioMsiChange::Disable) => self.disable_msix(),
- None => (),
+ Some(VfioMsiChange::FunctionChanged) => {
+ if let Err(e) = self.msix_vectors_update() {
+ error!("update msix vectors failed: {}", e);
+ }
+ }
+ _ => (),
}
self.device
@@ -1627,6 +1872,7 @@
let offset = addr - mmio_info.address();
let bar_index = mmio_info.bar_index() as u32;
if let Some(msix_cap) = &self.msix_cap {
+ let msix_cap = msix_cap.lock();
if msix_cap.is_msix_table(bar_index, offset) {
msix_cap.read_table(offset, data);
return;
@@ -1655,9 +1901,14 @@
let offset = addr - mmio_info.address();
let bar_index = mmio_info.bar_index() as u32;
- if let Some(msix_cap) = self.msix_cap.as_mut() {
+ if let Some(msix_cap) = &self.msix_cap {
+ let mut msix_cap = msix_cap.lock();
if msix_cap.is_msix_table(bar_index, offset) {
- msix_cap.write_table(offset, data);
+ let behavior = msix_cap.write_table(offset, data);
+ if let MsixStatus::EntryChanged(index) = behavior {
+ let irqfd = msix_cap.get_msix_irqfd(index);
+ self.msix_vector_update(index, irqfd);
+ }
return;
} else if msix_cap.is_msix_pba(bar_index, offset) {
msix_cap.write_pba(offset, data);
@@ -1676,6 +1927,11 @@
impl Drop for VfioPciDevice {
fn drop(&mut self) {
+ #[cfg(feature = "direct")]
+ if self.sysfs_path.is_some() {
+ let _ = VfioPciDevice::coordinated_pm(self.sysfs_path.as_ref().unwrap(), false);
+ }
+
if let Some(kill_evt) = self.kill_evt.take() {
let _ = kill_evt.write(1);
}
diff --git a/devices/src/pl030.rs b/devices/src/pl030.rs
index f295b96..ae24082 100644
--- a/devices/src/pl030.rs
+++ b/devices/src/pl030.rs
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::{warn, Event};
+use base::warn;
use std::convert::TryFrom;
use std::time::{SystemTime, UNIX_EPOCH};
-use crate::{BusAccessInfo, BusDevice};
+use crate::{BusAccessInfo, BusDevice, IrqEdgeEvent};
// Register offsets
// Data register
@@ -36,7 +36,7 @@
/// An emulated ARM pl030 RTC
pub struct Pl030 {
// Event to be used to interrupt the guest for an alarm event
- alarm_evt: Event,
+ alarm_evt: IrqEdgeEvent,
// This is the delta we subtract from current time to get the
// counter value
@@ -60,7 +60,7 @@
impl Pl030 {
/// Constructs a Pl030 device
- pub fn new(evt: Event) -> Pl030 {
+ pub fn new(evt: IrqEdgeEvent) -> Pl030 {
Pl030 {
alarm_evt: evt,
counter_delta_time: get_epoch_time(),
@@ -100,7 +100,7 @@
if reg_val == 0 {
self.interrupt_active = false;
} else {
- self.alarm_evt.write(1).unwrap();
+ self.alarm_evt.trigger().unwrap();
self.interrupt_active = true;
}
}
@@ -161,7 +161,7 @@
#[test]
fn test_interrupt_status_register() {
- let event = Event::new().unwrap();
+ let event = IrqEdgeEvent::new().unwrap();
let mut device = Pl030::new(event.try_clone().unwrap());
let mut register = [0, 0, 0, 0];
@@ -169,7 +169,7 @@
device.write(pl030_bus_address(RTCEOI), &[1, 0, 0, 0]);
device.read(pl030_bus_address(RTCSTAT), &mut register);
assert_eq!(register, [1, 0, 0, 0]);
- assert_eq!(event.read().unwrap(), 1);
+ assert_eq!(event.get_trigger().read().unwrap(), 1);
// clear interrupt
device.write(pl030_bus_address(RTCEOI), &[0, 0, 0, 0]);
@@ -179,7 +179,7 @@
#[test]
fn test_match_register() {
- let mut device = Pl030::new(Event::new().unwrap());
+ let mut device = Pl030::new(IrqEdgeEvent::new().unwrap());
let mut register = [0, 0, 0, 0];
device.write(pl030_bus_address(RTCMR), &[1, 2, 3, 4]);
diff --git a/devices/src/platform/vfio_platform.rs b/devices/src/platform/vfio_platform.rs
index 610aced..f064c29 100644
--- a/devices/src/platform/vfio_platform.rs
+++ b/devices/src/platform/vfio_platform.rs
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::vfio::{VfioDevice, VfioError, VfioIrq};
-use crate::{BusAccessInfo, BusDevice, BusDeviceObj};
+use crate::{BusAccessInfo, BusDevice, BusDeviceObj, IrqEdgeEvent, IrqLevelEvent};
+use anyhow::{bail, Context, Result};
use base::{
- error, pagesize, AsRawDescriptor, Event, MappedRegion, MemoryMapping, MemoryMappingBuilder,
- RawDescriptor, Tube,
+ error, pagesize, AsRawDescriptor, AsRawDescriptors, Event, MappedRegion, MemoryMapping,
+ MemoryMappingBuilder, RawDescriptor, Tube,
};
use resources::SystemAllocator;
use std::fs::File;
@@ -22,7 +23,8 @@
pub struct VfioPlatformDevice {
device: Arc<VfioDevice>,
- interrupt_evt: Vec<(Option<Event>, Option<Event>)>,
+ interrupt_edge_evt: Vec<IrqEdgeEvent>,
+ interrupt_level_evt: Vec<IrqLevelEvent>,
mmio_regions: Vec<MmioInfo>,
vm_socket_mem: Tube,
// scratch MemoryMapping to avoid unmap beform vm exit
@@ -61,7 +63,8 @@
let dev = Arc::new(device);
VfioPlatformDevice {
device: dev,
- interrupt_evt: Vec::new(),
+ interrupt_edge_evt: Vec::new(),
+ interrupt_level_evt: Vec::new(),
mmio_regions: Vec::new(),
vm_socket_mem: vfio_device_socket_mem,
mem: Vec::new(),
@@ -76,34 +79,37 @@
irq.flags & VFIO_IRQ_INFO_AUTOMASKED != 0
}
- pub fn assign_platform_irq(
- &mut self,
- irq_evt: Event,
- irq_resample_evt: Option<Event>,
- index: u32,
- ) {
- if let Err(e) = self.device.irq_enable(&[&irq_evt], index) {
- error!("platform irq enable failed: {}", e);
- return;
+ fn setup_irq_resample(&mut self, resample_evt: &Event, index: u32) -> Result<()> {
+ self.device.irq_mask(index).context("Intx mask failed")?;
+ self.device
+ .resample_virq_enable(resample_evt, index)
+ .context("resample enable failed")?;
+ self.device
+ .irq_unmask(index)
+ .context("Intx unmask failed")?;
+ Ok(())
+ }
+
+ pub fn assign_edge_platform_irq(&mut self, irq_evt: &IrqEdgeEvent, index: u32) -> Result<()> {
+ let interrupt_evt = irq_evt.try_clone().context("failed to clone irq event")?;
+ self.device
+ .irq_enable(&[Some(interrupt_evt.get_trigger())], index, 0)
+ .context("platform irq enable failed")?;
+ self.interrupt_edge_evt.push(interrupt_evt);
+ Ok(())
+ }
+
+ pub fn assign_level_platform_irq(&mut self, irq_evt: &IrqLevelEvent, index: u32) -> Result<()> {
+ let interrupt_evt = irq_evt.try_clone().context("failed to clone irq event")?;
+ self.device
+ .irq_enable(&[Some(interrupt_evt.get_trigger())], index, 0)
+ .context("platform irq enable failed")?;
+ if let Err(e) = self.setup_irq_resample(interrupt_evt.get_resample(), index) {
+ self.disable_irqs(index);
+ bail!("failed to set up irq resampling: {}", e);
}
- if let Some(ref irq_res_evt) = irq_resample_evt {
- if let Err(e) = self.device.irq_mask(index) {
- error!("Intx mask failed: {}", e);
- self.disable_irqs(index);
- return;
- }
- if let Err(e) = self.device.resample_virq_enable(irq_res_evt, index) {
- error!("resample enable failed: {}", e);
- self.disable_irqs(index);
- return;
- }
- if let Err(e) = self.device.irq_unmask(index) {
- error!("Intx unmask failed: {}", e);
- self.disable_irqs(index);
- return;
- }
- }
- self.interrupt_evt.push((Some(irq_evt), irq_resample_evt));
+ self.interrupt_level_evt.push(interrupt_evt);
+ Ok(())
}
fn find_region(&self, addr: u64) -> Option<MmioInfo> {
@@ -261,14 +267,14 @@
pub fn keep_rds(&self) -> Vec<RawDescriptor> {
let mut rds = self.device.keep_rds();
- for (irq_evt, itq_res_evt) in self.interrupt_evt.iter() {
- if let Some(ref interrupt_evt) = irq_evt {
- rds.push(interrupt_evt.as_raw_descriptor());
- }
- if let Some(ref interrupt_resample_evt) = itq_res_evt {
- rds.push(interrupt_resample_evt.as_raw_descriptor());
- }
+ for irq_evt in self.interrupt_edge_evt.iter() {
+ rds.extend(irq_evt.as_raw_descriptors());
}
+
+ for irq_evt in self.interrupt_level_evt.iter() {
+ rds.extend(irq_evt.as_raw_descriptors());
+ }
+
rds.push(self.vm_socket_mem.as_raw_descriptor());
rds
}
diff --git a/devices/src/software_tpm.rs b/devices/src/software_tpm.rs
new file mode 100644
index 0000000..43c4068
--- /dev/null
+++ b/devices/src/software_tpm.rs
@@ -0,0 +1,33 @@
+// Copyright 2022 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.
+
+//! Software TPM backend using the TPM2 simulator from the `tpm2` crate.
+
+use std::env;
+use std::fs;
+use std::path::Path;
+
+use anyhow::Context;
+use tpm2::Simulator;
+
+use super::virtio::TpmBackend;
+
+pub struct SoftwareTpm {
+ simulator: Simulator,
+}
+
+impl SoftwareTpm {
+ pub fn new<P: AsRef<Path>>(storage: P) -> anyhow::Result<Self> {
+ fs::create_dir_all(storage.as_ref()).context("failed to create directory for simulator")?;
+ env::set_current_dir(storage).context("failed to change into simulator directory")?;
+ let simulator = Simulator::singleton_in_current_directory();
+ Ok(SoftwareTpm { simulator })
+ }
+}
+
+impl TpmBackend for SoftwareTpm {
+ fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
+ self.simulator.execute_command(command)
+ }
+}
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs
index 7286bbf..0475edc 100644
--- a/devices/src/usb/host_backend/host_device.rs
+++ b/devices/src/usb/host_backend/host_device.rs
@@ -341,7 +341,7 @@
);
self.release_interfaces();
- let _cur_config = match self.device.lock().get_active_configuration() {
+ let cur_config = match self.device.lock().get_active_configuration() {
Ok(c) => Some(c),
Err(e) => {
// The device may be in the default state, in which case
@@ -352,11 +352,12 @@
None
}
};
-
- self.device
- .lock()
- .set_active_configuration(config)
- .map_err(Error::SetActiveConfig)?;
+ if Some(config) != cur_config {
+ self.device
+ .lock()
+ .set_active_configuration(config)
+ .map_err(Error::SetActiveConfig)?;
+ }
let config_descriptor = self
.device
diff --git a/devices/src/usb/xhci/xhci.rs b/devices/src/usb/xhci/xhci.rs
index d0ea933..56e9a04 100644
--- a/devices/src/usb/xhci/xhci.rs
+++ b/devices/src/usb/xhci/xhci.rs
@@ -15,7 +15,8 @@
host_backend_device_provider::HostBackendDeviceProvider,
};
use crate::utils::{Error as UtilsError, EventLoop, FailHandle};
-use base::{error, Event};
+use crate::IrqLevelEvent;
+use base::error;
use remain::sorted;
use std::sync::Arc;
use std::thread;
@@ -26,6 +27,10 @@
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
+ #[error("failed to clone irq event: {0}")]
+ CloneIrqEvent(base::Error),
+ #[error("failed to clone resample event: {0}")]
+ CloneResampleEvent(base::Error),
#[error("failed to create command ring controller: {0}")]
CreateCommandRingController(CommandRingControllerError),
#[error("failed to enable interrupter: {0}")]
@@ -78,15 +83,22 @@
fail_handle: Arc<dyn FailHandle>,
mem: GuestMemory,
device_provider: HostBackendDeviceProvider,
- irq_evt: Event,
- irq_resample_evt: Event,
+ interrupt_evt: IrqLevelEvent,
regs: XhciRegs,
) -> Result<Arc<Self>> {
let (event_loop, join_handle) =
EventLoop::start("xhci".to_string(), Some(fail_handle.clone()))
.map_err(Error::StartEventLoop)?;
+ let irq_evt = interrupt_evt
+ .get_trigger()
+ .try_clone()
+ .map_err(Error::CloneIrqEvent)?;
let interrupter = Arc::new(Mutex::new(Interrupter::new(mem.clone(), irq_evt, ®s)));
let event_loop = Arc::new(event_loop);
+ let irq_resample_evt = interrupt_evt
+ .get_resample()
+ .try_clone()
+ .map_err(Error::CloneResampleEvent)?;
let intr_resample_handler =
IntrResampleHandler::start(&event_loop, interrupter.clone(), irq_resample_evt)
.ok_or(Error::StartResampleHandler)?;
diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs
index 8453378..132dd39 100644
--- a/devices/src/usb/xhci/xhci_controller.rs
+++ b/devices/src/usb/xhci/xhci_controller.rs
@@ -14,7 +14,8 @@
use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
use crate::usb::xhci::xhci_regs::{init_xhci_mmio_space_and_regs, XhciRegs};
use crate::utils::FailHandle;
-use base::{error, AsRawDescriptor, Event, RawDescriptor};
+use crate::IrqLevelEvent;
+use base::{error, AsRawDescriptor, RawDescriptor};
use resources::{Alloc, MmioType, SystemAllocator};
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
@@ -81,8 +82,7 @@
},
IrqAssigned {
device_provider: HostBackendDeviceProvider,
- irq_evt: Event,
- irq_resample_evt: Event,
+ irq_evt: IrqLevelEvent,
},
Initialized {
mmio: RegisterSpace,
@@ -131,7 +131,6 @@
XhciControllerState::IrqAssigned {
device_provider,
irq_evt,
- irq_resample_evt,
} => {
let (mmio, regs) = init_xhci_mmio_space_and_regs();
let fail_handle: Arc<dyn FailHandle> = Arc::new(XhciFailHandle::new(®s));
@@ -140,7 +139,6 @@
self.mem.clone(),
device_provider,
irq_evt,
- irq_resample_evt,
regs,
) {
Ok(xhci) => Some(xhci),
@@ -193,11 +191,10 @@
XhciControllerState::IrqAssigned {
device_provider,
irq_evt,
- irq_resample_evt,
} => {
let mut keep_rds = device_provider.keep_rds();
- keep_rds.push(irq_evt.as_raw_descriptor());
- keep_rds.push(irq_resample_evt.as_raw_descriptor());
+ keep_rds.push(irq_evt.get_trigger().as_raw_descriptor());
+ keep_rds.push(irq_evt.get_resample().as_raw_descriptor());
keep_rds
}
_ => {
@@ -209,8 +206,7 @@
fn assign_irq(
&mut self,
- irq_evt: &Event,
- irq_resample_evt: &Event,
+ irq_evt: &IrqLevelEvent,
irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
let gsi = irq_num?;
@@ -224,7 +220,6 @@
self.state = XhciControllerState::IrqAssigned {
device_provider,
irq_evt: irq_evt.try_clone().ok()?,
- irq_resample_evt: irq_resample_evt.try_clone().ok()?,
}
}
_ => {
diff --git a/devices/src/utils/event_loop.rs b/devices/src/utils/event_loop.rs
index a8fed3a..f2bb8fd 100644
--- a/devices/src/utils/event_loop.rs
+++ b/devices/src/utils/event_loop.rs
@@ -4,8 +4,8 @@
use super::error::{Error, Result};
use base::{
- error, warn, wrap_descriptor, AsRawDescriptor, Descriptor, EpollContext, EpollEvents, Event,
- RawDescriptor, WatchingEvents,
+ error, warn, AsRawDescriptor, Descriptor, EpollContext, EpollEvents, Event, RawDescriptor,
+ WatchingEvents,
};
use std::collections::BTreeMap;
use std::mem::drop;
@@ -65,11 +65,8 @@
Arc::new(Mutex::new(BTreeMap::new()));
let poll_ctx: EpollContext<Descriptor> = EpollContext::new()
.and_then(|pc| {
- pc.add(
- &wrap_descriptor(&stop_evt),
- Descriptor(stop_evt.as_raw_descriptor()),
- )
- .and(Ok(pc))
+ pc.add(&stop_evt, Descriptor(stop_evt.as_raw_descriptor()))
+ .and(Ok(pc))
})
.map_err(Error::CreateWaitContext)?;
@@ -163,7 +160,7 @@
// This might fail due to epoll syscall. Check epoll_ctl(2).
self.poll_ctx
.add_fd_with_events(
- &wrap_descriptor(descriptor),
+ descriptor,
events,
Descriptor(descriptor.as_raw_descriptor()),
)
@@ -179,7 +176,7 @@
}
// This might fail due to epoll syscall. Check epoll_ctl(2).
self.poll_ctx
- .delete(&wrap_descriptor(descriptor))
+ .delete(descriptor)
.map_err(Error::WaitContextDeleteDescriptor)?;
self.handlers.lock().remove(&descriptor.as_raw_descriptor());
Ok(())
diff --git a/devices/src/vfio.rs b/devices/src/vfio.rs
index 620ead9..f99d744 100644
--- a/devices/src/vfio.rs
+++ b/devices/src/vfio.rs
@@ -16,18 +16,20 @@
use std::u32;
use crate::IommuDevType;
+use base::error;
use base::{
- ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val, warn,
- AsRawDescriptor, Error, Event, FromRawDescriptor, RawDescriptor, SafeDescriptor,
+ ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val,
+ warn, AsRawDescriptor, Error, Event, FromRawDescriptor, RawDescriptor, SafeDescriptor,
};
use data_model::{vec_with_array_field, DataInit};
use hypervisor::{DeviceKind, Vm};
use once_cell::sync::OnceCell;
use remain::sorted;
+use resources::address_allocator::AddressAllocator;
+use resources::{Alloc, Error as ResourcesError};
use sync::Mutex;
use thiserror::Error;
use vfio_sys::*;
-use vm_memory::GuestMemory;
#[sorted]
#[derive(Error, Debug)]
@@ -56,14 +58,20 @@
IommuDmaMap(Error),
#[error("failed to remove guest memory map from iommu table: {0}")]
IommuDmaUnmap(Error),
+ #[error("failed to get IOMMU cap info from host")]
+ IommuGetCapInfo,
#[error("failed to get IOMMU info from host: {0}")]
IommuGetInfo(Error),
#[error("failed to set KVM vfio device's attribute: {0}")]
KvmSetDeviceAttr(Error),
+ #[error("AddressAllocator is unavailable")]
+ NoRescAlloc,
#[error("failed to open /dev/vfio/vfio container: {0}")]
OpenContainer(io::Error),
#[error("failed to open /dev/vfio/$group_num group: {0}")]
OpenGroup(io::Error),
+ #[error("resources error: {0}")]
+ Resources(ResourcesError),
#[error(
"vfio API version doesn't match with VFIO_API_VERSION defined in vfio_sys/src/vfio.rs"
)]
@@ -100,19 +108,24 @@
#[repr(u32)]
enum IommuType {
Type1V2 = VFIO_TYPE1v2_IOMMU,
- NoIommu = VFIO_NOIOMMU_IOMMU,
}
/// VfioContainer contain multi VfioGroup, and delegate an IOMMU domain table
pub struct VfioContainer {
container: File,
groups: HashMap<u32, Arc<Mutex<VfioGroup>>>,
- host_iommu: bool,
+}
+
+fn extract_vfio_struct<T>(bytes: &[u8], offset: usize) -> T
+where
+ T: DataInit,
+{
+ T::from_reader(&bytes[offset..(offset + mem::size_of::<T>())]).expect("malformed kernel data")
}
const VFIO_API_VERSION: u8 = 0;
impl VfioContainer {
- fn new_inner(host_iommu: bool) -> Result<Self> {
+ pub fn new() -> Result<Self> {
let container = OpenOptions::new()
.read(true)
.write(true)
@@ -128,20 +141,9 @@
Ok(VfioContainer {
container,
groups: HashMap::new(),
- host_iommu,
})
}
- /// Open VfioContainer with IOMMU enabled.
- pub fn new() -> Result<Self> {
- Self::new_inner(true /* host_iommu */)
- }
-
- /// Open VfioContainer with IOMMU disabled.
- pub fn new_noiommu() -> Result<Self> {
- Self::new_inner(false /* host_iommu */)
- }
-
// Construct a VfioContainer from an exist container file.
pub fn new_from_container(container: File) -> Result<Self> {
// Safe as file is vfio container descriptor and ioctl is defined by kernel.
@@ -153,7 +155,6 @@
Ok(VfioContainer {
container,
groups: HashMap::new(),
- host_iommu: true,
})
}
@@ -205,6 +206,7 @@
flags: 0,
iova,
size,
+ ..Default::default()
};
// Safe as file is vfio container, dma_unmap is constructed by us, and
@@ -222,6 +224,7 @@
argsz: mem::size_of::<vfio_iommu_type1_info>() as u32,
flags: 0,
iova_pgsizes: 0,
+ ..Default::default()
};
// Safe as file is vfio container, iommu_info has valid values,
@@ -234,7 +237,76 @@
Ok(iommu_info.iova_pgsizes)
}
- fn init(&mut self, guest_mem: &GuestMemory, iommu_enabled: bool) -> Result<()> {
+ pub fn vfio_iommu_iova_get_iova_ranges(&self) -> Result<Vec<vfio_iova_range>> {
+ // Query the buffer size needed fetch the capabilities.
+ let mut iommu_info_argsz = vfio_iommu_type1_info {
+ argsz: mem::size_of::<vfio_iommu_type1_info>() as u32,
+ flags: 0,
+ iova_pgsizes: 0,
+ ..Default::default()
+ };
+
+ // Safe as file is vfio container, iommu_info_argsz has valid values,
+ // and we check the return value
+ let ret = unsafe { ioctl_with_mut_ref(self, VFIO_IOMMU_GET_INFO(), &mut iommu_info_argsz) };
+ if ret != 0 {
+ return Err(VfioError::IommuGetInfo(get_error()));
+ }
+
+ if (iommu_info_argsz.flags & VFIO_IOMMU_INFO_CAPS) == 0 {
+ return Err(VfioError::IommuGetCapInfo);
+ }
+
+ let mut iommu_info = vec_with_array_field::<vfio_iommu_type1_info, u8>(
+ iommu_info_argsz.argsz as usize - mem::size_of::<vfio_iommu_type1_info>(),
+ );
+ iommu_info[0].argsz = iommu_info_argsz.argsz;
+ // Safe as file is vfio container, iommu_info has valid values,
+ // and we check the return value
+ let ret =
+ unsafe { ioctl_with_mut_ptr(self, VFIO_IOMMU_GET_INFO(), iommu_info.as_mut_ptr()) };
+ if ret != 0 {
+ return Err(VfioError::IommuGetInfo(get_error()));
+ }
+
+ // Safe because we initialized iommu_info with enough space, u8 has less strict
+ // alignment, and since it will no longer be mutated.
+ let info_bytes = unsafe {
+ std::slice::from_raw_parts(
+ iommu_info.as_ptr() as *const u8,
+ iommu_info_argsz.argsz as usize,
+ )
+ };
+
+ if (iommu_info[0].flags & VFIO_IOMMU_INFO_CAPS) == 0 {
+ return Err(VfioError::IommuGetCapInfo);
+ }
+
+ let mut offset = iommu_info[0].cap_offset as usize;
+ while offset != 0 {
+ let header = extract_vfio_struct::<vfio_info_cap_header>(info_bytes, offset);
+
+ if header.id == VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE as u16 && header.version == 1 {
+ let iova_header = extract_vfio_struct::<vfio_iommu_type1_info_cap_iova_range_header>(
+ info_bytes, offset,
+ );
+ let range_offset = offset + mem::size_of::<vfio_iommu_type1_info_cap_iova_range>();
+ let mut ret = Vec::new();
+ for i in 0..iova_header.nr_iovas {
+ ret.push(extract_vfio_struct::<vfio_iova_range>(
+ info_bytes,
+ range_offset + i as usize * mem::size_of::<vfio_iova_range>(),
+ ));
+ }
+ return Ok(ret);
+ }
+ offset = header.next as usize;
+ }
+
+ Err(VfioError::IommuGetCapInfo)
+ }
+
+ fn init_vfio_iommu(&mut self) -> Result<()> {
if !self.check_extension(IommuType::Type1V2) {
return Err(VfioError::VfioType1V2);
}
@@ -243,15 +315,6 @@
return Err(VfioError::ContainerSetIOMMU(get_error()));
}
- // Add all guest memory regions into vfio container's iommu table,
- // then vfio kernel driver could access guest memory from gfn
- if !iommu_enabled {
- guest_mem.with_regions(|_index, guest_addr, size, host_addr, _mmap, _fd_offset| {
- // Safe because the guest regions are guaranteed not to overlap
- unsafe { self.vfio_dma_map(guest_addr.0, size as u64, host_addr as u64, true) }
- })?;
- }
-
Ok(())
}
@@ -264,11 +327,27 @@
match self.groups.get(&id) {
Some(group) => Ok(group.clone()),
None => {
- let group = Arc::new(Mutex::new(VfioGroup::new(self, self.host_iommu, id)?));
+ let group = Arc::new(Mutex::new(VfioGroup::new(self, id)?));
if self.groups.is_empty() {
- // Before the first group is added into container, do once cotainer
- // initialize for a vm
- self.init(vm.get_memory(), iommu_enabled)?;
+ // Before the first group is added into container, do once per
+ // container initialization.
+ self.init_vfio_iommu()?;
+
+ if !iommu_enabled {
+ vm.get_memory().with_regions(
+ |_index, guest_addr, size, host_addr, _mmap, _fd_offset| {
+ // Safe because the guest regions are guaranteed not to overlap
+ unsafe {
+ self.vfio_dma_map(
+ guest_addr.0,
+ size as u64,
+ host_addr as u64,
+ true,
+ )
+ }
+ },
+ )?;
+ }
}
let kvm_vfio_file = KVM_VFIO_FILE
@@ -289,12 +368,12 @@
match self.groups.get(&id) {
Some(group) => Ok(group.clone()),
None => {
- let group = Arc::new(Mutex::new(VfioGroup::new(self, self.host_iommu, id)?));
+ let group = Arc::new(Mutex::new(VfioGroup::new(self, id)?));
- if self.groups.is_empty() && !self.host_iommu {
- if self.set_iommu(IommuType::NoIommu) < 0 {
- return Err(VfioError::ContainerSetIOMMU(get_error()));
- }
+ if self.groups.is_empty() {
+ // Before the first group is added into container, do once per
+ // container initialization.
+ self.init_vfio_iommu()?;
}
self.groups.insert(id, group.clone());
@@ -350,12 +429,8 @@
}
impl VfioGroup {
- fn new(container: &VfioContainer, host_iommu: bool, id: u32) -> Result<Self> {
- let group_path = if host_iommu {
- format!("/dev/vfio/{}", id)
- } else {
- format!("/dev/vfio/noiommu-{}", id)
- };
+ fn new(container: &VfioContainer, id: u32) -> Result<Self> {
+ let group_path = format!("/dev/vfio/{}", id);
let group_file = OpenOptions::new()
.read(true)
.write(true)
@@ -626,6 +701,8 @@
group_id: u32,
// vec for vfio device's regions
regions: Vec<VfioRegion>,
+
+ iova_alloc: Option<Arc<Mutex<AddressAllocator>>>,
}
impl VfioDevice {
@@ -661,6 +738,7 @@
group_descriptor,
group_id,
regions,
+ iova_alloc: None,
})
}
@@ -694,6 +772,14 @@
group.lock().add_device_num();
let group_descriptor = group.lock().as_raw_descriptor();
+ let iova_ranges = container
+ .lock()
+ .vfio_iommu_iova_get_iova_ranges()?
+ .into_iter()
+ .map(|r| std::ops::RangeInclusive::new(r.start, r.end));
+ let iova_alloc = AddressAllocator::new_from_list(iova_ranges, None, None)
+ .map_err(VfioError::Resources)?;
+
Ok(VfioDevice {
dev,
name,
@@ -701,6 +787,7 @@
group_descriptor,
group_id,
regions,
+ iova_alloc: Some(Arc::new(Mutex::new(iova_alloc))),
})
}
@@ -715,18 +802,25 @@
}
/// Enable vfio device's irq and associate Irqfd Event with device.
- /// When MSIx is enabled, multi vectors will be supported, so descriptors is vector and the vector
- /// length is the num of MSIx vectors.
+ /// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to subindex +
+ /// descriptors length will be assigned with irqfd in the descriptors array.
/// when index = VFIO_PCI_REQ_IRQ_INDEX, kernel vfio will trigger this event when physical device
/// is removed.
- pub fn irq_enable(&self, descriptors: &[&Event], index: u32) -> Result<()> {
+ /// If descriptor is None, -1 is assigned to the irq. A value of -1 is used to either de-assign
+ /// interrupts if already assigned or skip un-assigned interrupts.
+ pub fn irq_enable(
+ &self,
+ descriptors: &[Option<&Event>],
+ index: u32,
+ subindex: u32,
+ ) -> Result<()> {
let count = descriptors.len();
let u32_size = mem::size_of::<u32>();
let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(count);
irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + count * u32_size) as u32;
irq_set[0].flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
irq_set[0].index = index;
- irq_set[0].start = 0;
+ irq_set[0].start = subindex;
irq_set[0].count = count as u32;
// irq_set.data could be none, bool or descriptor according to flags, so irq_set.data
@@ -736,7 +830,10 @@
let mut data = unsafe { irq_set[0].data.as_mut_slice(count * u32_size) };
for descriptor in descriptors.iter().take(count) {
let (left, right) = data.split_at_mut(u32_size);
- left.copy_from_slice(&descriptor.as_raw_descriptor().to_ne_bytes()[..]);
+ match descriptor {
+ Some(fd) => left.copy_from_slice(&fd.as_raw_descriptor().to_ne_bytes()[..]),
+ None => left.copy_from_slice(&(-1i32).to_ne_bytes()[..]),
+ }
data = right;
}
@@ -860,6 +957,7 @@
flags: 0,
num_regions: 0,
num_irqs: 0,
+ ..Default::default()
};
// Safe as we are the owner of device_file and dev_info which are valid value,
@@ -919,6 +1017,7 @@
flags: 0,
num_regions: 0,
num_irqs: 0,
+ ..Default::default()
};
// Safe as we are the owner of dev and dev_info which are valid value,
// and we verify the return value.
@@ -1248,6 +1347,20 @@
self.container.lock().vfio_dma_unmap(iova, size)
}
+ pub fn vfio_get_iommu_page_size_mask(&self) -> Result<u64> {
+ self.container.lock().vfio_get_iommu_page_size_mask()
+ }
+
+ pub fn alloc_iova(&self, size: u64, align_size: u64, alloc: Alloc) -> Result<u64> {
+ match &self.iova_alloc {
+ None => Err(VfioError::NoRescAlloc),
+ Some(iova_alloc) => iova_alloc
+ .lock()
+ .allocate_with_align(size, alloc, "alloc_iova".to_owned(), align_size)
+ .map_err(VfioError::Resources),
+ }
+ }
+
/// Gets the vfio device backing `File`.
pub fn device_file(&self) -> &File {
&self.dev
@@ -1284,6 +1397,24 @@
offset.into(),
);
}
+
+ /// Set the VFIO device this config refers to as the bus master.
+ pub fn set_bus_master(&self) {
+ /// Constant definitions from `linux/pci_regs.h`.
+ const PCI_COMMAND: u32 = 0x4;
+ /// Enable bus mastering
+ const PCI_COMMAND_MASTER: u16 = 0x4;
+
+ let mut cmd: u16 = self.read_config(PCI_COMMAND);
+
+ if cmd & PCI_COMMAND_MASTER != 0 {
+ return;
+ }
+
+ cmd |= PCI_COMMAND_MASTER;
+
+ self.write_config(cmd, PCI_COMMAND);
+ }
}
impl AsRawDescriptor for VfioDevice {
diff --git a/devices/src/virtio/block/asynchronous.rs b/devices/src/virtio/block/asynchronous.rs
index 64fc80a..ffb6bd3 100644
--- a/devices/src/virtio/block/asynchronous.rs
+++ b/devices/src/virtio/block/asynchronous.rs
@@ -3,7 +3,6 @@
// found in the LICENSE file.
use std::cell::RefCell;
-use std::cmp::{max, min};
use std::io::{self, Write};
use std::mem::size_of;
use std::rc::Rc;
@@ -20,9 +19,7 @@
use base::Error as SysError;
use base::Result as SysResult;
-use base::{
- error, info, iov_max, warn, AsRawDescriptor, Event, RawDescriptor, Timer, Tube, TubeError,
-};
+use base::{error, info, warn, AsRawDescriptor, Event, RawDescriptor, Timer, Tube, TubeError};
use cros_async::{
select5, sync::Mutex as AsyncMutex, AsyncError, AsyncTube, EventAsync, Executor, SelectResult,
TimerAsync,
@@ -34,8 +31,8 @@
use super::common::*;
use crate::virtio::{
- async_utils, copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader,
- SignalableInterrupt, VirtioDevice, Writer, TYPE_BLOCK,
+ async_utils, block::sys::*, copy_config, DescriptorChain, DescriptorError, Interrupt, Queue,
+ Reader, SignalableInterrupt, VirtioDevice, Writer, TYPE_BLOCK,
};
const QUEUE_SIZE: u16 = 256;
@@ -231,13 +228,13 @@
// There is one async task running `handle_queue` per virtio queue in use.
// Receives messages from the guest and queues a task to complete the operations with the async
// executor.
-async fn handle_queue(
- ex: &Executor,
- mem: &GuestMemory,
+pub async fn handle_queue<I: SignalableInterrupt + Clone + 'static>(
+ ex: Executor,
+ mem: GuestMemory,
disk_state: Rc<AsyncMutex<DiskState>>,
queue: Rc<RefCell<Queue>>,
evt: EventAsync,
- interrupt: Rc<RefCell<Interrupt>>,
+ interrupt: I,
flush_timer: Rc<RefCell<TimerAsync>>,
flush_timer_armed: Rc<RefCell<bool>>,
) {
@@ -246,11 +243,11 @@
error!("Failed to read the next queue event: {}", e);
continue;
}
- while let Some(descriptor_chain) = queue.borrow_mut().pop(mem) {
+ while let Some(descriptor_chain) = queue.borrow_mut().pop(&mem) {
let queue = Rc::clone(&queue);
let disk_state = Rc::clone(&disk_state);
let mem = mem.clone();
- let interrupt = Rc::clone(&interrupt);
+ let interrupt = interrupt.clone();
let flush_timer = Rc::clone(&flush_timer);
let flush_timer_armed = Rc::clone(&flush_timer_armed);
@@ -260,7 +257,7 @@
descriptor_chain,
disk_state,
mem,
- &*interrupt.borrow(),
+ &interrupt,
flush_timer,
flush_timer_armed,
)
@@ -415,17 +412,13 @@
EventAsync::new(e.0, &ex).expect("Failed to create async event for queue")
}))
.map(|(queue, event)| {
- // alias some refs so the lifetimes work.
- let mem = &mem;
- let disk_state = &disk_state;
- let interrupt = &interrupt;
handle_queue(
- &ex,
- mem,
+ ex.clone(),
+ mem.clone(),
Rc::clone(disk_state),
Rc::clone(&queue),
event,
- Rc::clone(interrupt),
+ Rc::clone(&interrupt),
Rc::clone(&flush_timer),
Rc::clone(&flush_timer_armed),
)
@@ -435,7 +428,7 @@
// Flushes the disk periodically.
let flush_timer = TimerAsync::new(timer.0, &ex).expect("Failed to create an async timer");
- let disk_flush = flush_disk(disk_state.clone(), flush_timer, flush_timer_armed.clone());
+ let disk_flush = flush_disk(disk_state.clone(), flush_timer, flush_timer_armed);
pin_mut!(disk_flush);
// Exit if the kill event is triggered.
@@ -503,12 +496,7 @@
let avail_features = build_avail_features(base_features, read_only, sparse, true);
- let seg_max = min(max(iov_max(), 1), u32::max_value() as usize) as u32;
-
- // Since we do not currently support indirect descriptors, the maximum
- // number of segments must be smaller than the queue size.
- // In addition, the request header and status each consume a descriptor.
- let seg_max = min(seg_max, u32::from(QUEUE_SIZE) - 2);
+ let seg_max = get_seg_max(QUEUE_SIZE);
Ok(BlockAsync {
kill_evt: None,
diff --git a/devices/src/virtio/block/block.rs b/devices/src/virtio/block/block.rs
index 2fe2a06..10f9698 100644
--- a/devices/src/virtio/block/block.rs
+++ b/devices/src/virtio/block/block.rs
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::cmp::{max, min};
use std::io::{self, Write};
use std::mem::size_of;
use std::path::PathBuf;
@@ -15,8 +14,7 @@
use base::Error as SysError;
use base::Result as SysResult;
use base::{
- error, info, iov_max, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, Timer, Tube,
- WaitContext,
+ error, info, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, Timer, Tube, WaitContext,
};
use data_model::DataInit;
use disk::DiskFile;
@@ -30,8 +28,8 @@
use super::common::*;
use crate::virtio::{
- copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt,
- VirtioDevice, Writer, TYPE_BLOCK,
+ block::sys::*, copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader,
+ SignalableInterrupt, VirtioDevice, Writer, TYPE_BLOCK,
};
const QUEUE_SIZE: u16 = 256;
@@ -440,12 +438,7 @@
let avail_features = build_avail_features(base_features, read_only, sparse, false);
- let seg_max = min(max(iov_max(), 1), u32::max_value() as usize) as u32;
-
- // Since we do not currently support indirect descriptors, the maximum
- // number of segments must be smaller than the queue size.
- // In addition, the request header and status each consume a descriptor.
- let seg_max = min(seg_max, u32::from(QUEUE_SIZE) - 2);
+ let seg_max = get_seg_max(QUEUE_SIZE);
Ok(Block {
kill_evt: None,
diff --git a/devices/src/virtio/block/mod.rs b/devices/src/virtio/block/mod.rs
index 0909b4e..d564fc4 100644
--- a/devices/src/virtio/block/mod.rs
+++ b/devices/src/virtio/block/mod.rs
@@ -5,6 +5,7 @@
pub mod asynchronous;
pub mod block;
pub(crate) mod common;
+pub(crate) mod sys;
pub use asynchronous::{BlockAsync, DiskState};
pub use block::Block;
diff --git a/devices/src/virtio/block/sys/mod.rs b/devices/src/virtio/block/sys/mod.rs
new file mode 100644
index 0000000..99fe229
--- /dev/null
+++ b/devices/src/virtio/block/sys/mod.rs
@@ -0,0 +1,13 @@
+// Copyright 2022 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.
+
+cfg_if::cfg_if! {
+ if #[cfg(unix)] {
+ mod unix;
+ pub use self::unix::*;
+ } else if #[cfg(windows)] {
+ mod windows;
+ pub use self::windows::*;
+ }
+}
diff --git a/devices/src/virtio/block/sys/unix.rs b/devices/src/virtio/block/sys/unix.rs
new file mode 100644
index 0000000..a51e875
--- /dev/null
+++ b/devices/src/virtio/block/sys/unix.rs
@@ -0,0 +1,15 @@
+// Copyright 2022 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 base::iov_max;
+use std::cmp::{max, min};
+
+pub fn get_seg_max(queue_size: u16) -> u32 {
+ let seg_max = min(max(iov_max(), 1), u32::max_value() as usize) as u32;
+
+ // Since we do not currently support indirect descriptors, the maximum
+ // number of segments must be smaller than the queue size.
+ // In addition, the request header and status each consume a descriptor.
+ min(seg_max, u32::from(queue_size) - 2)
+}
diff --git a/devices/src/virtio/block/sys/windows.rs b/devices/src/virtio/block/sys/windows.rs
new file mode 100644
index 0000000..d4b2661
--- /dev/null
+++ b/devices/src/virtio/block/sys/windows.rs
@@ -0,0 +1,8 @@
+// Copyright 2022 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.
+
+pub fn get_seg_max(_queue_size: u16) -> u32 {
+ // Allow a single segment per request, since vectored I/O is not implemented for Windows yet.
+ 1
+}
diff --git a/devices/src/virtio/console.rs b/devices/src/virtio/console.rs
index 7fa55db..d0d665a 100644
--- a/devices/src/virtio/console.rs
+++ b/devices/src/virtio/console.rs
@@ -63,23 +63,17 @@
buffer: &mut VecDeque<u8>,
receive_queue: &mut Queue,
) -> result::Result<(), ConsoleError> {
- let mut exhausted_queue = false;
-
loop {
- let desc = match receive_queue.peek(mem) {
- Some(d) => d,
- None => {
- exhausted_queue = true;
- break;
- }
- };
+ let desc = receive_queue
+ .peek(mem)
+ .ok_or(ConsoleError::RxDescriptorsExhausted)?;
let desc_index = desc.index;
// TODO(morg): Handle extra error cases as Err(ConsoleError) instead of just returning.
let mut writer = match Writer::new(mem.clone(), desc) {
Ok(w) => w,
Err(e) => {
error!("console: failed to create Writer: {}", e);
- break;
+ return Ok(());
}
};
@@ -103,15 +97,9 @@
}
if bytes_written == 0 {
- break;
+ return Ok(());
}
}
-
- if exhausted_queue {
- Err(ConsoleError::RxDescriptorsExhausted)
- } else {
- Ok(())
- }
}
/// Processes the data taken from the given transmit queue into the output sink.
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index b623897..0c8aab5 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -8,16 +8,14 @@
mod virtio_gpu;
use std::cell::RefCell;
-use std::collections::{BTreeMap, HashMap, VecDeque};
+use std::collections::{BTreeMap, VecDeque};
use std::convert::TryFrom;
-use std::i64;
use std::io::Read;
use std::mem::{self, size_of};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::thread;
-use std::time::Duration;
use anyhow::Context;
@@ -102,7 +100,6 @@
// First queue is for virtio gpu commands. Second queue is for cursor commands, which we expect
// there to be fewer of.
pub const QUEUE_SIZES: &[u16] = &[256, 16];
-pub const FENCE_POLL_INTERVAL: Duration = Duration::from_millis(1);
pub const GPU_BAR_NUM: u8 = 4;
pub const GPU_BAR_OFFSET: u64 = 0;
@@ -140,7 +137,7 @@
pub offsets: [u32; 4],
}
-#[derive(Hash, Eq, PartialEq)]
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum VirtioGpuRing {
Global,
ContextSpecific { ctx_id: u32, ring_idx: u8 },
@@ -156,7 +153,7 @@
#[derive(Default)]
pub struct FenceState {
descs: Vec<FenceDescriptor>,
- completed_fences: HashMap<VirtioGpuRing, u64>,
+ completed_fences: BTreeMap<VirtioGpuRing, u64>,
}
pub trait QueueReader {
@@ -775,12 +772,8 @@
self.return_cursor_descriptors.pop_front()
}
- pub fn fence_poll(&mut self) {
- self.virtio_gpu.fence_poll();
- }
-
- pub fn has_pending_fences(&self) -> bool {
- !self.fence_state.lock().descs.is_empty()
+ pub fn poll(&self) {
+ self.virtio_gpu.poll();
}
}
@@ -807,6 +800,7 @@
InterruptResample,
Kill,
ResourceBridge { index: usize },
+ VirtioGpuPoll,
}
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
@@ -837,6 +831,13 @@
}
}
+ if let Some(poll_desc) = self.state.virtio_gpu.poll_descriptor() {
+ if let Err(e) = wait_ctx.add(&poll_desc, Token::VirtioGpuPoll) {
+ error!("failed adding poll eventfd to WaitContext: {}", e);
+ return;
+ }
+ }
+
// TODO(davidriley): The entire main loop processing is somewhat racey and incorrect with
// respect to cursor vs control queue processing. As both currently and originally
// written, while the control queue is only processed/read from after the the cursor queue
@@ -848,14 +849,7 @@
// Declare this outside the loop so we don't keep allocating and freeing the vector.
let mut process_resource_bridge = Vec::with_capacity(self.resource_bridges.len());
'wait: loop {
- // If there are outstanding fences, wake up early to poll them.
- let duration = if self.state.has_pending_fences() {
- FENCE_POLL_INTERVAL
- } else {
- Duration::new(i64::MAX as u64, 0)
- };
-
- let events = match wait_ctx.wait_timeout(duration) {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -905,6 +899,9 @@
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
+ Token::VirtioGpuPoll => {
+ self.state.poll();
+ }
Token::Kill => {
break 'wait;
}
@@ -921,8 +918,6 @@
signal_used_ctrl = true;
}
- self.state.fence_poll();
-
// Process the entire control queue before the resource bridge in case a resource is
// created or destroyed by the control queue. Processing the resource bridge first may
// lead to a race condition.
@@ -1019,7 +1014,9 @@
.use_surfaceless(gpu_parameters.renderer_use_surfaceless)
.use_external_blob(external_blob)
.use_venus(gpu_parameters.use_vulkan)
- .use_render_server(render_server_fd.is_some());
+ .use_render_server(render_server_fd.is_some())
+ .use_thread_sync(true)
+ .use_async_fence_cb(true);
let gfxstream_flags = GfxstreamFlags::new()
.use_egl(gpu_parameters.renderer_use_egl)
.use_gles(gpu_parameters.renderer_use_gles)
@@ -1027,7 +1024,8 @@
.use_surfaceless(gpu_parameters.renderer_use_surfaceless)
.use_guest_angle(gpu_parameters.gfxstream_use_guest_angle)
.use_syncfd(gpu_parameters.gfxstream_use_syncfd)
- .use_vulkan(gpu_parameters.use_vulkan);
+ .use_vulkan(gpu_parameters.use_vulkan)
+ .use_async_fence_cb(true);
let mut rutabaga_channels: Vec<RutabagaChannel> = Vec::new();
for (channel_name, path) in &channels {
diff --git a/devices/src/virtio/gpu/virtio_gpu.rs b/devices/src/virtio/gpu/virtio_gpu.rs
index ec75baa..1c4f4f6 100644
--- a/devices/src/virtio/gpu/virtio_gpu.rs
+++ b/devices/src/virtio/gpu/virtio_gpu.rs
@@ -559,9 +559,15 @@
Ok(OkNoData)
}
- /// Returns an array of RutabagaFence, describing completed fences.
- pub fn fence_poll(&mut self) -> Vec<RutabagaFence> {
- self.rutabaga.poll()
+ /// Polls the Rutabaga backend.
+ pub fn poll(&self) {
+ self.rutabaga.poll();
+ }
+
+ /// Gets a pollable eventfd that signals the device to wakeup and poll the
+ /// Rutabaga backend.
+ pub fn poll_descriptor(&self) -> Option<SafeDescriptor> {
+ self.rutabaga.poll_descriptor()
}
/// Creates a 3D resource with the given properties and resource_id.
diff --git a/devices/src/virtio/interrupt.rs b/devices/src/virtio/interrupt.rs
index ba21054..3ed6ccc 100644
--- a/devices/src/virtio/interrupt.rs
+++ b/devices/src/virtio/interrupt.rs
@@ -3,8 +3,11 @@
// found in the LICENSE file.
use super::{INTERRUPT_STATUS_CONFIG_CHANGED, INTERRUPT_STATUS_USED_RING, VIRTIO_MSI_NO_VECTOR};
+use crate::irq_event::IrqLevelEvent;
use crate::pci::MsixConfig;
use base::Event;
+use std::cell::RefCell;
+use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use sync::Mutex;
@@ -31,8 +34,7 @@
pub struct Interrupt {
interrupt_status: Arc<AtomicUsize>,
- interrupt_evt: Event,
- interrupt_resample_evt: Event,
+ interrupt_evt: IrqLevelEvent,
msix_config: Option<Arc<Mutex<MsixConfig>>>,
config_msix_vector: u16,
}
@@ -62,7 +64,7 @@
== 0
{
// Write to irqfd to inject INTx interrupt
- self.interrupt_evt.write(1).unwrap();
+ self.interrupt_evt.trigger().unwrap();
}
}
@@ -71,12 +73,12 @@
}
fn get_resample_evt(&self) -> Option<&Event> {
- Some(&self.interrupt_resample_evt)
+ Some(self.interrupt_evt.get_resample())
}
fn do_interrupt_resample(&self) {
if self.interrupt_status.load(Ordering::SeqCst) != 0 {
- self.interrupt_evt.write(1).unwrap();
+ self.interrupt_evt.trigger().unwrap();
}
}
}
@@ -102,18 +104,37 @@
fn do_interrupt_resample(&self) {}
}
+impl<I: SignalableInterrupt> SignalableInterrupt for Rc<RefCell<I>> {
+ fn signal(&self, vector: u16, interrupt_status_mask: u32) {
+ self.borrow().signal(vector, interrupt_status_mask);
+ }
+
+ fn signal_used_queue(&self, vector: u16) {
+ self.borrow().signal_used_queue(vector);
+ }
+
+ fn signal_config_changed(&self) {
+ self.borrow().signal_config_changed();
+ }
+
+ fn get_resample_evt(&self) -> Option<&Event> {
+ // Cannot get resample event from a borrowed item.
+ None
+ }
+
+ fn do_interrupt_resample(&self) {}
+}
+
impl Interrupt {
pub fn new(
interrupt_status: Arc<AtomicUsize>,
- interrupt_evt: Event,
- interrupt_resample_evt: Event,
+ interrupt_evt: IrqLevelEvent,
msix_config: Option<Arc<Mutex<MsixConfig>>>,
config_msix_vector: u16,
) -> Interrupt {
Interrupt {
interrupt_status,
interrupt_evt,
- interrupt_resample_evt,
msix_config,
config_msix_vector,
}
@@ -121,12 +142,12 @@
/// Get a reference to the interrupt event.
pub fn get_interrupt_evt(&self) -> &Event {
- &self.interrupt_evt
+ self.interrupt_evt.get_trigger()
}
/// Handle interrupt resampling event, reading the value from the event and doing the resample.
pub fn interrupt_resample(&self) {
- let _ = self.interrupt_resample_evt.read();
+ self.interrupt_evt.clear_resample();
self.do_interrupt_resample();
}
diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs
index 6ff03f0..8ec8bfb 100644
--- a/devices/src/virtio/mod.rs
+++ b/devices/src/virtio/mod.rs
@@ -102,7 +102,7 @@
const TYPE_VHOST_USER: u32 = MAX_VIRTIO_DEVICE_ID - 2;
pub const VIRTIO_F_VERSION_1: u32 = 32;
-const VIRTIO_F_ACCESS_PLATFORM: u32 = 33;
+pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33;
const INTERRUPT_STATUS_USED_RING: u32 = 0x1;
const INTERRUPT_STATUS_CONFIG_CHANGED: u32 = 0x2;
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index b232109..1ab9724 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -584,12 +584,12 @@
pub fn validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError> {
let flags = tap.if_flags();
let mut required_flags = vec![
- (net_sys::IFF_TAP, "IFF_TAP"),
- (net_sys::IFF_NO_PI, "IFF_NO_PI"),
- (net_sys::IFF_VNET_HDR, "IFF_VNET_HDR"),
+ (libc::IFF_TAP, "IFF_TAP"),
+ (libc::IFF_NO_PI, "IFF_NO_PI"),
+ (libc::IFF_VNET_HDR, "IFF_VNET_HDR"),
];
if vq_pairs > 1 {
- required_flags.push((net_sys::IFF_MULTI_QUEUE, "IFF_MULTI_QUEUE"));
+ required_flags.push((libc::IFF_MULTI_QUEUE, "IFF_MULTI_QUEUE"));
}
let missing_flags = required_flags
.iter()
diff --git a/devices/src/virtio/queue.rs b/devices/src/virtio/queue.rs
index 7b47d3d..a436f74 100644
--- a/devices/src/virtio/queue.rs
+++ b/devices/src/virtio/queue.rs
@@ -621,7 +621,7 @@
mod tests {
use super::super::Interrupt;
use super::*;
- use base::Event;
+ use crate::IrqLevelEvent;
use std::convert::TryInto;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
@@ -723,8 +723,7 @@
let interrupt = Interrupt::new(
Arc::new(AtomicUsize::new(0)),
- Event::new().unwrap(),
- Event::new().unwrap(),
+ IrqLevelEvent::new().unwrap(),
None,
10,
);
@@ -800,8 +799,7 @@
let interrupt = Interrupt::new(
Arc::new(AtomicUsize::new(0)),
- Event::new().unwrap(),
- Event::new().unwrap(),
+ IrqLevelEvent::new().unwrap(),
None,
10,
);
diff --git a/devices/src/virtio/tpm.rs b/devices/src/virtio/tpm.rs
index 6ab6dbc..a3b4ffe 100644
--- a/devices/src/virtio/tpm.rs
+++ b/devices/src/virtio/tpm.rs
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::env;
-use std::fs;
use std::io::{self, Read, Write};
use std::ops::BitOrAssign;
-use std::path::PathBuf;
+use std::sync::Arc;
use std::thread;
use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use remain::sorted;
+use sync::Mutex;
use thiserror::Error;
use vm_memory::GuestMemory;
@@ -36,17 +35,17 @@
mem: GuestMemory,
queue_evt: Event,
kill_evt: Event,
- device: Device,
+ backend: Arc<Mutex<dyn TpmBackend>>,
}
-struct Device {
- simulator: tpm2::Simulator,
+pub trait TpmBackend: Send {
+ fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8];
}
-impl Device {
- fn perform_work(&mut self, mem: &GuestMemory, desc: DescriptorChain) -> Result<u32> {
- let mut reader = Reader::new(mem.clone(), desc.clone()).map_err(Error::Descriptor)?;
- let mut writer = Writer::new(mem.clone(), desc).map_err(Error::Descriptor)?;
+impl Worker {
+ fn perform_work(&mut self, desc: DescriptorChain) -> Result<u32> {
+ let mut reader = Reader::new(self.mem.clone(), desc.clone()).map_err(Error::Descriptor)?;
+ let mut writer = Writer::new(self.mem.clone(), desc).map_err(Error::Descriptor)?;
let available_bytes = reader.available_bytes();
if available_bytes > TPM_BUFSIZE {
@@ -58,7 +57,9 @@
let mut command = vec![0u8; available_bytes];
reader.read_exact(&mut command).map_err(Error::Read)?;
- let response = self.simulator.execute_command(&command);
+ let mut backend = self.backend.lock();
+
+ let response = backend.execute_command(&command);
if response.len() > TPM_BUFSIZE {
return Err(Error::ResponseTooLong {
@@ -78,15 +79,13 @@
Ok(writer.bytes_written() as u32)
}
-}
-impl Worker {
fn process_queue(&mut self) -> NeedsInterrupt {
let mut needs_interrupt = NeedsInterrupt::No;
while let Some(avail_desc) = self.queue.pop(&self.mem) {
let index = avail_desc.index;
- let len = match self.device.perform_work(&self.mem, avail_desc) {
+ let len = match self.perform_work(avail_desc) {
Ok(len) => len,
Err(err) => {
error!("{}", err);
@@ -163,15 +162,15 @@
/// Virtio vTPM device.
pub struct Tpm {
- storage: PathBuf,
+ backend: Arc<Mutex<dyn TpmBackend>>,
kill_evt: Option<Event>,
worker_thread: Option<thread::JoinHandle<()>>,
}
impl Tpm {
- pub fn new(storage: PathBuf) -> Tpm {
+ pub fn new(backend: Arc<Mutex<dyn TpmBackend>>) -> Tpm {
Tpm {
- storage,
+ backend,
kill_evt: None,
worker_thread: None,
}
@@ -216,15 +215,7 @@
let queue = queues.remove(0);
let queue_evt = queue_evts.remove(0);
- if let Err(err) = fs::create_dir_all(&self.storage) {
- error!("vtpm failed to create directory for simulator: {}", err);
- return;
- }
- if let Err(err) = env::set_current_dir(&self.storage) {
- error!("vtpm failed to change into simulator directory: {}", err);
- return;
- }
- let simulator = tpm2::Simulator::singleton_in_current_directory();
+ let backend = self.backend.clone();
let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
Ok(v) => v,
@@ -241,7 +232,7 @@
mem,
queue_evt,
kill_evt,
- device: Device { simulator },
+ backend,
};
let worker_result = thread::Builder::new()
diff --git a/devices/src/virtio/vhost/mod.rs b/devices/src/virtio/vhost/mod.rs
index 88cc852..c76249b 100644
--- a/devices/src/virtio/vhost/mod.rs
+++ b/devices/src/virtio/vhost/mod.rs
@@ -13,7 +13,7 @@
mod control_socket;
mod net;
pub mod user;
-mod vsock;
+pub mod vsock;
mod worker;
pub use self::control_socket::*;
diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs
index 78af0f5..9fbdde5 100644
--- a/devices/src/virtio/vhost/net.rs
+++ b/devices/src/virtio/vhost/net.rs
@@ -355,6 +355,7 @@
use super::*;
use crate::virtio::base_features;
use crate::virtio::VIRTIO_MSI_NO_VECTOR;
+ use crate::IrqLevelEvent;
use hypervisor::ProtectionType;
use net_util::fakes::FakeTap;
use std::path::PathBuf;
@@ -417,8 +418,7 @@
guest_memory,
Interrupt::new(
Arc::new(AtomicUsize::new(0)),
- Event::new().unwrap(),
- Event::new().unwrap(),
+ IrqLevelEvent::new().unwrap(),
None,
VIRTIO_MSI_NO_VECTOR,
),
diff --git a/devices/src/virtio/vhost/user/device/block.rs b/devices/src/virtio/vhost/user/device/block.rs
index 1139cbf..262e656 100644
--- a/devices/src/virtio/vhost/user/device/block.rs
+++ b/devices/src/virtio/vhost/user/device/block.rs
@@ -3,7 +3,6 @@
// found in the LICENSE file.
use std::cell::RefCell;
-use std::cmp::{max, min};
use std::fs::OpenOptions;
use std::rc::Rc;
use std::sync::{atomic::AtomicU64, atomic::Ordering, Arc};
@@ -14,20 +13,20 @@
use sync::Mutex;
use vmm_vhost::message::*;
-use base::{error, iov_max, warn, Event, Timer};
+use base::{warn, Event, Timer};
use cros_async::{sync::Mutex as AsyncMutex, EventAsync, Executor, TimerAsync};
use data_model::DataInit;
use disk::create_async_disk_file;
use hypervisor::ProtectionType;
use vm_memory::GuestMemory;
-use crate::virtio::block::asynchronous::{flush_disk, process_one_chain};
+use crate::virtio::block::asynchronous::{flush_disk, handle_queue};
use crate::virtio::block::*;
use crate::virtio::vhost::user::device::{
handler::{DeviceRequestHandler, Doorbell, VhostUserBackend},
vvu::pci::VvuPciDevice,
};
-use crate::virtio::{self, base_features, copy_config, Queue};
+use crate::virtio::{self, base_features, block::sys::*, copy_config};
const QUEUE_SIZE: u16 = 256;
const NUM_QUEUES: u16 = 16;
@@ -86,12 +85,7 @@
let avail_features = build_avail_features(base_features, read_only, sparse, true)
| VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
- let seg_max = min(max(iov_max(), 1), u32::max_value() as usize) as u32;
-
- // Since we do not currently support indirect descriptors, the maximum
- // number of segments must be smaller than the queue size.
- // In addition, the request header and status each consume a descriptor.
- let seg_max = min(seg_max, u32::from(QUEUE_SIZE) - 2);
+ let seg_max = get_seg_max(QUEUE_SIZE);
let async_image = disk_image.to_async_disk(ex)?;
@@ -250,48 +244,6 @@
}
}
-// There is one async task running `handle_queue` per virtio queue in use.
-// Receives messages from the guest and queues a task to complete the operations with the async
-// executor.
-async fn handle_queue(
- ex: Executor,
- mem: GuestMemory,
- disk_state: Rc<AsyncMutex<DiskState>>,
- queue: Rc<RefCell<Queue>>,
- evt: EventAsync,
- interrupt: Arc<Mutex<Doorbell>>,
- flush_timer: Rc<RefCell<TimerAsync>>,
- flush_timer_armed: Rc<RefCell<bool>>,
-) {
- loop {
- if let Err(e) = evt.next_val().await {
- error!("Failed to read the next queue event: {}", e);
- continue;
- }
- while let Some(descriptor_chain) = queue.borrow_mut().pop(&mem) {
- let queue = Rc::clone(&queue);
- let disk_state = Rc::clone(&disk_state);
- let mem = mem.clone();
- let interrupt = Arc::clone(&interrupt);
- let flush_timer = Rc::clone(&flush_timer);
- let flush_timer_armed = Rc::clone(&flush_timer_armed);
- ex.spawn_local(async move {
- process_one_chain(
- queue,
- descriptor_chain,
- disk_state,
- mem,
- &interrupt,
- flush_timer,
- flush_timer_armed,
- )
- .await
- })
- .detach();
- }
- }
-}
-
#[derive(FromArgs)]
#[argh(description = "")]
struct Options {
diff --git a/devices/src/virtio/vhost/user/device/console.rs b/devices/src/virtio/vhost/user/device/console.rs
index 2425eeb..50d1f11 100644
--- a/devices/src/virtio/vhost/user/device/console.rs
+++ b/devices/src/virtio/vhost/user/device/console.rs
@@ -87,9 +87,8 @@
_out_timestamp: bool,
_keep_rds: Vec<RawDescriptor>,
) -> ConsoleDevice {
- let avail_features = 1u64 << crate::virtio::VIRTIO_F_VERSION_1
- | virtio::base_features(protected_vm)
- | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
+ let avail_features =
+ virtio::base_features(protected_vm) | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
ConsoleDevice {
input,
output,
diff --git a/devices/src/virtio/vhost/user/device/gpu.rs b/devices/src/virtio/vhost/user/device/gpu.rs
index 865d2cb..a6e5888 100644
--- a/devices/src/virtio/vhost/user/device/gpu.rs
+++ b/devices/src/virtio/vhost/user/device/gpu.rs
@@ -9,13 +9,9 @@
use async_task::Task;
use base::{
clone_descriptor, error, warn, Event, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor,
- TimerFd, Tube, UnixSeqpacketListener, UnlinkUnixSeqpacketListener,
+ Tube, UnixSeqpacketListener, UnlinkUnixSeqpacketListener,
};
-use cros_async::{AsyncTube, AsyncWrapper, EventAsync, Executor, IoSourceExt, TimerAsync};
-use futures::{
- future::{select, Either},
- pin_mut,
-};
+use cros_async::{AsyncTube, AsyncWrapper, EventAsync, Executor, IoSourceExt};
use hypervisor::ProtectionType;
use sync::Mutex;
use vm_memory::GuestMemory;
@@ -52,42 +48,15 @@
reader: SharedReader,
mem: GuestMemory,
kick_evt: EventAsync,
- mut timer: TimerAsync,
state: Rc<RefCell<gpu::Frontend>>,
) {
loop {
- if state.borrow().has_pending_fences() {
- if let Err(e) = timer.reset(gpu::FENCE_POLL_INTERVAL, None) {
- error!("Failed to reset fence timer: {}", e);
- break;
- }
-
- let kick_value = kick_evt.next_val();
- let timer_value = timer.next_val();
- pin_mut!(kick_value);
- pin_mut!(timer_value);
- match select(kick_value, timer_value).await {
- Either::Left((res, _)) => {
- if let Err(e) = res {
- error!("Failed to read kick event for ctrl queue: {}", e);
- break;
- }
- }
- Either::Right((res, _)) => {
- if let Err(e) = res {
- error!("Failed to read timer for ctrl queue: {}", e);
- break;
- }
- }
- }
- } else if let Err(e) = kick_evt.next_val().await {
+ if let Err(e) = kick_evt.next_val().await {
error!("Failed to read kick event for ctrl queue: {}", e);
- break;
}
let mut state = state.borrow_mut();
let needs_interrupt = state.process_queue(&mem, &reader);
- state.fence_poll();
if needs_interrupt {
reader.signal_used(&mem);
@@ -305,13 +274,9 @@
self.display_worker = Some(task);
}
- let timer = TimerFd::new()
- .context("failed to create TimerFd")
- .and_then(|t| TimerAsync::new(t, &self.ex).context("failed to create TimerAsync"))?;
let task = self
.ex
- .spawn_local(run_ctrl_queue(reader, mem, kick_evt, timer, state));
-
+ .spawn_local(run_ctrl_queue(reader, mem, kick_evt, state));
self.workers[idx] = Some(task);
Ok(())
}
diff --git a/devices/src/virtio/vhost/user/device/handler.rs b/devices/src/virtio/vhost/user/device/handler.rs
index 9e7d4bd..b5fd540 100644
--- a/devices/src/virtio/vhost/user/device/handler.rs
+++ b/devices/src/virtio/vhost/user/device/handler.rs
@@ -74,9 +74,11 @@
use vmm_vhost::{Error as VhostError, Result as VhostResult, VhostUserSlaveReqHandlerMut};
-use crate::vfio::VfioRegionAddr;
+use crate::vfio::{VfioDevice, VfioRegionAddr};
use crate::virtio::vhost::user::device::vvu::{
- device::VvuDevice, doorbell::DoorbellRegion, pci::VvuPciDevice,
+ device::VvuDevice,
+ doorbell::DoorbellRegion,
+ pci::{VvuPciCaps, VvuPciDevice},
};
use crate::virtio::{Queue, SignalableInterrupt};
@@ -162,16 +164,14 @@
}
pub fn create_vvu_guest_memory(
- device: &VvuPciDevice,
+ vfio_dev: &VfioDevice,
+ shared_mem_addr: &VfioRegionAddr,
contexts: &[VhostUserMemoryRegion],
) -> VhostResult<(GuestMemory, Vec<MappingInfo>)> {
- let file_offset = device
- .vfio_dev
- .get_offset_for_addr(device.caps.shared_mem_cfg_addr())
- .map_err(|e| {
- error!("failed to get underlying file: {}", e);
- VhostError::InvalidOperation
- })?;
+ let file_offset = vfio_dev.get_offset_for_addr(shared_mem_addr).map_err(|e| {
+ error!("failed to get underlying file: {}", e);
+ VhostError::InvalidOperation
+ })?;
let mut vmm_maps = Vec::with_capacity(contexts.len());
let mut regions = Vec::with_capacity(contexts.len());
@@ -186,7 +186,7 @@
size: region.memory_size,
});
- let cloned_file = device.vfio_dev.dev_file().try_clone().map_err(|e| {
+ let cloned_file = vfio_dev.dev_file().try_clone().map_err(|e| {
error!("failed to clone vfio device file: {}", e);
VhostError::InvalidOperation
})?;
@@ -332,9 +332,13 @@
}
}
-enum HandlerType {
+pub(super) enum HandlerType {
VhostUser,
- Vvu { device: Arc<Mutex<VvuPciDevice>> },
+ Vvu {
+ vfio_dev: Arc<VfioDevice>,
+ caps: VvuPciCaps,
+ notification_evts: Vec<Event>,
+ },
}
impl Default for HandlerType {
@@ -431,10 +435,13 @@
/// Starts listening virtio-vhost-user device with VFIO to handle incoming vhost-user messages
/// forwarded by it.
- pub async fn run_vvu(mut self, device: VvuPciDevice, ex: &Executor) -> Result<()> {
- let device = Arc::new(Mutex::new(device));
- let driver = VvuDevice::new(Arc::clone(&device));
- self.handler_type = HandlerType::Vvu { device };
+ pub async fn run_vvu(mut self, mut device: VvuPciDevice, ex: &Executor) -> Result<()> {
+ self.handler_type = HandlerType::Vvu {
+ vfio_dev: Arc::clone(&device.vfio_dev),
+ caps: device.caps.clone(),
+ notification_evts: std::mem::take(&mut device.notification_evts),
+ };
+ let driver = VvuDevice::new(device);
let mut listener = VfioListener::new(driver)
.map_err(|e| anyhow!("failed to create a VFIO listener: {}", e))
@@ -562,13 +569,16 @@
}
create_guest_memory(contexts, files)?
}
- HandlerType::Vvu { device, .. } => {
+ HandlerType::Vvu {
+ vfio_dev: device,
+ caps,
+ ..
+ } => {
// virtio-vhost-user doesn't pass FDs.
if !files.is_empty() {
return Err(VhostError::InvalidParam);
}
- let device = device.lock();
- create_vvu_guest_memory(&device, contexts)?
+ create_vvu_guest_memory(device.as_ref(), caps.shared_mem_cfg_addr(), contexts)?
}
};
@@ -669,16 +679,16 @@
// Safe because we own the file.
unsafe { Event::from_raw_descriptor(file.into_raw_descriptor()) }
}
- HandlerType::Vvu { device, .. } => {
+ HandlerType::Vvu {
+ notification_evts, ..
+ } => {
if file.is_some() {
return Err(VhostError::InvalidParam);
}
- device.lock().notification_evts[index as usize]
- .try_clone()
- .map_err(|e| {
- error!("failed to clone notification_evts[{}]: {}", index, e);
- VhostError::InvalidOperation
- })?
+ notification_evts[index as usize].try_clone().map_err(|e| {
+ error!("failed to clone notification_evts[{}]: {}", index, e);
+ VhostError::InvalidOperation
+ })?
}
};
@@ -720,15 +730,21 @@
VhostError::InvalidParam
})?)
}
- HandlerType::Vvu { device, .. } => {
- let device = device.lock();
- let vfio = Arc::clone(&device.vfio_dev);
- let base = device.caps.doorbell_base_addr();
+ HandlerType::Vvu {
+ vfio_dev: device,
+ caps,
+ ..
+ } => {
+ let base = caps.doorbell_base_addr();
let addr = VfioRegionAddr {
index: base.index,
- addr: base.addr + (index as u64 * device.caps.doorbell_off_multiplier() as u64),
+ addr: base.addr + (index as u64 * caps.doorbell_off_multiplier() as u64),
};
- Doorbell::Vfio(DoorbellRegion { vfio, index, addr })
+ Doorbell::Vfio(DoorbellRegion {
+ vfio: Arc::clone(device),
+ index,
+ addr,
+ })
}
};
diff --git a/devices/src/virtio/vhost/user/device/mod.rs b/devices/src/virtio/vhost/user/device/mod.rs
index 553e3f2..78c5d8a 100644
--- a/devices/src/virtio/vhost/user/device/mod.rs
+++ b/devices/src/virtio/vhost/user/device/mod.rs
@@ -22,6 +22,8 @@
pub use fs::run_fs_device;
#[cfg(feature = "gpu")]
pub use gpu::run_gpu_device;
+
+#[cfg(any(all(windows, feature = "slirp"), not(windows)))]
pub use net::run_net_device;
pub use vsock::run_vsock_device;
pub use wl::run_wl_device;
diff --git a/devices/src/virtio/vhost/user/device/net.rs b/devices/src/virtio/vhost/user/device/net.rs
index 6b36ac8..2b7a64f 100644
--- a/devices/src/virtio/vhost/user/device/net.rs
+++ b/devices/src/virtio/vhost/user/device/net.rs
@@ -2,43 +2,44 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::net::Ipv4Addr;
-use std::str::FromStr;
+#[cfg_attr(windows, path = "windows/net.rs")]
+#[cfg_attr(not(windows), path = "unix/net.rs")]
+mod net;
+
+// Only Windows exposes public symbols, but the module level use is used on both platforms.
+#[allow(unused_imports)]
+pub use net::*;
+
use std::sync::Arc;
-use std::thread;
use anyhow::{anyhow, bail, Context};
-use argh::FromArgs;
-use base::{error, validate_raw_descriptor, warn, Event, RawDescriptor};
-use cros_async::{EventAsync, Executor, IoSourceExt};
+use base::{error, Event};
+use cros_async::{EventAsync, Executor, IntoAsync};
use data_model::DataInit;
-use futures::future::{AbortHandle, Abortable};
-use hypervisor::ProtectionType;
-use net_util::{MacAddress, Tap, TapT};
+use futures::future::AbortHandle;
+use net_util::TapT;
use once_cell::sync::OnceCell;
use sync::Mutex;
-use virtio_sys::virtio_net;
use vm_memory::GuestMemory;
-use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
+use vmm_vhost::message::VhostUserProtocolFeatures;
use crate::virtio;
-use crate::virtio::net::{
- build_config, process_ctrl, process_rx, process_tx, validate_and_configure_tap,
- virtio_features_to_tap_offload, NetError,
-};
-use crate::virtio::vhost::user::device::{
- handler::{DeviceRequestHandler, Doorbell, VhostUserBackend},
- vvu::pci::VvuPciDevice,
-};
+use crate::virtio::net::{build_config, process_ctrl, process_tx, virtio_features_to_tap_offload};
+use crate::virtio::vhost::user::device::handler::{Doorbell, VhostUserBackend};
thread_local! {
- static NET_EXECUTOR: OnceCell<Executor> = OnceCell::new();
+ pub(crate) static NET_EXECUTOR: OnceCell<Executor> = OnceCell::new();
}
-async fn run_tx_queue(
+// TODO(b/188947559): Come up with better way to include these constants. Compiler errors happen
+// if they are kept in the trait.
+const MAX_QUEUE_NUM: usize = 3; /* rx, tx, ctrl */
+const MAX_VRING_LEN: u16 = 256;
+
+async fn run_tx_queue<T: TapT>(
mut queue: virtio::Queue,
mem: GuestMemory,
- mut tap: Tap,
+ mut tap: T,
doorbell: Arc<Mutex<Doorbell>>,
kick_evt: EventAsync,
) {
@@ -52,39 +53,10 @@
}
}
-async fn run_rx_queue(
+async fn run_ctrl_queue<T: TapT>(
mut queue: virtio::Queue,
mem: GuestMemory,
- mut tap: Box<dyn IoSourceExt<Tap>>,
- doorbell: Arc<Mutex<Doorbell>>,
- kick_evt: EventAsync,
-) {
- loop {
- if let Err(e) = tap.wait_readable().await {
- error!("Failed to wait for tap device to become readable: {}", e);
- break;
- }
-
- match process_rx(&doorbell, &mut queue, &mem, tap.as_source_mut()) {
- Ok(()) => {}
- Err(NetError::RxDescriptorsExhausted) => {
- if let Err(e) = kick_evt.next_val().await {
- error!("Failed to read kick event for rx queue: {}", e);
- break;
- }
- }
- Err(e) => {
- error!("Failed to process rx queue: {}", e);
- break;
- }
- }
- }
-}
-
-async fn run_ctrl_queue(
- mut queue: virtio::Queue,
- mem: GuestMemory,
- mut tap: Tap,
+ mut tap: T,
doorbell: Arc<Mutex<Doorbell>>,
kick_evt: EventAsync,
acked_features: u64,
@@ -110,110 +82,32 @@
}
}
-struct TapConfig {
- host_ip: Ipv4Addr,
- netmask: Ipv4Addr,
- mac: MacAddress,
-}
-
-impl FromStr for TapConfig {
- type Err = anyhow::Error;
-
- fn from_str(arg: &str) -> Result<Self, Self::Err> {
- let args: Vec<&str> = arg.split(',').collect();
- if args.len() != 3 {
- bail!("TAP config must consist of 3 parts but {}", args.len());
- }
-
- let host_ip: Ipv4Addr = args[0]
- .parse()
- .map_err(|e| anyhow!("invalid IP address: {}", e))?;
- let netmask: Ipv4Addr = args[1]
- .parse()
- .map_err(|e| anyhow!("invalid net mask: {}", e))?;
- let mac: MacAddress = args[2]
- .parse()
- .map_err(|e| anyhow!("invalid MAC address: {}", e))?;
-
- Ok(Self {
- host_ip,
- netmask,
- mac,
- })
- }
-}
-
-struct NetBackend {
- tap: Tap,
+pub(crate) struct NetBackend<T: TapT + IntoAsync> {
+ tap: T,
avail_features: u64,
acked_features: u64,
acked_protocol_features: VhostUserProtocolFeatures,
- workers: [Option<AbortHandle>; Self::MAX_QUEUE_NUM],
+ workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
mtu: u16,
+ #[cfg(all(windows, feature = "slirp"))]
+ slirp_kill_event: Event,
}
-impl NetBackend {
- pub fn new_from_config(config: &TapConfig) -> anyhow::Result<Self> {
- // Create a tap device.
- let tap = Tap::new(true /* vnet_hdr */, false /* multi_queue */)
- .context("failed to create tap device")?;
- tap.set_ip_addr(config.host_ip)
- .context("failed to set IP address")?;
- tap.set_netmask(config.netmask)
- .context("failed to set netmask")?;
- tap.set_mac_address(config.mac)
- .context("failed to set MAC address")?;
-
- Self::new(tap)
- }
-
- pub fn new_from_tap_fd(tap_fd: RawDescriptor) -> anyhow::Result<Self> {
- let tap_fd = validate_raw_descriptor(tap_fd).context("failed to validate tap fd")?;
- // Safe because we ensure that we get a unique handle to the fd.
- let tap =
- unsafe { Tap::from_raw_descriptor(tap_fd).context("failed to create tap device")? };
-
- Self::new(tap)
- }
-
- fn new(tap: Tap) -> anyhow::Result<Self> {
- let vq_pairs = Self::max_vq_pairs();
- tap.enable().context("failed to enable tap")?;
- validate_and_configure_tap(&tap, vq_pairs as u16)
- .context("failed to validate and configure tap")?;
-
- let avail_features = virtio::base_features(ProtectionType::Unprotected)
- | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
- | 1 << virtio_net::VIRTIO_NET_F_CSUM
- | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
- | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
- | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
- | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
- | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
- | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
- | 1 << virtio_net::VIRTIO_NET_F_MTU
- | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
-
- let mtu = tap.mtu()?;
-
- Ok(Self {
- tap,
- avail_features,
- acked_features: 0,
- acked_protocol_features: VhostUserProtocolFeatures::empty(),
- workers: Default::default(),
- mtu,
- })
- }
-
+impl<T: 'static> NetBackend<T>
+where
+ T: TapT + IntoAsync,
+{
fn max_vq_pairs() -> usize {
Self::MAX_QUEUE_NUM / 2
}
}
-impl VhostUserBackend for NetBackend {
- const MAX_QUEUE_NUM: usize = 3; /* rx, tx, ctrl */
- const MAX_VRING_LEN: u16 = 256;
+impl<T: 'static> VhostUserBackend for NetBackend<T>
+where
+ T: TapT + IntoAsync,
+{
+ const MAX_QUEUE_NUM: usize = MAX_QUEUE_NUM; /* rx, tx, ctrl */
+ const MAX_VRING_LEN: u16 = MAX_VRING_LEN;
type Error = anyhow::Error;
@@ -266,67 +160,12 @@
fn start_queue(
&mut self,
idx: usize,
- mut queue: virtio::Queue,
+ queue: virtio::Queue,
mem: GuestMemory,
doorbell: Arc<Mutex<Doorbell>>,
kick_evt: Event,
) -> anyhow::Result<()> {
- if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
- warn!("Starting new queue handler without stopping old handler");
- handle.abort();
- }
-
- // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
- queue.ack_features(self.acked_features);
-
- NET_EXECUTOR.with(|ex| {
- // Safe because the executor is initialized in main() below.
- let ex = ex.get().expect("Executor not initialized");
-
- let kick_evt = EventAsync::new(kick_evt.0, ex)
- .context("failed to create EventAsync for kick_evt")?;
- let tap = self.tap.try_clone().context("failed to clone tap device")?;
- let (handle, registration) = AbortHandle::new_pair();
- match idx {
- 0 => {
- let tap = ex
- .async_from(tap)
- .context("failed to create async tap device")?;
-
- ex.spawn_local(Abortable::new(
- run_rx_queue(queue, mem, tap, doorbell, kick_evt),
- registration,
- ))
- .detach();
- }
- 1 => {
- ex.spawn_local(Abortable::new(
- run_tx_queue(queue, mem, tap, doorbell, kick_evt),
- registration,
- ))
- .detach();
- }
- 2 => {
- ex.spawn_local(Abortable::new(
- run_ctrl_queue(
- queue,
- mem,
- tap,
- doorbell,
- kick_evt,
- self.acked_features,
- 1, /* vq_pairs */
- ),
- registration,
- ))
- .detach();
- }
- _ => bail!("attempted to start unknown queue: {}", idx),
- }
-
- self.workers[idx] = Some(handle);
- Ok(())
- })
+ net::start_queue(self, idx, queue, mem, doorbell, kick_evt)
}
fn stop_queue(&mut self, idx: usize) {
@@ -336,155 +175,7 @@
}
}
-#[derive(FromArgs)]
-#[argh(description = "")]
-struct Options {
- #[argh(
- option,
- description = "TAP device config. (e.g. \
- \"/path/to/sock,10.0.2.2,255.255.255.0,12:34:56:78:9a:bc\")",
- arg_name = "SOCKET_PATH,IP_ADDR,NET_MASK,MAC_ADDR"
- )]
- device: Vec<String>,
- #[argh(
- option,
- description = "TAP FD with a socket path",
- arg_name = "SOCKET_PATH,TAP_FD"
- )]
- tap_fd: Vec<String>,
- #[argh(
- option,
- description = "TAP device config for virtio-vhost-user. \
- (e.g. \"0000:00:07.0,10.0.2.2,255.255.255.0,12:34:56:78:9a:bc\")",
- arg_name = "DEVICE,IP_ADDR,NET_MASK,MAC_ADDR"
- )]
- vvu_device: Vec<String>,
- #[argh(
- option,
- description = "TAP FD with a vfio device name for virtio-vhost-user",
- arg_name = "DEVICE,TAP_FD"
- )]
- vvu_tap_fd: Vec<String>,
-}
-
-enum Connection {
- Socket(String),
- Vfio(String),
-}
-
-fn new_backend_from_device_arg(arg: &str) -> anyhow::Result<(String, NetBackend)> {
- let pos = match arg.find(',') {
- Some(p) => p,
- None => {
- bail!("device must take comma-separated argument");
- }
- };
- let conn = &arg[0..pos];
- let cfg = &arg[pos + 1..]
- .parse::<TapConfig>()
- .context("failed to parse tap config")?;
- let backend = NetBackend::new_from_config(cfg).context("failed to create NetBackend")?;
- Ok((conn.to_string(), backend))
-}
-
-fn new_backend_from_tapfd_arg(arg: &str) -> anyhow::Result<(String, NetBackend)> {
- let pos = match arg.find(',') {
- Some(p) => p,
- None => {
- bail!("'tap-fd' flag must take comma-separated argument");
- }
- };
- let conn = &arg[0..pos];
- let tap_fd = &arg[pos + 1..]
- .parse::<i32>()
- .context("failed to parse tap-fd")?;
- let backend = NetBackend::new_from_tap_fd(*tap_fd).context("failed to create NetBackend")?;
-
- Ok((conn.to_string(), backend))
-}
-
/// Starts a vhost-user net device.
-/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_net_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
- let opts = match Options::from_args(&[program_name], args) {
- Ok(opts) => opts,
- Err(e) => {
- if e.status.is_err() {
- bail!(e.output);
- } else {
- println!("{}", e.output);
- }
- return Ok(());
- }
- };
-
- let num_devices =
- opts.device.len() + opts.tap_fd.len() + opts.vvu_device.len() + opts.vvu_tap_fd.len();
-
- if num_devices == 0 {
- bail!("no device option was passed");
- }
-
- let mut devices: Vec<(Connection, NetBackend)> = Vec::with_capacity(num_devices);
-
- // vhost-user
- for arg in opts.device.iter() {
- devices.push(
- new_backend_from_device_arg(arg)
- .map(|(s, backend)| (Connection::Socket(s), backend))?,
- );
- }
- for arg in opts.tap_fd.iter() {
- devices.push(
- new_backend_from_tapfd_arg(arg).map(|(s, backend)| (Connection::Socket(s), backend))?,
- );
- }
-
- // virtio-vhost-user
- for arg in opts.vvu_device.iter() {
- devices.push(
- new_backend_from_device_arg(arg).map(|(s, backend)| (Connection::Vfio(s), backend))?,
- );
- }
- for arg in opts.vvu_tap_fd.iter() {
- devices.push(
- new_backend_from_tapfd_arg(arg).map(|(s, backend)| (Connection::Vfio(s), backend))?,
- );
- }
-
- let mut threads = Vec::with_capacity(num_devices);
-
- for (conn, backend) in devices {
- match conn {
- Connection::Socket(socket) => {
- let ex = Executor::new().context("failed to create executor")?;
- let handler = DeviceRequestHandler::new(backend);
- threads.push(thread::spawn(move || {
- NET_EXECUTOR.with(|thread_ex| {
- let _ = thread_ex.set(ex.clone());
- });
- ex.run_until(handler.run(&socket, &ex))?
- }));
- }
- Connection::Vfio(device_name) => {
- let device = VvuPciDevice::new(device_name.as_str(), NetBackend::MAX_QUEUE_NUM)?;
- let handler = DeviceRequestHandler::new(backend);
- let ex = Executor::new().context("failed to create executor")?;
- threads.push(thread::spawn(move || {
- NET_EXECUTOR.with(|thread_ex| {
- let _ = thread_ex.set(ex.clone());
- });
- ex.run_until(handler.run_vvu(device, &ex))?
- }));
- }
- };
- }
-
- for t in threads {
- match t.join() {
- Ok(r) => r?,
- Err(e) => bail!("thread panicked: {:?}", e),
- }
- }
- Ok(())
+ start_device(program_name, args)
}
diff --git a/devices/src/virtio/vhost/user/device/unix/net.rs b/devices/src/virtio/vhost/user/device/unix/net.rs
new file mode 100644
index 0000000..aca8573
--- /dev/null
+++ b/devices/src/virtio/vhost/user/device/unix/net.rs
@@ -0,0 +1,373 @@
+// Copyright 2022 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::net::Ipv4Addr;
+use std::str::FromStr;
+use std::sync::Arc;
+use std::thread;
+
+use anyhow::{anyhow, bail, Context};
+use argh::FromArgs;
+use base::validate_raw_descriptor;
+use base::{error, warn, Event, RawDescriptor};
+use cros_async::{EventAsync, Executor, IntoAsync, IoSourceExt};
+use futures::future::{AbortHandle, Abortable};
+use hypervisor::ProtectionType;
+use net_util::TapT;
+use net_util::{MacAddress, Tap};
+use sync::Mutex;
+use virtio_sys::virtio_net;
+use vm_memory::GuestMemory;
+use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
+
+use super::{run_ctrl_queue, run_tx_queue, NetBackend, NET_EXECUTOR};
+use crate::virtio;
+use crate::virtio::net::validate_and_configure_tap;
+use crate::virtio::net::{process_rx, NetError};
+use crate::virtio::vhost::user::device::handler::{
+ DeviceRequestHandler, Doorbell, VhostUserBackend,
+};
+use virtio::vhost::user::device::vvu::pci::VvuPciDevice;
+
+struct TapConfig {
+ host_ip: Ipv4Addr,
+ netmask: Ipv4Addr,
+ mac: MacAddress,
+}
+
+impl FromStr for TapConfig {
+ type Err = anyhow::Error;
+
+ fn from_str(arg: &str) -> Result<Self, Self::Err> {
+ let args: Vec<&str> = arg.split(',').collect();
+ if args.len() != 3 {
+ bail!("TAP config must consist of 3 parts but {}", args.len());
+ }
+
+ let host_ip: Ipv4Addr = args[0]
+ .parse()
+ .map_err(|e| anyhow!("invalid IP address: {}", e))?;
+ let netmask: Ipv4Addr = args[1]
+ .parse()
+ .map_err(|e| anyhow!("invalid net mask: {}", e))?;
+ let mac: MacAddress = args[2]
+ .parse()
+ .map_err(|e| anyhow!("invalid MAC address: {}", e))?;
+
+ Ok(Self {
+ host_ip,
+ netmask,
+ mac,
+ })
+ }
+}
+
+impl<T: 'static> NetBackend<T>
+where
+ T: TapT + IntoAsync,
+{
+ fn new_from_config(config: &TapConfig) -> anyhow::Result<Self> {
+ // Create a tap device.
+ let tap = T::new(true /* vnet_hdr */, false /* multi_queue */)
+ .context("failed to create tap device")?;
+ tap.set_ip_addr(config.host_ip)
+ .context("failed to set IP address")?;
+ tap.set_netmask(config.netmask)
+ .context("failed to set netmask")?;
+ tap.set_mac_address(config.mac)
+ .context("failed to set MAC address")?;
+
+ Self::new(tap)
+ }
+
+ pub fn new_from_tap_fd(tap_fd: RawDescriptor) -> anyhow::Result<Self> {
+ let tap_fd = validate_raw_descriptor(tap_fd).context("failed to validate tap fd")?;
+ // Safe because we ensure that we get a unique handle to the fd.
+ let tap = unsafe { T::from_raw_descriptor(tap_fd).context("failed to create tap device")? };
+
+ Self::new(tap)
+ }
+
+ fn new(tap: T) -> anyhow::Result<Self> {
+ let vq_pairs = Self::max_vq_pairs();
+ validate_and_configure_tap(&tap, vq_pairs as u16)
+ .context("failed to validate and configure tap")?;
+
+ let avail_features = virtio::base_features(ProtectionType::Unprotected)
+ | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
+ | 1 << virtio_net::VIRTIO_NET_F_CSUM
+ | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
+ | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
+ | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
+ | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
+ | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
+ | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
+ | 1 << virtio_net::VIRTIO_NET_F_MTU
+ | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
+
+ let mtu = tap.mtu()?;
+
+ Ok(Self {
+ tap,
+ avail_features,
+ acked_features: 0,
+ acked_protocol_features: VhostUserProtocolFeatures::empty(),
+ workers: Default::default(),
+ mtu,
+ })
+ }
+}
+
+async fn run_rx_queue<T: TapT>(
+ mut queue: virtio::Queue,
+ mem: GuestMemory,
+ mut tap: Box<dyn IoSourceExt<T>>,
+ doorbell: Arc<Mutex<Doorbell>>,
+ kick_evt: EventAsync,
+) {
+ loop {
+ if let Err(e) = tap.wait_readable().await {
+ error!("Failed to wait for tap device to become readable: {}", e);
+ break;
+ }
+ match process_rx(&doorbell, &mut queue, &mem, tap.as_source_mut()) {
+ Ok(()) => {}
+ Err(NetError::RxDescriptorsExhausted) => {
+ if let Err(e) = kick_evt.next_val().await {
+ error!("Failed to read kick event for rx queue: {}", e);
+ break;
+ }
+ }
+ Err(e) => {
+ error!("Failed to process rx queue: {}", e);
+ break;
+ }
+ }
+ }
+}
+
+/// Platform specific impl of VhostUserBackend::start_queue.
+pub(super) fn start_queue<T: 'static + IntoAsync + TapT>(
+ backend: &mut NetBackend<T>,
+ idx: usize,
+ mut queue: virtio::Queue,
+ mem: GuestMemory,
+ doorbell: Arc<Mutex<Doorbell>>,
+ kick_evt: Event,
+) -> anyhow::Result<()> {
+ if let Some(handle) = backend.workers.get_mut(idx).and_then(Option::take) {
+ warn!("Starting new queue handler without stopping old handler");
+ handle.abort();
+ }
+
+ // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
+ queue.ack_features(backend.acked_features);
+
+ NET_EXECUTOR.with(|ex| {
+ // Safe because the executor is initialized in main() below.
+ let ex = ex.get().expect("Executor not initialized");
+
+ let kick_evt =
+ EventAsync::new(kick_evt.0, ex).context("failed to create EventAsync for kick_evt")?;
+ let tap = backend
+ .tap
+ .try_clone()
+ .context("failed to clone tap device")?;
+ let (handle, registration) = AbortHandle::new_pair();
+ match idx {
+ 0 => {
+ let tap = ex
+ .async_from(tap)
+ .context("failed to create async tap device")?;
+
+ ex.spawn_local(Abortable::new(
+ run_rx_queue(queue, mem, tap, doorbell, kick_evt),
+ registration,
+ ))
+ .detach();
+ }
+ 1 => {
+ ex.spawn_local(Abortable::new(
+ run_tx_queue(queue, mem, tap, doorbell, kick_evt),
+ registration,
+ ))
+ .detach();
+ }
+ 2 => {
+ ex.spawn_local(Abortable::new(
+ run_ctrl_queue(
+ queue,
+ mem,
+ tap,
+ doorbell,
+ kick_evt,
+ backend.acked_features,
+ 1, /* vq_pairs */
+ ),
+ registration,
+ ))
+ .detach();
+ }
+ _ => bail!("attempted to start unknown queue: {}", idx),
+ }
+
+ backend.workers[idx] = Some(handle);
+ Ok(())
+ })
+}
+
+#[derive(FromArgs)]
+#[argh(description = "")]
+struct Options {
+ #[argh(
+ option,
+ description = "TAP device config. (e.g. \
+ \"/path/to/sock,10.0.2.2,255.255.255.0,12:34:56:78:9a:bc\")",
+ arg_name = "SOCKET_PATH,IP_ADDR,NET_MASK,MAC_ADDR"
+ )]
+ device: Vec<String>,
+ #[argh(
+ option,
+ description = "TAP FD with a socket path",
+ arg_name = "SOCKET_PATH,TAP_FD"
+ )]
+ tap_fd: Vec<String>,
+ #[argh(
+ option,
+ description = "TAP device config for virtio-vhost-user. \
+ (e.g. \"0000:00:07.0,10.0.2.2,255.255.255.0,12:34:56:78:9a:bc\")",
+ arg_name = "DEVICE,IP_ADDR,NET_MASK,MAC_ADDR"
+ )]
+ vvu_device: Vec<String>,
+ #[argh(
+ option,
+ description = "TAP FD with a vfio device name for virtio-vhost-user",
+ arg_name = "DEVICE,TAP_FD"
+ )]
+ vvu_tap_fd: Vec<String>,
+}
+
+enum Connection {
+ Socket(String),
+ Vfio(String),
+}
+
+fn new_backend_from_device_arg(arg: &str) -> anyhow::Result<(String, NetBackend<Tap>)> {
+ let pos = match arg.find(',') {
+ Some(p) => p,
+ None => {
+ bail!("device must take comma-separated argument");
+ }
+ };
+ let conn = &arg[0..pos];
+ let cfg = &arg[pos + 1..]
+ .parse::<TapConfig>()
+ .context("failed to parse tap config")?;
+ let backend = NetBackend::<Tap>::new_from_config(cfg).context("failed to create NetBackend")?;
+ Ok((conn.to_string(), backend))
+}
+
+fn new_backend_from_tapfd_arg(arg: &str) -> anyhow::Result<(String, NetBackend<Tap>)> {
+ let pos = match arg.find(',') {
+ Some(p) => p,
+ None => {
+ bail!("'tap-fd' flag must take comma-separated argument");
+ }
+ };
+ let conn = &arg[0..pos];
+ let tap_fd = &arg[pos + 1..]
+ .parse::<i32>()
+ .context("failed to parse tap-fd")?;
+ let backend =
+ NetBackend::<Tap>::new_from_tap_fd(*tap_fd).context("failed to create NetBackend")?;
+
+ Ok((conn.to_string(), backend))
+}
+
+/// Starts a vhost-user net device.
+/// Returns an error if the given `args` is invalid or the device fails to run.
+pub(crate) fn start_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
+ let opts = match Options::from_args(&[program_name], args) {
+ Ok(opts) => opts,
+ Err(e) => {
+ if e.status.is_err() {
+ bail!(e.output);
+ } else {
+ println!("{}", e.output);
+ }
+ return Ok(());
+ }
+ };
+
+ let num_devices =
+ opts.device.len() + opts.tap_fd.len() + opts.vvu_device.len() + opts.vvu_tap_fd.len();
+
+ if num_devices == 0 {
+ bail!("no device option was passed");
+ }
+
+ let mut devices: Vec<(Connection, NetBackend<Tap>)> = Vec::with_capacity(num_devices);
+
+ // vhost-user
+ for arg in opts.device.iter() {
+ devices.push(
+ new_backend_from_device_arg(arg)
+ .map(|(s, backend)| (Connection::Socket(s), backend))?,
+ );
+ }
+ for arg in opts.tap_fd.iter() {
+ devices.push(
+ new_backend_from_tapfd_arg(arg).map(|(s, backend)| (Connection::Socket(s), backend))?,
+ );
+ }
+
+ // virtio-vhost-user
+ for arg in opts.vvu_device.iter() {
+ devices.push(
+ new_backend_from_device_arg(arg).map(|(s, backend)| (Connection::Vfio(s), backend))?,
+ );
+ }
+ for arg in opts.vvu_tap_fd.iter() {
+ devices.push(
+ new_backend_from_tapfd_arg(arg).map(|(s, backend)| (Connection::Vfio(s), backend))?,
+ );
+ }
+
+ let mut threads = Vec::with_capacity(num_devices);
+
+ for (conn, backend) in devices {
+ match conn {
+ Connection::Socket(socket) => {
+ let ex = Executor::new().context("failed to create executor")?;
+ let handler = DeviceRequestHandler::new(backend);
+ threads.push(thread::spawn(move || {
+ NET_EXECUTOR.with(|thread_ex| {
+ let _ = thread_ex.set(ex.clone());
+ });
+ ex.run_until(handler.run(&socket, &ex))?
+ }));
+ }
+ Connection::Vfio(device_name) => {
+ let device =
+ VvuPciDevice::new(device_name.as_str(), NetBackend::<Tap>::MAX_QUEUE_NUM)?;
+ let handler = DeviceRequestHandler::new(backend);
+ let ex = Executor::new().context("failed to create executor")?;
+ threads.push(thread::spawn(move || {
+ NET_EXECUTOR.with(|thread_ex| {
+ let _ = thread_ex.set(ex.clone());
+ });
+ ex.run_until(handler.run_vvu(device, &ex))?
+ }));
+ }
+ };
+ }
+
+ for t in threads {
+ match t.join() {
+ Ok(r) => r?,
+ Err(e) => bail!("thread panicked: {:?}", e),
+ }
+ }
+ Ok(())
+}
diff --git a/devices/src/virtio/vhost/user/device/vsock.rs b/devices/src/virtio/vhost/user/device/vsock.rs
index 735a0de..1d06a22 100644
--- a/devices/src/virtio/vhost/user/device/vsock.rs
+++ b/devices/src/virtio/vhost/user/device/vsock.rs
@@ -44,7 +44,8 @@
vhost::{
user::device::{
handler::{
- create_guest_memory, create_vvu_guest_memory, vmm_va_to_gpa, MappingInfo,
+ create_guest_memory, create_vvu_guest_memory, vmm_va_to_gpa, HandlerType,
+ MappingInfo,
},
vvu::{doorbell::DoorbellRegion, pci::VvuPciDevice, VvuDevice},
},
@@ -63,7 +64,7 @@
handle: Vsock,
cid: u64,
features: u64,
- vvu_device: Option<Arc<Mutex<VvuPciDevice>>>,
+ handler_type: HandlerType,
protocol_features: VhostUserProtocolFeatures,
mem: Option<GuestMemory>,
vmm_maps: Option<Vec<MappingInfo>>,
@@ -77,7 +78,7 @@
ex: &Executor,
cid: u64,
vhost_socket: P,
- vvu_device: Option<Arc<Mutex<VvuPciDevice>>>,
+ handler_type: HandlerType,
) -> anyhow::Result<VsockBackend> {
let handle = Vsock::new(
OpenOptions::new()
@@ -95,7 +96,7 @@
handle,
cid,
features,
- vvu_device,
+ handler_type,
protocol_features,
mem: None,
vmm_maps: None,
@@ -119,10 +120,9 @@
impl VhostUserSlaveReqHandlerMut for VsockBackend {
fn protocol(&self) -> Protocol {
- if self.vvu_device.is_some() {
- Protocol::Virtio
- } else {
- Protocol::Regular
+ match self.handler_type {
+ HandlerType::VhostUser => Protocol::Regular,
+ HandlerType::Vvu { .. } => Protocol::Virtio,
}
}
@@ -165,15 +165,14 @@
contexts: &[VhostUserMemoryRegion],
files: Vec<File>,
) -> Result<()> {
- let (guest_mem, vmm_maps) = match self.vvu_device.as_ref() {
- None => create_guest_memory(contexts, files)?,
- Some(dev) => {
+ let (guest_mem, vmm_maps) = match &self.handler_type {
+ HandlerType::VhostUser => create_guest_memory(contexts, files)?,
+ HandlerType::Vvu { vfio_dev, caps, .. } => {
// virtio-vhost-user doesn't pass FDs.
if !files.is_empty() {
return Err(Error::InvalidParam);
}
- let device = dev.lock();
- create_vvu_guest_memory(&device, contexts)?
+ create_vvu_guest_memory(vfio_dev.as_ref(), caps.shared_mem_cfg_addr(), contexts)?
}
};
@@ -302,8 +301,10 @@
}
let index = usize::from(index);
- let event = match self.vvu_device.as_ref() {
- Some(dev) => {
+ let event = match &self.handler_type {
+ HandlerType::Vvu {
+ notification_evts, ..
+ } => {
if fd.is_some() {
return Err(Error::InvalidParam);
}
@@ -313,15 +314,12 @@
return Err(Error::InvalidOperation);
}
- let kick_evt = dev.lock().notification_evts[index]
- .try_clone()
- .map_err(|e| {
- error!("failed to clone notification_evts[{}]: {}", index, e);
- Error::InvalidOperation
- })?;
- kick_evt
+ notification_evts[index].try_clone().map_err(|e| {
+ error!("failed to clone notification_evts[{}]: {}", index, e);
+ Error::InvalidOperation
+ })?
}
- None => {
+ HandlerType::VhostUser => {
let file = fd.ok_or(Error::InvalidParam)?;
// Safe because the descriptor is uniquely owned by `file`.
@@ -352,14 +350,13 @@
}
let index = usize::from(index);
- let event = match self.vvu_device.as_ref() {
- Some(dev) => {
- let dev = dev.lock();
- let vfio = Arc::clone(&dev.vfio_dev);
- let base = dev.caps.doorbell_base_addr();
+ let event = match &self.handler_type {
+ HandlerType::Vvu { vfio_dev, caps, .. } => {
+ let vfio = Arc::clone(vfio_dev);
+ let base = caps.doorbell_base_addr();
let addr = VfioRegionAddr {
index: base.index,
- addr: base.addr + (index as u64 * dev.caps.doorbell_off_multiplier() as u64),
+ addr: base.addr + (index as u64 * caps.doorbell_off_multiplier() as u64),
};
let doorbell = DoorbellRegion {
@@ -398,7 +395,7 @@
.detach();
kernel_evt
}
- None => {
+ HandlerType::VhostUser => {
let file = fd.ok_or(Error::InvalidParam)?;
// Safe because the descriptor is uniquely owned by `file`.
unsafe { Event::from_raw_descriptor(file.into_raw_descriptor()) }
@@ -580,15 +577,22 @@
vhost_socket: P,
device_name: &str,
) -> anyhow::Result<()> {
- let device = VvuPciDevice::new(device_name, NUM_QUEUES)
- .map(Mutex::new)
- .map(Arc::new)
- .context("failed to create `VvuPciDevice`")?;
- let driver = VvuDevice::new(device.clone());
- let backend = VsockBackend::new(ex, cid, vhost_socket, Some(device))
- .map(StdMutex::new)
- .map(Arc::new)
- .context("failed to create `VsockBackend`")?;
+ let mut device =
+ VvuPciDevice::new(device_name, NUM_QUEUES).context("failed to create `VvuPciDevice`")?;
+ let backend = VsockBackend::new(
+ ex,
+ cid,
+ vhost_socket,
+ HandlerType::Vvu {
+ vfio_dev: Arc::clone(&device.vfio_dev),
+ caps: device.caps.clone(),
+ notification_evts: std::mem::take(&mut device.notification_evts),
+ },
+ )
+ .map(StdMutex::new)
+ .map(Arc::new)
+ .context("failed to create `VsockBackend`")?;
+ let driver = VvuDevice::new(device);
let mut listener = VfioListener::new(driver)
.context("failed to create `VfioListener`")
@@ -645,9 +649,10 @@
match (opts.socket, opts.vfio) {
(Some(socket), None) => {
- let backend = VsockBackend::new(&ex, opts.cid, opts.vhost_socket, None)
- .map(StdMutex::new)
- .map(Arc::new)?;
+ let backend =
+ VsockBackend::new(&ex, opts.cid, opts.vhost_socket, HandlerType::VhostUser)
+ .map(StdMutex::new)
+ .map(Arc::new)?;
// TODO: Replace the `and_then` with `Result::flatten` once it is stabilized.
ex.run_until(run_device(&ex, socket, backend))
diff --git a/devices/src/virtio/vhost/user/device/vvu/bus.rs b/devices/src/virtio/vhost/user/device/vvu/bus.rs
index d83cec1..6cc667c 100644
--- a/devices/src/virtio/vhost/user/device/vvu/bus.rs
+++ b/devices/src/virtio/vhost/user/device/vvu/bus.rs
@@ -7,120 +7,56 @@
use std::fs::write;
use std::sync::Arc;
-use anyhow::{anyhow, bail, ensure, Context, Result};
+use anyhow::{anyhow, Context, Result};
use sync::Mutex;
+use crate::pci::PciAddress;
use crate::vfio::{VfioContainer, VfioDevice};
-#[derive(PartialEq, Eq, Debug)]
-pub struct PciSlot {
- domain: u16,
- bus: u8,
- slot: u8,
- func: u8,
-}
+/// Opens the PCI device as `VfioDevice`.
+pub fn open_vfio_device(pci_address: PciAddress) -> Result<VfioDevice> {
+ // Convert the PCI address to "DDDD:bb:dd.f" format.
+ let addr_str = pci_address.to_string();
-impl std::fmt::Display for PciSlot {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(
- f,
- "{:04x}:{:02x}:{:02x}.{}",
- self.domain, self.bus, self.slot, self.func
- )
- }
-}
+ // Unbind virtio-pci from the device.
+ write("/sys/bus/pci/drivers/virtio-pci/unbind", &addr_str)
+ .context("failed to unbind as virtio-pci device")?;
-impl PciSlot {
- /// Creates a new `PciSlot` instance by parsing the given string which is of the form of
- /// `<domain>:<bus>:<slot>.<func>`, which is same as ones that
- /// [`lspci -s`](https://man7.org/linux/man-pages/man8/lspci.8.html) expects but we don't
- /// allow omitting 0s.
- pub fn new(s: &str) -> Result<Self> {
- let v: Vec<_> = s.split('.').collect();
- if v.len() != 2 {
- bail!("PCI slot must be specified like <domain>:<bus>:<slot>.<func>, but the number of '.' is incorrect: {}", s);
- }
- let func = u8::from_str_radix(v[1], 16).context("failed to parse func")?;
+ // Set "vfio-pci" for the driver so the device can be bound to our vfio driver.
+ write(
+ format!("/sys/bus/pci/devices/{}/driver_override", &addr_str),
+ "vfio-pci\n",
+ )
+ .context("failed to override driver")?;
- let v2: Vec<_> = v[0].split(':').collect();
- if v2.len() != 3 {
- bail!("PCI slot must be specified like <domain>:<bus>:<slot>.<func>, but the number of ':' is incorrect: {}", s);
- }
+ // Bind the device to the driver.
+ write("/sys/bus/pci/drivers/vfio-pci/bind", &addr_str).context("failed to bind VFIO device")?;
- let domain = u16::from_str_radix(v2[0], 16).context("failed to parse domain")?;
- let bus = u8::from_str_radix(v2[1], 16).context("failed to parse bus")?;
- let slot = u8::from_str_radix(v2[2], 16).context("failed to parse slot")?;
+ // Write the empty string to driver_override to return the device to standard matching rules
+ // binding. Note that this operation won't unbind the current driver or load a new driver.
+ write(
+ format!("/sys/bus/pci/devices/{}/driver_override", &addr_str),
+ "",
+ )
+ .context("failed to clear driver_override")?;
- let pci_slot = Self {
- domain,
- bus,
- slot,
- func,
- };
-
- pci_slot.validate()?;
- Ok(pci_slot)
- }
-
- fn validate(&self) -> Result<()> {
- // domains (0 to ffff), bus (0 to ff), slot (0 to 1f) and function (0 to 7).
- ensure!(
- self.slot <= 0x1f,
- "slot must be in [0x00, 0x1f] but 0x{:x}",
- self.slot
- );
- ensure!(self.func <= 7, "func must be in [0, 7] but {}", self.func);
- Ok(())
- }
-
- /// Opens the PCI device as `VfioDevice`.
- pub fn open(&self) -> Result<VfioDevice> {
- // Unbind virtio-pci from the device.
- write("/sys/bus/pci/drivers/virtio-pci/unbind", self.to_string())
- .context("failed to unbind as virtio-pci device")?;
-
- // Set "vfio-pci" for the driver so the device can be bound to our vfio driver.
- write(
- format!("/sys/bus/pci/devices/{}/driver_override", self),
- "vfio-pci\n",
- )
- .context("failed to override driver")?;
-
- // Bind the device to the driver.
- write("/sys/bus/pci/drivers/vfio-pci/bind", self.to_string())
- .context("failed to bind VFIO device")?;
-
- // Write the empty string to driver_override to return the device to standard matching rules
- // binding. Note that this operation won't unbind the current driver or load a new driver.
- write(format!("/sys/bus/pci/devices/{}/driver_override", self), "")
- .context("failed to clear driver_override")?;
-
- let vfio_path = format!("/sys/bus/pci/devices/{}", self);
- // TODO(b/202151642): Use `VfioContainer::new()` once virtio-iommu for VFIO is implemented.
- let vfio_container = Arc::new(Mutex::new(VfioContainer::new_noiommu()?));
- let vfio = VfioDevice::new(&vfio_path, vfio_container)
- .map_err(|e| anyhow!("failed to create VFIO device: {}", e))?;
- Ok(vfio)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_pci_slot_new() {
- assert_eq!(
- PciSlot::new("abcd:ef:12.3").unwrap(),
- PciSlot {
- domain: 0xabcd,
- bus: 0xef,
- slot: 0x12,
- func: 0x3,
+ let vfio_path = format!("/sys/bus/pci/devices/{}", &addr_str);
+ let mut last_err = None;
+ // We can't create the container until udev updates the permissions on
+ // /dev/vfio/$group_id. There's no easy way to wait for that to happen, so
+ // just poll. In practice, this should take <100ms.
+ for _ in 1..50 {
+ let vfio_container = Arc::new(Mutex::new(VfioContainer::new()?));
+ match VfioDevice::new(&vfio_path, vfio_container) {
+ Ok(vfio_dev) => return Ok(vfio_dev),
+ Err(e) => {
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ last_err = Some(e);
}
- );
-
- // 'ff' is too big for slot.
- assert!(PciSlot::new("ffff:ff:ff.0").is_err());
+ }
}
+ Err(anyhow!(
+ "failed to create VFIO device: {}",
+ last_err.unwrap()
+ ))
}
diff --git a/devices/src/virtio/vhost/user/device/vvu/device.rs b/devices/src/virtio/vhost/user/device/vvu/device.rs
index db8acad..e28f5f8 100644
--- a/devices/src/virtio/vhost/user/device/vvu/device.rs
+++ b/devices/src/virtio/vhost/user/device/vvu/device.rs
@@ -92,7 +92,7 @@
Initialized {
// TODO(keiichiw): Update `VfioDeviceTrait::start()` to take `VvuPciDevice` so that we can
// drop this field.
- device: Arc<Mutex<VvuPciDevice>>,
+ device: VvuPciDevice,
},
Running {
vfio: Arc<VfioDevice>,
@@ -113,7 +113,7 @@
}
impl VvuDevice {
- pub fn new(device: Arc<Mutex<VvuPciDevice>>) -> Self {
+ pub fn new(device: VvuPciDevice) -> Self {
Self {
state: DeviceState::Initialized { device },
rxq_evt: Event::new().expect("failed to create VvuDevice's rxq_evt"),
@@ -127,20 +127,18 @@
}
fn start(&mut self) -> Result<()> {
- let device = match &self.state {
- DeviceState::Initialized { device } => Arc::clone(device),
+ let device = match &mut self.state {
+ DeviceState::Initialized { device } => device,
DeviceState::Running { .. } => {
bail!("VvuDevice has already started");
}
};
let ex = Executor::new().expect("Failed to create an executor");
- let mut dev = device.lock();
- let mut irqs = mem::take(&mut dev.irqs);
- let mut queues = mem::take(&mut dev.queues);
- let mut queue_notifiers = mem::take(&mut dev.queue_notifiers);
- let vfio = Arc::clone(&dev.vfio_dev);
- drop(dev);
+ let mut irqs = mem::take(&mut device.irqs);
+ let mut queues = mem::take(&mut device.queues);
+ let mut queue_notifiers = mem::take(&mut device.queue_notifiers);
+ let vfio = Arc::clone(&device.vfio_dev);
let rxq = queues.remove(0);
let rxq_irq = irqs.remove(0);
@@ -154,10 +152,27 @@
let txq_irq = irqs.remove(0);
let txq_notifier = Arc::new(Mutex::new(queue_notifiers.remove(0)));
+ let old_state = std::mem::replace(
+ &mut self.state,
+ DeviceState::Running {
+ vfio,
+ rxq_notifier,
+ rxq_receiver,
+ rxq_buf: vec![],
+ txq,
+ txq_notifier,
+ },
+ );
+
+ let device = match old_state {
+ DeviceState::Initialized { device } => device,
+ _ => unreachable!(),
+ };
+
thread::Builder::new()
.name("virtio-vhost-user driver".to_string())
.spawn(move || {
- device.lock().start().expect("failed to start device");
+ device.start().expect("failed to start device");
if let Err(e) =
run_worker(ex, rxq, rxq_irq, rxq_sender, rxq_evt, txq_cloned, txq_irq)
{
@@ -165,15 +180,6 @@
}
})?;
- self.state = DeviceState::Running {
- vfio,
- rxq_notifier,
- rxq_receiver,
- rxq_buf: vec![],
- txq,
- txq_notifier,
- };
-
Ok(())
}
@@ -195,7 +201,7 @@
};
let size = iovs.iter().map(|v| v.len()).sum();
- let data: Vec<u8> = iovs.iter().map(|v| v.to_vec()).flatten().collect();
+ let data: Vec<u8> = iovs.iter().flat_map(|v| v.to_vec()).collect();
txq.lock().write(&data).context("Failed to send data")?;
txq_notifier.lock().notify(vfio, QueueType::Tx as u16);
diff --git a/devices/src/virtio/vhost/user/device/vvu/pci.rs b/devices/src/virtio/vhost/user/device/vvu/pci.rs
index a109d57..9cc70a0 100644
--- a/devices/src/virtio/vhost/user/device/vvu/pci.rs
+++ b/devices/src/virtio/vhost/user/device/vvu/pci.rs
@@ -4,6 +4,7 @@
//! Implement a userspace PCI device driver for the virtio vhost-user device.
+use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, Instant};
@@ -11,24 +12,20 @@
use base::{info, Event};
use data_model::DataInit;
use memoffset::offset_of;
+use resources::Alloc;
use vfio_sys::*;
use virtio_sys::vhost::VIRTIO_F_VERSION_1;
-use crate::pci::{MsixCap, PciCapabilityID, CAPABILITY_LIST_HEAD_OFFSET};
+use crate::pci::{MsixCap, PciAddress, PciCapabilityID, CAPABILITY_LIST_HEAD_OFFSET};
use crate::vfio::{VfioDevice, VfioPciConfig, VfioRegionAddr};
use crate::virtio::vhost::user::device::vvu::{
- bus::PciSlot,
- queue::{DescTableAddrs, UserQueue},
+ bus::open_vfio_device,
+ queue::{DescTableAddrs, IovaAllocator, UserQueue},
};
use crate::virtio::{PciCapabilityType, VirtioPciCap};
const VIRTIO_CONFIG_STATUS_RESET: u8 = 0;
-/// Getting constant definitions from `linux/pci_regs.h`.`
-const PCI_COMMAND: u32 = 0x4;
-/// Enable bus mastering
-const PCI_COMMAND_MASTER: u16 = 0x4;
-
fn get_pci_cap_addr(cap: &VirtioPciCap) -> Result<VfioRegionAddr> {
const PCI_MAX_RESOURCE: u8 = 6;
@@ -88,6 +85,7 @@
unsafe impl DataInit for virtio_pci_notification_cfg {}
+#[derive(Clone)]
pub struct VvuPciCaps {
msix_table_size: u16,
common_cfg_addr: VfioRegionAddr,
@@ -227,7 +225,6 @@
pub struct VvuPciDevice {
pub vfio_dev: Arc<VfioDevice>,
- config: VfioPciConfig,
pub caps: VvuPciCaps,
pub queues: Vec<UserQueue>,
pub queue_notifiers: Vec<QueueNotifier>,
@@ -249,17 +246,23 @@
/// * `pci_id` - PCI device ID such as `"0000:00:05.0"`.
/// * `device_vq_num` - number of virtqueues that the device backend (e.g. block) may use.
pub fn new(pci_id: &str, device_vq_num: usize) -> Result<Self> {
- let slot = PciSlot::new(pci_id)?;
- let vfio_dev = Arc::new(slot.open()?);
+ let pci_address = PciAddress::from_str(pci_id).context("failed to parse PCI address")?;
+ let vfio_dev = Arc::new(open_vfio_device(pci_address)?);
let config = VfioPciConfig::new(vfio_dev.clone());
let caps = VvuPciCaps::new(&config)?;
vfio_dev
.check_device_info()
.context("failed to check VFIO device information")?;
+ let page_mask = vfio_dev
+ .vfio_get_iommu_page_size_mask()
+ .context("failed to get iommu page size mask")?;
+ if page_mask & (base::pagesize() as u64) == 0 {
+ bail!("Unsupported iommu page mask {:x}", page_mask);
+ }
+
let mut pci_dev = Self {
vfio_dev,
- config,
caps,
queues: vec![],
queue_notifiers: vec![],
@@ -267,23 +270,12 @@
notification_evts: vec![],
};
+ config.set_bus_master();
pci_dev.init(device_vq_num)?;
Ok(pci_dev)
}
- fn set_bus_master(&self) {
- let mut cmd: u16 = self.config.read_config(PCI_COMMAND);
-
- if cmd & PCI_COMMAND_MASTER != 0 {
- return;
- }
-
- cmd |= PCI_COMMAND_MASTER;
-
- self.config.write_config(cmd, PCI_COMMAND);
- }
-
fn set_status(&self, status: u8) {
let new_status = if status == VIRTIO_CONFIG_STATUS_RESET {
VIRTIO_CONFIG_STATUS_RESET
@@ -326,7 +318,7 @@
QueueType::Rx => true,
QueueType::Tx => false,
};
- let queue = UserQueue::new(queue_size, device_writable)?;
+ let queue = UserQueue::new(queue_size, device_writable, typ as u8, self)?;
let DescTableAddrs { desc, avail, used } = queue.desc_table_addrs()?;
let desc_lo = (desc & 0xffffffff) as u32;
@@ -402,12 +394,12 @@
}
let mut msix_vec = Vec::with_capacity(msix_num);
- msix_vec.push(&vvu_irqs[0]);
- msix_vec.push(&vvu_irqs[1]);
- msix_vec.extend(notification_evts.iter().take(device_vq_num));
+ msix_vec.push(Some(&vvu_irqs[0]));
+ msix_vec.push(Some(&vvu_irqs[1]));
+ msix_vec.extend(notification_evts.iter().take(device_vq_num).map(Some));
self.vfio_dev
- .irq_enable(&msix_vec, VFIO_PCI_MSIX_IRQ_INDEX)
+ .irq_enable(&msix_vec, VFIO_PCI_MSIX_IRQ_INDEX, 0)
.map_err(|e| anyhow!("failed to enable irq: {}", e))?;
// Registers VVU virtqueue's irqs by writing `queue_msix_vector`.
@@ -445,8 +437,6 @@
}
fn init(&mut self, device_vq_num: usize) -> Result<()> {
- self.set_bus_master();
-
self.set_status(VIRTIO_CONFIG_STATUS_RESET as u8);
// Wait until reset is done with timeout.
let deadline = Instant::now() + Duration::from_secs(1);
@@ -510,3 +500,17 @@
Ok(())
}
}
+
+impl IovaAllocator for VvuPciDevice {
+ fn alloc_iova(&self, size: u64, tag: u8) -> Result<u64> {
+ self.vfio_dev
+ .alloc_iova(size, base::pagesize() as u64, Alloc::VvuQueue(tag))
+ .context("failed to find an iova region to map the gpa region to")
+ }
+
+ unsafe fn map_iova(&self, iova: u64, size: u64, addr: *const u8) -> Result<()> {
+ self.vfio_dev
+ .vfio_dma_map(iova, size, addr as u64, true)
+ .context("failed to map iova")
+ }
+}
diff --git a/devices/src/virtio/vhost/user/device/vvu/queue.rs b/devices/src/virtio/vhost/user/device/vvu/queue.rs
index 2891a41..86ede3e 100644
--- a/devices/src/virtio/vhost/user/device/vvu/queue.rs
+++ b/devices/src/virtio/vhost/user/device/vvu/queue.rs
@@ -8,13 +8,11 @@
use std::mem;
use std::num::Wrapping;
use std::sync::atomic::{fence, Ordering};
-#[cfg(not(test))]
-use std::{collections::BTreeMap, fs::File};
use anyhow::{anyhow, bail, Context, Result};
use data_model::{DataInit, Le16, Le32, Le64, VolatileSlice};
-use virtio_sys::vhost::VRING_DESC_F_WRITE;
-use vm_memory::{GuestAddress, GuestMemory};
+use virtio_sys::virtio_ring::VRING_DESC_F_WRITE;
+use vm_memory::{GuestAddress as IOVA, GuestMemory as QueueMemory};
use crate::virtio::Desc;
@@ -36,19 +34,17 @@
}
struct MemLayout {
- /// Address of the descriptor table.
- /// Since the vvu driver runs in the guest user space, `GuestAddress` here stores the guest
- /// virtual address.
- desc_table: GuestAddress,
+ /// Address of the descriptor table in UserQueue.mem.
+ desc_table: IOVA,
- /// Virtual address of the available ring
- avail_ring: GuestAddress,
+ /// Address of the available ring in UserQueue.mem.
+ avail_ring: IOVA,
- /// Virtual address of the used ring
- used_ring: GuestAddress,
+ /// Address of the used ring in UserQueue.mem.
+ used_ring: IOVA,
- /// Virtual address of the start of buffers.
- buffer_addr: GuestAddress,
+ /// Address of the start of buffers in UserQueue.mem.
+ buffer_addr: IOVA,
}
/// Represents a virtqueue that is allocated in the guest userspace and manipulated from a VFIO
@@ -59,8 +55,12 @@
///
/// # Memory Layout
///
-/// `mem` is a continuous memory allocated in the guest userspace and used to have a virtqueue.
-/// Its layout is defined in the following table and stored in `mem_layout`.
+/// `mem` is the memory allocated in the guest userspace for the virtqueue, which is mapped into
+/// the vvu device via VFIO. The GuestAddresses of `mem` are the IOVAs that should be used when
+/// communicating with the vvu device. All accesses to the shared memory from the device backend
+/// must be done through the GuestMemory read/write functions.
+///
+/// The layout `mem` is defined in the following table and stored in `mem_layout`.
///
/// | | Alignment | Size |
/// |-----------------------------------------------------------------|
@@ -81,7 +81,7 @@
size: Wrapping<u16>,
/// The underlying memory.
- mem: GuestMemory,
+ mem: QueueMemory,
/// Virtqueue layout on `mem`.
mem_layout: MemLayout,
@@ -100,21 +100,30 @@
/// one virtqueue. Also, it's better to use `crate::virtio::DescriptorChain` for descirptors as
/// a part of b/215153367.
device_writable: bool,
+}
- /// Mapping from a virtual address to the physical address.
- /// This mapping is initialized by reading `/proc/self/pagemap`.
- /// TODO(b/215310597): This workaround won't work if memory mapping is changed. Currently, we
- /// are assuming that memory mapping is fixed during the vvu negotiation.
- /// Once virtio-iommu supports VFIO usage, we can remove this workaround and we should use
- /// VFIO_IOMMU_MAP_DMA call to get physical addresses.
- #[cfg(not(test))]
- addr_table: BTreeMap<GuestAddress, u64>,
+/// Interface used by UserQueue to interact with the IOMMU.
+pub trait IovaAllocator {
+ /// Allocates an IO virtual address region of the requested size.
+ fn alloc_iova(&self, size: u64, tag: u8) -> Result<u64>;
+ /// Maps the given address at the given IOVA.
+ ///
+ /// # Safety
+ ///
+ /// `addr` must reference a region of at least length `size`. Memory passed
+ /// to this function may be mutated at any time, so `addr` must not be memory
+ /// that is directly managed by rust.
+ unsafe fn map_iova(&self, iova: u64, size: u64, addr: *const u8) -> Result<()>;
}
impl UserQueue {
/// Creats a `UserQueue` instance.
- pub fn new(queue_size: u16, device_writable: bool) -> Result<Self> {
- let (mem, size, mem_layout) = Self::init_memory(queue_size)?;
+ pub fn new<I>(queue_size: u16, device_writable: bool, tag: u8, iova_alloc: &I) -> Result<Self>
+ where
+ I: IovaAllocator,
+ {
+ let (mem, size, mem_layout) = Self::init_memory(queue_size, tag, iova_alloc)?;
+
let mut queue = Self {
mem,
size: Wrapping(size),
@@ -123,8 +132,6 @@
used_count: Wrapping(0),
free_count: Wrapping(size),
device_writable,
- #[cfg(not(test))]
- addr_table: Default::default(),
};
queue.init_descriptor_table()?;
@@ -133,7 +140,14 @@
}
/// Allocates memory region and returns addresses on the regions for (`desc_table`, `avail_ring`, `used_ring`, `buffer``).
- fn init_memory(max_queue_size: u16) -> Result<(GuestMemory, u16, MemLayout)> {
+ fn init_memory<I>(
+ max_queue_size: u16,
+ tag: u8,
+ iova_alloc: &I,
+ ) -> Result<(QueueMemory, u16, MemLayout)>
+ where
+ I: IovaAllocator,
+ {
// Since vhost-user negotiation finishes within ~20 messages, queue size 32 is enough.
const MAX_QUEUE_SIZE: u16 = 256;
@@ -149,51 +163,44 @@
((n + m - 1) / m) * m
}
- let desc_table = GuestAddress(0);
+ let desc_table = IOVA(0);
let desc_size = 16u64 * u64::from(queue_size);
let desc_end = desc_table.0 + desc_size;
- let avail_ring = GuestAddress(align(desc_end, 2));
+ let avail_ring = IOVA(align(desc_end, 2));
let avail_size = 6 + 2 * u64::from(queue_size);
let avail_end = avail_ring.0 + avail_size;
- let used_ring = GuestAddress(align(avail_end, 4));
+ let used_ring = IOVA(align(avail_end, 4));
let used_size = 6 + 8 * u64::from(queue_size);
let used_end = used_ring.0 + used_size;
- let buffer_addr = GuestAddress(align(used_end, BUF_SIZE));
+ let buffer_addr = IOVA(align(used_end, BUF_SIZE));
let buffer_size = BUF_SIZE * u64::from(queue_size);
let mem_size = align(buffer_addr.0 + buffer_size, base::pagesize() as u64);
+ let iova_start = iova_alloc
+ .alloc_iova(mem_size, tag)
+ .context("failed to allocate queue iova")?;
- let mem = GuestMemory::new(&[(desc_table, mem_size)])
- .map_err(|e| anyhow!("failed to create GuestMemory for virtqueue: {}", e))?;
+ let mem = QueueMemory::new(&[(IOVA(iova_start), mem_size)])
+ .map_err(|e| anyhow!("failed to create QueueMemory for virtqueue: {}", e))?;
- // Call `mlock()` to guarantees that pages will stay in RAM.
- // Note that this can't ensure that physical address mapping is consistent.
- // TODO(b/215310597) We're assume that the kernel won't swap these memory region at least
- // during the vvu negotiation. Although this assumption is risky, it'll be resolved once
- // virtio-iommu for virtio devices is supported.
- mem.with_regions(|_, _, size, ptr, _, _| {
- let ret = unsafe { libc::mlock(ptr as *const libc::c_void, size) };
- if ret == -1 {
- bail!("failed to mlock(): {}", base::Error::last());
- }
- Ok(())
- })?;
-
- // To ensure the GuestMemory is mapped to physical memory, read the entire buffer first.
- // Otherwise, reading `/proc/self/pagemap` returns invalid values.
- // TODO(b/215310597): Once we use iommu for VFIO, we can probably remove this workaround.
- let mut buf = vec![0; mem_size as usize];
- mem.read_at_addr(&mut buf, desc_table)
- .map_err(|e| anyhow!("failed to read_slice: {}", e))?;
+ let host_addr = mem
+ .get_host_address_range(IOVA(iova_start), mem_size as usize)
+ .context("failed to get host address")?;
+ // Safe because the region being mapped is managed via the GuestMemory interface.
+ unsafe {
+ iova_alloc
+ .map_iova(iova_start, mem_size, host_addr)
+ .context("failed to map queue")?;
+ }
let mem_layout = MemLayout {
- desc_table,
- avail_ring,
- used_ring,
- buffer_addr,
+ desc_table: desc_table.unchecked_add(iova_start),
+ avail_ring: avail_ring.unchecked_add(iova_start),
+ used_ring: used_ring.unchecked_add(iova_start),
+ buffer_addr: buffer_addr.unchecked_add(iova_start),
};
Ok((mem, queue_size, mem_layout))
@@ -201,8 +208,6 @@
/// Initialize the descriptor table.
fn init_descriptor_table(&mut self) -> Result<()> {
- self.init_addr_table()?;
-
let flags = if self.device_writable {
Le16::from(VRING_DESC_F_WRITE as u16)
} else {
@@ -214,9 +219,9 @@
// Register pre-allocated buffers to the descriptor area.
for i in 0..self.size.0 {
let idx = Wrapping(i);
- let addr = Le64::from(self.to_phys_addr(&self.buffer_guest_addr(idx)?)?);
+ let iova = self.buffer_address(idx)?.offset();
let desc = Desc {
- addr,
+ addr: iova.into(),
len,
flags,
next,
@@ -247,91 +252,16 @@
Ok(())
}
- #[cfg(not(test))]
- /// Reads `/proc/self/pagemap` and stores mapping from virtual addresses for virtqueue
- /// information and buffers to physical addresses.
- fn init_addr_table(&mut self) -> Result<()> {
- let pagemap = File::open("/proc/self/pagemap").context("failed to open pagemap")?;
- self.register_addr(&pagemap, &self.mem_layout.desc_table.clone())?;
- self.register_addr(&pagemap, &self.mem_layout.avail_ring.clone())?;
- self.register_addr(&pagemap, &self.mem_layout.used_ring.clone())?;
- self.register_addr(&pagemap, &self.mem_layout.buffer_addr.clone())?;
- // Register addresses of buffers.
- for i in 0..self.size.0 {
- self.register_addr(&pagemap, &self.buffer_guest_addr(Wrapping(i))?)?;
- }
- Ok(())
- }
-
- #[cfg(test)]
- fn init_addr_table(&mut self) -> Result<()> {
- Ok(())
- }
-
- /// Registers an address mapping for the given virtual address to `self.addr_table`.
- // TODO(b/215310597): This function reads `/proc/self/pagemap`, which requires root
- // privileges. Instead, we should use VFIO_IOMMU_MAP_DMA call with virtio-iommu to get
- // physical addresses.
- #[cfg(not(test))]
- fn register_addr(&mut self, pagemap_file: &File, addr: &GuestAddress) -> Result<u64> {
- use std::os::unix::fs::FileExt;
-
- let vaddr = self
- .mem
- .get_slice_at_addr(*addr, 1)
- .context("failed to get slice")?
- .as_ptr() as u64;
-
- let page_size = base::pagesize() as u64;
- let virt_page_number = vaddr / page_size;
- let offset = std::mem::size_of::<u64>() as u64 * virt_page_number;
-
- let mut buf = [0u8; 8];
- pagemap_file
- .read_exact_at(&mut buf, offset)
- .context("failed to read pagemap")?;
-
- let pagemap = u64::from_le_bytes(buf);
- // Bit 55 is soft-dirty.
- if (pagemap & (1u64 << 55)) != 0 {
- bail!("page table entry is soft-dirty")
- }
- // page frame numbers are bits 0-54
- let page = pagemap & 0x7f_ffff_ffff_ffffu64;
- if page == 0 {
- bail!("failed to get page frame number: page={:x}", page);
- }
-
- let paddr = page * page_size + (vaddr % page_size);
- self.addr_table.insert(*addr, paddr);
- Ok(paddr)
- }
-
- /// Translate a virtual address to the physical address.
- #[cfg(not(test))]
- fn to_phys_addr(&self, addr: &GuestAddress) -> Result<u64> {
- self.addr_table
- .get(addr)
- .context(anyhow!("addr {} not found", addr))
- .map(|v| *v)
- }
-
- #[cfg(test)]
- fn to_phys_addr(&self, addr: &GuestAddress) -> Result<u64> {
- Ok(addr.0)
- }
-
- /// Returns physical addresses of the descriptor table, the avail ring and the used ring.
pub fn desc_table_addrs(&self) -> Result<DescTableAddrs> {
- let desc = self.to_phys_addr(&self.mem_layout.desc_table)?;
- let avail = self.to_phys_addr(&self.mem_layout.avail_ring)?;
- let used = self.to_phys_addr(&self.mem_layout.used_ring)?;
-
- Ok(DescTableAddrs { desc, avail, used })
+ Ok(DescTableAddrs {
+ desc: self.mem_layout.desc_table.offset(),
+ avail: self.mem_layout.avail_ring.offset(),
+ used: self.mem_layout.used_ring.offset(),
+ })
}
- /// Returns a virtual address of the buffer for the given `index`.
- fn buffer_guest_addr(&self, index: Wrapping<u16>) -> Result<GuestAddress> {
+ /// Returns the IOVA of the buffer for the given `index`.
+ fn buffer_address(&self, index: Wrapping<u16>) -> Result<IOVA> {
let offset = u64::from((index % self.size).0) * BUF_SIZE;
self.mem_layout
.buffer_addr
@@ -341,7 +271,10 @@
/// Writes the given descriptor table entry.
fn write_desc_entry(&self, index: Wrapping<u16>, desc: Desc) -> Result<()> {
- let addr = GuestAddress(u64::from((index % self.size).0) * mem::size_of::<Desc>() as u64);
+ let addr = self
+ .mem_layout
+ .desc_table
+ .unchecked_add(u64::from((index % self.size).0) * mem::size_of::<Desc>() as u64);
fence(Ordering::SeqCst);
self.mem
.write_obj_at_addr(desc, addr)
@@ -402,7 +335,7 @@
let id = Wrapping(u32::from(elem.id) as u16);
let len = u32::from(elem.len) as usize;
- let addr = self.buffer_guest_addr(id)?;
+ let addr = self.buffer_address(id)?;
fence(Ordering::SeqCst);
let s = self
@@ -419,7 +352,7 @@
/// Writes data into virtqueue's buffer and returns its address.
///
/// TODO: Use `descriptor_utils::Writer`.
- fn write_to_buffer(&self, index: Wrapping<u16>, data: &[u8]) -> Result<GuestAddress> {
+ fn write_to_buffer(&self, index: Wrapping<u16>, data: &[u8]) -> Result<IOVA> {
if data.len() as u64 > BUF_SIZE {
bail!(
"data size {} is larger than the buffer size {}",
@@ -428,7 +361,7 @@
);
}
- let addr = self.buffer_guest_addr(index)?;
+ let addr = self.buffer_address(index)?;
fence(Ordering::SeqCst);
let written = self
.mem
@@ -473,7 +406,7 @@
.context("failed to write data to virtqueue")?;
let desc = Desc {
- addr: Le64::from(self.to_phys_addr(&addr)?),
+ addr: Le64::from(addr.offset()),
len: Le32::from(data.len() as u32),
flags: Le16::from(0),
next: Le16::from(0),
@@ -492,19 +425,40 @@
mod test {
use super::*;
+ use std::cell::RefCell;
use std::io::Read;
use std::io::Write;
use crate::virtio::{Queue as DeviceQueue, Reader, Writer};
+ // An allocator that just allocates 0 as an IOVA.
+ struct SimpleIovaAllocator(RefCell<bool>);
+
+ impl IovaAllocator for SimpleIovaAllocator {
+ fn alloc_iova(&self, _size: u64, _tag: u8) -> Result<u64> {
+ if *self.0.borrow() {
+ bail!("exhaused");
+ }
+ *self.0.borrow_mut() = true;
+ Ok(0)
+ }
+
+ unsafe fn map_iova(&self, _iova: u64, _size: u64, _addr: *const u8) -> Result<()> {
+ if !*self.0.borrow() {
+ bail!("not allocated");
+ }
+ Ok(())
+ }
+ }
+
fn setup_vq(queue: &mut DeviceQueue, addrs: DescTableAddrs) {
- queue.desc_table = GuestAddress(addrs.desc);
- queue.avail_ring = GuestAddress(addrs.avail);
- queue.used_ring = GuestAddress(addrs.used);
+ queue.desc_table = IOVA(addrs.desc);
+ queue.avail_ring = IOVA(addrs.avail);
+ queue.used_ring = IOVA(addrs.used);
queue.ready = true;
}
- fn device_write(mem: &GuestMemory, q: &mut DeviceQueue, data: &[u8]) -> usize {
+ fn device_write(mem: &QueueMemory, q: &mut DeviceQueue, data: &[u8]) -> usize {
let desc_chain = q.pop(mem).unwrap();
let index = desc_chain.index;
@@ -514,7 +468,7 @@
written
}
- fn device_read(mem: &GuestMemory, q: &mut DeviceQueue, len: usize) -> Vec<u8> {
+ fn device_read(mem: &QueueMemory, q: &mut DeviceQueue, len: usize) -> Vec<u8> {
let desc_chain = q.pop(mem).unwrap();
let desc_index = desc_chain.index;
let mut reader = Reader::new(mem.clone(), desc_chain).unwrap();
@@ -538,7 +492,9 @@
// Send an array from the driver to the device `count` times.
fn drv_to_dev(queue_size: u16, count: u32) {
- let mut drv_queue = UserQueue::new(queue_size, false /* device_writable */).unwrap();
+ let iova_alloc = SimpleIovaAllocator(RefCell::new(false));
+ let mut drv_queue =
+ UserQueue::new(queue_size, false /* device_writable */, 0, &iova_alloc).unwrap();
let mut dev_queue = DeviceQueue::new(queue_size);
setup_vq(&mut dev_queue, drv_queue.desc_table_addrs().unwrap());
@@ -582,7 +538,9 @@
// Send an array from the device to the driver `count` times.
fn dev_to_drv(queue_size: u16, count: u32) {
- let mut drv_queue = UserQueue::new(queue_size, true /* device_writable */).unwrap();
+ let iova_alloc = SimpleIovaAllocator(RefCell::new(false));
+ let mut drv_queue =
+ UserQueue::new(queue_size, true /* device_writable */, 0, &iova_alloc).unwrap();
let mut dev_queue = DeviceQueue::new(queue_size);
setup_vq(&mut dev_queue, drv_queue.desc_table_addrs().unwrap());
diff --git a/devices/src/virtio/vhost/user/device/windows/net.rs b/devices/src/virtio/vhost/user/device/windows/net.rs
new file mode 100644
index 0000000..67b5395
--- /dev/null
+++ b/devices/src/virtio/vhost/user/device/windows/net.rs
@@ -0,0 +1,288 @@
+// Copyright 2022 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 anyhow::{bail, Context};
+use argh::FromArgs;
+use base::named_pipes::{OverlappedWrapper, PipeConnection};
+use base::{error, warn, Event, RawDescriptor};
+use cros_async::{EventAsync, Executor, IntoAsync, IoSourceExt};
+use futures::future::{AbortHandle, Abortable};
+use hypervisor::ProtectionType;
+#[cfg(feature = "slirp")]
+use net_util::Slirp;
+use net_util::TapT;
+#[cfg(feature = "slirp")]
+use serde::{Deserialize, Serialize};
+use std::sync::Arc;
+use sync::Mutex;
+use virtio_sys::virtio_net;
+use vm_memory::GuestMemory;
+use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
+
+use super::{run_ctrl_queue, run_tx_queue, NetBackend, NET_EXECUTOR};
+use crate::virtio;
+#[cfg(feature = "slirp")]
+use crate::virtio::net::MAX_BUFFER_SIZE;
+use crate::virtio::net::{process_rx, NetError};
+use crate::virtio::vhost::user::device::handler::read_from_tube_transporter;
+use crate::virtio::vhost::user::device::handler::{DeviceRequestHandler, Doorbell};
+use crate::virtio::{base_features, SignalableInterrupt};
+use broker_ipc::{common_child_setup, CommonChildStartupArgs};
+use tube_transporter::TubeToken;
+
+impl<T: 'static> NetBackend<T>
+where
+ T: TapT + IntoAsync,
+{
+ #[cfg(feature = "slirp")]
+ pub fn new_slirp(
+ guest_pipe: PipeConnection,
+ slirp_kill_event: Event,
+ ) -> anyhow::Result<NetBackend<Slirp>> {
+ let avail_features = base_features(ProtectionType::Unprotected)
+ | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
+ | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
+ let slirp = Slirp::new_for_multi_process(guest_pipe).map_err(NetError::SlirpCreateError)?;
+
+ Ok(NetBackend::<Slirp> {
+ tap: slirp,
+ avail_features,
+ acked_features: 0,
+ acked_protocol_features: VhostUserProtocolFeatures::empty(),
+ workers: Default::default(),
+ mtu: 1500,
+ slirp_kill_event,
+ })
+ }
+}
+
+async fn run_rx_queue<T: TapT>(
+ mut queue: virtio::Queue,
+ mem: GuestMemory,
+ mut tap: Box<dyn IoSourceExt<T>>,
+ call_evt: Arc<Mutex<Doorbell>>,
+ kick_evt: EventAsync,
+ read_notifier: EventAsync,
+ mut overlapped_wrapper: OverlappedWrapper,
+) {
+ let mut rx_buf = [0u8; MAX_BUFFER_SIZE];
+ let mut rx_count = 0;
+ let mut deferred_rx = false;
+ tap.as_source_mut()
+ .read_overlapped(&mut rx_buf, &mut overlapped_wrapper)
+ .expect("read_overlapped failed");
+ loop {
+ // If we already have a packet from deferred RX, we don't need to wait for the slirp device.
+ if !deferred_rx {
+ if let Err(e) = read_notifier.next_val().await {
+ error!("Failed to wait for tap device to become readable: {}", e);
+ break;
+ }
+ }
+
+ let needs_interrupt = process_rx(
+ &call_evt,
+ &mut queue,
+ &mem,
+ tap.as_source_mut(),
+ &mut rx_buf,
+ &mut deferred_rx,
+ &mut rx_count,
+ &mut overlapped_wrapper,
+ );
+ if needs_interrupt {
+ call_evt.lock().signal_used_queue(queue.vector);
+ }
+
+ // There aren't any RX descriptors available for us to write packets to. Wait for the guest
+ // to consume some packets and make more descriptors available to us.
+ if deferred_rx {
+ if let Err(e) = kick_evt.next_val().await {
+ error!("Failed to read kick event for rx queue: {}", e);
+ break;
+ }
+ }
+ }
+}
+
+/// Platform specific impl of VhostUserBackend::start_queue.
+pub(super) fn start_queue<T: 'static + IntoAsync + TapT>(
+ backend: &mut NetBackend<T>,
+ idx: usize,
+ mut queue: virtio::Queue,
+ mem: GuestMemory,
+ doorbell: Arc<Mutex<Doorbell>>,
+ kick_evt: Event,
+) -> anyhow::Result<()> {
+ if let Some(handle) = backend.workers.get_mut(idx).and_then(Option::take) {
+ warn!("Starting new queue handler without stopping old handler");
+ handle.abort();
+ }
+
+ // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
+ queue.ack_features(backend.acked_features);
+
+ let overlapped_wrapper =
+ OverlappedWrapper::new(true).expect("Failed to create overlapped wrapper");
+
+ super::NET_EXECUTOR.with(|ex| {
+ // Safe because the executor is initialized in main() below.
+ let ex = ex.get().expect("Executor not initialized");
+
+ let kick_evt =
+ EventAsync::new(kick_evt.0, ex).context("failed to create EventAsync for kick_evt")?;
+ let tap = backend
+ .tap
+ .try_clone()
+ .context("failed to clone tap device")?;
+ let (handle, registration) = AbortHandle::new_pair();
+ match idx {
+ 0 => {
+ let tap = ex
+ .async_from(tap)
+ .context("failed to create async tap device")?;
+ let read_notifier = overlapped_wrapper
+ .get_h_event_ref()
+ .unwrap()
+ .try_clone()
+ .unwrap();
+ let read_notifier = EventAsync::new_without_reset(read_notifier, &ex)
+ .context("failed to create async read notifier")?;
+
+ ex.spawn_local(Abortable::new(
+ run_rx_queue(
+ queue,
+ mem,
+ tap,
+ doorbell,
+ kick_evt,
+ read_notifier,
+ overlapped_wrapper,
+ ),
+ registration,
+ ))
+ .detach();
+ }
+ 1 => {
+ ex.spawn_local(Abortable::new(
+ run_tx_queue(queue, mem, tap, doorbell, kick_evt),
+ registration,
+ ))
+ .detach();
+ }
+ 2 => {
+ ex.spawn_local(Abortable::new(
+ run_ctrl_queue(
+ queue,
+ mem,
+ tap,
+ doorbell,
+ kick_evt,
+ backend.acked_features,
+ 1, /* vq_pairs */
+ ),
+ registration,
+ ))
+ .detach();
+ }
+ _ => bail!("attempted to start unknown queue: {}", idx),
+ }
+
+ backend.workers[idx] = Some(handle);
+ Ok(())
+ })
+}
+
+#[cfg(feature = "slirp")]
+impl<T> Drop for NetBackend<T>
+where
+ T: TapT + IntoAsync,
+{
+ fn drop(&mut self) {
+ let _ = self.slirp_kill_event.write(1);
+ }
+}
+
+/// Config arguments passed through the bootstrap Tube from the broker to the Net backend
+/// process.
+#[cfg(feature = "slirp")]
+#[derive(Serialize, Deserialize, Debug)]
+pub struct NetBackendConfig {
+ pub guest_pipe: PipeConnection,
+ pub slirp_kill_event: Event,
+}
+
+#[derive(FromArgs)]
+#[argh(description = "")]
+struct Options {
+ #[argh(
+ option,
+ description = "pipe handle end for Tube Transporter",
+ arg_name = "HANDLE"
+ )]
+ bootstrap: usize,
+}
+
+#[cfg(all(windows, not(feature = "slirp")))]
+compile_error!("vhost-user net device requires slirp feature on Windows.");
+
+#[cfg(feature = "slirp")]
+pub fn run_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
+ let opts = match Options::from_args(&[program_name], args) {
+ Ok(opts) => opts,
+ Err(e) => {
+ if e.status.is_err() {
+ bail!(e.output);
+ } else {
+ println!("{}", e.output);
+ }
+ return Ok(());
+ }
+ };
+
+ // Get the Tubes from the TubeTransporter. Then get the "Config" from the bootstrap_tube
+ // which will contain slirp settings.
+ let raw_transport_tube = opts.bootstrap as RawDescriptor;
+
+ let mut tubes = read_from_tube_transporter(raw_transport_tube).unwrap();
+
+ let vhost_user_tube = tubes.get_tube(TubeToken::VhostUser).unwrap();
+ let bootstrap_tube = tubes.get_tube(TubeToken::Bootstrap).unwrap();
+
+ let startup_args: CommonChildStartupArgs =
+ bootstrap_tube.recv::<CommonChildStartupArgs>().unwrap();
+ common_child_setup(startup_args).unwrap();
+
+ let net_backend_config = bootstrap_tube.recv::<NetBackendConfig>().unwrap();
+
+ let exit_event = bootstrap_tube.recv::<Event>()?;
+
+ // We only have one net device for now.
+ let dev = NetBackend::<net_util::Slirp>::new_slirp(
+ net_backend_config.guest_pipe,
+ net_backend_config.slirp_kill_event,
+ )
+ .unwrap();
+
+ let handler = DeviceRequestHandler::new(dev);
+
+ let ex = Executor::new().context("failed to create executor")?;
+
+ NET_EXECUTOR.with(|net_ex| {
+ let _ = net_ex.set(ex.clone());
+ });
+
+ if sandbox::is_sandbox_target() {
+ sandbox::TargetServices::get()
+ .expect("failed to get target services")
+ .unwrap()
+ .lower_token();
+ }
+
+ if let Err(e) = ex.run_until(handler.run(vhost_user_tube, exit_event, &ex)) {
+ bail!("error occurred: {}", e);
+ }
+
+ Ok(())
+}
diff --git a/devices/src/virtio/vhost/user/proxy.rs b/devices/src/virtio/vhost/user/proxy.rs
index 022ab99..a156eed 100644
--- a/devices/src/virtio/vhost/user/proxy.rs
+++ b/devices/src/virtio/vhost/user/proxy.rs
@@ -46,7 +46,7 @@
PciBarConfiguration, PciBarIndex, PciBarPrefetchable, PciBarRegionType, PciCapability,
PciCapabilityID,
},
- virtio::VIRTIO_MSI_NO_VECTOR,
+ virtio::{VIRTIO_F_ACCESS_PLATFORM, VIRTIO_MSI_NO_VECTOR},
};
use remain::sorted;
@@ -71,17 +71,6 @@
const VIRTIO_VHOST_USER_STATUS_SLAVE_UP: u8 = 0;
const BAR_INDEX: u8 = 2;
-// Bar size represents the amount of memory to be mapped for a sibling VM. Each
-// Virtio Vhost User Slave implementation requires access to the entire sibling
-// memory. It's assumed that sibling VM memory would be <= 8GB, hence this
-// constant value.
-//
-// TODO(abhishekbh): Understand why shared memory region size and overall bar
-// size differ in the QEMU implementation. The metadata required to map sibling
-// memory is about 16 MB per GB of sibling memory per device. Therefore, it is
-// in our interest to not waste space here and correlate it tightly to the
-// actual maximum memory a sibling VM can have.
-const BAR_SIZE: u64 = 1 << 33;
// Bar configuration.
// All offsets are from the starting of bar `BAR_INDEX`.
@@ -92,8 +81,8 @@
const NOTIFICATIONS_SIZE: u64 = 0x1000;
const SHARED_MEMORY_OFFSET: u64 = NOTIFICATIONS_OFFSET + NOTIFICATIONS_SIZE;
// TODO(abhishekbh): Copied from qemu with VVU support. This should be same as
-// `BAR_SIZE` but it's significantly lower than the memory allocated to a
-// sibling VM. Figure out how these two are related.
+// VirtioVhostUser.device_bar_size, but it's significantly lower than the
+// memory allocated to a sibling VM. Figure out how these two are related.
const SHARED_MEMORY_SIZE: u64 = 0x1000;
// Notifications region related constants.
@@ -241,11 +230,11 @@
}
impl VirtioVhostUserConfig {
- fn is_slave_up(&mut self) -> bool {
+ fn is_slave_up(&self) -> bool {
self.check_status_bit(VIRTIO_VHOST_USER_STATUS_SLAVE_UP)
}
- fn check_status_bit(&mut self, bit: u8) -> bool {
+ fn check_status_bit(&self, bit: u8) -> bool {
let status = self.status.to_native();
status & (1 << bit) > 0
}
@@ -953,6 +942,14 @@
pub struct VirtioVhostUser {
base_features: u64,
+ // Represents the amount of memory to be mapped for a sibling VM. Each
+ // Virtio Vhost User Slave implementation requires access to the entire sibling
+ // memory.
+ //
+ // TODO(abhishekbh): Understand why shared memory region size and overall bar
+ // size differ in the QEMU implementation.
+ device_bar_size: u64,
+
// Bound socket waiting to accept a socket connection from the Vhost-user
// sibling.
listener: Option<UnixListener>,
@@ -995,9 +992,15 @@
main_process_tube: Tube,
pci_address: Option<PciAddress>,
uuid: Option<Uuid>,
+ max_sibling_mem_size: u64,
) -> Result<VirtioVhostUser> {
+ let device_bar_size = max_sibling_mem_size
+ .checked_next_power_of_two()
+ .expect("Sibling too large");
+
Ok(VirtioVhostUser {
- base_features,
+ base_features: base_features | 1 << VIRTIO_F_ACCESS_PLATFORM,
+ device_bar_size,
listener: Some(listener),
config: VirtioVhostUserConfig {
status: Le32::from(0),
@@ -1334,7 +1337,7 @@
vec![PciBarConfiguration::new(
BAR_INDEX as usize,
- BAR_SIZE as u64,
+ self.device_bar_size,
PciBarRegionType::Memory64BitRegion,
// NotPrefetchable so as to exit on every read / write event in the
// guest.
diff --git a/devices/src/virtio/vhost/vsock.rs b/devices/src/virtio/vhost/vsock.rs
index fc8b980..6ae6c64 100644
--- a/devices/src/virtio/vhost/vsock.rs
+++ b/devices/src/virtio/vhost/vsock.rs
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::fs::File;
+use std::fs::{File, OpenOptions};
+use std::os::unix::prelude::{FromRawFd, OpenOptionsExt};
+use std::path::PathBuf;
use std::thread;
+use anyhow::Context;
+use base::{error, validate_raw_descriptor, warn, AsRawDescriptor, Event, RawDescriptor};
use data_model::{DataInit, Le64};
-
-use base::{error, warn, AsRawDescriptor, Event, RawDescriptor};
+use serde::Deserialize;
use vhost::Vhost;
use vhost::Vsock as VhostVsockHandle;
use vm_memory::GuestMemory;
@@ -19,6 +22,28 @@
pub const QUEUE_SIZE: u16 = 256;
const NUM_QUEUES: usize = 3;
pub const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
+static VHOST_VSOCK_DEFAULT_PATH: &str = "/dev/vhost-vsock";
+
+#[derive(Debug, Deserialize, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct VhostVsockConfig {
+ #[serde(default)]
+ pub device: VhostVsockDeviceParameter,
+ pub cid: u64,
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq)]
+#[serde(untagged)]
+pub enum VhostVsockDeviceParameter {
+ Path(PathBuf),
+ Fd(RawDescriptor),
+}
+
+impl Default for VhostVsockDeviceParameter {
+ fn default() -> Self {
+ VhostVsockDeviceParameter::Path(PathBuf::from(VHOST_VSOCK_DEFAULT_PATH))
+ }
+}
pub struct Vsock {
worker_kill_evt: Option<Event>,
@@ -32,9 +57,25 @@
impl Vsock {
/// Create a new virtio-vsock device with the given VM cid.
- pub fn new(vhost_vsock_file: File, base_features: u64, cid: u64) -> Result<Vsock> {
+ pub fn new(base_features: u64, vhost_config: &VhostVsockConfig) -> anyhow::Result<Vsock> {
+ let device_file = match &vhost_config.device {
+ VhostVsockDeviceParameter::Fd(fd) => {
+ let fd = validate_raw_descriptor(*fd)
+ .context("failed to validate fd for virtual socket device")?;
+ // Safe because the `fd` is actually owned by this process and
+ // we have a unique handle to it.
+ unsafe { File::from_raw_fd(fd) }
+ }
+ VhostVsockDeviceParameter::Path(path) => OpenOptions::new()
+ .read(true)
+ .write(true)
+ .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
+ .open(path)
+ .context("failed to open virtual socket device")?,
+ };
+
let kill_evt = Event::new().map_err(Error::CreateKillEvent)?;
- let handle = VhostVsockHandle::new(vhost_vsock_file);
+ let handle = VhostVsockHandle::new(device_file);
let avail_features = base_features
| 1 << virtio_sys::vhost::VIRTIO_F_NOTIFY_ON_EMPTY
@@ -52,7 +93,7 @@
worker_kill_evt: Some(kill_evt.try_clone().map_err(Error::CloneKillEvent)?),
kill_evt: Some(kill_evt),
vhost_handle: Some(handle),
- cid,
+ cid: vhost_config.cid,
interrupts: Some(interrupts),
avail_features,
acked_features: 0,
@@ -212,9 +253,12 @@
#[cfg(test)]
mod tests {
- use super::*;
-
use std::convert::TryInto;
+ use std::result::Result;
+
+ use serde_keyvalue::*;
+
+ use super::*;
#[test]
fn ack_features() {
@@ -287,4 +331,100 @@
let vsock = Vsock::new_for_testing(cid, features);
assert_eq!(features, vsock.features());
}
+
+ fn from_vsock_arg(options: &str) -> Result<VhostVsockConfig, ParseError> {
+ from_key_values(options)
+ }
+
+ #[test]
+ fn params_from_key_values() {
+ // Fd device
+ let params = from_vsock_arg("device=42,cid=56").unwrap();
+ assert_eq!(
+ params,
+ VhostVsockConfig {
+ device: VhostVsockDeviceParameter::Fd(42),
+ cid: 56,
+ }
+ );
+ // No key for fd device
+ let params = from_vsock_arg("42,cid=56").unwrap();
+ assert_eq!(
+ params,
+ VhostVsockConfig {
+ device: VhostVsockDeviceParameter::Fd(42),
+ cid: 56,
+ }
+ );
+ // Path device
+ let params = from_vsock_arg("device=/some/path,cid=56").unwrap();
+ assert_eq!(
+ params,
+ VhostVsockConfig {
+ device: VhostVsockDeviceParameter::Path("/some/path".into()),
+ cid: 56,
+ }
+ );
+ // No key for path device
+ let params = from_vsock_arg("/some/path,cid=56").unwrap();
+ assert_eq!(
+ params,
+ VhostVsockConfig {
+ device: VhostVsockDeviceParameter::Path("/some/path".into()),
+ cid: 56,
+ }
+ );
+ // Default device
+ let params = from_vsock_arg("cid=56").unwrap();
+ assert_eq!(
+ params,
+ VhostVsockConfig {
+ device: VhostVsockDeviceParameter::Path(VHOST_VSOCK_DEFAULT_PATH.into()),
+ cid: 56,
+ }
+ );
+
+ // No argument
+ assert_eq!(
+ from_vsock_arg("").unwrap_err(),
+ ParseError {
+ kind: ErrorKind::SerdeError("missing field `cid`".into()),
+ pos: 0
+ }
+ );
+ // Missing cid
+ assert_eq!(
+ from_vsock_arg("device=42").unwrap_err(),
+ ParseError {
+ kind: ErrorKind::SerdeError("missing field `cid`".into()),
+ pos: 0,
+ }
+ );
+ // Cid passed twice
+ assert_eq!(
+ from_vsock_arg("cid=42,cid=56").unwrap_err(),
+ ParseError {
+ kind: ErrorKind::SerdeError("duplicate field `cid`".into()),
+ pos: 0,
+ }
+ );
+ // Device passed twice
+ assert_eq!(
+ from_vsock_arg("cid=56,device=42,device=/some/path").unwrap_err(),
+ ParseError {
+ kind: ErrorKind::SerdeError("duplicate field `device`".into()),
+ pos: 0,
+ }
+ );
+ // Invalid argument
+ assert_eq!(
+ from_vsock_arg("invalid=foo").unwrap_err(),
+ ParseError {
+ kind: ErrorKind::SerdeError(
+ "unknown field `invalid`, expected `device` or `cid`".into()
+ ),
+ pos: 0,
+ }
+ );
+ }
}
diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs
index a8f73f1..fc1a852 100644
--- a/devices/src/virtio/virtio_pci_device.rs
+++ b/devices/src/virtio/virtio_pci_device.rs
@@ -8,8 +8,8 @@
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use acpi_tables::sdt::SDT;
-use anyhow::{bail, Context};
-use base::{error, warn, AsRawDescriptor, AsRawDescriptors, Event, RawDescriptor, Result, Tube};
+use anyhow::{anyhow, bail, Context};
+use base::{error, AsRawDescriptors, Event, RawDescriptor, Result, Tube};
use data_model::{DataInit, Le32};
use hypervisor::Datamatch;
use libc::ERANGE;
@@ -20,9 +20,10 @@
use crate::pci::{
BarRange, MsixCap, MsixConfig, PciAddress, PciBarConfiguration, PciBarPrefetchable,
PciBarRegionType, PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciDevice,
- PciDeviceError, PciDisplaySubclass, PciHeaderType, PciInterruptPin, PciSubclass,
+ PciDeviceError, PciDisplaySubclass, PciHeaderType, PciId, PciInterruptPin, PciSubclass,
};
use crate::virtio::ipc_memory_mapper::IpcMemoryMapper;
+use crate::IrqLevelEvent;
use self::virtio_pci_common_config::VirtioPciCommonConfig;
@@ -232,8 +233,7 @@
device_activated: bool,
interrupt_status: Arc<AtomicUsize>,
- interrupt_evt: Option<Event>,
- interrupt_resample_evt: Option<Event>,
+ interrupt_evt: Option<IrqLevelEvent>,
queues: Vec<Queue>,
queue_evts: Vec<Event>,
mem: GuestMemory,
@@ -279,7 +279,12 @@
// One MSI-X vector per queue plus one for configuration changes.
let msix_num = u16::try_from(num_interrupts + 1).map_err(|_| base::Error::new(ERANGE))?;
- let msix_config = Arc::new(Mutex::new(MsixConfig::new(msix_num, msi_device_tube)));
+ let msix_config = Arc::new(Mutex::new(MsixConfig::new(
+ msix_num,
+ msi_device_tube,
+ PciId::new(VIRTIO_PCI_VENDOR_ID, pci_device_id).into(),
+ device.debug_label(),
+ )));
let config_regs = PciConfiguration::new(
VIRTIO_PCI_VENDOR_ID,
@@ -300,7 +305,6 @@
device_activated: false,
interrupt_status: Arc::new(AtomicUsize::new(0)),
interrupt_evt: None,
- interrupt_resample_evt: None,
queues,
queue_evts,
mem,
@@ -415,39 +419,18 @@
/// Activates the underlying `VirtioDevice`. `assign_irq` has to be called first.
fn activate(&mut self) -> anyhow::Result<()> {
- let interrupt_evt = self.interrupt_evt.take().context("interrupt_evt is none")?;
- self.interrupt_evt = match interrupt_evt.try_clone() {
- Ok(evt) => Some(evt),
- Err(e) => {
- warn!(
- "{} failed to clone interrupt_evt: {}",
- self.debug_label(),
- e
- );
- None
- }
+ let interrupt_evt = if let Some(ref evt) = self.interrupt_evt {
+ evt.try_clone()
+ .with_context(|| format!("{} failed to clone interrupt_evt", self.debug_label()))?
+ } else {
+ return Err(anyhow!("{} interrupt_evt is none", self.debug_label()));
};
- let interrupt_resample_evt = self
- .interrupt_resample_evt
- .take()
- .context("interrupt_resample_evt is none")?;
- self.interrupt_resample_evt = match interrupt_resample_evt.try_clone() {
- Ok(evt) => Some(evt),
- Err(e) => {
- warn!(
- "{} failed to clone interrupt_resample_evt: {}",
- self.debug_label(),
- e
- );
- None
- }
- };
+
let mem = self.mem.clone();
let interrupt = Interrupt::new(
self.interrupt_status.clone(),
interrupt_evt,
- interrupt_resample_evt,
Some(self.msix_config.clone()),
self.common_config.msix_config,
);
@@ -510,10 +493,7 @@
fn keep_rds(&self) -> Vec<RawDescriptor> {
let mut rds = self.device.keep_rds();
if let Some(interrupt_evt) = &self.interrupt_evt {
- rds.push(interrupt_evt.as_raw_descriptor());
- }
- if let Some(interrupt_resample_evt) = &self.interrupt_resample_evt {
- rds.push(interrupt_resample_evt.as_raw_descriptor());
+ rds.extend(interrupt_evt.as_raw_descriptors());
}
let descriptor = self.msix_config.lock().get_msi_socket();
rds.push(descriptor);
@@ -525,12 +505,10 @@
fn assign_irq(
&mut self,
- irq_evt: &Event,
- irq_resample_evt: &Event,
+ irq_evt: &IrqLevelEvent,
irq_num: Option<u32>,
) -> Option<(u32, PciInterruptPin)> {
self.interrupt_evt = Some(irq_evt.try_clone().ok()?);
- self.interrupt_resample_evt = Some(irq_resample_evt.try_clone().ok()?);
let gsi = irq_num?;
let pin = self.pci_address.map_or(
PciInterruptPin::IntA,
@@ -686,6 +664,7 @@
// expression `COMMON_CONFIG_BAR_OFFSET <= o` is always true, but this code
// is written such that the value of the const may be changed independently.
#[allow(clippy::absurd_extreme_comparisons)]
+ #[allow(clippy::manual_range_contains)]
fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
// The driver is only allowed to do aligned, properly sized access.
let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize);
@@ -745,6 +724,7 @@
}
#[allow(clippy::absurd_extreme_comparisons)]
+ #[allow(clippy::manual_range_contains)]
fn write_bar(&mut self, addr: u64, data: &[u8]) {
let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize);
if addr < bar0 || addr >= bar0 + CAPABILITY_BAR_SIZE {
diff --git a/disk/src/composite.rs b/disk/src/composite.rs
index a537d0b..3e09b6c 100644
--- a/disk/src/composite.rs
+++ b/disk/src/composite.rs
@@ -379,8 +379,7 @@
fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
self.component_disks
.iter()
- .map(|d| d.file.as_raw_descriptors())
- .flatten()
+ .flat_map(|d| d.file.as_raw_descriptors())
.collect()
}
}
diff --git a/docs/book/src/running_crosvm/custom_kernel_rootfs.md b/docs/book/src/running_crosvm/custom_kernel_rootfs.md
index d263717..7e48000 100644
--- a/docs/book/src/running_crosvm/custom_kernel_rootfs.md
+++ b/docs/book/src/running_crosvm/custom_kernel_rootfs.md
@@ -20,8 +20,9 @@
Either way that you get the kernel, the next steps are to configure and build the bzImage:
-```bas
-make chromiumos-container-vm-x86_64_defconfig
+```bash
+CHROMEOS_KERNEL_FAMILY=termina ./chromeos/scripts/prepareconfig container-vm-x86_64
+make olddefconfig
make -j$(nproc) bzImage
```
diff --git a/gpu_display/Android.bp b/gpu_display/Android.bp
index f4f3ac2..8251933 100644
--- a/gpu_display/Android.bp
+++ b/gpu_display/Android.bp
@@ -1,4 +1,5 @@
-// This file is manually copied from old Android.bp
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
// cargo2android.py limitations:
// does not handle "-l dylib=wayland-client" yet
@@ -20,8 +21,10 @@
defaults: ["crosvm_defaults"],
host_supported: true,
crate_name: "gpu_display",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.1.0",
srcs: ["src/lib.rs"],
- edition: "2018",
+ edition: "2021",
rustlibs: [
"libbase_rust",
"libdata_model",
@@ -29,12 +32,8 @@
"liblinux_input_sys",
"libthiserror",
],
- static_libs: [
- "libdisplay_wl",
- ],
- proc_macros: [
- "libremain",
- ],
+ proc_macros: ["libremain"],
+ static_libs: ["libdisplay_wl"],
// added manually
target: {
diff --git a/gpu_display/cargo2android.json b/gpu_display/cargo2android.json
index 9e26dfe..26b463a 100644
--- a/gpu_display/cargo2android.json
+++ b/gpu_display/cargo2android.json
@@ -1 +1,8 @@
-{}
\ No newline at end of file
+{
+ "run": true,
+ "device": true,
+ "tests": true,
+ "global_defaults": "crosvm_defaults",
+ "add_workspace": true,
+ "patch": "patches/Android.bp.patch"
+}
diff --git a/gpu_display/patches/Android.bp.patch b/gpu_display/patches/Android.bp.patch
new file mode 100644
index 0000000..f03d8de
--- /dev/null
+++ b/gpu_display/patches/Android.bp.patch
@@ -0,0 +1,121 @@
+diff --git b/gpu_display/Android.bp a/gpu_display/Android.bp
+--- b/gpu_display/Android.bp
++++ a/gpu_display/Android.bp
+@@ -32,7 +32,116 @@ rust_library {
+ "liblinux_input_sys",
+ "libthiserror",
+ ],
+ proc_macros: ["libremain"],
+ static_libs: ["libdisplay_wl"],
+- shared_libs: ["libwayland-client"],
++
++ // added manually
++ target: {
++ host: {
++ shared_libs: ["libwayland_client"],
++ },
++ android: {
++ static_libs: [
++ "libwayland_client_static",
++ "libffi",
++ ],
++ },
++ },
++}
++
++cc_library_static {
++ name: "libdisplay_wl",
++ host_supported: true,
++ c_std: "c11",
++ srcs: ["src/display_wl.c"],
++
++ generated_sources: [
++ "gpu_display_protocol_sources",
++ "wayland_extension_protocol_sources",
++ ],
++ generated_headers: [
++ "gpu_display_client_protocol_headers",
++ "wayland_extension_client_protocol_headers",
++ ],
++ export_generated_headers: [
++ "gpu_display_client_protocol_headers",
++ "wayland_extension_client_protocol_headers",
++ ],
++
++ // added manually
++ target: {
++ host: {
++ shared_libs: ["libwayland_client"],
++ },
++ android: {
++ static_libs: [
++ "libwayland_client_static",
++ "libffi",
++ ],
++ },
++ linux_glibc_x86: {
++ // libffi broken on x86, see b/162610242
++ enabled: false,
++ },
++ },
++ apex_available: [
++ "//apex_available:platform",
++ "com.android.virt",
++ ],
++}
++
++wayland_protocol_codegen {
++ name: "gpu_display_protocol_sources",
++ cmd: "$(location wayland_scanner) private-code < $(in) > $(out)",
++ suffix: ".c",
++ srcs: [
++ "protocol/aura-shell.xml",
++ "protocol/linux-dmabuf-unstable-v1.xml",
++ "protocol/viewporter.xml",
++ "protocol/virtio-gpu-metadata-v1.xml",
++ ],
++ tools: ["wayland_scanner"],
++}
++
++wayland_protocol_codegen {
++ name: "gpu_display_client_protocol_headers",
++ cmd: "$(location wayland_scanner) client-header < $(in) > $(out)",
++ suffix: ".h",
++ srcs: [
++ "protocol/aura-shell.xml",
++ "protocol/linux-dmabuf-unstable-v1.xml",
++ "protocol/viewporter.xml",
++ "protocol/virtio-gpu-metadata-v1.xml",
++ ],
++ tools: ["wayland_scanner"],
++}
++
++wayland_protocol_codegen {
++ name: "gpu_display_server_protocol_headers",
++ cmd: "$(location wayland_scanner) server-header < $(in) > $(out)",
++ suffix: ".h",
++ srcs: [
++ "protocol/aura-shell.xml",
++ "protocol/linux-dmabuf-unstable-v1.xml",
++ "protocol/viewporter.xml",
++ "protocol/virtio-gpu-metadata-v1.xml",
++ ],
++ tools: ["wayland_scanner"],
++}
++
++cc_library_static {
++ name: "libwayland_crosvm_gpu_display_extension_server_protocols",
++ vendor_available: true,
++ host_supported: true,
++ cflags: [
++ "-Wall",
++ "-Wextra",
++ "-Werror",
++ "-g",
++ "-fvisibility=hidden",
++ ],
++ static_libs: ["libwayland_server"],
++ generated_sources: ["gpu_display_protocol_sources"],
++ generated_headers: ["gpu_display_server_protocol_headers"],
++ export_generated_headers: ["gpu_display_server_protocol_headers"],
+ }
diff --git a/hypervisor/src/aarch64.rs b/hypervisor/src/aarch64.rs
index b5c85e9..316f08c 100644
--- a/hypervisor/src/aarch64.rs
+++ b/hypervisor/src/aarch64.rs
@@ -2,18 +2,43 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::Result;
+use std::convert::TryFrom;
+
+use base::{Error, Result};
use downcast_rs::impl_downcast;
+use libc::EINVAL;
use vm_memory::GuestAddress;
use crate::{Hypervisor, IrqRoute, IrqSource, IrqSourceChip, Vcpu, Vm};
/// Represents a version of Power State Coordination Interface (PSCI).
+#[derive(Eq, Ord, PartialEq, PartialOrd)]
pub struct PsciVersion {
- pub major: u32,
- pub minor: u32,
+ pub major: u16,
+ pub minor: u16,
}
+impl PsciVersion {
+ pub fn new(major: u16, minor: u16) -> Result<Self> {
+ if (major as i16) < 0 {
+ Err(Error::new(EINVAL))
+ } else {
+ Ok(Self { major, minor })
+ }
+ }
+}
+
+impl TryFrom<u32> for PsciVersion {
+ type Error = base::Error;
+
+ fn try_from(item: u32) -> Result<Self> {
+ Self::new((item >> 16) as u16, item as u16)
+ }
+}
+
+pub const PSCI_0_2: PsciVersion = PsciVersion { major: 0, minor: 2 };
+pub const PSCI_1_0: PsciVersion = PsciVersion { major: 1, minor: 0 };
+
/// A wrapper for using a VM on aarch64 and getting/setting its state.
pub trait VmAArch64: Vm {
/// Gets the `Hypervisor` that created this VM.
diff --git a/hypervisor/src/kvm/aarch64.rs b/hypervisor/src/kvm/aarch64.rs
index 60a5fc1..d535d03 100644
--- a/hypervisor/src/kvm/aarch64.rs
+++ b/hypervisor/src/kvm/aarch64.rs
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use libc::{EINVAL, ENOMEM, ENXIO};
+use std::convert::TryFrom;
+
+use libc::{EINVAL, ENOMEM, ENOTSUP, ENXIO};
use base::{
errno_result, error, ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val, warn, Error,
@@ -14,7 +16,7 @@
use super::{Kvm, KvmCap, KvmVcpu, KvmVm};
use crate::{
ClockState, DeviceKind, Hypervisor, IrqSourceChip, ProtectionType, PsciVersion, VcpuAArch64,
- VcpuExit, VcpuFeature, Vm, VmAArch64, VmCap,
+ VcpuExit, VcpuFeature, Vm, VmAArch64, VmCap, PSCI_0_2,
};
/// Gives the ID for a register to be used with `set_one_reg`.
@@ -145,6 +147,11 @@
)
}
}
+
+ /// Enable userspace msr. This is not available on ARM, just succeed.
+ pub fn enable_userspace_msr(&self) -> Result<()> {
+ Ok(())
+ }
}
#[repr(C)]
@@ -363,17 +370,20 @@
const KVM_REG_ARM_PSCI_VERSION: u64 =
KVM_REG_ARM64 | (KVM_REG_SIZE_U64 as u64) | (KVM_REG_ARM_FW as u64);
- match self.get_one_reg(KVM_REG_ARM_PSCI_VERSION) {
- Ok(v) => {
- let major = (v >> PSCI_VERSION_MAJOR_SHIFT) as u32;
- let minor = (v as u32) & PSCI_VERSION_MINOR_MASK;
- Ok(PsciVersion { major, minor })
- }
- Err(_) => {
- // When `KVM_REG_ARM_PSCI_VERSION` is not supported, we can return PSCI 0.2, as vCPU
- // has been initialized with `KVM_ARM_VCPU_PSCI_0_2` successfully.
- Ok(PsciVersion { major: 0, minor: 2 })
- }
+ let version = if let Ok(v) = self.get_one_reg(KVM_REG_ARM_PSCI_VERSION) {
+ let v = u32::try_from(v).map_err(|_| Error::new(EINVAL))?;
+ PsciVersion::try_from(v)?
+ } else {
+ // When `KVM_REG_ARM_PSCI_VERSION` is not supported, we can return PSCI 0.2, as vCPU
+ // has been initialized with `KVM_ARM_VCPU_PSCI_0_2` successfully.
+ PSCI_0_2
+ };
+
+ if version < PSCI_0_2 {
+ // PSCI v0.1 isn't currently supported for guests
+ Err(Error::new(ENOTSUP))
+ } else {
+ Ok(version)
}
}
}
diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs
index 2527829..19d3cef 100644
--- a/hypervisor/src/kvm/mod.rs
+++ b/hypervisor/src/kvm/mod.rs
@@ -15,11 +15,11 @@
use std::cell::RefCell;
use std::cmp::{min, Reverse};
use std::collections::{BTreeMap, BinaryHeap};
-use std::convert::TryFrom;
+use std::convert::{TryFrom, TryInto};
use std::ffi::CString;
use std::mem::{size_of, ManuallyDrop};
use std::os::raw::{c_int, c_ulong, c_void};
-use std::os::unix::{io::AsRawFd, prelude::OsStrExt};
+use std::os::unix::prelude::OsStrExt;
use std::path::{Path, PathBuf};
use std::ptr::copy_nonoverlapping;
use std::sync::atomic::AtomicU64;
@@ -623,7 +623,7 @@
slot: u32,
offset: usize,
size: usize,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
fd_offset: u64,
prot: Protection,
) -> Result<()> {
@@ -837,6 +837,20 @@
}
Ok(())
}
+ KVM_EXIT_X86_RDMSR => {
+ // Safe because the exit_reason (which comes from the kernel) told us which
+ // union field to use.
+ let msr = unsafe { &mut run.__bindgen_anon_1.msr };
+
+ match data.try_into() {
+ Ok(data) => {
+ msr.data = u64::from_ne_bytes(data);
+ msr.error = 0;
+ }
+ _ => return Err(Error::new(EINVAL)),
+ }
+ Ok(())
+ }
_ => Err(Error::new(EINVAL)),
}
}
@@ -914,7 +928,7 @@
// Safe because we know we mapped enough memory to hold the kvm_run struct because the
// kernel told us how large it was.
- let run = unsafe { &*(self.run_mmap.as_ptr() as *const kvm_run) };
+ let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
match run.exit_reason {
KVM_EXIT_IO => {
// Safe because the exit_reason (which comes from the kernel) told us which
@@ -1036,6 +1050,25 @@
}
}
}
+ KVM_EXIT_X86_RDMSR => {
+ // Safe because the exit_reason (which comes from the kernel) told us which
+ // union field to use.
+ let msr = unsafe { &mut run.__bindgen_anon_1.msr };
+ let index = msr.index;
+ // By default fail the MSR read unless it was handled later.
+ msr.error = 1;
+ Ok(VcpuExit::RdMsr { index })
+ }
+ KVM_EXIT_X86_WRMSR => {
+ // Safe because the exit_reason (which comes from the kernel) told us which
+ // union field to use.
+ let msr = unsafe { &mut run.__bindgen_anon_1.msr };
+ // By default fail the MSR write.
+ msr.error = 1;
+ let index = msr.index;
+ let data = msr.data;
+ Ok(VcpuExit::WrMsr { index, data })
+ }
r => panic!("unknown kvm exit reason: {}", r),
}
}
diff --git a/hypervisor/src/kvm/x86_64.rs b/hypervisor/src/kvm/x86_64.rs
index bc2d923..9239884 100644
--- a/hypervisor/src/kvm/x86_64.rs
+++ b/hypervisor/src/kvm/x86_64.rs
@@ -315,6 +315,29 @@
}
}
+ /// Enable userspace msr.
+ pub fn enable_userspace_msr(&self) -> Result<()> {
+ let mut cap = kvm_enable_cap {
+ cap: KVM_CAP_X86_USER_SPACE_MSR,
+ ..Default::default()
+ };
+ cap.args[0] = (KVM_MSR_EXIT_REASON_UNKNOWN
+ | KVM_MSR_EXIT_REASON_INVAL
+ | KVM_MSR_EXIT_REASON_FILTER) as u64;
+ // TODO(b/215297064): Filter only the ones we care about with ioctl
+ // KVM_X86_SET_MSR_FILTER
+
+ // Safe because we know that our file is a VM fd, we know that the
+ // kernel will only read correct amount of memory from our pointer, and
+ // we verify the return result.
+ let ret = unsafe { ioctl_with_ref(self, KVM_ENABLE_CAP(), &cap) };
+ if ret < 0 {
+ errno_result()
+ } else {
+ Ok(())
+ }
+ }
+
/// Enable support for split-irqchip.
pub fn enable_split_irqchip(&self, ioapic_pins: usize) -> Result<()> {
let mut cap = kvm_enable_cap {
diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs
index 3bbfb08..e089d57 100644
--- a/hypervisor/src/lib.rs
+++ b/hypervisor/src/lib.rs
@@ -11,11 +11,10 @@
pub mod x86_64;
use std::os::raw::c_int;
-use std::os::unix::io::AsRawFd;
use serde::{Deserialize, Serialize};
-use base::{Event, MappedRegion, Protection, Result, SafeDescriptor};
+use base::{AsRawDescriptor, Event, MappedRegion, Protection, Result, SafeDescriptor};
use vm_memory::{GuestAddress, GuestMemory};
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
@@ -153,7 +152,7 @@
slot: u32,
offset: usize,
size: usize,
- fd: &dyn AsRawFd,
+ fd: &dyn AsRawDescriptor,
fd_offset: u64,
prot: Protection,
) -> Result<()>;
@@ -373,6 +372,13 @@
SystemEventReset,
SystemEventCrash,
SystemEventS2Idle,
+ RdMsr {
+ index: u32,
+ },
+ WrMsr {
+ index: u32,
+ data: u64,
+ },
}
/// A device type to create with `Vm.create_device`.
diff --git a/io_uring/Android.bp b/io_uring/Android.bp
index 94fb700..3fc4598 100644
--- a/io_uring/Android.bp
+++ b/io_uring/Android.bp
@@ -16,7 +16,7 @@
host_supported: true,
crate_name: "io_uring",
cargo_env_compat: true,
- cargo_pkg_version: "0.1.0",
+ cargo_pkg_version: "0.1.1",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
@@ -41,7 +41,7 @@
host_supported: true,
crate_name: "io_uring",
cargo_env_compat: true,
- cargo_pkg_version: "0.1.0",
+ cargo_pkg_version: "0.1.1",
srcs: ["src/lib.rs"],
edition: "2021",
rustlibs: [
diff --git a/io_uring/Cargo.toml b/io_uring/Cargo.toml
index 287dba2..4061179 100644
--- a/io_uring/Cargo.toml
+++ b/io_uring/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "io_uring"
-version = "0.1.0"
+version = "0.1.1"
authors = ["The Chromium OS Authors"]
edition = "2021"
diff --git a/io_uring/bindgen.sh b/io_uring/bindgen.sh
index 33b8aa1..363a2f6 100755
--- a/io_uring/bindgen.sh
+++ b/io_uring/bindgen.sh
@@ -6,7 +6,7 @@
# Regenerate io_uring bindgen bindings.
set -euo pipefail
-cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
source tools/impl/bindgen-common.sh
diff --git a/io_uring/src/uring.rs b/io_uring/src/uring.rs
index 0d96f9c..f730d71 100644
--- a/io_uring/src/uring.rs
+++ b/io_uring/src/uring.rs
@@ -13,7 +13,10 @@
use std::pin::Pin;
use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicU64, AtomicUsize, Ordering};
-use base::{MappedRegion, MemoryMapping, MemoryMappingBuilder, Protection, WatchingEvents};
+use base::{
+ AsRawDescriptor, MappedRegion, MemoryMapping, MemoryMappingBuilder, Protection, RawDescriptor,
+ WatchingEvents,
+};
use data_model::IoBufMut;
use remain::sorted;
use sync::Mutex;
@@ -659,6 +662,12 @@
}
}
+impl AsRawDescriptor for URingContext {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.ring_file.as_raw_descriptor()
+ }
+}
+
struct SubmitQueueEntries {
mmap: MemoryMapping,
len: usize,
diff --git a/libvda/Android.bp b/media/libvda/Android.bp
similarity index 100%
rename from libvda/Android.bp
rename to media/libvda/Android.bp
diff --git a/libvda/Cargo.toml b/media/libvda/Cargo.toml
similarity index 100%
rename from libvda/Cargo.toml
rename to media/libvda/Cargo.toml
diff --git a/libvda/README.md b/media/libvda/README.md
similarity index 100%
rename from libvda/README.md
rename to media/libvda/README.md
diff --git a/libvda/bindgen.sh b/media/libvda/bindgen.sh
similarity index 89%
rename from libvda/bindgen.sh
rename to media/libvda/bindgen.sh
index 099dd22..69d245c 100755
--- a/libvda/bindgen.sh
+++ b/media/libvda/bindgen.sh
@@ -6,14 +6,14 @@
# Regenerate libvda bindgen bindings.
set -euo pipefail
-cd "$(dirname "${BASH_SOURCE[0]}")/.."
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
source tools/impl/bindgen-common.sh
bindgen_generate \
--allowlist-type='video_.*' \
"${BINDGEN_PLATFORM2}/arc/vm/libvda/libvda_common.h" \
- > libvda/src/bindings.rs
+ > media/libvda/src/bindings.rs
bindgen_generate \
--raw-line 'pub use crate::bindings::*;' \
@@ -28,7 +28,7 @@
"${BINDGEN_PLATFORM2}/arc/vm/libvda/libvda_decode.h" \
-- \
-I "${BINDGEN_PLATFORM2}" \
- > libvda/src/decode/bindings.rs
+ > media/libvda/src/decode/bindings.rs
bindgen_generate \
--raw-line 'pub use crate::bindings::*;' \
@@ -43,4 +43,4 @@
"${BINDGEN_PLATFORM2}/arc/vm/libvda/libvda_encode.h" \
-- \
-I "${BINDGEN_PLATFORM2}" \
- > libvda/src/encode/bindings.rs
+ > media/libvda/src/encode/bindings.rs
diff --git a/libvda/build.rs b/media/libvda/build.rs
similarity index 100%
rename from libvda/build.rs
rename to media/libvda/build.rs
diff --git a/libvda/cargo2android.json b/media/libvda/cargo2android.json
similarity index 100%
rename from libvda/cargo2android.json
rename to media/libvda/cargo2android.json
diff --git a/libvda/src/bindings.rs b/media/libvda/src/bindings.rs
similarity index 100%
rename from libvda/src/bindings.rs
rename to media/libvda/src/bindings.rs
diff --git a/libvda/src/decode/bindings.rs b/media/libvda/src/decode/bindings.rs
similarity index 100%
rename from libvda/src/decode/bindings.rs
rename to media/libvda/src/decode/bindings.rs
diff --git a/libvda/src/decode/event.rs b/media/libvda/src/decode/event.rs
similarity index 100%
rename from libvda/src/decode/event.rs
rename to media/libvda/src/decode/event.rs
diff --git a/libvda/src/decode/format.rs b/media/libvda/src/decode/format.rs
similarity index 100%
rename from libvda/src/decode/format.rs
rename to media/libvda/src/decode/format.rs
diff --git a/libvda/src/decode/mod.rs b/media/libvda/src/decode/mod.rs
similarity index 100%
rename from libvda/src/decode/mod.rs
rename to media/libvda/src/decode/mod.rs
diff --git a/libvda/src/decode/session.rs b/media/libvda/src/decode/session.rs
similarity index 100%
rename from libvda/src/decode/session.rs
rename to media/libvda/src/decode/session.rs
diff --git a/libvda/src/decode/vda_instance.rs b/media/libvda/src/decode/vda_instance.rs
similarity index 100%
rename from libvda/src/decode/vda_instance.rs
rename to media/libvda/src/decode/vda_instance.rs
diff --git a/libvda/src/encode/bindings.rs b/media/libvda/src/encode/bindings.rs
similarity index 100%
rename from libvda/src/encode/bindings.rs
rename to media/libvda/src/encode/bindings.rs
diff --git a/libvda/src/encode/event.rs b/media/libvda/src/encode/event.rs
similarity index 100%
rename from libvda/src/encode/event.rs
rename to media/libvda/src/encode/event.rs
diff --git a/libvda/src/encode/format.rs b/media/libvda/src/encode/format.rs
similarity index 100%
rename from libvda/src/encode/format.rs
rename to media/libvda/src/encode/format.rs
diff --git a/libvda/src/encode/mod.rs b/media/libvda/src/encode/mod.rs
similarity index 100%
rename from libvda/src/encode/mod.rs
rename to media/libvda/src/encode/mod.rs
diff --git a/libvda/src/encode/session.rs b/media/libvda/src/encode/session.rs
similarity index 100%
rename from libvda/src/encode/session.rs
rename to media/libvda/src/encode/session.rs
diff --git a/libvda/src/encode/vea_instance.rs b/media/libvda/src/encode/vea_instance.rs
similarity index 100%
rename from libvda/src/encode/vea_instance.rs
rename to media/libvda/src/encode/vea_instance.rs
diff --git a/libvda/src/error.rs b/media/libvda/src/error.rs
similarity index 100%
rename from libvda/src/error.rs
rename to media/libvda/src/error.rs
diff --git a/libvda/src/format.rs b/media/libvda/src/format.rs
similarity index 100%
rename from libvda/src/format.rs
rename to media/libvda/src/format.rs
diff --git a/libvda/src/lib.rs b/media/libvda/src/lib.rs
similarity index 100%
rename from libvda/src/lib.rs
rename to media/libvda/src/lib.rs
diff --git a/libvda/tests/decode_tests.rs b/media/libvda/tests/decode_tests.rs
similarity index 100%
rename from libvda/tests/decode_tests.rs
rename to media/libvda/tests/decode_tests.rs
diff --git a/libvda/tests/encode_tests.rs b/media/libvda/tests/encode_tests.rs
similarity index 100%
rename from libvda/tests/encode_tests.rs
rename to media/libvda/tests/encode_tests.rs
diff --git a/net_sys/Android.bp b/net_sys/Android.bp
index b056e4c..73838d3 100644
--- a/net_sys/Android.bp
+++ b/net_sys/Android.bp
@@ -21,24 +21,6 @@
edition: "2021",
rustlibs: [
"libbase_rust",
- ],
-}
-
-rust_test {
- name: "net_sys_test_src_lib",
- defaults: ["crosvm_defaults"],
- host_supported: true,
- crate_name: "net_sys",
- cargo_env_compat: true,
- cargo_pkg_version: "0.1.0",
- srcs: ["src/lib.rs"],
- test_suites: ["general-tests"],
- auto_gen_config: true,
- test_options: {
- unit_test: true,
- },
- edition: "2021",
- rustlibs: [
- "libbase_rust",
+ "liblibc",
],
}
diff --git a/net_sys/Cargo.toml b/net_sys/Cargo.toml
index 107c9c9..5da75af 100644
--- a/net_sys/Cargo.toml
+++ b/net_sys/Cargo.toml
@@ -6,3 +6,4 @@
[dependencies]
base = { path = "../base" }
+libc = "*"
diff --git a/net_sys/bindgen.sh b/net_sys/bindgen.sh
new file mode 100755
index 0000000..221cc68
--- /dev/null
+++ b/net_sys/bindgen.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# Copyright 2022 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.
+#
+# Regenerate net_sys bindgen bindings.
+
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+
+source tools/impl/bindgen-common.sh
+
+# Replace definition of struct sockaddr with an import of libc::sockaddr.
+replace_sockaddr_libc() {
+ # Match the following structure definition across multiple lines:
+ #
+ # #[repr(C)]
+ # #[derive(Debug, Default, Copy, Clone)]
+ # pub struct sockaddr {
+ # pub sa_family: sa_family_t,
+ # pub sa_data: [::std::os::raw::c_char; 14usize],
+ # }
+ sed -E \
+ -e '1h;2,$H;$!d;g' \
+ -e 's/#\[repr\(C\)\]\n#\[derive\([^)]+\)\]\npub struct sockaddr \{\n( pub [^\n]+\n)+\}/\nuse libc::sockaddr;\n/'
+}
+
+# Remove custom sa_family_t type in favor of libc::sa_family_t.
+remove_sa_family_t() {
+ grep -v "pub type sa_family_t = "
+}
+
+bindgen_generate \
+ --allowlist-type='ifreq' \
+ --allowlist-type='net_device_flags' \
+ --bitfield-enum='net_device_flags' \
+ "${BINDGEN_LINUX_X86_HEADERS}/include/linux/if.h" \
+ | replace_linux_int_types \
+ | replace_sockaddr_libc \
+ | remove_sa_family_t \
+ | rustfmt \
+ > net_sys/src/iff.rs
+
+bindgen_generate \
+ --allowlist-type='sock_fprog' \
+ --allowlist-var='TUN_.*' \
+ "${BINDGEN_LINUX}/include/uapi/linux/if_tun.h" \
+ | replace_linux_int_types \
+ > net_sys/src/if_tun.rs
+
+bindgen_generate \
+ --allowlist-var='SIOC.*' \
+ "${BINDGEN_LINUX}/include/uapi/linux/sockios.h" \
+ | replace_linux_int_types \
+ > net_sys/src/sockios.rs
diff --git a/net_sys/src/if_tun.rs b/net_sys/src/if_tun.rs
index 09c65b3..d960c7e 100644
--- a/net_sys/src/if_tun.rs
+++ b/net_sys/src/if_tun.rs
@@ -1,603 +1,40 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-#![allow(warnings)]
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
-/* automatically generated by rust-bindgen */
-
+pub const TUN_READQ_SIZE: u32 = 500;
+pub const TUN_TYPE_MASK: u32 = 15;
+pub const TUN_TX_TIMESTAMP: u32 = 1;
+pub const TUN_F_CSUM: u32 = 1;
+pub const TUN_F_TSO4: u32 = 2;
+pub const TUN_F_TSO6: u32 = 4;
+pub const TUN_F_TSO_ECN: u32 = 8;
+pub const TUN_F_UFO: u32 = 16;
+pub const TUN_PKT_STRIP: u32 = 1;
+pub const TUN_FLT_ALLMULTI: u32 = 1;
#[repr(C)]
-#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
-impl<T> __IncompleteArrayField<T> {
- #[inline]
- pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData)
- }
- #[inline]
- pub unsafe fn as_ptr(&self) -> *const T {
- ::std::mem::transmute(self)
- }
- #[inline]
- pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
- ::std::mem::transmute(self)
- }
- #[inline]
- pub unsafe fn as_slice(&self, len: usize) -> &[T] {
- ::std::slice::from_raw_parts(self.as_ptr(), len)
- }
- #[inline]
- pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
- ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
- }
-}
-impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
- fmt.write_str("__IncompleteArrayField")
- }
-}
-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
-}
-impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
-pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
-pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
-pub const ETH_ALEN: ::std::os::raw::c_uint = 6;
-pub const ETH_HLEN: ::std::os::raw::c_uint = 14;
-pub const ETH_ZLEN: ::std::os::raw::c_uint = 60;
-pub const ETH_DATA_LEN: ::std::os::raw::c_uint = 1500;
-pub const ETH_FRAME_LEN: ::std::os::raw::c_uint = 1514;
-pub const ETH_FCS_LEN: ::std::os::raw::c_uint = 4;
-pub const ETH_P_LOOP: ::std::os::raw::c_uint = 96;
-pub const ETH_P_PUP: ::std::os::raw::c_uint = 512;
-pub const ETH_P_PUPAT: ::std::os::raw::c_uint = 513;
-pub const ETH_P_TSN: ::std::os::raw::c_uint = 8944;
-pub const ETH_P_IP: ::std::os::raw::c_uint = 2048;
-pub const ETH_P_X25: ::std::os::raw::c_uint = 2053;
-pub const ETH_P_ARP: ::std::os::raw::c_uint = 2054;
-pub const ETH_P_BPQ: ::std::os::raw::c_uint = 2303;
-pub const ETH_P_IEEEPUP: ::std::os::raw::c_uint = 2560;
-pub const ETH_P_IEEEPUPAT: ::std::os::raw::c_uint = 2561;
-pub const ETH_P_BATMAN: ::std::os::raw::c_uint = 17157;
-pub const ETH_P_DEC: ::std::os::raw::c_uint = 24576;
-pub const ETH_P_DNA_DL: ::std::os::raw::c_uint = 24577;
-pub const ETH_P_DNA_RC: ::std::os::raw::c_uint = 24578;
-pub const ETH_P_DNA_RT: ::std::os::raw::c_uint = 24579;
-pub const ETH_P_LAT: ::std::os::raw::c_uint = 24580;
-pub const ETH_P_DIAG: ::std::os::raw::c_uint = 24581;
-pub const ETH_P_CUST: ::std::os::raw::c_uint = 24582;
-pub const ETH_P_SCA: ::std::os::raw::c_uint = 24583;
-pub const ETH_P_TEB: ::std::os::raw::c_uint = 25944;
-pub const ETH_P_RARP: ::std::os::raw::c_uint = 32821;
-pub const ETH_P_ATALK: ::std::os::raw::c_uint = 32923;
-pub const ETH_P_AARP: ::std::os::raw::c_uint = 33011;
-pub const ETH_P_8021Q: ::std::os::raw::c_uint = 33024;
-pub const ETH_P_IPX: ::std::os::raw::c_uint = 33079;
-pub const ETH_P_IPV6: ::std::os::raw::c_uint = 34525;
-pub const ETH_P_PAUSE: ::std::os::raw::c_uint = 34824;
-pub const ETH_P_SLOW: ::std::os::raw::c_uint = 34825;
-pub const ETH_P_WCCP: ::std::os::raw::c_uint = 34878;
-pub const ETH_P_MPLS_UC: ::std::os::raw::c_uint = 34887;
-pub const ETH_P_MPLS_MC: ::std::os::raw::c_uint = 34888;
-pub const ETH_P_ATMMPOA: ::std::os::raw::c_uint = 34892;
-pub const ETH_P_PPP_DISC: ::std::os::raw::c_uint = 34915;
-pub const ETH_P_PPP_SES: ::std::os::raw::c_uint = 34916;
-pub const ETH_P_LINK_CTL: ::std::os::raw::c_uint = 34924;
-pub const ETH_P_ATMFATE: ::std::os::raw::c_uint = 34948;
-pub const ETH_P_PAE: ::std::os::raw::c_uint = 34958;
-pub const ETH_P_AOE: ::std::os::raw::c_uint = 34978;
-pub const ETH_P_8021AD: ::std::os::raw::c_uint = 34984;
-pub const ETH_P_802_EX1: ::std::os::raw::c_uint = 34997;
-pub const ETH_P_TIPC: ::std::os::raw::c_uint = 35018;
-pub const ETH_P_8021AH: ::std::os::raw::c_uint = 35047;
-pub const ETH_P_MVRP: ::std::os::raw::c_uint = 35061;
-pub const ETH_P_1588: ::std::os::raw::c_uint = 35063;
-pub const ETH_P_PRP: ::std::os::raw::c_uint = 35067;
-pub const ETH_P_FCOE: ::std::os::raw::c_uint = 35078;
-pub const ETH_P_TDLS: ::std::os::raw::c_uint = 35085;
-pub const ETH_P_FIP: ::std::os::raw::c_uint = 35092;
-pub const ETH_P_80221: ::std::os::raw::c_uint = 35095;
-pub const ETH_P_LOOPBACK: ::std::os::raw::c_uint = 36864;
-pub const ETH_P_QINQ1: ::std::os::raw::c_uint = 37120;
-pub const ETH_P_QINQ2: ::std::os::raw::c_uint = 37376;
-pub const ETH_P_QINQ3: ::std::os::raw::c_uint = 37632;
-pub const ETH_P_EDSA: ::std::os::raw::c_uint = 56026;
-pub const ETH_P_AF_IUCV: ::std::os::raw::c_uint = 64507;
-pub const ETH_P_802_3_MIN: ::std::os::raw::c_uint = 1536;
-pub const ETH_P_802_3: ::std::os::raw::c_uint = 1;
-pub const ETH_P_AX25: ::std::os::raw::c_uint = 2;
-pub const ETH_P_ALL: ::std::os::raw::c_uint = 3;
-pub const ETH_P_802_2: ::std::os::raw::c_uint = 4;
-pub const ETH_P_SNAP: ::std::os::raw::c_uint = 5;
-pub const ETH_P_DDCMP: ::std::os::raw::c_uint = 6;
-pub const ETH_P_WAN_PPP: ::std::os::raw::c_uint = 7;
-pub const ETH_P_PPP_MP: ::std::os::raw::c_uint = 8;
-pub const ETH_P_LOCALTALK: ::std::os::raw::c_uint = 9;
-pub const ETH_P_CAN: ::std::os::raw::c_uint = 12;
-pub const ETH_P_CANFD: ::std::os::raw::c_uint = 13;
-pub const ETH_P_PPPTALK: ::std::os::raw::c_uint = 16;
-pub const ETH_P_TR_802_2: ::std::os::raw::c_uint = 17;
-pub const ETH_P_MOBITEX: ::std::os::raw::c_uint = 21;
-pub const ETH_P_CONTROL: ::std::os::raw::c_uint = 22;
-pub const ETH_P_IRDA: ::std::os::raw::c_uint = 23;
-pub const ETH_P_ECONET: ::std::os::raw::c_uint = 24;
-pub const ETH_P_HDLC: ::std::os::raw::c_uint = 25;
-pub const ETH_P_ARCNET: ::std::os::raw::c_uint = 26;
-pub const ETH_P_DSA: ::std::os::raw::c_uint = 27;
-pub const ETH_P_TRAILER: ::std::os::raw::c_uint = 28;
-pub const ETH_P_PHONET: ::std::os::raw::c_uint = 245;
-pub const ETH_P_IEEE802154: ::std::os::raw::c_uint = 246;
-pub const ETH_P_CAIF: ::std::os::raw::c_uint = 247;
-pub const ETH_P_XDSA: ::std::os::raw::c_uint = 248;
-pub const BPF_LD: ::std::os::raw::c_uint = 0;
-pub const BPF_LDX: ::std::os::raw::c_uint = 1;
-pub const BPF_ST: ::std::os::raw::c_uint = 2;
-pub const BPF_STX: ::std::os::raw::c_uint = 3;
-pub const BPF_ALU: ::std::os::raw::c_uint = 4;
-pub const BPF_JMP: ::std::os::raw::c_uint = 5;
-pub const BPF_RET: ::std::os::raw::c_uint = 6;
-pub const BPF_MISC: ::std::os::raw::c_uint = 7;
-pub const BPF_W: ::std::os::raw::c_uint = 0;
-pub const BPF_H: ::std::os::raw::c_uint = 8;
-pub const BPF_B: ::std::os::raw::c_uint = 16;
-pub const BPF_IMM: ::std::os::raw::c_uint = 0;
-pub const BPF_ABS: ::std::os::raw::c_uint = 32;
-pub const BPF_IND: ::std::os::raw::c_uint = 64;
-pub const BPF_MEM: ::std::os::raw::c_uint = 96;
-pub const BPF_LEN: ::std::os::raw::c_uint = 128;
-pub const BPF_MSH: ::std::os::raw::c_uint = 160;
-pub const BPF_ADD: ::std::os::raw::c_uint = 0;
-pub const BPF_SUB: ::std::os::raw::c_uint = 16;
-pub const BPF_MUL: ::std::os::raw::c_uint = 32;
-pub const BPF_DIV: ::std::os::raw::c_uint = 48;
-pub const BPF_OR: ::std::os::raw::c_uint = 64;
-pub const BPF_AND: ::std::os::raw::c_uint = 80;
-pub const BPF_LSH: ::std::os::raw::c_uint = 96;
-pub const BPF_RSH: ::std::os::raw::c_uint = 112;
-pub const BPF_NEG: ::std::os::raw::c_uint = 128;
-pub const BPF_MOD: ::std::os::raw::c_uint = 144;
-pub const BPF_XOR: ::std::os::raw::c_uint = 160;
-pub const BPF_JA: ::std::os::raw::c_uint = 0;
-pub const BPF_JEQ: ::std::os::raw::c_uint = 16;
-pub const BPF_JGT: ::std::os::raw::c_uint = 32;
-pub const BPF_JGE: ::std::os::raw::c_uint = 48;
-pub const BPF_JSET: ::std::os::raw::c_uint = 64;
-pub const BPF_K: ::std::os::raw::c_uint = 0;
-pub const BPF_X: ::std::os::raw::c_uint = 8;
-pub const BPF_MAXINSNS: ::std::os::raw::c_uint = 4096;
-pub const BPF_MAJOR_VERSION: ::std::os::raw::c_uint = 1;
-pub const BPF_MINOR_VERSION: ::std::os::raw::c_uint = 1;
-pub const BPF_A: ::std::os::raw::c_uint = 16;
-pub const BPF_TAX: ::std::os::raw::c_uint = 0;
-pub const BPF_TXA: ::std::os::raw::c_uint = 128;
-pub const BPF_MEMWORDS: ::std::os::raw::c_uint = 16;
-pub const SKF_AD_OFF: ::std::os::raw::c_int = -4096;
-pub const SKF_AD_PROTOCOL: ::std::os::raw::c_uint = 0;
-pub const SKF_AD_PKTTYPE: ::std::os::raw::c_uint = 4;
-pub const SKF_AD_IFINDEX: ::std::os::raw::c_uint = 8;
-pub const SKF_AD_NLATTR: ::std::os::raw::c_uint = 12;
-pub const SKF_AD_NLATTR_NEST: ::std::os::raw::c_uint = 16;
-pub const SKF_AD_MARK: ::std::os::raw::c_uint = 20;
-pub const SKF_AD_QUEUE: ::std::os::raw::c_uint = 24;
-pub const SKF_AD_HATYPE: ::std::os::raw::c_uint = 28;
-pub const SKF_AD_RXHASH: ::std::os::raw::c_uint = 32;
-pub const SKF_AD_CPU: ::std::os::raw::c_uint = 36;
-pub const SKF_AD_ALU_XOR_X: ::std::os::raw::c_uint = 40;
-pub const SKF_AD_VLAN_TAG: ::std::os::raw::c_uint = 44;
-pub const SKF_AD_VLAN_TAG_PRESENT: ::std::os::raw::c_uint = 48;
-pub const SKF_AD_PAY_OFFSET: ::std::os::raw::c_uint = 52;
-pub const SKF_AD_RANDOM: ::std::os::raw::c_uint = 56;
-pub const SKF_AD_VLAN_TPID: ::std::os::raw::c_uint = 60;
-pub const SKF_AD_MAX: ::std::os::raw::c_uint = 64;
-pub const SKF_NET_OFF: ::std::os::raw::c_int = -1048576;
-pub const SKF_LL_OFF: ::std::os::raw::c_int = -2097152;
-pub const BPF_NET_OFF: ::std::os::raw::c_int = -1048576;
-pub const BPF_LL_OFF: ::std::os::raw::c_int = -2097152;
-pub const TUN_READQ_SIZE: ::std::os::raw::c_uint = 500;
-pub const TUN_TYPE_MASK: ::std::os::raw::c_uint = 15;
-pub const IFF_TUN: ::std::os::raw::c_uint = 1;
-pub const IFF_TAP: ::std::os::raw::c_uint = 2;
-pub const IFF_NO_PI: ::std::os::raw::c_uint = 4096;
-pub const IFF_ONE_QUEUE: ::std::os::raw::c_uint = 8192;
-pub const IFF_VNET_HDR: ::std::os::raw::c_uint = 16384;
-pub const IFF_TUN_EXCL: ::std::os::raw::c_uint = 32768;
-pub const IFF_MULTI_QUEUE: ::std::os::raw::c_uint = 256;
-pub const IFF_ATTACH_QUEUE: ::std::os::raw::c_uint = 512;
-pub const IFF_DETACH_QUEUE: ::std::os::raw::c_uint = 1024;
-pub const IFF_PERSIST: ::std::os::raw::c_uint = 2048;
-pub const IFF_NOFILTER: ::std::os::raw::c_uint = 4096;
-pub const TUN_TX_TIMESTAMP: ::std::os::raw::c_uint = 1;
-pub const TUN_F_CSUM: ::std::os::raw::c_uint = 1;
-pub const TUN_F_TSO4: ::std::os::raw::c_uint = 2;
-pub const TUN_F_TSO6: ::std::os::raw::c_uint = 4;
-pub const TUN_F_TSO_ECN: ::std::os::raw::c_uint = 8;
-pub const TUN_F_UFO: ::std::os::raw::c_uint = 16;
-pub const TUN_PKT_STRIP: ::std::os::raw::c_uint = 1;
-pub const TUN_FLT_ALLMULTI: ::std::os::raw::c_uint = 1;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-#[test]
-#[ignore]
-fn bindgen_test_layout___kernel_fd_set() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fd_set>(),
- 128usize,
- concat!("Size of: ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fd_set>(),
- 8usize,
- concat!("Alignment of ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fd_set),
- "::",
- stringify!(fds_bits)
- )
- );
-}
-impl Clone for __kernel_fd_set {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-#[test]
-fn bindgen_test_layout___kernel_fsid_t() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fsid_t>(),
- 8usize,
- concat!("Size of: ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fsid_t>(),
- 4usize,
- concat!("Alignment of ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fsid_t),
- "::",
- stringify!(val)
- )
- );
-}
-impl Clone for __kernel_fsid_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
-#[repr(C, packed)]
-#[derive(Debug, Default, Copy)]
-pub struct ethhdr {
- pub h_dest: [::std::os::raw::c_uchar; 6usize],
- pub h_source: [::std::os::raw::c_uchar; 6usize],
- pub h_proto: __be16,
-}
-#[test]
-fn bindgen_test_layout_ethhdr() {
- assert_eq!(
- ::std::mem::size_of::<ethhdr>(),
- 14usize,
- concat!("Size of: ", stringify!(ethhdr))
- );
- assert_eq!(
- ::std::mem::align_of::<ethhdr>(),
- 1usize,
- concat!("Alignment of ", stringify!(ethhdr))
- );
- assert_eq!(
- unsafe { &(*(0 as *const ethhdr)).h_dest as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(ethhdr),
- "::",
- stringify!(h_dest)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ethhdr)).h_source as *const _ as usize },
- 6usize,
- concat!(
- "Alignment of field: ",
- stringify!(ethhdr),
- "::",
- stringify!(h_source)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ethhdr)).h_proto as *const _ as usize },
- 12usize,
- concat!(
- "Alignment of field: ",
- stringify!(ethhdr),
- "::",
- stringify!(h_proto)
- )
- );
-}
-impl Clone for ethhdr {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct sock_filter {
- pub code: __u16,
- pub jt: __u8,
- pub jf: __u8,
- pub k: __u32,
-}
-#[test]
-fn bindgen_test_layout_sock_filter() {
- assert_eq!(
- ::std::mem::size_of::<sock_filter>(),
- 8usize,
- concat!("Size of: ", stringify!(sock_filter))
- );
- assert_eq!(
- ::std::mem::align_of::<sock_filter>(),
- 4usize,
- concat!("Alignment of ", stringify!(sock_filter))
- );
- assert_eq!(
- unsafe { &(*(0 as *const sock_filter)).code as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(sock_filter),
- "::",
- stringify!(code)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sock_filter)).jt as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(sock_filter),
- "::",
- stringify!(jt)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sock_filter)).jf as *const _ as usize },
- 3usize,
- concat!(
- "Alignment of field: ",
- stringify!(sock_filter),
- "::",
- stringify!(jf)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sock_filter)).k as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(sock_filter),
- "::",
- stringify!(k)
- )
- );
-}
-impl Clone for sock_filter {
- fn clone(&self) -> Self {
- *self
- }
+ pub code: u16,
+ pub jt: u8,
+ pub jf: u8,
+ pub k: u32,
}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Copy, Clone)]
pub struct sock_fprog {
pub len: ::std::os::raw::c_ushort,
pub filter: *mut sock_filter,
}
-#[test]
-#[ignore]
-fn bindgen_test_layout_sock_fprog() {
- assert_eq!(
- ::std::mem::size_of::<sock_fprog>(),
- 16usize,
- concat!("Size of: ", stringify!(sock_fprog))
- );
- assert_eq!(
- ::std::mem::align_of::<sock_fprog>(),
- 8usize,
- concat!("Alignment of ", stringify!(sock_fprog))
- );
- assert_eq!(
- unsafe { &(*(0 as *const sock_fprog)).len as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(sock_fprog),
- "::",
- stringify!(len)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sock_fprog)).filter as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(sock_fprog),
- "::",
- stringify!(filter)
- )
- );
-}
-impl Clone for sock_fprog {
- fn clone(&self) -> Self {
- *self
- }
-}
impl Default for sock_fprog {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct tun_pi {
- pub flags: __u16,
- pub proto: __be16,
-}
-#[test]
-fn bindgen_test_layout_tun_pi() {
- assert_eq!(
- ::std::mem::size_of::<tun_pi>(),
- 4usize,
- concat!("Size of: ", stringify!(tun_pi))
- );
- assert_eq!(
- ::std::mem::align_of::<tun_pi>(),
- 2usize,
- concat!("Alignment of ", stringify!(tun_pi))
- );
- assert_eq!(
- unsafe { &(*(0 as *const tun_pi)).flags as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(tun_pi),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const tun_pi)).proto as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(tun_pi),
- "::",
- stringify!(proto)
- )
- );
-}
-impl Clone for tun_pi {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct tun_filter {
- pub flags: __u16,
- pub count: __u16,
- pub addr: __IncompleteArrayField<[__u8; 6usize]>,
-}
-#[test]
-fn bindgen_test_layout_tun_filter() {
- assert_eq!(
- ::std::mem::size_of::<tun_filter>(),
- 4usize,
- concat!("Size of: ", stringify!(tun_filter))
- );
- assert_eq!(
- ::std::mem::align_of::<tun_filter>(),
- 2usize,
- concat!("Alignment of ", stringify!(tun_filter))
- );
- assert_eq!(
- unsafe { &(*(0 as *const tun_filter)).flags as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(tun_filter),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const tun_filter)).count as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(tun_filter),
- "::",
- stringify!(count)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const tun_filter)).addr as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(tun_filter),
- "::",
- stringify!(addr)
- )
- );
-}
-impl Clone for tun_filter {
- fn clone(&self) -> Self {
- *self
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
diff --git a/net_sys/src/iff.rs b/net_sys/src/iff.rs
index 928a2cc..1b5bf1c 100644
--- a/net_sys/src/iff.rs
+++ b/net_sys/src/iff.rs
@@ -1,1070 +1,12 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-/* automatically generated by rust-bindgen */
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
-#[repr(C)]
-#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
-impl<T> __IncompleteArrayField<T> {
- #[inline]
- pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData, [])
- }
- #[inline]
- pub unsafe fn as_ptr(&self) -> *const T {
- ::std::mem::transmute(self)
- }
- #[inline]
- pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
- ::std::mem::transmute(self)
- }
- #[inline]
- pub unsafe fn as_slice(&self, len: usize) -> &[T] {
- ::std::slice::from_raw_parts(self.as_ptr(), len)
- }
- #[inline]
- pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
- ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
- }
-}
-impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
- fmt.write_str("__IncompleteArrayField")
- }
-}
-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
-}
-pub const __UAPI_DEF_IF_IFCONF: u32 = 1;
-pub const __UAPI_DEF_IF_IFMAP: u32 = 1;
-pub const __UAPI_DEF_IF_IFNAMSIZ: u32 = 1;
-pub const __UAPI_DEF_IF_IFREQ: u32 = 1;
-pub const __UAPI_DEF_IF_NET_DEVICE_FLAGS: u32 = 1;
-pub const __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO: u32 = 1;
-pub const __UAPI_DEF_IN_ADDR: u32 = 1;
-pub const __UAPI_DEF_IN_IPPROTO: u32 = 1;
-pub const __UAPI_DEF_IN_PKTINFO: u32 = 1;
-pub const __UAPI_DEF_IP_MREQ: u32 = 1;
-pub const __UAPI_DEF_SOCKADDR_IN: u32 = 1;
-pub const __UAPI_DEF_IN_CLASS: u32 = 1;
-pub const __UAPI_DEF_IN6_ADDR: u32 = 1;
-pub const __UAPI_DEF_IN6_ADDR_ALT: u32 = 1;
-pub const __UAPI_DEF_SOCKADDR_IN6: u32 = 1;
-pub const __UAPI_DEF_IPV6_MREQ: u32 = 1;
-pub const __UAPI_DEF_IPPROTO_V6: u32 = 1;
-pub const __UAPI_DEF_IPV6_OPTIONS: u32 = 1;
-pub const __UAPI_DEF_IN6_PKTINFO: u32 = 1;
-pub const __UAPI_DEF_IP6_MTUINFO: u32 = 1;
-pub const __UAPI_DEF_SOCKADDR_IPX: u32 = 1;
-pub const __UAPI_DEF_IPX_ROUTE_DEFINITION: u32 = 1;
-pub const __UAPI_DEF_IPX_INTERFACE_DEFINITION: u32 = 1;
-pub const __UAPI_DEF_IPX_CONFIG_DATA: u32 = 1;
-pub const __UAPI_DEF_IPX_ROUTE_DEF: u32 = 1;
-pub const __UAPI_DEF_XATTR: u32 = 1;
-pub const __BITS_PER_LONG: u32 = 64;
-pub const __FD_SETSIZE: u32 = 1024;
-pub const _K_SS_MAXSIZE: u32 = 128;
-pub const _SYS_SOCKET_H: u32 = 1;
-pub const _FEATURES_H: u32 = 1;
-pub const _DEFAULT_SOURCE: u32 = 1;
-pub const __USE_ISOC11: u32 = 1;
-pub const __USE_ISOC99: u32 = 1;
-pub const __USE_ISOC95: u32 = 1;
-pub const __USE_POSIX_IMPLICITLY: u32 = 1;
-pub const _POSIX_SOURCE: u32 = 1;
-pub const _POSIX_C_SOURCE: u32 = 200809;
-pub const __USE_POSIX: u32 = 1;
-pub const __USE_POSIX2: u32 = 1;
-pub const __USE_POSIX199309: u32 = 1;
-pub const __USE_POSIX199506: u32 = 1;
-pub const __USE_XOPEN2K: u32 = 1;
-pub const __USE_XOPEN2K8: u32 = 1;
-pub const _ATFILE_SOURCE: u32 = 1;
-pub const __USE_MISC: u32 = 1;
-pub const __USE_ATFILE: u32 = 1;
-pub const __USE_FORTIFY_LEVEL: u32 = 0;
-pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0;
-pub const _STDC_PREDEF_H: u32 = 1;
-pub const __STDC_IEC_559__: u32 = 1;
-pub const __STDC_IEC_559_COMPLEX__: u32 = 1;
-pub const __STDC_ISO_10646__: u32 = 201706;
-pub const __STDC_NO_THREADS__: u32 = 1;
-pub const __GNU_LIBRARY__: u32 = 6;
-pub const __GLIBC__: u32 = 2;
-pub const __GLIBC_MINOR__: u32 = 27;
-pub const _SYS_CDEFS_H: u32 = 1;
-pub const __glibc_c99_flexarr_available: u32 = 1;
-pub const __WORDSIZE: u32 = 64;
-pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
-pub const __SYSCALL_WORDSIZE: u32 = 64;
-pub const __HAVE_GENERIC_SELECTION: u32 = 1;
-pub const __iovec_defined: u32 = 1;
-pub const _SYS_TYPES_H: u32 = 1;
-pub const _BITS_TYPES_H: u32 = 1;
-pub const _BITS_TYPESIZES_H: u32 = 1;
-pub const __OFF_T_MATCHES_OFF64_T: u32 = 1;
-pub const __INO_T_MATCHES_INO64_T: u32 = 1;
-pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1;
-pub const __clock_t_defined: u32 = 1;
-pub const __clockid_t_defined: u32 = 1;
-pub const __time_t_defined: u32 = 1;
-pub const __timer_t_defined: u32 = 1;
-pub const _BITS_STDINT_INTN_H: u32 = 1;
-pub const __BIT_TYPES_DEFINED__: u32 = 1;
-pub const _ENDIAN_H: u32 = 1;
-pub const __LITTLE_ENDIAN: u32 = 1234;
-pub const __BIG_ENDIAN: u32 = 4321;
-pub const __PDP_ENDIAN: u32 = 3412;
-pub const __BYTE_ORDER: u32 = 1234;
-pub const __FLOAT_WORD_ORDER: u32 = 1234;
-pub const LITTLE_ENDIAN: u32 = 1234;
-pub const BIG_ENDIAN: u32 = 4321;
-pub const PDP_ENDIAN: u32 = 3412;
-pub const BYTE_ORDER: u32 = 1234;
-pub const _BITS_BYTESWAP_H: u32 = 1;
-pub const _BITS_UINTN_IDENTITY_H: u32 = 1;
-pub const _SYS_SELECT_H: u32 = 1;
-pub const __FD_ZERO_STOS: &'static [u8; 6usize] = b"stosq\0";
-pub const __sigset_t_defined: u32 = 1;
-pub const __timeval_defined: u32 = 1;
-pub const _STRUCT_TIMESPEC: u32 = 1;
-pub const FD_SETSIZE: u32 = 1024;
-pub const _BITS_PTHREADTYPES_COMMON_H: u32 = 1;
-pub const _THREAD_SHARED_TYPES_H: u32 = 1;
-pub const _BITS_PTHREADTYPES_ARCH_H: u32 = 1;
-pub const __SIZEOF_PTHREAD_MUTEX_T: u32 = 40;
-pub const __SIZEOF_PTHREAD_ATTR_T: u32 = 56;
-pub const __SIZEOF_PTHREAD_RWLOCK_T: u32 = 56;
-pub const __SIZEOF_PTHREAD_BARRIER_T: u32 = 32;
-pub const __SIZEOF_PTHREAD_MUTEXATTR_T: u32 = 4;
-pub const __SIZEOF_PTHREAD_COND_T: u32 = 48;
-pub const __SIZEOF_PTHREAD_CONDATTR_T: u32 = 4;
-pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: u32 = 8;
-pub const __SIZEOF_PTHREAD_BARRIERATTR_T: u32 = 4;
-pub const __PTHREAD_MUTEX_LOCK_ELISION: u32 = 1;
-pub const __PTHREAD_MUTEX_NUSERS_AFTER_KIND: u32 = 0;
-pub const __PTHREAD_MUTEX_USE_UNION: u32 = 0;
-pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: u32 = 1;
-pub const __PTHREAD_MUTEX_HAVE_PREV: u32 = 1;
-pub const __have_pthread_attr_t: u32 = 1;
-pub const PF_UNSPEC: u32 = 0;
-pub const PF_LOCAL: u32 = 1;
-pub const PF_UNIX: u32 = 1;
-pub const PF_FILE: u32 = 1;
-pub const PF_INET: u32 = 2;
-pub const PF_AX25: u32 = 3;
-pub const PF_IPX: u32 = 4;
-pub const PF_APPLETALK: u32 = 5;
-pub const PF_NETROM: u32 = 6;
-pub const PF_BRIDGE: u32 = 7;
-pub const PF_ATMPVC: u32 = 8;
-pub const PF_X25: u32 = 9;
-pub const PF_INET6: u32 = 10;
-pub const PF_ROSE: u32 = 11;
-pub const PF_DECnet: u32 = 12;
-pub const PF_NETBEUI: u32 = 13;
-pub const PF_SECURITY: u32 = 14;
-pub const PF_KEY: u32 = 15;
-pub const PF_NETLINK: u32 = 16;
-pub const PF_ROUTE: u32 = 16;
-pub const PF_PACKET: u32 = 17;
-pub const PF_ASH: u32 = 18;
-pub const PF_ECONET: u32 = 19;
-pub const PF_ATMSVC: u32 = 20;
-pub const PF_RDS: u32 = 21;
-pub const PF_SNA: u32 = 22;
-pub const PF_IRDA: u32 = 23;
-pub const PF_PPPOX: u32 = 24;
-pub const PF_WANPIPE: u32 = 25;
-pub const PF_LLC: u32 = 26;
-pub const PF_IB: u32 = 27;
-pub const PF_MPLS: u32 = 28;
-pub const PF_CAN: u32 = 29;
-pub const PF_TIPC: u32 = 30;
-pub const PF_BLUETOOTH: u32 = 31;
-pub const PF_IUCV: u32 = 32;
-pub const PF_RXRPC: u32 = 33;
-pub const PF_ISDN: u32 = 34;
-pub const PF_PHONET: u32 = 35;
-pub const PF_IEEE802154: u32 = 36;
-pub const PF_CAIF: u32 = 37;
-pub const PF_ALG: u32 = 38;
-pub const PF_NFC: u32 = 39;
-pub const PF_VSOCK: u32 = 40;
-pub const PF_KCM: u32 = 41;
-pub const PF_QIPCRTR: u32 = 42;
-pub const PF_SMC: u32 = 43;
-pub const PF_MAX: u32 = 44;
-pub const AF_UNSPEC: u32 = 0;
-pub const AF_LOCAL: u32 = 1;
-pub const AF_UNIX: u32 = 1;
-pub const AF_FILE: u32 = 1;
-pub const AF_INET: u32 = 2;
-pub const AF_AX25: u32 = 3;
-pub const AF_IPX: u32 = 4;
-pub const AF_APPLETALK: u32 = 5;
-pub const AF_NETROM: u32 = 6;
-pub const AF_BRIDGE: u32 = 7;
-pub const AF_ATMPVC: u32 = 8;
-pub const AF_X25: u32 = 9;
-pub const AF_INET6: u32 = 10;
-pub const AF_ROSE: u32 = 11;
-pub const AF_DECnet: u32 = 12;
-pub const AF_NETBEUI: u32 = 13;
-pub const AF_SECURITY: u32 = 14;
-pub const AF_KEY: u32 = 15;
-pub const AF_NETLINK: u32 = 16;
-pub const AF_ROUTE: u32 = 16;
-pub const AF_PACKET: u32 = 17;
-pub const AF_ASH: u32 = 18;
-pub const AF_ECONET: u32 = 19;
-pub const AF_ATMSVC: u32 = 20;
-pub const AF_RDS: u32 = 21;
-pub const AF_SNA: u32 = 22;
-pub const AF_IRDA: u32 = 23;
-pub const AF_PPPOX: u32 = 24;
-pub const AF_WANPIPE: u32 = 25;
-pub const AF_LLC: u32 = 26;
-pub const AF_IB: u32 = 27;
-pub const AF_MPLS: u32 = 28;
-pub const AF_CAN: u32 = 29;
-pub const AF_TIPC: u32 = 30;
-pub const AF_BLUETOOTH: u32 = 31;
-pub const AF_IUCV: u32 = 32;
-pub const AF_RXRPC: u32 = 33;
-pub const AF_ISDN: u32 = 34;
-pub const AF_PHONET: u32 = 35;
-pub const AF_IEEE802154: u32 = 36;
-pub const AF_CAIF: u32 = 37;
-pub const AF_ALG: u32 = 38;
-pub const AF_NFC: u32 = 39;
-pub const AF_VSOCK: u32 = 40;
-pub const AF_KCM: u32 = 41;
-pub const AF_QIPCRTR: u32 = 42;
-pub const AF_SMC: u32 = 43;
-pub const AF_MAX: u32 = 44;
-pub const SOL_RAW: u32 = 255;
-pub const SOL_DECNET: u32 = 261;
-pub const SOL_X25: u32 = 262;
-pub const SOL_PACKET: u32 = 263;
-pub const SOL_ATM: u32 = 264;
-pub const SOL_AAL: u32 = 265;
-pub const SOL_IRDA: u32 = 266;
-pub const SOL_NETBEUI: u32 = 267;
-pub const SOL_LLC: u32 = 268;
-pub const SOL_DCCP: u32 = 269;
-pub const SOL_NETLINK: u32 = 270;
-pub const SOL_TIPC: u32 = 271;
-pub const SOL_RXRPC: u32 = 272;
-pub const SOL_PPPOL2TP: u32 = 273;
-pub const SOL_BLUETOOTH: u32 = 274;
-pub const SOL_PNPIPE: u32 = 275;
-pub const SOL_RDS: u32 = 276;
-pub const SOL_IUCV: u32 = 277;
-pub const SOL_CAIF: u32 = 278;
-pub const SOL_ALG: u32 = 279;
-pub const SOL_NFC: u32 = 280;
-pub const SOL_KCM: u32 = 281;
-pub const SOL_TLS: u32 = 282;
-pub const SOMAXCONN: u32 = 128;
-pub const _BITS_SOCKADDR_H: u32 = 1;
-pub const _SS_SIZE: u32 = 128;
-pub const FIOSETOWN: u32 = 35073;
-pub const SIOCSPGRP: u32 = 35074;
-pub const FIOGETOWN: u32 = 35075;
-pub const SIOCGPGRP: u32 = 35076;
-pub const SIOCATMARK: u32 = 35077;
-pub const SIOCGSTAMP: u32 = 35078;
-pub const SIOCGSTAMPNS: u32 = 35079;
-pub const SOL_SOCKET: u32 = 1;
-pub const SO_DEBUG: u32 = 1;
-pub const SO_REUSEADDR: u32 = 2;
-pub const SO_TYPE: u32 = 3;
-pub const SO_ERROR: u32 = 4;
-pub const SO_DONTROUTE: u32 = 5;
-pub const SO_BROADCAST: u32 = 6;
-pub const SO_SNDBUF: u32 = 7;
-pub const SO_RCVBUF: u32 = 8;
-pub const SO_SNDBUFFORCE: u32 = 32;
-pub const SO_RCVBUFFORCE: u32 = 33;
-pub const SO_KEEPALIVE: u32 = 9;
-pub const SO_OOBINLINE: u32 = 10;
-pub const SO_NO_CHECK: u32 = 11;
-pub const SO_PRIORITY: u32 = 12;
-pub const SO_LINGER: u32 = 13;
-pub const SO_BSDCOMPAT: u32 = 14;
-pub const SO_REUSEPORT: u32 = 15;
-pub const SO_PASSCRED: u32 = 16;
-pub const SO_PEERCRED: u32 = 17;
-pub const SO_RCVLOWAT: u32 = 18;
-pub const SO_SNDLOWAT: u32 = 19;
-pub const SO_RCVTIMEO: u32 = 20;
-pub const SO_SNDTIMEO: u32 = 21;
-pub const SO_SECURITY_AUTHENTICATION: u32 = 22;
-pub const SO_SECURITY_ENCRYPTION_TRANSPORT: u32 = 23;
-pub const SO_SECURITY_ENCRYPTION_NETWORK: u32 = 24;
-pub const SO_BINDTODEVICE: u32 = 25;
-pub const SO_ATTACH_FILTER: u32 = 26;
-pub const SO_DETACH_FILTER: u32 = 27;
-pub const SO_GET_FILTER: u32 = 26;
-pub const SO_PEERNAME: u32 = 28;
-pub const SO_TIMESTAMP: u32 = 29;
-pub const SCM_TIMESTAMP: u32 = 29;
-pub const SO_ACCEPTCONN: u32 = 30;
-pub const SO_PEERSEC: u32 = 31;
-pub const SO_PASSSEC: u32 = 34;
-pub const SO_TIMESTAMPNS: u32 = 35;
-pub const SCM_TIMESTAMPNS: u32 = 35;
-pub const SO_MARK: u32 = 36;
-pub const SO_TIMESTAMPING: u32 = 37;
-pub const SCM_TIMESTAMPING: u32 = 37;
-pub const SO_PROTOCOL: u32 = 38;
-pub const SO_DOMAIN: u32 = 39;
-pub const SO_RXQ_OVFL: u32 = 40;
-pub const SO_WIFI_STATUS: u32 = 41;
-pub const SCM_WIFI_STATUS: u32 = 41;
-pub const SO_PEEK_OFF: u32 = 42;
-pub const SO_NOFCS: u32 = 43;
-pub const SO_LOCK_FILTER: u32 = 44;
-pub const SO_SELECT_ERR_QUEUE: u32 = 45;
-pub const SO_BUSY_POLL: u32 = 46;
-pub const SO_MAX_PACING_RATE: u32 = 47;
-pub const SO_BPF_EXTENSIONS: u32 = 48;
-pub const SO_INCOMING_CPU: u32 = 49;
-pub const SO_ATTACH_BPF: u32 = 50;
-pub const SO_DETACH_BPF: u32 = 27;
-pub const SO_ATTACH_REUSEPORT_CBPF: u32 = 51;
-pub const SO_ATTACH_REUSEPORT_EBPF: u32 = 52;
-pub const SO_CNX_ADVICE: u32 = 53;
-pub const SCM_TIMESTAMPING_OPT_STATS: u32 = 54;
-pub const SO_MEMINFO: u32 = 55;
-pub const SO_INCOMING_NAPI_ID: u32 = 56;
-pub const SO_COOKIE: u32 = 57;
-pub const SCM_TIMESTAMPING_PKTINFO: u32 = 58;
-pub const SO_PEERGROUPS: u32 = 59;
-pub const SO_ZEROCOPY: u32 = 60;
-pub const __osockaddr_defined: u32 = 1;
-pub const IFNAMSIZ: u32 = 16;
-pub const IFALIASZ: u32 = 256;
-pub const GENERIC_HDLC_VERSION: u32 = 4;
-pub const CLOCK_DEFAULT: u32 = 0;
-pub const CLOCK_EXT: u32 = 1;
-pub const CLOCK_INT: u32 = 2;
-pub const CLOCK_TXINT: u32 = 3;
-pub const CLOCK_TXFROMRX: u32 = 4;
-pub const ENCODING_DEFAULT: u32 = 0;
-pub const ENCODING_NRZ: u32 = 1;
-pub const ENCODING_NRZI: u32 = 2;
-pub const ENCODING_FM_MARK: u32 = 3;
-pub const ENCODING_FM_SPACE: u32 = 4;
-pub const ENCODING_MANCHESTER: u32 = 5;
-pub const PARITY_DEFAULT: u32 = 0;
-pub const PARITY_NONE: u32 = 1;
-pub const PARITY_CRC16_PR0: u32 = 2;
-pub const PARITY_CRC16_PR1: u32 = 3;
-pub const PARITY_CRC16_PR0_CCITT: u32 = 4;
-pub const PARITY_CRC16_PR1_CCITT: u32 = 5;
-pub const PARITY_CRC32_PR0_CCITT: u32 = 6;
-pub const PARITY_CRC32_PR1_CCITT: u32 = 7;
-pub const LMI_DEFAULT: u32 = 0;
-pub const LMI_NONE: u32 = 1;
-pub const LMI_ANSI: u32 = 2;
-pub const LMI_CCITT: u32 = 3;
-pub const LMI_CISCO: u32 = 4;
-pub const IF_GET_IFACE: u32 = 1;
-pub const IF_GET_PROTO: u32 = 2;
-pub const IF_IFACE_V35: u32 = 4096;
-pub const IF_IFACE_V24: u32 = 4097;
-pub const IF_IFACE_X21: u32 = 4098;
-pub const IF_IFACE_T1: u32 = 4099;
-pub const IF_IFACE_E1: u32 = 4100;
-pub const IF_IFACE_SYNC_SERIAL: u32 = 4101;
-pub const IF_IFACE_X21D: u32 = 4102;
-pub const IF_PROTO_HDLC: u32 = 8192;
-pub const IF_PROTO_PPP: u32 = 8193;
-pub const IF_PROTO_CISCO: u32 = 8194;
-pub const IF_PROTO_FR: u32 = 8195;
-pub const IF_PROTO_FR_ADD_PVC: u32 = 8196;
-pub const IF_PROTO_FR_DEL_PVC: u32 = 8197;
-pub const IF_PROTO_X25: u32 = 8198;
-pub const IF_PROTO_HDLC_ETH: u32 = 8199;
-pub const IF_PROTO_FR_ADD_ETH_PVC: u32 = 8200;
-pub const IF_PROTO_FR_DEL_ETH_PVC: u32 = 8201;
-pub const IF_PROTO_FR_PVC: u32 = 8202;
-pub const IF_PROTO_FR_ETH_PVC: u32 = 8203;
-pub const IF_PROTO_RAW: u32 = 8204;
-pub const IFHWADDRLEN: u32 = 6;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
-pub type __kernel_sa_family_t = ::std::os::raw::c_ushort;
-#[repr(C)]
-#[repr(align(8))]
-#[derive(Copy, Clone)]
-pub struct __kernel_sockaddr_storage {
- pub ss_family: __kernel_sa_family_t,
- pub __data: [::std::os::raw::c_char; 126usize],
-}
-impl Default for __kernel_sockaddr_storage {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct iovec {
- pub iov_base: *mut ::std::os::raw::c_void,
- pub iov_len: usize,
-}
-impl Default for iovec {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub type __u_char = ::std::os::raw::c_uchar;
-pub type __u_short = ::std::os::raw::c_ushort;
-pub type __u_int = ::std::os::raw::c_uint;
-pub type __u_long = ::std::os::raw::c_ulong;
-pub type __int8_t = ::std::os::raw::c_schar;
-pub type __uint8_t = ::std::os::raw::c_uchar;
-pub type __int16_t = ::std::os::raw::c_short;
-pub type __uint16_t = ::std::os::raw::c_ushort;
-pub type __int32_t = ::std::os::raw::c_int;
-pub type __uint32_t = ::std::os::raw::c_uint;
-pub type __int64_t = ::std::os::raw::c_long;
-pub type __uint64_t = ::std::os::raw::c_ulong;
-pub type __quad_t = ::std::os::raw::c_long;
-pub type __u_quad_t = ::std::os::raw::c_ulong;
-pub type __intmax_t = ::std::os::raw::c_long;
-pub type __uintmax_t = ::std::os::raw::c_ulong;
-pub type __dev_t = ::std::os::raw::c_ulong;
-pub type __uid_t = ::std::os::raw::c_uint;
-pub type __gid_t = ::std::os::raw::c_uint;
-pub type __ino_t = ::std::os::raw::c_ulong;
-pub type __ino64_t = ::std::os::raw::c_ulong;
-pub type __mode_t = ::std::os::raw::c_uint;
-pub type __nlink_t = ::std::os::raw::c_ulong;
-pub type __off_t = ::std::os::raw::c_long;
-pub type __off64_t = ::std::os::raw::c_long;
-pub type __pid_t = ::std::os::raw::c_int;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __fsid_t {
- pub __val: [::std::os::raw::c_int; 2usize],
-}
-pub type __clock_t = ::std::os::raw::c_long;
-pub type __rlim_t = ::std::os::raw::c_ulong;
-pub type __rlim64_t = ::std::os::raw::c_ulong;
-pub type __id_t = ::std::os::raw::c_uint;
-pub type __time_t = ::std::os::raw::c_long;
-pub type __useconds_t = ::std::os::raw::c_uint;
-pub type __suseconds_t = ::std::os::raw::c_long;
-pub type __daddr_t = ::std::os::raw::c_int;
-pub type __key_t = ::std::os::raw::c_int;
-pub type __clockid_t = ::std::os::raw::c_int;
-pub type __timer_t = *mut ::std::os::raw::c_void;
-pub type __blksize_t = ::std::os::raw::c_long;
-pub type __blkcnt_t = ::std::os::raw::c_long;
-pub type __blkcnt64_t = ::std::os::raw::c_long;
-pub type __fsblkcnt_t = ::std::os::raw::c_ulong;
-pub type __fsblkcnt64_t = ::std::os::raw::c_ulong;
-pub type __fsfilcnt_t = ::std::os::raw::c_ulong;
-pub type __fsfilcnt64_t = ::std::os::raw::c_ulong;
-pub type __fsword_t = ::std::os::raw::c_long;
-pub type __ssize_t = ::std::os::raw::c_long;
-pub type __syscall_slong_t = ::std::os::raw::c_long;
-pub type __syscall_ulong_t = ::std::os::raw::c_ulong;
-pub type __loff_t = __off64_t;
-pub type __caddr_t = *mut ::std::os::raw::c_char;
-pub type __intptr_t = ::std::os::raw::c_long;
-pub type __socklen_t = ::std::os::raw::c_uint;
-pub type __sig_atomic_t = ::std::os::raw::c_int;
-pub type u_char = __u_char;
-pub type u_short = __u_short;
-pub type u_int = __u_int;
-pub type u_long = __u_long;
-pub type quad_t = __quad_t;
-pub type u_quad_t = __u_quad_t;
-pub type fsid_t = __fsid_t;
-pub type loff_t = __loff_t;
-pub type ino_t = __ino_t;
-pub type dev_t = __dev_t;
-pub type gid_t = __gid_t;
-pub type mode_t = __mode_t;
-pub type nlink_t = __nlink_t;
-pub type uid_t = __uid_t;
-pub type off_t = __off_t;
-pub type pid_t = __pid_t;
-pub type id_t = __id_t;
-pub type daddr_t = __daddr_t;
-pub type caddr_t = __caddr_t;
-pub type key_t = __key_t;
-pub type clock_t = __clock_t;
-pub type clockid_t = __clockid_t;
-pub type time_t = __time_t;
-pub type timer_t = __timer_t;
-pub type ulong = ::std::os::raw::c_ulong;
-pub type ushort = ::std::os::raw::c_ushort;
-pub type uint = ::std::os::raw::c_uint;
-pub type u_int8_t = ::std::os::raw::c_uchar;
-pub type u_int16_t = ::std::os::raw::c_ushort;
-pub type u_int32_t = ::std::os::raw::c_uint;
-pub type u_int64_t = ::std::os::raw::c_ulong;
-pub type register_t = ::std::os::raw::c_long;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __sigset_t {
- pub __val: [::std::os::raw::c_ulong; 16usize],
-}
-pub type sigset_t = __sigset_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct timeval {
- pub tv_sec: __time_t,
- pub tv_usec: __suseconds_t,
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct timespec {
- pub tv_sec: __time_t,
- pub tv_nsec: __syscall_slong_t,
-}
-pub type suseconds_t = __suseconds_t;
-pub type __fd_mask = ::std::os::raw::c_long;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct fd_set {
- pub __fds_bits: [__fd_mask; 16usize],
-}
-pub type fd_mask = __fd_mask;
-extern "C" {
- pub fn select(
- __nfds: ::std::os::raw::c_int,
- __readfds: *mut fd_set,
- __writefds: *mut fd_set,
- __exceptfds: *mut fd_set,
- __timeout: *mut timeval,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn pselect(
- __nfds: ::std::os::raw::c_int,
- __readfds: *mut fd_set,
- __writefds: *mut fd_set,
- __exceptfds: *mut fd_set,
- __timeout: *const timespec,
- __sigmask: *const __sigset_t,
- ) -> ::std::os::raw::c_int;
-}
-pub type blksize_t = __blksize_t;
-pub type blkcnt_t = __blkcnt_t;
-pub type fsblkcnt_t = __fsblkcnt_t;
-pub type fsfilcnt_t = __fsfilcnt_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __pthread_rwlock_arch_t {
- pub __readers: ::std::os::raw::c_uint,
- pub __writers: ::std::os::raw::c_uint,
- pub __wrphase_futex: ::std::os::raw::c_uint,
- pub __writers_futex: ::std::os::raw::c_uint,
- pub __pad3: ::std::os::raw::c_uint,
- pub __pad4: ::std::os::raw::c_uint,
- pub __cur_writer: ::std::os::raw::c_int,
- pub __shared: ::std::os::raw::c_int,
- pub __rwelision: ::std::os::raw::c_schar,
- pub __pad1: [::std::os::raw::c_uchar; 7usize],
- pub __pad2: ::std::os::raw::c_ulong,
- pub __flags: ::std::os::raw::c_uint,
-}
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct __pthread_internal_list {
- pub __prev: *mut __pthread_internal_list,
- pub __next: *mut __pthread_internal_list,
-}
-impl Default for __pthread_internal_list {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub type __pthread_list_t = __pthread_internal_list;
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct __pthread_mutex_s {
- pub __lock: ::std::os::raw::c_int,
- pub __count: ::std::os::raw::c_uint,
- pub __owner: ::std::os::raw::c_int,
- pub __nusers: ::std::os::raw::c_uint,
- pub __kind: ::std::os::raw::c_int,
- pub __spins: ::std::os::raw::c_short,
- pub __elision: ::std::os::raw::c_short,
- pub __list: __pthread_list_t,
-}
-impl Default for __pthread_mutex_s {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct __pthread_cond_s {
- pub __bindgen_anon_1: __pthread_cond_s__bindgen_ty_1,
- pub __bindgen_anon_2: __pthread_cond_s__bindgen_ty_2,
- pub __g_refs: [::std::os::raw::c_uint; 2usize],
- pub __g_size: [::std::os::raw::c_uint; 2usize],
- pub __g1_orig_size: ::std::os::raw::c_uint,
- pub __wrefs: ::std::os::raw::c_uint,
- pub __g_signals: [::std::os::raw::c_uint; 2usize],
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union __pthread_cond_s__bindgen_ty_1 {
- pub __wseq: ::std::os::raw::c_ulonglong,
- pub __wseq32: __pthread_cond_s__bindgen_ty_1__bindgen_ty_1,
- _bindgen_union_align: u64,
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __pthread_cond_s__bindgen_ty_1__bindgen_ty_1 {
- pub __low: ::std::os::raw::c_uint,
- pub __high: ::std::os::raw::c_uint,
-}
-impl Default for __pthread_cond_s__bindgen_ty_1 {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union __pthread_cond_s__bindgen_ty_2 {
- pub __g1_start: ::std::os::raw::c_ulonglong,
- pub __g1_start32: __pthread_cond_s__bindgen_ty_2__bindgen_ty_1,
- _bindgen_union_align: u64,
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __pthread_cond_s__bindgen_ty_2__bindgen_ty_1 {
- pub __low: ::std::os::raw::c_uint,
- pub __high: ::std::os::raw::c_uint,
-}
-impl Default for __pthread_cond_s__bindgen_ty_2 {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-impl Default for __pthread_cond_s {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub type pthread_t = ::std::os::raw::c_ulong;
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_mutexattr_t {
- pub __size: [::std::os::raw::c_char; 4usize],
- pub __align: ::std::os::raw::c_int,
- _bindgen_union_align: u32,
-}
-impl Default for pthread_mutexattr_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_condattr_t {
- pub __size: [::std::os::raw::c_char; 4usize],
- pub __align: ::std::os::raw::c_int,
- _bindgen_union_align: u32,
-}
-impl Default for pthread_condattr_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub type pthread_key_t = ::std::os::raw::c_uint;
-pub type pthread_once_t = ::std::os::raw::c_int;
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_attr_t {
- pub __size: [::std::os::raw::c_char; 56usize],
- pub __align: ::std::os::raw::c_long,
- _bindgen_union_align: [u64; 7usize],
-}
-impl Default for pthread_attr_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_mutex_t {
- pub __data: __pthread_mutex_s,
- pub __size: [::std::os::raw::c_char; 40usize],
- pub __align: ::std::os::raw::c_long,
- _bindgen_union_align: [u64; 5usize],
-}
-impl Default for pthread_mutex_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_cond_t {
- pub __data: __pthread_cond_s,
- pub __size: [::std::os::raw::c_char; 48usize],
- pub __align: ::std::os::raw::c_longlong,
- _bindgen_union_align: [u64; 6usize],
-}
-impl Default for pthread_cond_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_rwlock_t {
- pub __data: __pthread_rwlock_arch_t,
- pub __size: [::std::os::raw::c_char; 56usize],
- pub __align: ::std::os::raw::c_long,
- _bindgen_union_align: [u64; 7usize],
-}
-impl Default for pthread_rwlock_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_rwlockattr_t {
- pub __size: [::std::os::raw::c_char; 8usize],
- pub __align: ::std::os::raw::c_long,
- _bindgen_union_align: u64,
-}
-impl Default for pthread_rwlockattr_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub type pthread_spinlock_t = ::std::os::raw::c_int;
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_barrier_t {
- pub __size: [::std::os::raw::c_char; 32usize],
- pub __align: ::std::os::raw::c_long,
- _bindgen_union_align: [u64; 4usize],
-}
-impl Default for pthread_barrier_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union pthread_barrierattr_t {
- pub __size: [::std::os::raw::c_char; 4usize],
- pub __align: ::std::os::raw::c_int,
- _bindgen_union_align: u32,
-}
-impl Default for pthread_barrierattr_t {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub type socklen_t = __socklen_t;
-pub const __socket_type_SOCK_STREAM: __socket_type = 1;
-pub const __socket_type_SOCK_DGRAM: __socket_type = 2;
-pub const __socket_type_SOCK_RAW: __socket_type = 3;
-pub const __socket_type_SOCK_RDM: __socket_type = 4;
-pub const __socket_type_SOCK_SEQPACKET: __socket_type = 5;
-pub const __socket_type_SOCK_DCCP: __socket_type = 6;
-pub const __socket_type_SOCK_PACKET: __socket_type = 10;
-pub const __socket_type_SOCK_CLOEXEC: __socket_type = 524288;
-pub const __socket_type_SOCK_NONBLOCK: __socket_type = 2048;
-pub type __socket_type = u32;
-pub type sa_family_t = ::std::os::raw::c_ushort;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct sockaddr {
- pub sa_family: sa_family_t,
- pub sa_data: [::std::os::raw::c_char; 14usize],
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct sockaddr_storage {
- pub ss_family: sa_family_t,
- pub __ss_padding: [::std::os::raw::c_char; 118usize],
- pub __ss_align: ::std::os::raw::c_ulong,
-}
-impl Default for sockaddr_storage {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub const MSG_OOB: _bindgen_ty_1 = 1;
-pub const MSG_PEEK: _bindgen_ty_1 = 2;
-pub const MSG_DONTROUTE: _bindgen_ty_1 = 4;
-pub const MSG_CTRUNC: _bindgen_ty_1 = 8;
-pub const MSG_PROXY: _bindgen_ty_1 = 16;
-pub const MSG_TRUNC: _bindgen_ty_1 = 32;
-pub const MSG_DONTWAIT: _bindgen_ty_1 = 64;
-pub const MSG_EOR: _bindgen_ty_1 = 128;
-pub const MSG_WAITALL: _bindgen_ty_1 = 256;
-pub const MSG_FIN: _bindgen_ty_1 = 512;
-pub const MSG_SYN: _bindgen_ty_1 = 1024;
-pub const MSG_CONFIRM: _bindgen_ty_1 = 2048;
-pub const MSG_RST: _bindgen_ty_1 = 4096;
-pub const MSG_ERRQUEUE: _bindgen_ty_1 = 8192;
-pub const MSG_NOSIGNAL: _bindgen_ty_1 = 16384;
-pub const MSG_MORE: _bindgen_ty_1 = 32768;
-pub const MSG_WAITFORONE: _bindgen_ty_1 = 65536;
-pub const MSG_BATCH: _bindgen_ty_1 = 262144;
-pub const MSG_ZEROCOPY: _bindgen_ty_1 = 67108864;
-pub const MSG_FASTOPEN: _bindgen_ty_1 = 536870912;
-pub const MSG_CMSG_CLOEXEC: _bindgen_ty_1 = 1073741824;
-pub type _bindgen_ty_1 = u32;
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct msghdr {
- pub msg_name: *mut ::std::os::raw::c_void,
- pub msg_namelen: socklen_t,
- pub msg_iov: *mut iovec,
- pub msg_iovlen: usize,
- pub msg_control: *mut ::std::os::raw::c_void,
- pub msg_controllen: usize,
- pub msg_flags: ::std::os::raw::c_int,
-}
-impl Default for msghdr {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Debug, Default)]
-pub struct cmsghdr {
- pub cmsg_len: usize,
- pub cmsg_level: ::std::os::raw::c_int,
- pub cmsg_type: ::std::os::raw::c_int,
- pub __cmsg_data: __IncompleteArrayField<::std::os::raw::c_uchar>,
-}
-extern "C" {
- pub fn __cmsg_nxthdr(__mhdr: *mut msghdr, __cmsg: *mut cmsghdr) -> *mut cmsghdr;
-}
-pub const SCM_RIGHTS: _bindgen_ty_2 = 1;
-pub type _bindgen_ty_2 = u32;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct linger {
- pub l_onoff: ::std::os::raw::c_int,
- pub l_linger: ::std::os::raw::c_int,
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct osockaddr {
- pub sa_family: ::std::os::raw::c_ushort,
- pub sa_data: [::std::os::raw::c_uchar; 14usize],
-}
-pub const SHUT_RD: _bindgen_ty_3 = 0;
-pub const SHUT_WR: _bindgen_ty_3 = 1;
-pub const SHUT_RDWR: _bindgen_ty_3 = 2;
-pub type _bindgen_ty_3 = u32;
-extern "C" {
- pub fn socket(
- __domain: ::std::os::raw::c_int,
- __type: ::std::os::raw::c_int,
- __protocol: ::std::os::raw::c_int,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn socketpair(
- __domain: ::std::os::raw::c_int,
- __type: ::std::os::raw::c_int,
- __protocol: ::std::os::raw::c_int,
- __fds: *mut ::std::os::raw::c_int,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn bind(
- __fd: ::std::os::raw::c_int,
- __addr: *const sockaddr,
- __len: socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn getsockname(
- __fd: ::std::os::raw::c_int,
- __addr: *mut sockaddr,
- __len: *mut socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn connect(
- __fd: ::std::os::raw::c_int,
- __addr: *const sockaddr,
- __len: socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn getpeername(
- __fd: ::std::os::raw::c_int,
- __addr: *mut sockaddr,
- __len: *mut socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn send(
- __fd: ::std::os::raw::c_int,
- __buf: *const ::std::os::raw::c_void,
- __n: usize,
- __flags: ::std::os::raw::c_int,
- ) -> isize;
-}
-extern "C" {
- pub fn recv(
- __fd: ::std::os::raw::c_int,
- __buf: *mut ::std::os::raw::c_void,
- __n: usize,
- __flags: ::std::os::raw::c_int,
- ) -> isize;
-}
-extern "C" {
- pub fn sendto(
- __fd: ::std::os::raw::c_int,
- __buf: *const ::std::os::raw::c_void,
- __n: usize,
- __flags: ::std::os::raw::c_int,
- __addr: *const sockaddr,
- __addr_len: socklen_t,
- ) -> isize;
-}
-extern "C" {
- pub fn recvfrom(
- __fd: ::std::os::raw::c_int,
- __buf: *mut ::std::os::raw::c_void,
- __n: usize,
- __flags: ::std::os::raw::c_int,
- __addr: *mut sockaddr,
- __addr_len: *mut socklen_t,
- ) -> isize;
-}
-extern "C" {
- pub fn sendmsg(
- __fd: ::std::os::raw::c_int,
- __message: *const msghdr,
- __flags: ::std::os::raw::c_int,
- ) -> isize;
-}
-extern "C" {
- pub fn recvmsg(
- __fd: ::std::os::raw::c_int,
- __message: *mut msghdr,
- __flags: ::std::os::raw::c_int,
- ) -> isize;
-}
-extern "C" {
- pub fn getsockopt(
- __fd: ::std::os::raw::c_int,
- __level: ::std::os::raw::c_int,
- __optname: ::std::os::raw::c_int,
- __optval: *mut ::std::os::raw::c_void,
- __optlen: *mut socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn setsockopt(
- __fd: ::std::os::raw::c_int,
- __level: ::std::os::raw::c_int,
- __optname: ::std::os::raw::c_int,
- __optval: *const ::std::os::raw::c_void,
- __optlen: socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn listen(__fd: ::std::os::raw::c_int, __n: ::std::os::raw::c_int)
- -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn accept(
- __fd: ::std::os::raw::c_int,
- __addr: *mut sockaddr,
- __addr_len: *mut socklen_t,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn shutdown(
- __fd: ::std::os::raw::c_int,
- __how: ::std::os::raw::c_int,
- ) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn sockatmark(__fd: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
-}
-extern "C" {
- pub fn isfdtype(
- __fd: ::std::os::raw::c_int,
- __fdtype: ::std::os::raw::c_int,
- ) -> ::std::os::raw::c_int;
-}
+use libc::sockaddr;
+
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct sync_serial_settings {
@@ -1114,37 +56,102 @@
pub interval: ::std::os::raw::c_uint,
pub timeout: ::std::os::raw::c_uint,
}
-pub const net_device_flags_IFF_UP: net_device_flags = 1;
-pub const net_device_flags_IFF_BROADCAST: net_device_flags = 2;
-pub const net_device_flags_IFF_DEBUG: net_device_flags = 4;
-pub const net_device_flags_IFF_LOOPBACK: net_device_flags = 8;
-pub const net_device_flags_IFF_POINTOPOINT: net_device_flags = 16;
-pub const net_device_flags_IFF_NOTRAILERS: net_device_flags = 32;
-pub const net_device_flags_IFF_RUNNING: net_device_flags = 64;
-pub const net_device_flags_IFF_NOARP: net_device_flags = 128;
-pub const net_device_flags_IFF_PROMISC: net_device_flags = 256;
-pub const net_device_flags_IFF_ALLMULTI: net_device_flags = 512;
-pub const net_device_flags_IFF_MASTER: net_device_flags = 1024;
-pub const net_device_flags_IFF_SLAVE: net_device_flags = 2048;
-pub const net_device_flags_IFF_MULTICAST: net_device_flags = 4096;
-pub const net_device_flags_IFF_PORTSEL: net_device_flags = 8192;
-pub const net_device_flags_IFF_AUTOMEDIA: net_device_flags = 16384;
-pub const net_device_flags_IFF_DYNAMIC: net_device_flags = 32768;
-pub const net_device_flags_IFF_LOWER_UP: net_device_flags = 65536;
-pub const net_device_flags_IFF_DORMANT: net_device_flags = 131072;
-pub const net_device_flags_IFF_ECHO: net_device_flags = 262144;
-pub type net_device_flags = u32;
-pub const IF_OPER_UNKNOWN: _bindgen_ty_4 = 0;
-pub const IF_OPER_NOTPRESENT: _bindgen_ty_4 = 1;
-pub const IF_OPER_DOWN: _bindgen_ty_4 = 2;
-pub const IF_OPER_LOWERLAYERDOWN: _bindgen_ty_4 = 3;
-pub const IF_OPER_TESTING: _bindgen_ty_4 = 4;
-pub const IF_OPER_DORMANT: _bindgen_ty_4 = 5;
-pub const IF_OPER_UP: _bindgen_ty_4 = 6;
-pub type _bindgen_ty_4 = u32;
-pub const IF_LINK_MODE_DEFAULT: _bindgen_ty_5 = 0;
-pub const IF_LINK_MODE_DORMANT: _bindgen_ty_5 = 1;
-pub type _bindgen_ty_5 = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct x25_hdlc_proto {
+ pub dce: ::std::os::raw::c_ushort,
+ pub modulo: ::std::os::raw::c_uint,
+ pub window: ::std::os::raw::c_uint,
+ pub t1: ::std::os::raw::c_uint,
+ pub t2: ::std::os::raw::c_uint,
+ pub n2: ::std::os::raw::c_uint,
+}
+impl net_device_flags {
+ pub const IFF_UP: net_device_flags = net_device_flags(1);
+}
+impl net_device_flags {
+ pub const IFF_BROADCAST: net_device_flags = net_device_flags(2);
+}
+impl net_device_flags {
+ pub const IFF_DEBUG: net_device_flags = net_device_flags(4);
+}
+impl net_device_flags {
+ pub const IFF_LOOPBACK: net_device_flags = net_device_flags(8);
+}
+impl net_device_flags {
+ pub const IFF_POINTOPOINT: net_device_flags = net_device_flags(16);
+}
+impl net_device_flags {
+ pub const IFF_NOTRAILERS: net_device_flags = net_device_flags(32);
+}
+impl net_device_flags {
+ pub const IFF_RUNNING: net_device_flags = net_device_flags(64);
+}
+impl net_device_flags {
+ pub const IFF_NOARP: net_device_flags = net_device_flags(128);
+}
+impl net_device_flags {
+ pub const IFF_PROMISC: net_device_flags = net_device_flags(256);
+}
+impl net_device_flags {
+ pub const IFF_ALLMULTI: net_device_flags = net_device_flags(512);
+}
+impl net_device_flags {
+ pub const IFF_MASTER: net_device_flags = net_device_flags(1024);
+}
+impl net_device_flags {
+ pub const IFF_SLAVE: net_device_flags = net_device_flags(2048);
+}
+impl net_device_flags {
+ pub const IFF_MULTICAST: net_device_flags = net_device_flags(4096);
+}
+impl net_device_flags {
+ pub const IFF_PORTSEL: net_device_flags = net_device_flags(8192);
+}
+impl net_device_flags {
+ pub const IFF_AUTOMEDIA: net_device_flags = net_device_flags(16384);
+}
+impl net_device_flags {
+ pub const IFF_DYNAMIC: net_device_flags = net_device_flags(32768);
+}
+impl net_device_flags {
+ pub const IFF_LOWER_UP: net_device_flags = net_device_flags(65536);
+}
+impl net_device_flags {
+ pub const IFF_DORMANT: net_device_flags = net_device_flags(131072);
+}
+impl net_device_flags {
+ pub const IFF_ECHO: net_device_flags = net_device_flags(262144);
+}
+impl ::std::ops::BitOr<net_device_flags> for net_device_flags {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, other: Self) -> Self {
+ net_device_flags(self.0 | other.0)
+ }
+}
+impl ::std::ops::BitOrAssign for net_device_flags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: net_device_flags) {
+ self.0 |= rhs.0;
+ }
+}
+impl ::std::ops::BitAnd<net_device_flags> for net_device_flags {
+ type Output = Self;
+ #[inline]
+ fn bitand(self, other: Self) -> Self {
+ net_device_flags(self.0 & other.0)
+ }
+}
+impl ::std::ops::BitAndAssign for net_device_flags {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: net_device_flags) {
+ self.0 &= rhs.0;
+ }
+}
+#[repr(transparent)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct net_device_flags(pub ::std::os::raw::c_uint);
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct ifmap {
@@ -1170,18 +177,26 @@
pub fr: *mut fr_proto,
pub fr_pvc: *mut fr_proto_pvc,
pub fr_pvc_info: *mut fr_proto_pvc_info,
+ pub x25: *mut x25_hdlc_proto,
pub sync: *mut sync_serial_settings,
pub te1: *mut te1_settings,
- _bindgen_union_align: u64,
}
impl Default for if_settings__bindgen_ty_1 {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
impl Default for if_settings {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
@@ -1194,11 +209,14 @@
#[derive(Copy, Clone)]
pub union ifreq__bindgen_ty_1 {
pub ifrn_name: [::std::os::raw::c_char; 16usize],
- _bindgen_union_align: [u8; 16usize],
}
impl Default for ifreq__bindgen_ty_1 {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
@@ -1217,38 +235,22 @@
pub ifru_newname: [::std::os::raw::c_char; 16usize],
pub ifru_data: *mut ::std::os::raw::c_void,
pub ifru_settings: if_settings,
- _bindgen_union_align: [u64; 3usize],
}
impl Default for ifreq__bindgen_ty_2 {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
impl Default for ifreq {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct ifconf {
- pub ifc_len: ::std::os::raw::c_int,
- pub ifc_ifcu: ifconf__bindgen_ty_1,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union ifconf__bindgen_ty_1 {
- pub ifcu_buf: *mut ::std::os::raw::c_char,
- pub ifcu_req: *mut ifreq,
- _bindgen_union_align: u64,
-}
-impl Default for ifconf__bindgen_ty_1 {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-impl Default for ifconf {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
diff --git a/net_sys/src/inn.rs b/net_sys/src/inn.rs
deleted file mode 100644
index f0b11d1..0000000
--- a/net_sys/src/inn.rs
+++ /dev/null
@@ -1,846 +0,0 @@
-// Copyright 2019 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.
-
-#![allow(warnings)]
-
-/* automatically generated by rust-bindgen */
-
-pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
-pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
-pub const __UAPI_DEF_IN_ADDR: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IN_IPPROTO: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IN_PKTINFO: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IP_MREQ: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_SOCKADDR_IN: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IN_CLASS: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IN6_ADDR: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IN6_ADDR_ALT: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_SOCKADDR_IN6: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IPV6_MREQ: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IPPROTO_V6: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IPV6_OPTIONS: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IN6_PKTINFO: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_IP6_MTUINFO: ::std::os::raw::c_uint = 1;
-pub const __UAPI_DEF_XATTR: ::std::os::raw::c_uint = 1;
-pub const _K_SS_MAXSIZE: ::std::os::raw::c_uint = 128;
-pub const IP_TOS: ::std::os::raw::c_uint = 1;
-pub const IP_TTL: ::std::os::raw::c_uint = 2;
-pub const IP_HDRINCL: ::std::os::raw::c_uint = 3;
-pub const IP_OPTIONS: ::std::os::raw::c_uint = 4;
-pub const IP_ROUTER_ALERT: ::std::os::raw::c_uint = 5;
-pub const IP_RECVOPTS: ::std::os::raw::c_uint = 6;
-pub const IP_RETOPTS: ::std::os::raw::c_uint = 7;
-pub const IP_PKTINFO: ::std::os::raw::c_uint = 8;
-pub const IP_PKTOPTIONS: ::std::os::raw::c_uint = 9;
-pub const IP_MTU_DISCOVER: ::std::os::raw::c_uint = 10;
-pub const IP_RECVERR: ::std::os::raw::c_uint = 11;
-pub const IP_RECVTTL: ::std::os::raw::c_uint = 12;
-pub const IP_RECVTOS: ::std::os::raw::c_uint = 13;
-pub const IP_MTU: ::std::os::raw::c_uint = 14;
-pub const IP_FREEBIND: ::std::os::raw::c_uint = 15;
-pub const IP_IPSEC_POLICY: ::std::os::raw::c_uint = 16;
-pub const IP_XFRM_POLICY: ::std::os::raw::c_uint = 17;
-pub const IP_PASSSEC: ::std::os::raw::c_uint = 18;
-pub const IP_TRANSPARENT: ::std::os::raw::c_uint = 19;
-pub const IP_RECVRETOPTS: ::std::os::raw::c_uint = 7;
-pub const IP_ORIGDSTADDR: ::std::os::raw::c_uint = 20;
-pub const IP_RECVORIGDSTADDR: ::std::os::raw::c_uint = 20;
-pub const IP_MINTTL: ::std::os::raw::c_uint = 21;
-pub const IP_NODEFRAG: ::std::os::raw::c_uint = 22;
-pub const IP_CHECKSUM: ::std::os::raw::c_uint = 23;
-pub const IP_BIND_ADDRESS_NO_PORT: ::std::os::raw::c_uint = 24;
-pub const IP_RECVFRAGSIZE: ::std::os::raw::c_uint = 25;
-pub const IP_PMTUDISC_DONT: ::std::os::raw::c_uint = 0;
-pub const IP_PMTUDISC_WANT: ::std::os::raw::c_uint = 1;
-pub const IP_PMTUDISC_DO: ::std::os::raw::c_uint = 2;
-pub const IP_PMTUDISC_PROBE: ::std::os::raw::c_uint = 3;
-pub const IP_PMTUDISC_INTERFACE: ::std::os::raw::c_uint = 4;
-pub const IP_PMTUDISC_OMIT: ::std::os::raw::c_uint = 5;
-pub const IP_MULTICAST_IF: ::std::os::raw::c_uint = 32;
-pub const IP_MULTICAST_TTL: ::std::os::raw::c_uint = 33;
-pub const IP_MULTICAST_LOOP: ::std::os::raw::c_uint = 34;
-pub const IP_ADD_MEMBERSHIP: ::std::os::raw::c_uint = 35;
-pub const IP_DROP_MEMBERSHIP: ::std::os::raw::c_uint = 36;
-pub const IP_UNBLOCK_SOURCE: ::std::os::raw::c_uint = 37;
-pub const IP_BLOCK_SOURCE: ::std::os::raw::c_uint = 38;
-pub const IP_ADD_SOURCE_MEMBERSHIP: ::std::os::raw::c_uint = 39;
-pub const IP_DROP_SOURCE_MEMBERSHIP: ::std::os::raw::c_uint = 40;
-pub const IP_MSFILTER: ::std::os::raw::c_uint = 41;
-pub const MCAST_JOIN_GROUP: ::std::os::raw::c_uint = 42;
-pub const MCAST_BLOCK_SOURCE: ::std::os::raw::c_uint = 43;
-pub const MCAST_UNBLOCK_SOURCE: ::std::os::raw::c_uint = 44;
-pub const MCAST_LEAVE_GROUP: ::std::os::raw::c_uint = 45;
-pub const MCAST_JOIN_SOURCE_GROUP: ::std::os::raw::c_uint = 46;
-pub const MCAST_LEAVE_SOURCE_GROUP: ::std::os::raw::c_uint = 47;
-pub const MCAST_MSFILTER: ::std::os::raw::c_uint = 48;
-pub const IP_MULTICAST_ALL: ::std::os::raw::c_uint = 49;
-pub const IP_UNICAST_IF: ::std::os::raw::c_uint = 50;
-pub const MCAST_EXCLUDE: ::std::os::raw::c_uint = 0;
-pub const MCAST_INCLUDE: ::std::os::raw::c_uint = 1;
-pub const IP_DEFAULT_MULTICAST_TTL: ::std::os::raw::c_uint = 1;
-pub const IP_DEFAULT_MULTICAST_LOOP: ::std::os::raw::c_uint = 1;
-pub const __SOCK_SIZE__: ::std::os::raw::c_uint = 16;
-pub const IN_CLASSA_NET: ::std::os::raw::c_uint = 4278190080;
-pub const IN_CLASSA_NSHIFT: ::std::os::raw::c_uint = 24;
-pub const IN_CLASSA_HOST: ::std::os::raw::c_uint = 16777215;
-pub const IN_CLASSA_MAX: ::std::os::raw::c_uint = 128;
-pub const IN_CLASSB_NET: ::std::os::raw::c_uint = 4294901760;
-pub const IN_CLASSB_NSHIFT: ::std::os::raw::c_uint = 16;
-pub const IN_CLASSB_HOST: ::std::os::raw::c_uint = 65535;
-pub const IN_CLASSB_MAX: ::std::os::raw::c_uint = 65536;
-pub const IN_CLASSC_NET: ::std::os::raw::c_uint = 4294967040;
-pub const IN_CLASSC_NSHIFT: ::std::os::raw::c_uint = 8;
-pub const IN_CLASSC_HOST: ::std::os::raw::c_uint = 255;
-pub const IN_MULTICAST_NET: ::std::os::raw::c_uint = 4026531840;
-pub const IN_LOOPBACKNET: ::std::os::raw::c_uint = 127;
-pub const INADDR_LOOPBACK: ::std::os::raw::c_uint = 2130706433;
-pub const INADDR_UNSPEC_GROUP: ::std::os::raw::c_uint = 3758096384;
-pub const INADDR_ALLHOSTS_GROUP: ::std::os::raw::c_uint = 3758096385;
-pub const INADDR_ALLRTRS_GROUP: ::std::os::raw::c_uint = 3758096386;
-pub const INADDR_MAX_LOCAL_GROUP: ::std::os::raw::c_uint = 3758096639;
-pub const __LITTLE_ENDIAN: ::std::os::raw::c_uint = 1234;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-#[test]
-#[ignore]
-fn bindgen_test_layout___kernel_fd_set() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fd_set>(),
- 128usize,
- concat!("Size of: ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fd_set>(),
- 8usize,
- concat!("Alignment of ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fd_set),
- "::",
- stringify!(fds_bits)
- )
- );
-}
-impl Clone for __kernel_fd_set {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-#[test]
-fn bindgen_test_layout___kernel_fsid_t() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fsid_t>(),
- 8usize,
- concat!("Size of: ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fsid_t>(),
- 4usize,
- concat!("Alignment of ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fsid_t),
- "::",
- stringify!(val)
- )
- );
-}
-impl Clone for __kernel_fsid_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
-pub type __kernel_sa_family_t = ::std::os::raw::c_ushort;
-#[repr(C)]
-pub struct __kernel_sockaddr_storage {
- pub ss_family: __kernel_sa_family_t,
- pub __data: [::std::os::raw::c_char; 126usize],
- pub __bindgen_align: [u64; 0usize],
-}
-#[test]
-fn bindgen_test_layout___kernel_sockaddr_storage() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_sockaddr_storage>(),
- 128usize,
- concat!("Size of: ", stringify!(__kernel_sockaddr_storage))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_sockaddr_storage>(),
- 8usize,
- concat!("Alignment of ", stringify!(__kernel_sockaddr_storage))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_sockaddr_storage)).ss_family as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_sockaddr_storage),
- "::",
- stringify!(ss_family)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_sockaddr_storage)).__data as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_sockaddr_storage),
- "::",
- stringify!(__data)
- )
- );
-}
-impl Default for __kernel_sockaddr_storage {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-pub const IPPROTO_IP: _bindgen_ty_1 = 0;
-pub const IPPROTO_ICMP: _bindgen_ty_1 = 1;
-pub const IPPROTO_IGMP: _bindgen_ty_1 = 2;
-pub const IPPROTO_IPIP: _bindgen_ty_1 = 4;
-pub const IPPROTO_TCP: _bindgen_ty_1 = 6;
-pub const IPPROTO_EGP: _bindgen_ty_1 = 8;
-pub const IPPROTO_PUP: _bindgen_ty_1 = 12;
-pub const IPPROTO_UDP: _bindgen_ty_1 = 17;
-pub const IPPROTO_IDP: _bindgen_ty_1 = 22;
-pub const IPPROTO_TP: _bindgen_ty_1 = 29;
-pub const IPPROTO_DCCP: _bindgen_ty_1 = 33;
-pub const IPPROTO_IPV6: _bindgen_ty_1 = 41;
-pub const IPPROTO_RSVP: _bindgen_ty_1 = 46;
-pub const IPPROTO_GRE: _bindgen_ty_1 = 47;
-pub const IPPROTO_ESP: _bindgen_ty_1 = 50;
-pub const IPPROTO_AH: _bindgen_ty_1 = 51;
-pub const IPPROTO_MTP: _bindgen_ty_1 = 92;
-pub const IPPROTO_BEETPH: _bindgen_ty_1 = 94;
-pub const IPPROTO_ENCAP: _bindgen_ty_1 = 98;
-pub const IPPROTO_PIM: _bindgen_ty_1 = 103;
-pub const IPPROTO_COMP: _bindgen_ty_1 = 108;
-pub const IPPROTO_SCTP: _bindgen_ty_1 = 132;
-pub const IPPROTO_UDPLITE: _bindgen_ty_1 = 136;
-pub const IPPROTO_MPLS: _bindgen_ty_1 = 137;
-pub const IPPROTO_RAW: _bindgen_ty_1 = 255;
-pub const IPPROTO_MAX: _bindgen_ty_1 = 256;
-pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct in_addr {
- pub s_addr: __be32,
-}
-#[test]
-fn bindgen_test_layout_in_addr() {
- assert_eq!(
- ::std::mem::size_of::<in_addr>(),
- 4usize,
- concat!("Size of: ", stringify!(in_addr))
- );
- assert_eq!(
- ::std::mem::align_of::<in_addr>(),
- 4usize,
- concat!("Alignment of ", stringify!(in_addr))
- );
- assert_eq!(
- unsafe { &(*(0 as *const in_addr)).s_addr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(in_addr),
- "::",
- stringify!(s_addr)
- )
- );
-}
-impl Clone for in_addr {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct ip_mreq {
- pub imr_multiaddr: in_addr,
- pub imr_interface: in_addr,
-}
-#[test]
-fn bindgen_test_layout_ip_mreq() {
- assert_eq!(
- ::std::mem::size_of::<ip_mreq>(),
- 8usize,
- concat!("Size of: ", stringify!(ip_mreq))
- );
- assert_eq!(
- ::std::mem::align_of::<ip_mreq>(),
- 4usize,
- concat!("Alignment of ", stringify!(ip_mreq))
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreq)).imr_multiaddr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreq),
- "::",
- stringify!(imr_multiaddr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreq)).imr_interface as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreq),
- "::",
- stringify!(imr_interface)
- )
- );
-}
-impl Clone for ip_mreq {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct ip_mreqn {
- pub imr_multiaddr: in_addr,
- pub imr_address: in_addr,
- pub imr_ifindex: ::std::os::raw::c_int,
-}
-#[test]
-fn bindgen_test_layout_ip_mreqn() {
- assert_eq!(
- ::std::mem::size_of::<ip_mreqn>(),
- 12usize,
- concat!("Size of: ", stringify!(ip_mreqn))
- );
- assert_eq!(
- ::std::mem::align_of::<ip_mreqn>(),
- 4usize,
- concat!("Alignment of ", stringify!(ip_mreqn))
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreqn)).imr_multiaddr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreqn),
- "::",
- stringify!(imr_multiaddr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreqn)).imr_address as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreqn),
- "::",
- stringify!(imr_address)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreqn)).imr_ifindex as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreqn),
- "::",
- stringify!(imr_ifindex)
- )
- );
-}
-impl Clone for ip_mreqn {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct ip_mreq_source {
- pub imr_multiaddr: __be32,
- pub imr_interface: __be32,
- pub imr_sourceaddr: __be32,
-}
-#[test]
-fn bindgen_test_layout_ip_mreq_source() {
- assert_eq!(
- ::std::mem::size_of::<ip_mreq_source>(),
- 12usize,
- concat!("Size of: ", stringify!(ip_mreq_source))
- );
- assert_eq!(
- ::std::mem::align_of::<ip_mreq_source>(),
- 4usize,
- concat!("Alignment of ", stringify!(ip_mreq_source))
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreq_source)).imr_multiaddr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreq_source),
- "::",
- stringify!(imr_multiaddr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreq_source)).imr_interface as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreq_source),
- "::",
- stringify!(imr_interface)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_mreq_source)).imr_sourceaddr as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_mreq_source),
- "::",
- stringify!(imr_sourceaddr)
- )
- );
-}
-impl Clone for ip_mreq_source {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct ip_msfilter {
- pub imsf_multiaddr: __be32,
- pub imsf_interface: __be32,
- pub imsf_fmode: __u32,
- pub imsf_numsrc: __u32,
- pub imsf_slist: [__be32; 1usize],
-}
-#[test]
-fn bindgen_test_layout_ip_msfilter() {
- assert_eq!(
- ::std::mem::size_of::<ip_msfilter>(),
- 20usize,
- concat!("Size of: ", stringify!(ip_msfilter))
- );
- assert_eq!(
- ::std::mem::align_of::<ip_msfilter>(),
- 4usize,
- concat!("Alignment of ", stringify!(ip_msfilter))
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_msfilter)).imsf_multiaddr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_msfilter),
- "::",
- stringify!(imsf_multiaddr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_msfilter)).imsf_interface as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_msfilter),
- "::",
- stringify!(imsf_interface)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_msfilter)).imsf_fmode as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_msfilter),
- "::",
- stringify!(imsf_fmode)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_msfilter)).imsf_numsrc as *const _ as usize },
- 12usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_msfilter),
- "::",
- stringify!(imsf_numsrc)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ip_msfilter)).imsf_slist as *const _ as usize },
- 16usize,
- concat!(
- "Alignment of field: ",
- stringify!(ip_msfilter),
- "::",
- stringify!(imsf_slist)
- )
- );
-}
-impl Clone for ip_msfilter {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-pub struct group_req {
- pub gr_interface: __u32,
- pub gr_group: __kernel_sockaddr_storage,
-}
-#[test]
-fn bindgen_test_layout_group_req() {
- assert_eq!(
- ::std::mem::size_of::<group_req>(),
- 136usize,
- concat!("Size of: ", stringify!(group_req))
- );
- assert_eq!(
- ::std::mem::align_of::<group_req>(),
- 8usize,
- concat!("Alignment of ", stringify!(group_req))
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_req)).gr_interface as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_req),
- "::",
- stringify!(gr_interface)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_req)).gr_group as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_req),
- "::",
- stringify!(gr_group)
- )
- );
-}
-impl Default for group_req {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-pub struct group_source_req {
- pub gsr_interface: __u32,
- pub gsr_group: __kernel_sockaddr_storage,
- pub gsr_source: __kernel_sockaddr_storage,
-}
-#[test]
-fn bindgen_test_layout_group_source_req() {
- assert_eq!(
- ::std::mem::size_of::<group_source_req>(),
- 264usize,
- concat!("Size of: ", stringify!(group_source_req))
- );
- assert_eq!(
- ::std::mem::align_of::<group_source_req>(),
- 8usize,
- concat!("Alignment of ", stringify!(group_source_req))
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_source_req)).gsr_interface as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_source_req),
- "::",
- stringify!(gsr_interface)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_source_req)).gsr_group as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_source_req),
- "::",
- stringify!(gsr_group)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_source_req)).gsr_source as *const _ as usize },
- 136usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_source_req),
- "::",
- stringify!(gsr_source)
- )
- );
-}
-impl Default for group_source_req {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-pub struct group_filter {
- pub gf_interface: __u32,
- pub gf_group: __kernel_sockaddr_storage,
- pub gf_fmode: __u32,
- pub gf_numsrc: __u32,
- pub gf_slist: [__kernel_sockaddr_storage; 1usize],
-}
-#[test]
-fn bindgen_test_layout_group_filter() {
- assert_eq!(
- ::std::mem::size_of::<group_filter>(),
- 272usize,
- concat!("Size of: ", stringify!(group_filter))
- );
- assert_eq!(
- ::std::mem::align_of::<group_filter>(),
- 8usize,
- concat!("Alignment of ", stringify!(group_filter))
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_filter)).gf_interface as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_filter),
- "::",
- stringify!(gf_interface)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_filter)).gf_group as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_filter),
- "::",
- stringify!(gf_group)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_filter)).gf_fmode as *const _ as usize },
- 136usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_filter),
- "::",
- stringify!(gf_fmode)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_filter)).gf_numsrc as *const _ as usize },
- 140usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_filter),
- "::",
- stringify!(gf_numsrc)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const group_filter)).gf_slist as *const _ as usize },
- 144usize,
- concat!(
- "Alignment of field: ",
- stringify!(group_filter),
- "::",
- stringify!(gf_slist)
- )
- );
-}
-impl Default for group_filter {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct in_pktinfo {
- pub ipi_ifindex: ::std::os::raw::c_int,
- pub ipi_spec_dst: in_addr,
- pub ipi_addr: in_addr,
-}
-#[test]
-fn bindgen_test_layout_in_pktinfo() {
- assert_eq!(
- ::std::mem::size_of::<in_pktinfo>(),
- 12usize,
- concat!("Size of: ", stringify!(in_pktinfo))
- );
- assert_eq!(
- ::std::mem::align_of::<in_pktinfo>(),
- 4usize,
- concat!("Alignment of ", stringify!(in_pktinfo))
- );
- assert_eq!(
- unsafe { &(*(0 as *const in_pktinfo)).ipi_ifindex as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(in_pktinfo),
- "::",
- stringify!(ipi_ifindex)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const in_pktinfo)).ipi_spec_dst as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(in_pktinfo),
- "::",
- stringify!(ipi_spec_dst)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const in_pktinfo)).ipi_addr as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(in_pktinfo),
- "::",
- stringify!(ipi_addr)
- )
- );
-}
-impl Clone for in_pktinfo {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct sockaddr_in {
- pub sin_family: __kernel_sa_family_t,
- pub sin_port: __be16,
- pub sin_addr: in_addr,
- pub __pad: [::std::os::raw::c_uchar; 8usize],
-}
-#[test]
-fn bindgen_test_layout_sockaddr_in() {
- assert_eq!(
- ::std::mem::size_of::<sockaddr_in>(),
- 16usize,
- concat!("Size of: ", stringify!(sockaddr_in))
- );
- assert_eq!(
- ::std::mem::align_of::<sockaddr_in>(),
- 4usize,
- concat!("Alignment of ", stringify!(sockaddr_in))
- );
- assert_eq!(
- unsafe { &(*(0 as *const sockaddr_in)).sin_family as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(sockaddr_in),
- "::",
- stringify!(sin_family)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sockaddr_in)).sin_port as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(sockaddr_in),
- "::",
- stringify!(sin_port)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sockaddr_in)).sin_addr as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(sockaddr_in),
- "::",
- stringify!(sin_addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const sockaddr_in)).__pad as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(sockaddr_in),
- "::",
- stringify!(__pad)
- )
- );
-}
-impl Clone for sockaddr_in {
- fn clone(&self) -> Self {
- *self
- }
-}
diff --git a/net_sys/src/lib.rs b/net_sys/src/lib.rs
index 1db9a6d..13515a1 100644
--- a/net_sys/src/lib.rs
+++ b/net_sys/src/lib.rs
@@ -8,34 +8,14 @@
use base::{ioctl_ior_nr, ioctl_iow_nr};
-// generated with bindgen /usr/include/linux/if.h --no-unstable-rust
-// --constified-enum '*' --with-derive-default -- -D __UAPI_DEF_IF_IFNAMSIZ -D
-// __UAPI_DEF_IF_NET_DEVICE_FLAGS -D __UAPI_DEF_IF_IFREQ -D __UAPI_DEF_IF_IFMAP
-// Name is "iff" to avoid conflicting with "if" keyword.
-// Generated against Linux 4.11 to include fix "uapi: fix linux/if.h userspace
-// compilation errors".
-// Manual fixup of ifrn_name to be of type c_uchar instead of c_char.
-#[allow(clippy::all)]
-pub mod iff;
-// generated with bindgen /usr/include/linux/if_tun.h --no-unstable-rust
-// --constified-enum '*' --with-derive-default
pub mod if_tun;
-// generated with bindgen /usr/include/linux/in.h --no-unstable-rust
-// --constified-enum '*' --with-derive-default
-// Name is "inn" to avoid conflicting with "in" keyword.
-pub mod inn;
-// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
-// --constified-enum '*' --with-derive-default
+pub mod iff; // Named "iff" to avoid conflicting with "if" keyword.
pub mod sockios;
-pub use crate::if_tun::*;
-pub use crate::iff::*;
-pub use crate::inn::*;
-pub use crate::sockios::*;
+pub use crate::if_tun::{sock_fprog, TUN_F_CSUM, TUN_F_TSO4, TUN_F_TSO6, TUN_F_TSO_ECN, TUN_F_UFO};
+pub use crate::iff::{ifreq, net_device_flags};
pub const TUNTAP: ::std::os::raw::c_uint = 84;
-pub const ARPHRD_ETHER: sa_family_t = 1;
-
ioctl_iow_nr!(TUNSETNOCSUM, TUNTAP, 200, ::std::os::raw::c_int);
ioctl_iow_nr!(TUNSETDEBUG, TUNTAP, 201, ::std::os::raw::c_int);
ioctl_iow_nr!(TUNSETIFF, TUNTAP, 202, ::std::os::raw::c_int);
diff --git a/net_sys/src/sockios.rs b/net_sys/src/sockios.rs
index 0c0af76..6207044 100644
--- a/net_sys/src/sockios.rs
+++ b/net_sys/src/sockios.rs
@@ -1,89 +1,88 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-/* automatically generated by rust-bindgen */
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
-pub const FIOSETOWN: ::std::os::raw::c_uint = 35073;
-pub const SIOCSPGRP: ::std::os::raw::c_uint = 35074;
-pub const FIOGETOWN: ::std::os::raw::c_uint = 35075;
-pub const SIOCGPGRP: ::std::os::raw::c_uint = 35076;
-pub const SIOCATMARK: ::std::os::raw::c_uint = 35077;
-pub const SIOCGSTAMP: ::std::os::raw::c_uint = 35078;
-pub const SIOCGSTAMPNS: ::std::os::raw::c_uint = 35079;
-pub const SOCK_IOC_TYPE: ::std::os::raw::c_uint = 137;
-pub const SIOCADDRT: ::std::os::raw::c_uint = 35083;
-pub const SIOCDELRT: ::std::os::raw::c_uint = 35084;
-pub const SIOCRTMSG: ::std::os::raw::c_uint = 35085;
-pub const SIOCGIFNAME: ::std::os::raw::c_uint = 35088;
-pub const SIOCSIFLINK: ::std::os::raw::c_uint = 35089;
-pub const SIOCGIFCONF: ::std::os::raw::c_uint = 35090;
-pub const SIOCGIFFLAGS: ::std::os::raw::c_uint = 35091;
-pub const SIOCSIFFLAGS: ::std::os::raw::c_uint = 35092;
-pub const SIOCGIFADDR: ::std::os::raw::c_uint = 35093;
-pub const SIOCSIFADDR: ::std::os::raw::c_uint = 35094;
-pub const SIOCGIFDSTADDR: ::std::os::raw::c_uint = 35095;
-pub const SIOCSIFDSTADDR: ::std::os::raw::c_uint = 35096;
-pub const SIOCGIFBRDADDR: ::std::os::raw::c_uint = 35097;
-pub const SIOCSIFBRDADDR: ::std::os::raw::c_uint = 35098;
-pub const SIOCGIFNETMASK: ::std::os::raw::c_uint = 35099;
-pub const SIOCSIFNETMASK: ::std::os::raw::c_uint = 35100;
-pub const SIOCGIFMETRIC: ::std::os::raw::c_uint = 35101;
-pub const SIOCSIFMETRIC: ::std::os::raw::c_uint = 35102;
-pub const SIOCGIFMEM: ::std::os::raw::c_uint = 35103;
-pub const SIOCSIFMEM: ::std::os::raw::c_uint = 35104;
-pub const SIOCGIFMTU: ::std::os::raw::c_uint = 35105;
-pub const SIOCSIFMTU: ::std::os::raw::c_uint = 35106;
-pub const SIOCSIFNAME: ::std::os::raw::c_uint = 35107;
-pub const SIOCSIFHWADDR: ::std::os::raw::c_uint = 35108;
-pub const SIOCGIFENCAP: ::std::os::raw::c_uint = 35109;
-pub const SIOCSIFENCAP: ::std::os::raw::c_uint = 35110;
-pub const SIOCGIFHWADDR: ::std::os::raw::c_uint = 35111;
-pub const SIOCGIFSLAVE: ::std::os::raw::c_uint = 35113;
-pub const SIOCSIFSLAVE: ::std::os::raw::c_uint = 35120;
-pub const SIOCADDMULTI: ::std::os::raw::c_uint = 35121;
-pub const SIOCDELMULTI: ::std::os::raw::c_uint = 35122;
-pub const SIOCGIFINDEX: ::std::os::raw::c_uint = 35123;
-pub const SIOGIFINDEX: ::std::os::raw::c_uint = 35123;
-pub const SIOCSIFPFLAGS: ::std::os::raw::c_uint = 35124;
-pub const SIOCGIFPFLAGS: ::std::os::raw::c_uint = 35125;
-pub const SIOCDIFADDR: ::std::os::raw::c_uint = 35126;
-pub const SIOCSIFHWBROADCAST: ::std::os::raw::c_uint = 35127;
-pub const SIOCGIFCOUNT: ::std::os::raw::c_uint = 35128;
-pub const SIOCGIFBR: ::std::os::raw::c_uint = 35136;
-pub const SIOCSIFBR: ::std::os::raw::c_uint = 35137;
-pub const SIOCGIFTXQLEN: ::std::os::raw::c_uint = 35138;
-pub const SIOCSIFTXQLEN: ::std::os::raw::c_uint = 35139;
-pub const SIOCETHTOOL: ::std::os::raw::c_uint = 35142;
-pub const SIOCGMIIPHY: ::std::os::raw::c_uint = 35143;
-pub const SIOCGMIIREG: ::std::os::raw::c_uint = 35144;
-pub const SIOCSMIIREG: ::std::os::raw::c_uint = 35145;
-pub const SIOCWANDEV: ::std::os::raw::c_uint = 35146;
-pub const SIOCOUTQNSD: ::std::os::raw::c_uint = 35147;
-pub const SIOCGSKNS: ::std::os::raw::c_uint = 35148;
-pub const SIOCDARP: ::std::os::raw::c_uint = 35155;
-pub const SIOCGARP: ::std::os::raw::c_uint = 35156;
-pub const SIOCSARP: ::std::os::raw::c_uint = 35157;
-pub const SIOCDRARP: ::std::os::raw::c_uint = 35168;
-pub const SIOCGRARP: ::std::os::raw::c_uint = 35169;
-pub const SIOCSRARP: ::std::os::raw::c_uint = 35170;
-pub const SIOCGIFMAP: ::std::os::raw::c_uint = 35184;
-pub const SIOCSIFMAP: ::std::os::raw::c_uint = 35185;
-pub const SIOCADDDLCI: ::std::os::raw::c_uint = 35200;
-pub const SIOCDELDLCI: ::std::os::raw::c_uint = 35201;
-pub const SIOCGIFVLAN: ::std::os::raw::c_uint = 35202;
-pub const SIOCSIFVLAN: ::std::os::raw::c_uint = 35203;
-pub const SIOCBONDENSLAVE: ::std::os::raw::c_uint = 35216;
-pub const SIOCBONDRELEASE: ::std::os::raw::c_uint = 35217;
-pub const SIOCBONDSETHWADDR: ::std::os::raw::c_uint = 35218;
-pub const SIOCBONDSLAVEINFOQUERY: ::std::os::raw::c_uint = 35219;
-pub const SIOCBONDINFOQUERY: ::std::os::raw::c_uint = 35220;
-pub const SIOCBONDCHANGEACTIVE: ::std::os::raw::c_uint = 35221;
-pub const SIOCBRADDBR: ::std::os::raw::c_uint = 35232;
-pub const SIOCBRDELBR: ::std::os::raw::c_uint = 35233;
-pub const SIOCBRADDIF: ::std::os::raw::c_uint = 35234;
-pub const SIOCBRDELIF: ::std::os::raw::c_uint = 35235;
-pub const SIOCSHWTSTAMP: ::std::os::raw::c_uint = 35248;
-pub const SIOCGHWTSTAMP: ::std::os::raw::c_uint = 35249;
-pub const SIOCDEVPRIVATE: ::std::os::raw::c_uint = 35312;
-pub const SIOCPROTOPRIVATE: ::std::os::raw::c_uint = 35296;
+pub const SIOCSPGRP: u32 = 35074;
+pub const SIOCGPGRP: u32 = 35076;
+pub const SIOCATMARK: u32 = 35077;
+pub const SIOCGSTAMP_OLD: u32 = 35078;
+pub const SIOCGSTAMPNS_OLD: u32 = 35079;
+pub const SIOCGSTAMP: u32 = 35078;
+pub const SIOCGSTAMPNS: u32 = 35079;
+pub const SIOCADDRT: u32 = 35083;
+pub const SIOCDELRT: u32 = 35084;
+pub const SIOCRTMSG: u32 = 35085;
+pub const SIOCGIFNAME: u32 = 35088;
+pub const SIOCSIFLINK: u32 = 35089;
+pub const SIOCGIFCONF: u32 = 35090;
+pub const SIOCGIFFLAGS: u32 = 35091;
+pub const SIOCSIFFLAGS: u32 = 35092;
+pub const SIOCGIFADDR: u32 = 35093;
+pub const SIOCSIFADDR: u32 = 35094;
+pub const SIOCGIFDSTADDR: u32 = 35095;
+pub const SIOCSIFDSTADDR: u32 = 35096;
+pub const SIOCGIFBRDADDR: u32 = 35097;
+pub const SIOCSIFBRDADDR: u32 = 35098;
+pub const SIOCGIFNETMASK: u32 = 35099;
+pub const SIOCSIFNETMASK: u32 = 35100;
+pub const SIOCGIFMETRIC: u32 = 35101;
+pub const SIOCSIFMETRIC: u32 = 35102;
+pub const SIOCGIFMEM: u32 = 35103;
+pub const SIOCSIFMEM: u32 = 35104;
+pub const SIOCGIFMTU: u32 = 35105;
+pub const SIOCSIFMTU: u32 = 35106;
+pub const SIOCSIFNAME: u32 = 35107;
+pub const SIOCSIFHWADDR: u32 = 35108;
+pub const SIOCGIFENCAP: u32 = 35109;
+pub const SIOCSIFENCAP: u32 = 35110;
+pub const SIOCGIFHWADDR: u32 = 35111;
+pub const SIOCGIFSLAVE: u32 = 35113;
+pub const SIOCSIFSLAVE: u32 = 35120;
+pub const SIOCADDMULTI: u32 = 35121;
+pub const SIOCDELMULTI: u32 = 35122;
+pub const SIOCGIFINDEX: u32 = 35123;
+pub const SIOCSIFPFLAGS: u32 = 35124;
+pub const SIOCGIFPFLAGS: u32 = 35125;
+pub const SIOCDIFADDR: u32 = 35126;
+pub const SIOCSIFHWBROADCAST: u32 = 35127;
+pub const SIOCGIFCOUNT: u32 = 35128;
+pub const SIOCGIFBR: u32 = 35136;
+pub const SIOCSIFBR: u32 = 35137;
+pub const SIOCGIFTXQLEN: u32 = 35138;
+pub const SIOCSIFTXQLEN: u32 = 35139;
+pub const SIOCETHTOOL: u32 = 35142;
+pub const SIOCGMIIPHY: u32 = 35143;
+pub const SIOCGMIIREG: u32 = 35144;
+pub const SIOCSMIIREG: u32 = 35145;
+pub const SIOCWANDEV: u32 = 35146;
+pub const SIOCOUTQNSD: u32 = 35147;
+pub const SIOCGSKNS: u32 = 35148;
+pub const SIOCDARP: u32 = 35155;
+pub const SIOCGARP: u32 = 35156;
+pub const SIOCSARP: u32 = 35157;
+pub const SIOCDRARP: u32 = 35168;
+pub const SIOCGRARP: u32 = 35169;
+pub const SIOCSRARP: u32 = 35170;
+pub const SIOCGIFMAP: u32 = 35184;
+pub const SIOCSIFMAP: u32 = 35185;
+pub const SIOCADDDLCI: u32 = 35200;
+pub const SIOCDELDLCI: u32 = 35201;
+pub const SIOCGIFVLAN: u32 = 35202;
+pub const SIOCSIFVLAN: u32 = 35203;
+pub const SIOCBONDENSLAVE: u32 = 35216;
+pub const SIOCBONDRELEASE: u32 = 35217;
+pub const SIOCBONDSETHWADDR: u32 = 35218;
+pub const SIOCBONDSLAVEINFOQUERY: u32 = 35219;
+pub const SIOCBONDINFOQUERY: u32 = 35220;
+pub const SIOCBONDCHANGEACTIVE: u32 = 35221;
+pub const SIOCBRADDBR: u32 = 35232;
+pub const SIOCBRDELBR: u32 = 35233;
+pub const SIOCBRADDIF: u32 = 35234;
+pub const SIOCBRDELIF: u32 = 35235;
+pub const SIOCSHWTSTAMP: u32 = 35248;
+pub const SIOCGHWTSTAMP: u32 = 35249;
+pub const SIOCDEVPRIVATE: u32 = 35312;
+pub const SIOCPROTOPRIVATE: u32 = 35296;
diff --git a/net_util/src/lib.rs b/net_util/src/lib.rs
index 217ef30..42e4658 100644
--- a/net_util/src/lib.rs
+++ b/net_util/src/lib.rs
@@ -59,25 +59,25 @@
/// Create a sockaddr_in from an IPv4 address, and expose it as
/// an opaque sockaddr suitable for usage by socket ioctls.
-fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_sys::sockaddr {
+fn create_sockaddr(ip_addr: net::Ipv4Addr) -> libc::sockaddr {
// IPv4 addresses big-endian (network order), but Ipv4Addr will give us
// a view of those bytes directly so we can avoid any endian trickiness.
- let addr_in = net_sys::sockaddr_in {
- sin_family: net_sys::AF_INET as u16,
+ let addr_in = libc::sockaddr_in {
+ sin_family: libc::AF_INET as u16,
sin_port: 0,
sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
- __pad: [0; 8usize],
+ sin_zero: [0; 8usize],
};
unsafe { mem::transmute(addr_in) }
}
/// Extract the IPv4 address from a sockaddr. Assumes the sockaddr is a sockaddr_in.
-fn read_ipv4_addr(addr: &net_sys::sockaddr) -> net::Ipv4Addr {
- debug_assert_eq!(addr.sa_family as u32, net_sys::AF_INET);
+fn read_ipv4_addr(addr: &libc::sockaddr) -> net::Ipv4Addr {
+ debug_assert_eq!(addr.sa_family as libc::c_int, libc::AF_INET);
// This is safe because sockaddr and sockaddr_in are the same size, and we've checked that
// this address is AF_INET.
- let in_addr: net_sys::sockaddr_in = unsafe { mem::transmute(*addr) };
+ let in_addr: libc::sockaddr_in = unsafe { mem::transmute(*addr) };
net::Ipv4Addr::from(in_addr.sin_addr.s_addr)
}
@@ -107,7 +107,7 @@
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MacAddress {
- family: net_sys::sa_family_t,
+ family: libc::sa_family_t,
addr: [u8; 6usize],
__pad: [u8; 8usize],
}
@@ -128,7 +128,7 @@
}
let mut result = MacAddress {
- family: net_sys::ARPHRD_ETHER,
+ family: libc::ARPHRD_ETHER,
addr: [0; 6usize],
__pad: [0; 8usize],
};
@@ -165,24 +165,6 @@
}
impl Tap {
- pub unsafe fn from_raw_descriptor(fd: RawDescriptor) -> Result<Tap> {
- let tap_file = File::from_raw_descriptor(fd);
-
- // Get the interface name since we will need it for some ioctls.
- let mut ifreq: net_sys::ifreq = Default::default();
- let ret = ioctl_with_mut_ref(&tap_file, net_sys::TUNGETIFF(), &mut ifreq);
-
- if ret < 0 {
- return Err(Error::IoctlError(SysError::last()));
- }
-
- Ok(Tap {
- tap_file,
- if_name: ifreq.ifr_ifrn.ifrn_name,
- if_flags: ifreq.ifr_ifru.ifru_flags,
- })
- }
-
pub fn create_tap_with_ifreq(ifreq: &mut net_sys::ifreq) -> Result<Tap> {
// Open calls are safe because we give a constant nul-terminated
// string and verify the result.
@@ -218,18 +200,6 @@
if_flags: unsafe { ifreq.ifr_ifru.ifru_flags },
})
}
-
- pub fn try_clone(&self) -> Result<Tap> {
- self.tap_file
- .try_clone()
- .map(|tap_file| Tap {
- tap_file,
- if_name: self.if_name,
- if_flags: self.if_flags,
- })
- .map_err(SysError::from)
- .map_err(Error::CloneTap)
- }
}
pub trait TapT: FileReadWriteVolatile + Read + Write + AsRawDescriptor + Send + Sized {
@@ -292,7 +262,13 @@
fn get_ifreq(&self) -> net_sys::ifreq;
/// Get the interface flags
- fn if_flags(&self) -> u32;
+ fn if_flags(&self) -> i32;
+
+ /// Try to clone
+ fn try_clone(&self) -> Result<Self>;
+
+ /// Convert raw descriptor to TapT.
+ unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Result<Self>;
}
impl TapT for Tap {
@@ -310,12 +286,11 @@
{
*dst = *src as c_char;
}
- ifreq.ifr_ifru.ifru_flags = (net_sys::IFF_TAP
- | net_sys::IFF_NO_PI
- | if vnet_hdr { net_sys::IFF_VNET_HDR } else { 0 })
- as c_short;
+ ifreq.ifr_ifru.ifru_flags =
+ (libc::IFF_TAP | libc::IFF_NO_PI | if vnet_hdr { libc::IFF_VNET_HDR } else { 0 })
+ as c_short;
if multi_vq {
- ifreq.ifr_ifru.ifru_flags |= net_sys::IFF_MULTI_QUEUE as c_short;
+ ifreq.ifr_ifru.ifru_flags |= libc::IFF_MULTI_QUEUE as c_short;
}
}
@@ -510,7 +485,7 @@
let mut ifreq = self.get_ifreq();
ifreq.ifr_ifru.ifru_flags =
- (net_sys::net_device_flags_IFF_UP | net_sys::net_device_flags_IFF_RUNNING) as i16;
+ (net_sys::net_device_flags::IFF_UP | net_sys::net_device_flags::IFF_RUNNING).0 as i16;
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
@@ -549,8 +524,40 @@
ifreq
}
- fn if_flags(&self) -> u32 {
- self.if_flags as u32
+ fn if_flags(&self) -> i32 {
+ self.if_flags.into()
+ }
+
+ fn try_clone(&self) -> Result<Tap> {
+ self.tap_file
+ .try_clone()
+ .map(|tap_file| Tap {
+ tap_file,
+ if_name: self.if_name,
+ if_flags: self.if_flags,
+ })
+ .map_err(SysError::from)
+ .map_err(Error::CloneTap)
+ }
+
+ /// # Safety: fd is a valid FD and ownership of it is transferred when
+ /// calling this function.
+ unsafe fn from_raw_descriptor(fd: RawDescriptor) -> Result<Tap> {
+ let tap_file = File::from_raw_descriptor(fd);
+
+ // Get the interface name since we will need it for some ioctls.
+ let mut ifreq: net_sys::ifreq = Default::default();
+ let ret = ioctl_with_mut_ref(&tap_file, net_sys::TUNGETIFF(), &mut ifreq);
+
+ if ret < 0 {
+ return Err(Error::IoctlError(SysError::last()));
+ }
+
+ Ok(Tap {
+ tap_file,
+ if_name: ifreq.ifr_ifrn.ifrn_name,
+ if_flags: ifreq.ifr_ifru.ifru_flags,
+ })
}
}
@@ -662,8 +669,17 @@
ifreq
}
- fn if_flags(&self) -> u32 {
- net_sys::IFF_TAP
+ fn if_flags(&self) -> i32 {
+ libc::IFF_TAP
+ }
+
+ fn try_clone(&self) -> Result<Self> {
+ unimplemented!()
+ }
+
+ /// # Safety: panics on call / does nothing.
+ unsafe fn from_raw_descriptor(_descriptor: RawDescriptor) -> Result<Self> {
+ unimplemented!()
}
}
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index df65a13..574f4e7 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -12,7 +12,7 @@
pub use crate::system_allocator::{MemRegion, MmioType, SystemAllocator, SystemAllocatorConfig};
-mod address_allocator;
+pub mod address_allocator;
mod system_allocator;
/// Used to tag SystemAllocator allocations.
@@ -36,6 +36,8 @@
PciBridgePrefetchWindow { bus: u8, dev: u8, func: u8 },
/// File-backed memory mapping.
FileBacked(u64),
+ /// virtio vhost user queue with queue id
+ VvuQueue(u8),
}
#[sorted]
diff --git a/rutabaga_gfx/src/cross_domain/cross_domain.rs b/rutabaga_gfx/src/cross_domain/cross_domain.rs
index 909ba2c..08d3403 100644
--- a/rutabaga_gfx/src/cross_domain/cross_domain.rs
+++ b/rutabaga_gfx/src/cross_domain/cross_domain.rs
@@ -277,7 +277,7 @@
fn receive_msg(
&self,
- opaque_data: &mut Vec<u8>,
+ opaque_data: &mut [u8],
descriptors: &mut [i32; CROSS_DOMAIN_MAX_IDENTIFIERS],
) -> RutabagaResult<(usize, Vec<File>)> {
// If any errors happen, the socket will get dropped, preventing more reading.
@@ -320,7 +320,7 @@
&mut self,
fence: RutabagaFence,
resample_evt: &Event,
- receive_buf: &mut Vec<u8>,
+ receive_buf: &mut [u8],
) -> RutabagaResult<bool> {
let events = self.wait_ctx.wait()?;
let mut stop_thread = false;
diff --git a/rutabaga_gfx/src/gfxstream.rs b/rutabaga_gfx/src/gfxstream.rs
index 8d20efc..47d5cce 100644
--- a/rutabaga_gfx/src/gfxstream.rs
+++ b/rutabaga_gfx/src/gfxstream.rs
@@ -8,12 +8,10 @@
#![cfg(feature = "gfxstream")]
-use std::cell::RefCell;
use std::convert::TryInto;
use std::mem::{size_of, transmute};
use std::os::raw::{c_char, c_int, c_uint, c_void};
use std::ptr::{null, null_mut};
-use std::rc::Rc;
use std::sync::Arc;
use base::{
@@ -31,12 +29,35 @@
use data_model::VolatileSlice;
+#[repr(C)]
+pub struct VirglRendererGlCtxParam {
+ pub version: c_int,
+ pub shared: bool,
+ pub major_ver: c_int,
+ pub minor_ver: c_int,
+}
+
// In gfxstream, only write_fence is used (for synchronization of commands delivered)
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct GfxstreamRendererCallbacks {
+pub struct VirglRendererCallbacks {
pub version: c_int,
pub write_fence: unsafe extern "C" fn(cookie: *mut c_void, fence: u32),
+ pub create_gl_context: Option<
+ unsafe extern "C" fn(
+ cookie: *mut c_void,
+ scanout_idx: c_int,
+ param: *mut VirglRendererGlCtxParam,
+ ) -> *mut c_void,
+ >,
+ pub destroy_gl_context: Option<unsafe extern "C" fn(cookie: *mut c_void, ctx: *mut c_void)>,
+ pub make_current: Option<
+ unsafe extern "C" fn(cookie: *mut c_void, scanout_idx: c_int, ctx: *mut c_void) -> c_int,
+ >,
+
+ pub get_drm_fd: Option<unsafe extern "C" fn(cookie: *mut c_void) -> c_int>,
+ pub write_context_fence:
+ unsafe extern "C" fn(cookie: *mut c_void, fence_id: u64, ctx_id: u32, ring_idx: u8),
}
#[repr(C)]
@@ -60,7 +81,7 @@
display_type: u32,
renderer_cookie: *mut c_void,
renderer_flags: i32,
- renderer_callbacks: *mut GfxstreamRendererCallbacks,
+ renderer_callbacks: *mut VirglRendererCallbacks,
gfxstream_callbacks: *mut c_void,
);
@@ -70,7 +91,6 @@
// forwarding and the notification of new API calls forwarded by the guest, unless they
// correspond to minigbm resource targets (PIPE_TEXTURE_2D), in which case they create globally
// visible shared GL textures to support gralloc.
- fn pipe_virgl_renderer_poll();
fn pipe_virgl_renderer_resource_create(
args: *mut virgl_renderer_resource_create_args,
iov: *mut iovec,
@@ -138,13 +158,11 @@
) -> c_int;
fn stream_renderer_resource_unmap(res_handle: u32) -> c_int;
fn stream_renderer_resource_map_info(res_handle: u32, map_info: *mut u32) -> c_int;
+ fn stream_renderer_context_create_fence(fence_id: u64, ctx_id: u32, ring_idx: u8) -> c_int;
}
/// The virtio-gpu backend state tracker which supports accelerated rendering.
-pub struct Gfxstream {
- fence_state: Rc<RefCell<FenceState>>,
- fence_handler: RutabagaFenceHandler,
-}
+pub struct Gfxstream;
struct GfxstreamContext {
ctx_id: u32,
@@ -193,6 +211,15 @@
fn component_type(&self) -> RutabagaComponentType {
RutabagaComponentType::Gfxstream
}
+
+ fn context_create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()> {
+ // Safe becase only integers are given to gfxstream, not memory.
+ let ret = unsafe {
+ stream_renderer_context_create_fence(fence.fence_id, fence.ctx_id, fence.ring_idx)
+ };
+
+ ret_to_res(ret)
+ }
}
impl Drop for GfxstreamContext {
@@ -204,9 +231,14 @@
}
}
-const GFXSTREAM_RENDERER_CALLBACKS: &GfxstreamRendererCallbacks = &GfxstreamRendererCallbacks {
- version: 1,
+const GFXSTREAM_RENDERER_CALLBACKS: &VirglRendererCallbacks = &VirglRendererCallbacks {
+ version: 3,
write_fence,
+ create_gl_context: None,
+ destroy_gl_context: None,
+ make_current: None,
+ get_drm_fd: None,
+ write_context_fence,
};
fn map_func(resource_id: u32) -> ExternalMappingResult<(u64, usize)> {
@@ -233,14 +265,9 @@
gfxstream_flags: GfxstreamFlags,
fence_handler: RutabagaFenceHandler,
) -> RutabagaResult<Box<dyn RutabagaComponent>> {
- let fence_state = Rc::new(RefCell::new(FenceState {
- latest_fence: 0,
- handler: None,
- }));
-
let cookie: *mut VirglCookie = Box::into_raw(Box::new(VirglCookie {
- fence_state: Rc::clone(&fence_state),
render_server_fd: None,
+ fence_handler: Some(fence_handler),
}));
unsafe {
@@ -255,10 +282,7 @@
);
}
- Ok(Box::new(Gfxstream {
- fence_state,
- fence_handler,
- }))
+ Ok(Box::new(Gfxstream))
}
fn map_info(&self, resource_id: u32) -> RutabagaResult<u32> {
@@ -297,15 +321,8 @@
fn create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()> {
let ret = unsafe { pipe_virgl_renderer_create_fence(fence.fence_id as i32, fence.ctx_id) };
- // This can be moved to the cookie once gfxstream directly calls the
- // write_fence callback in pipe_virgl_renderer_create_fence
- self.fence_handler.call(fence);
- ret_to_res(ret)
- }
- fn poll(&self) -> u32 {
- unsafe { pipe_virgl_renderer_poll() };
- self.fence_state.borrow().latest_fence
+ ret_to_res(ret)
}
fn create_3d(
diff --git a/rutabaga_gfx/src/renderer_utils.rs b/rutabaga_gfx/src/renderer_utils.rs
index 3cac704..ecb4acf 100644
--- a/rutabaga_gfx/src/renderer_utils.rs
+++ b/rutabaga_gfx/src/renderer_utils.rs
@@ -4,9 +4,9 @@
//! renderer_utils: Utility functions and structs used by virgl_renderer and gfxstream.
-use std::cell::RefCell;
use std::os::raw::{c_int, c_void};
-use std::rc::Rc;
+use std::panic::catch_unwind;
+use std::process::abort;
use base::{IntoRawDescriptor, SafeDescriptor};
@@ -14,6 +14,9 @@
RutabagaError, RutabagaFence, RutabagaFenceHandler, RutabagaResult, RUTABAGA_FLAG_FENCE,
};
+#[cfg(feature = "gfxstream")]
+use crate::rutabaga_utils::RUTABAGA_FLAG_INFO_RING_IDX;
+
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct VirglBox {
@@ -32,54 +35,69 @@
}
}
-pub struct FenceState {
- pub latest_fence: u32,
- pub handler: Option<RutabagaFenceHandler>,
-}
-
-impl FenceState {
- pub fn write(&mut self, latest_fence: u32) {
- if latest_fence > self.latest_fence {
- self.latest_fence = latest_fence;
- if let Some(handler) = &self.handler {
- handler.call(RutabagaFence {
- flags: RUTABAGA_FLAG_FENCE,
- fence_id: latest_fence as u64,
- ctx_id: 0,
- ring_idx: 0,
- });
- }
- }
- }
-}
-
pub struct VirglCookie {
- pub fence_state: Rc<RefCell<FenceState>>,
pub render_server_fd: Option<SafeDescriptor>,
+ pub fence_handler: Option<RutabagaFenceHandler>,
}
pub unsafe extern "C" fn write_fence(cookie: *mut c_void, fence: u32) {
- assert!(!cookie.is_null());
- let cookie = &*(cookie as *mut VirglCookie);
+ catch_unwind(|| {
+ assert!(!cookie.is_null());
+ let cookie = &*(cookie as *mut VirglCookie);
- // Track the most recent fence.
- let mut fence_state = cookie.fence_state.borrow_mut();
- fence_state.write(fence);
+ // Call fence completion callback
+ if let Some(handler) = &cookie.fence_handler {
+ handler.call(RutabagaFence {
+ flags: RUTABAGA_FLAG_FENCE,
+ fence_id: fence as u64,
+ ctx_id: 0,
+ ring_idx: 0,
+ });
+ }
+ })
+ .unwrap_or_else(|_| abort())
+}
+
+#[cfg(feature = "gfxstream")]
+pub extern "C" fn write_context_fence(
+ cookie: *mut c_void,
+ fence_id: u64,
+ ctx_id: u32,
+ ring_idx: u8,
+) {
+ catch_unwind(|| {
+ assert!(!cookie.is_null());
+ let cookie = unsafe { &*(cookie as *mut VirglCookie) };
+
+ // Call fence completion callback
+ if let Some(handler) = &cookie.fence_handler {
+ handler.call(RutabagaFence {
+ flags: RUTABAGA_FLAG_FENCE | RUTABAGA_FLAG_INFO_RING_IDX,
+ fence_id,
+ ctx_id,
+ ring_idx,
+ });
+ }
+ })
+ .unwrap_or_else(|_| abort())
}
#[allow(dead_code)]
pub unsafe extern "C" fn get_server_fd(cookie: *mut c_void, version: u32) -> c_int {
- assert!(!cookie.is_null());
- let cookie = &mut *(cookie as *mut VirglCookie);
+ catch_unwind(|| {
+ assert!(!cookie.is_null());
+ let cookie = &mut *(cookie as *mut VirglCookie);
- if version != 0 {
- return -1;
- }
+ if version != 0 {
+ return -1;
+ }
- // Transfer the fd ownership to virglrenderer.
- cookie
- .render_server_fd
- .take()
- .map(SafeDescriptor::into_raw_descriptor)
- .unwrap_or(-1)
+ // Transfer the fd ownership to virglrenderer.
+ cookie
+ .render_server_fd
+ .take()
+ .map(SafeDescriptor::into_raw_descriptor)
+ .unwrap_or(-1)
+ })
+ .unwrap_or_else(|_| abort())
}
diff --git a/rutabaga_gfx/src/rutabaga_2d.rs b/rutabaga_gfx/src/rutabaga_2d.rs
index 579b339..a4956f1 100644
--- a/rutabaga_gfx/src/rutabaga_2d.rs
+++ b/rutabaga_gfx/src/rutabaga_2d.rs
@@ -133,30 +133,21 @@
}
pub struct Rutabaga2D {
- latest_created_fence_id: u32,
fence_handler: RutabagaFenceHandler,
}
impl Rutabaga2D {
pub fn init(fence_handler: RutabagaFenceHandler) -> RutabagaResult<Box<dyn RutabagaComponent>> {
- Ok(Box::new(Rutabaga2D {
- latest_created_fence_id: 0,
- fence_handler,
- }))
+ Ok(Box::new(Rutabaga2D { fence_handler }))
}
}
impl RutabagaComponent for Rutabaga2D {
fn create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()> {
- self.latest_created_fence_id = fence.fence_id as u32;
self.fence_handler.call(fence);
Ok(())
}
- fn poll(&self) -> u32 {
- self.latest_created_fence_id
- }
-
fn create_3d(
&self,
resource_id: u32,
diff --git a/rutabaga_gfx/src/rutabaga_core.rs b/rutabaga_gfx/src/rutabaga_core.rs
index 3231815..8729a80 100644
--- a/rutabaga_gfx/src/rutabaga_core.rs
+++ b/rutabaga_gfx/src/rutabaga_core.rs
@@ -71,9 +71,13 @@
Err(RutabagaError::Unsupported)
}
- /// Implementations must return the last completed fence_id.
- fn poll(&self) -> u32 {
- 0
+ /// Used only by VirglRenderer to poll when its poll_descriptor is signaled.
+ fn poll(&self) {}
+
+ /// Used only by VirglRenderer to return a poll_descriptor that is signaled when a poll() is
+ /// necessary.
+ fn poll_descriptor(&self) -> Option<SafeDescriptor> {
+ None
}
/// Implementations must create a resource with the given metadata. For 2D rutabaga components,
@@ -183,17 +187,11 @@
fn detach(&mut self, _resource: &RutabagaResource);
/// Implementations must create a fence on specified `ring_idx` in `fence`. This
- /// allows for multiple syncrhonizations timelines per RutabagaContext.
+ /// allows for multiple synchronizations timelines per RutabagaContext.
fn context_create_fence(&mut self, _fence: RutabagaFence) -> RutabagaResult<()> {
Err(RutabagaError::Unsupported)
}
- /// Implementations must return an array of fences that have completed. This will be used by
- /// the cross-domain context for asynchronous Tx/Rx.
- fn context_poll(&mut self) -> Option<Vec<RutabagaFence>> {
- None
- }
-
/// Implementations must return the component type associated with the context.
fn component_type(&self) -> RutabagaComponentType;
}
@@ -303,32 +301,19 @@
Ok(())
}
- /// Polls all rutabaga components and contexts, and returns a vector of RutabagaFence
- /// describing which fences have completed.
- pub fn poll(&mut self) -> Vec<RutabagaFence> {
- let mut completed_fences: Vec<RutabagaFence> = Vec::new();
- // Poll the default component -- this the global timeline which does not take into account
- // `ctx_id` or `ring_idx`. This path exists for OpenGL legacy reasons and 2D mode.
- let component = self
- .components
- .get_mut(&self.default_component)
- .ok_or(0)
- .unwrap();
-
- let global_fence_id = component.poll();
- completed_fences.push(RutabagaFence {
- flags: RUTABAGA_FLAG_FENCE,
- fence_id: global_fence_id as u64,
- ctx_id: 0,
- ring_idx: 0,
- });
-
- for ctx in self.contexts.values_mut() {
- if let Some(ref mut ctx_completed_fences) = ctx.context_poll() {
- completed_fences.append(ctx_completed_fences);
- }
+ /// Polls the default rutabaga component. In practice, only called if the default component is
+ /// virglrenderer.
+ pub fn poll(&self) {
+ if let Some(component) = self.components.get(&self.default_component) {
+ component.poll();
}
- completed_fences
+ }
+
+ /// Returns a pollable descriptor for the default rutabaga component. In practice, it is only
+ /// not None if the default component is virglrenderer.
+ pub fn poll_descriptor(&self) -> Option<SafeDescriptor> {
+ let component = self.components.get(&self.default_component).or(None)?;
+ component.poll_descriptor()
}
/// Creates a resource with the `resource_create_3d` metadata.
diff --git a/rutabaga_gfx/src/rutabaga_utils.rs b/rutabaga_gfx/src/rutabaga_utils.rs
index ff5374d..04f7b48 100644
--- a/rutabaga_gfx/src/rutabaga_utils.rs
+++ b/rutabaga_gfx/src/rutabaga_utils.rs
@@ -396,6 +396,7 @@
const GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT: u32 = 1 << 5;
const GFXSTREAM_RENDERER_FLAGS_NO_SYNCFD_BIT: u32 = 1 << 20;
const GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE: u32 = 1 << 21;
+const GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB: u32 = 1 << 23;
/// gfxstream flag struct.
#[derive(Copy, Clone, Default)]
@@ -449,6 +450,11 @@
pub fn use_guest_angle(self, v: bool) -> GfxstreamFlags {
self.set_flag(GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE, v)
}
+
+ /// Use async fence completion callback.
+ pub fn use_async_fence_cb(self, v: bool) -> GfxstreamFlags {
+ self.set_flag(GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB, v)
+ }
}
impl From<GfxstreamFlags> for i32 {
@@ -510,7 +516,7 @@
}
/// Enumeration of possible rutabaga components.
-#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum RutabagaComponentType {
Rutabaga2D,
VirglRenderer,
diff --git a/rutabaga_gfx/src/virgl_renderer.rs b/rutabaga_gfx/src/virgl_renderer.rs
index bac8dec..5bd7a66 100644
--- a/rutabaga_gfx/src/virgl_renderer.rs
+++ b/rutabaga_gfx/src/virgl_renderer.rs
@@ -7,12 +7,14 @@
#![cfg(feature = "virgl_renderer")]
-use std::cell::RefCell;
use std::cmp::min;
+use std::convert::TryFrom;
use std::mem::{size_of, transmute};
use std::os::raw::{c_char, c_void};
+use std::os::unix::io::AsRawFd;
+use std::panic::catch_unwind;
+use std::process::abort;
use std::ptr::null_mut;
-use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
@@ -32,11 +34,7 @@
type Query = virgl_renderer_export_query;
/// The virtio-gpu backend state tracker which supports accelerated rendering.
-pub struct VirglRenderer {
- // Cookie must be kept alive until VirglRenderer is dropped.
- _cookie: Box<VirglCookie>,
- fence_state: Rc<RefCell<FenceState>>,
-}
+pub struct VirglRenderer;
struct VirglRendererContext {
ctx_id: u32,
@@ -79,6 +77,18 @@
fn component_type(&self) -> RutabagaComponentType {
RutabagaComponentType::VirglRenderer
}
+
+ fn context_create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()> {
+ let ret = unsafe {
+ virgl_renderer_context_create_fence(
+ fence.ctx_id,
+ fence.flags,
+ fence.ring_idx as u64,
+ fence.fence_id as *mut ::std::os::raw::c_void,
+ )
+ };
+ ret_to_res(ret)
+ }
}
impl Drop for VirglRendererContext {
@@ -117,6 +127,35 @@
}
}
+/// Virglrenderer's vtest renderer currently expects an opaque "void *fence_cookie" rather than a
+/// bare "u64 fence_id", so we cannot use the common implementation from renderer_utils yet.
+///
+/// TODO(ryanneph): re-evaluate if vtest can be modified so this can be unified with
+/// write_context_fence() from renderer_utils before promoting to cfg(feature = "virgl_renderer").
+#[cfg(feature = "virgl_renderer_next")]
+extern "C" fn write_context_fence(
+ cookie: *mut c_void,
+ ctx_id: u32,
+ ring_idx: u64,
+ fence_cookie: *mut c_void,
+) {
+ catch_unwind(|| {
+ assert!(!cookie.is_null());
+ let cookie = unsafe { &*(cookie as *mut VirglCookie) };
+
+ // Call fence completion callback
+ if let Some(handler) = &cookie.fence_handler {
+ handler.call(RutabagaFence {
+ flags: RUTABAGA_FLAG_FENCE | RUTABAGA_FLAG_INFO_RING_IDX,
+ fence_id: fence_cookie as u64,
+ ctx_id,
+ ring_idx: ring_idx as u8,
+ });
+ }
+ })
+ .unwrap_or_else(|_| abort())
+}
+
const VIRGL_RENDERER_CALLBACKS: &virgl_renderer_callbacks = &virgl_renderer_callbacks {
#[cfg(not(feature = "virgl_renderer_next"))]
version: 1,
@@ -127,7 +166,10 @@
destroy_gl_context: None,
make_current: None,
get_drm_fd: None,
+ #[cfg(not(feature = "virgl_renderer_next"))]
write_context_fence: None,
+ #[cfg(feature = "virgl_renderer_next")]
+ write_context_fence: Some(write_context_fence),
#[cfg(not(feature = "virgl_renderer_next"))]
get_server_fd: None,
#[cfg(feature = "virgl_renderer_next")]
@@ -210,15 +252,14 @@
return Err(RutabagaError::AlreadyInUse);
}
- let fence_state = Rc::new(RefCell::new(FenceState {
- latest_fence: 0,
- handler: Some(fence_handler),
- }));
-
- let mut cookie = Box::new(VirglCookie {
- fence_state: Rc::clone(&fence_state),
+ // Cookie is intentionally never freed because virglrenderer never gets uninitialized.
+ // Otherwise, Resource and Context would become invalid because their lifetime is not tied
+ // to the Renderer instance. Doing so greatly simplifies the ownership for users of this
+ // library.
+ let cookie: *mut VirglCookie = Box::into_raw(Box::new(VirglCookie {
render_server_fd,
- });
+ fence_handler: Some(fence_handler),
+ }));
#[cfg(any(target_arch = "arm", target_arch = "x86", target_arch = "x86_64"))]
unsafe {
@@ -229,17 +270,14 @@
// error.
let ret = unsafe {
virgl_renderer_init(
- &mut *cookie as *mut _ as *mut c_void,
+ cookie as *mut c_void,
virglrenderer_flags.into(),
transmute(VIRGL_RENDERER_CALLBACKS),
)
};
ret_to_res(ret)?;
- Ok(Box::new(VirglRenderer {
- _cookie: cookie,
- fence_state,
- }))
+ Ok(Box::new(VirglRenderer))
}
#[allow(unused_variables)]
@@ -352,9 +390,19 @@
ret_to_res(ret)
}
- fn poll(&self) -> u32 {
+ fn poll(&self) {
unsafe { virgl_renderer_poll() };
- self.fence_state.borrow().latest_fence
+ }
+
+ fn poll_descriptor(&self) -> Option<SafeDescriptor> {
+ // Safe because it can be called anytime and returns -1 in the event of an error.
+ let fd = unsafe { virgl_renderer_get_poll_fd() };
+ if fd >= 0 {
+ if let Ok(dup_fd) = SafeDescriptor::try_from(&fd as &dyn AsRawFd) {
+ return Some(dup_fd);
+ }
+ }
+ None
}
fn create_3d(
diff --git a/src/argument.rs b/src/argument.rs
index e659391..a825822 100644
--- a/src/argument.rs
+++ b/src/argument.rs
@@ -445,14 +445,30 @@
)))
}
+ fn get_numeric<T>(&self, val: &str) -> Result<T>
+ where
+ T: TryFrom<u64>,
+ <T as TryFrom<u64>>::Error: std::error::Error,
+ {
+ let num = parse_hex_or_decimal(val)?;
+ self.handle_parse_err(T::try_from(num))
+ }
+
pub fn parse_numeric<T>(&self) -> Result<T>
where
T: TryFrom<u64>,
<T as TryFrom<u64>>::Error: std::error::Error,
{
let val = self.value()?;
- let num = parse_hex_or_decimal(val)?;
- self.handle_parse_err(T::try_from(num))
+ self.get_numeric(val)
+ }
+
+ pub fn key_numeric<T>(&self) -> Result<T>
+ where
+ T: TryFrom<u64>,
+ <T as TryFrom<u64>>::Error: std::error::Error,
+ {
+ self.get_numeric(self.key())
}
pub fn parse<T>(&self) -> Result<T>
@@ -726,4 +742,19 @@
assert!(parse_hex_or_decimal("0xz").is_err());
assert!(parse_hex_or_decimal("hello world").is_err());
}
+
+ #[test]
+ fn parse_key_value_options_numeric_key() {
+ let mut opts = parse_key_value_options("test", "0x30,0x100=value,nonnumeric=value", ',');
+ let kv = opts.next().unwrap();
+ assert_eq!(kv.key_numeric::<u32>().unwrap(), 0x30);
+
+ let kv = opts.next().unwrap();
+ assert_eq!(kv.key_numeric::<u32>().unwrap(), 0x100);
+ assert_eq!(kv.value().unwrap(), "value");
+
+ let kv = opts.next().unwrap();
+ assert!(kv.key_numeric::<u32>().is_err());
+ assert_eq!(kv.key(), "nonnumeric");
+ }
}
diff --git a/src/crosvm.rs b/src/crosvm.rs
index 1cc77f3..c79ef01 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -13,7 +13,7 @@
#[cfg(feature = "plugin")]
pub mod plugin;
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, BTreeSet};
use std::net;
use std::ops::RangeInclusive;
use std::os::unix::io::RawFd;
@@ -21,7 +21,6 @@
use std::str::FromStr;
use arch::{Pstore, VcpuAffinity};
-use base::RawDescriptor;
use devices::serial_device::{SerialHardware, SerialParameters};
use devices::virtio::block::block::DiskOption;
#[cfg(feature = "audio_cras")]
@@ -29,6 +28,7 @@
use devices::virtio::fs::passthrough;
#[cfg(feature = "gpu")]
use devices::virtio::gpu::GpuParameters;
+use devices::virtio::vhost::vsock::VhostVsockDeviceParameter;
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
use devices::virtio::VideoBackendType;
#[cfg(feature = "audio")]
@@ -44,7 +44,6 @@
use vm_control::BatteryType;
static KVM_PATH: &str = "/dev/kvm";
-static VHOST_VSOCK_PATH: &str = "/dev/vhost-vsock";
static VHOST_NET_PATH: &str = "/dev/vhost-net";
static SECCOMP_POLICY_DIR: &str = "/usr/share/policy/crosvm";
@@ -272,7 +271,7 @@
fn validate_params(kind: &str, value: &str) -> Result<(), argument::Error> {
match kind {
"guest-address" => {
- if value.eq_ignore_ascii_case("auto") || PciAddress::from_string(value).is_ok() {
+ if value.eq_ignore_ascii_case("auto") || PciAddress::from_str(value).is_ok() {
Ok(())
} else {
Err(argument::Error::InvalidValue {
@@ -307,7 +306,7 @@
pub fn guest_address(&self) -> Option<PciAddress> {
self.params
.get("guest-address")
- .and_then(|addr| PciAddress::from_string(addr).ok())
+ .and_then(|addr| PciAddress::from_str(addr).ok())
}
pub fn iommu_dev_type(&self) -> IommuDevType {
@@ -320,17 +319,6 @@
}
}
-pub enum VhostVsockDeviceParameter {
- Path(PathBuf),
- Fd(RawDescriptor),
-}
-
-impl Default for VhostVsockDeviceParameter {
- fn default() -> Self {
- VhostVsockDeviceParameter::Path(PathBuf::from(VHOST_VSOCK_PATH))
- }
-}
-
#[derive(Debug)]
pub struct FileBackedMappingParameters {
pub address: u64,
@@ -347,6 +335,23 @@
pub hp_gpe: Option<u32>,
}
+#[derive(Debug)]
+pub struct JailConfig {
+ pub pivot_root: PathBuf,
+ pub seccomp_policy_dir: PathBuf,
+ pub seccomp_log_failures: bool,
+}
+
+impl Default for JailConfig {
+ fn default() -> Self {
+ JailConfig {
+ pivot_root: PathBuf::from(option_env!("DEFAULT_PIVOT_ROOT").unwrap_or("/var/empty")),
+ seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
+ seccomp_log_failures: false,
+ }
+ }
+}
+
/// Aggregate of all configurable options for a running VM.
pub struct Config {
pub kvm_device_path: PathBuf,
@@ -370,6 +375,8 @@
pub executable_path: Option<Executable>,
pub android_fstab: Option<PathBuf>,
pub initrd_path: Option<PathBuf>,
+ pub jail_config: Option<JailConfig>,
+ pub jail_enabled: bool,
pub params: Vec<String>,
pub socket_path: Option<PathBuf>,
pub balloon_control: Option<PathBuf>,
@@ -390,9 +397,6 @@
pub wayland_socket_paths: BTreeMap<String, PathBuf>,
pub x_display: Option<String>,
pub shared_dirs: Vec<SharedDir>,
- pub sandbox: bool,
- pub seccomp_policy_dir: PathBuf,
- pub seccomp_log_failures: bool,
#[cfg(feature = "gpu")]
pub gpu_parameters: Option<GpuParameters>,
#[cfg(feature = "gpu")]
@@ -447,6 +451,8 @@
#[cfg(feature = "direct")]
pub direct_edge_irq: Vec<u32>,
#[cfg(feature = "direct")]
+ pub direct_wake_irq: Vec<u32>,
+ #[cfg(feature = "direct")]
pub direct_gpe: Vec<u32>,
pub dmi_path: Option<PathBuf>,
pub no_legacy: bool,
@@ -460,10 +466,12 @@
#[cfg(feature = "direct")]
pub pcie_rp: Vec<HostPcieRootPortParameters>,
pub rng: bool,
- pub pivot_root: Option<PathBuf>,
pub force_s2idle: bool,
pub strict_balloon: bool,
pub mmio_address_ranges: Vec<RangeInclusive<u64>>,
+ pub userspace_msr: BTreeSet<u32>,
+ #[cfg(target_os = "android")]
+ pub task_profiles: Vec<String>,
}
impl Default for Config {
@@ -490,6 +498,12 @@
executable_path: None,
android_fstab: None,
initrd_path: None,
+ // We initialize the jail configuration with a default value so jail-related options can
+ // apply irrespective of whether jail is enabled or not. `jail_config` will then be
+ // assigned `None` if it turns out that `jail_enabled` is `false` after we parse all the
+ // arguments.
+ jail_config: Some(Default::default()),
+ jail_enabled: !cfg!(feature = "default-no-sandbox"),
params: Vec::new(),
socket_path: None,
balloon_control: None,
@@ -517,9 +531,6 @@
display_window_keyboard: false,
display_window_mouse: false,
shared_dirs: Vec::new(),
- sandbox: !cfg!(feature = "default-no-sandbox"),
- seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
- seccomp_log_failures: false,
#[cfg(feature = "audio")]
ac97_parameters: Vec::new(),
#[cfg(feature = "audio")]
@@ -568,6 +579,8 @@
#[cfg(feature = "direct")]
direct_edge_irq: Vec::new(),
#[cfg(feature = "direct")]
+ direct_wake_irq: Vec::new(),
+ #[cfg(feature = "direct")]
direct_gpe: Vec::new(),
dmi_path: None,
no_legacy: false,
@@ -580,10 +593,12 @@
#[cfg(feature = "direct")]
pcie_rp: Vec::new(),
rng: true,
- pivot_root: None,
force_s2idle: false,
strict_balloon: false,
mmio_address_ranges: Vec::new(),
+ userspace_msr: BTreeSet::new(),
+ #[cfg(target_os = "android")]
+ task_profiles: Vec::new(),
}
}
}
diff --git a/src/linux/android.rs b/src/linux/android.rs
new file mode 100644
index 0000000..dd61c75
--- /dev/null
+++ b/src/linux/android.rs
@@ -0,0 +1,53 @@
+// Copyright 2022 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.
+
+#![cfg(target_os = "android")]
+
+use anyhow::{anyhow, Result};
+use libc;
+use std::ffi::{CStr, CString};
+
+// #[link(name = "processgroup")]
+// extern "C" {
+// fn android_set_process_profiles(
+// uid: libc::uid_t,
+// pid: libc::pid_t,
+// num_profiles: libc::size_t,
+// profiles: *const *const libc::c_char,
+// ) -> bool;
+// }
+
+// ANDROID PATCH: The real android_set_process_profiles implementation isn't available to link
+// against yet, so it is replaced with a stub.
+unsafe fn android_set_process_profiles(
+ uid: libc::uid_t,
+ pid: libc::pid_t,
+ num_profiles: libc::size_t,
+ profiles: *const *const libc::c_char,
+) -> bool {
+ return true;
+}
+
+
+// Apply the listed task profiles to all tasks (current and future) in this process.
+pub fn set_process_profiles(profiles: &Vec<String>) -> Result<()> {
+ if (profiles.is_empty()) {
+ return Ok(());
+ }
+ let owned: Vec<CString> = profiles
+ .iter()
+ .map(|s| CString::new(s.clone()).unwrap())
+ .collect();
+ let ptrs: Vec<*const libc::c_char> = owned.iter().map(|s| s.as_ptr()).collect();
+ // SAFETY: the ownership of the array of string is not passed. The function copies it
+ // internally.
+ unsafe {
+ if (android_set_process_profiles(libc::getuid(), libc::getpid(), ptrs.len(), ptrs.as_ptr()))
+ {
+ Ok(())
+ } else {
+ Err(anyhow!("failed to set task profiles"))
+ }
+ }
+}
diff --git a/src/linux/device_helpers.rs b/src/linux/device_helpers.rs
index 7539195..cb402d3 100644
--- a/src/linux/device_helpers.rs
+++ b/src/linux/device_helpers.rs
@@ -8,14 +8,14 @@
use std::net::Ipv4Addr;
use std::ops::RangeInclusive;
use std::os::unix::net::UnixListener;
-use std::os::unix::{io::FromRawFd, net::UnixStream, prelude::OpenOptionsExt};
+use std::os::unix::{net::UnixStream, prelude::OpenOptionsExt};
use std::path::{Path, PathBuf};
use std::str;
use std::sync::Arc;
use crate::{
Config, DiskOption, TouchDeviceOption, VhostUserFsOption, VhostUserOption, VhostUserWlOption,
- VhostVsockDeviceParameter, VvuOption,
+ VvuOption,
};
use anyhow::{anyhow, bail, Context, Result};
use arch::{self, VirtioDeviceStub};
@@ -35,16 +35,19 @@
Mac80211Hwsim as VhostUserMac80211Hwsim, Net as VhostUserNet, Vsock as VhostUserVsock,
Wl as VhostUserWl,
};
+use devices::virtio::vhost::vsock::VhostVsockConfig;
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
use devices::virtio::VideoBackendType;
use devices::virtio::{self, BalloonMode, Console, VirtioDevice};
use devices::IommuDevType;
+#[cfg(feature = "tpm")]
+use devices::SoftwareTpm;
use devices::{
self, BusDeviceObj, PciAddress, PciDevice, VfioDevice, VfioPciDevice, VfioPlatformDevice,
};
use hypervisor::Vm;
use minijail::{self, Minijail};
-use net_util::{MacAddress, Tap};
+use net_util::{MacAddress, Tap, TapT};
use resources::{Alloc, MmioType, SystemAllocator};
use sync::Mutex;
use vm_memory::GuestAddress;
@@ -160,7 +163,7 @@
Ok(VirtioDeviceStub {
dev,
- jail: simple_jail(cfg, "block_device")?,
+ jail: simple_jail(&cfg.jail_config, "block_device")?,
})
}
@@ -227,7 +230,12 @@
})
}
-pub fn create_vvu_proxy_device(cfg: &Config, opt: &VvuOption, tube: Tube) -> DeviceResult {
+pub fn create_vvu_proxy_device(
+ cfg: &Config,
+ opt: &VvuOption,
+ tube: Tube,
+ max_sibling_mem_size: u64,
+) -> DeviceResult {
let listener = UnixListener::bind(&opt.socket).map_err(|e| {
error!("failed to bind listener for vvu proxy device: {}", e);
e
@@ -239,12 +247,13 @@
tube,
opt.addr,
opt.uuid,
+ max_sibling_mem_size,
)
.context("failed to create VVU proxy device")?;
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "vvu_proxy_device")?,
+ jail: simple_jail(&cfg.jail_config, "vvu_proxy_device")?,
})
}
@@ -254,7 +263,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "rng_device")?,
+ jail: simple_jail(&cfg.jail_config, "rng_device")?,
})
}
@@ -266,7 +275,7 @@
)
.context("failed to create cras sound device")?;
- let jail = match simple_jail(&cfg, "cras_snd_device")? {
+ let jail = match simple_jail(&cfg.jail_config, "cras_snd_device")? {
Some(mut jail) => {
// Create a tmpfs in the device's root directory for cras_snd_device.
// The size is 20*1024, or 20 KB.
@@ -295,13 +304,13 @@
}
#[cfg(feature = "tpm")]
-pub fn create_tpm_device(cfg: &Config) -> DeviceResult {
+pub fn create_software_tpm_device(cfg: &Config) -> DeviceResult {
use std::ffi::CString;
use std::fs;
use std::process;
let tpm_storage: PathBuf;
- let mut tpm_jail = simple_jail(cfg, "tpm_device")?;
+ let mut tpm_jail = simple_jail(&cfg.jail_config, "tpm_device")?;
match &mut tpm_jail {
Some(jail) => {
@@ -335,7 +344,8 @@
}
}
- let dev = virtio::Tpm::new(tpm_storage);
+ let backend = SoftwareTpm::new(tpm_storage).context("failed to create SoftwareTpm")?;
+ let dev = virtio::Tpm::new(Arc::new(Mutex::new(backend)));
Ok(VirtioDeviceStub {
dev: Box::new(dev),
@@ -367,7 +377,7 @@
.context("failed to set up input device")?;
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -396,7 +406,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -422,7 +432,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -441,7 +451,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -460,7 +470,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -479,7 +489,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -495,7 +505,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
})
}
@@ -520,7 +530,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "balloon_device")?,
+ jail: simple_jail(&cfg.jail_config, "balloon_device")?,
})
}
@@ -544,7 +554,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev) as Box<dyn VirtioDevice>,
- jail: simple_jail(cfg, policy)?,
+ jail: simple_jail(&cfg.jail_config, policy)?,
})
}
@@ -660,7 +670,7 @@
)
.context("failed to create wayland device")?;
- let jail = match simple_jail(cfg, "wl_device")? {
+ let jail = match simple_jail(&cfg.jail_config, "wl_device")? {
Some(mut jail) => {
// Create a tmpfs in the device's root directory so that we can bind mount the wayland
// socket directory into it. The size=67108864 is size=64*1024*1024 or size=64MB.
@@ -699,7 +709,7 @@
typ: devices::virtio::VideoDeviceType,
resource_bridge: Tube,
) -> DeviceResult {
- let jail = match simple_jail(cfg, "video_device")? {
+ let jail = match simple_jail(&cfg.jail_config, "video_device")? {
Some(mut jail) => {
match typ {
#[cfg(feature = "video-decoder")]
@@ -780,35 +790,15 @@
Ok(())
}
-pub fn create_vhost_vsock_device(cfg: &Config, cid: u64) -> DeviceResult {
+pub fn create_vhost_vsock_device(cfg: &Config, vhost_config: &VhostVsockConfig) -> DeviceResult {
let features = virtio::base_features(cfg.protected_vm);
- let device_file = match cfg
- .vhost_vsock_device
- .as_ref()
- .unwrap_or(&VhostVsockDeviceParameter::default())
- {
- VhostVsockDeviceParameter::Fd(fd) => {
- let fd = validate_raw_descriptor(*fd)
- .context("failed to validate fd for virtual socket device")?;
- // Safe because the `fd` is actually owned by this process and
- // we have a unique handle to it.
- unsafe { File::from_raw_fd(fd) }
- }
- VhostVsockDeviceParameter::Path(path) => OpenOptions::new()
- .read(true)
- .write(true)
- .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
- .open(path)
- .context("failed to open virtual socket device")?,
- };
-
- let dev = virtio::vhost::Vsock::new(device_file, features, cid)
+ let dev = virtio::vhost::Vsock::new(features, vhost_config)
.context("failed to set up virtual socket device")?;
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "vhost_vsock_device")?,
+ jail: simple_jail(&cfg.jail_config, "vhost_vsock_device")?,
})
}
@@ -823,13 +813,13 @@
) -> DeviceResult {
let max_open_files =
base::get_max_open_files().context("failed to get max number of open files")?;
- let j = if cfg.sandbox {
- let seccomp_policy = cfg.seccomp_policy_dir.join("fs_device");
+ let j = if let Some(jail_config) = &cfg.jail_config {
+ let seccomp_policy = jail_config.seccomp_policy_dir.join("fs_device");
let config = SandboxConfig {
limit_caps: false,
uid_map: Some(uid_map),
gid_map: Some(gid_map),
- log_failures: cfg.seccomp_log_failures,
+ log_failures: jail_config.seccomp_log_failures,
seccomp_policy: &seccomp_policy,
// We want bind mounts from the parent namespaces to propagate into the fs device's
// namespace.
@@ -862,13 +852,13 @@
) -> DeviceResult {
let max_open_files =
base::get_max_open_files().context("failed to get max number of open files")?;
- let (jail, root) = if cfg.sandbox {
- let seccomp_policy = cfg.seccomp_policy_dir.join("9p_device");
+ let (jail, root) = if let Some(jail_config) = &cfg.jail_config {
+ let seccomp_policy = jail_config.seccomp_policy_dir.join("9p_device");
let config = SandboxConfig {
limit_caps: false,
uid_map: Some(uid_map),
gid_map: Some(gid_map),
- log_failures: cfg.seccomp_log_failures,
+ log_failures: jail_config.seccomp_log_failures,
seccomp_policy: &seccomp_policy,
// We want bind mounts from the parent namespaces to propagate into the 9p server's
// namespace.
@@ -1000,7 +990,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev) as Box<dyn VirtioDevice>,
- jail: simple_jail(cfg, "pmem_device")?,
+ jail: simple_jail(&cfg.jail_config, "pmem_device")?,
})
}
@@ -1026,7 +1016,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "iommu_device")?,
+ jail: simple_jail(&cfg.jail_config, "iommu_device")?,
})
}
@@ -1051,7 +1041,7 @@
.create_serial_device::<Console>(cfg.protected_vm, &evt, &mut keep_rds)
.context("failed to create console device")?;
- let jail = match simple_jail(cfg, "serial")? {
+ let jail = match simple_jail(&cfg.jail_config, "serial")? {
Some(mut jail) => {
// Create a tmpfs in the device's root directory so that we can bind mount the
// log socket directory into it.
@@ -1086,7 +1076,7 @@
Ok(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "vios_audio_device")?,
+ jail: simple_jail(&cfg.jail_config, "vios_audio_device")?,
})
}
@@ -1135,6 +1125,8 @@
)
.context("failed to create vfio device")?;
let mut vfio_pci_device = Box::new(VfioPciDevice::new(
+ #[cfg(feature = "direct")]
+ vfio_path,
vfio_device,
bus_num,
guest_address,
@@ -1171,7 +1163,10 @@
if hotplug {
Ok((vfio_pci_device, None))
} else {
- Ok((vfio_pci_device, simple_jail(cfg, "vfio_device")?))
+ Ok((
+ vfio_pci_device,
+ simple_jail(&cfg.jail_config, "vfio_device")?,
+ ))
}
}
@@ -1200,14 +1195,17 @@
.context("Failed to create vfio device")?;
let vfio_plat_dev = VfioPlatformDevice::new(vfio_device, vfio_device_tube_mem);
- Ok((vfio_plat_dev, simple_jail(cfg, "vfio_platform_device")?))
+ Ok((
+ vfio_plat_dev,
+ simple_jail(&cfg.jail_config, "vfio_platform_device")?,
+ ))
}
/// Setup for devices with VIRTIO_F_ACCESS_PLATFORM
pub fn setup_virtio_access_platform(
resources: &mut SystemAllocator,
iommu_attached_endpoints: &mut BTreeMap<u32, Arc<Mutex<Box<dyn MemoryMapperTrait>>>>,
- devices: &mut Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
+ devices: &mut [(Box<dyn BusDeviceObj>, Option<Minijail>)],
) -> DeviceResult<(Option<BTreeMap<u32, Tube>>, Option<Tube>)> {
let mut translate_response_senders: Option<
BTreeMap<
diff --git a/src/linux/gpu.rs b/src/linux/gpu.rs
index 94d017d..7fe860a 100644
--- a/src/linux/gpu.rs
+++ b/src/linux/gpu.rs
@@ -10,7 +10,7 @@
use devices::virtio::vhost::user::vmm::Gpu as VhostUserGpu;
-use crate::VhostUserOption;
+use crate::{JailConfig, VhostUserOption};
use super::*;
@@ -37,8 +37,8 @@
})
}
-pub fn gpu_jail(cfg: &Config, policy: &str) -> Result<Option<Minijail>> {
- match simple_jail(cfg, policy)? {
+pub fn gpu_jail(jail_config: &Option<JailConfig>, policy: &str) -> Result<Option<Minijail>> {
+ match simple_jail(jail_config, policy)? {
Some(mut jail) => {
// Create a tmpfs in the device's root directory so that we can bind mount the
// dri directory into it. The size=67108864 is size=64*1024*1024 or size=64MB.
@@ -190,12 +190,12 @@
render_server_fd,
event_devices,
map_request,
- cfg.sandbox,
+ cfg.jail_config.is_some(),
virtio::base_features(cfg.protected_vm),
cfg.wayland_socket_paths.clone(),
);
- let jail = match gpu_jail(cfg, "gpu_device")? {
+ let jail = match gpu_jail(&cfg.jail_config, "gpu_device")? {
Some(mut jail) => {
// Prepare GPU shader disk cache directory.
let (cache_dir, cache_size) = cfg
@@ -203,7 +203,7 @@
.as_ref()
.map(|params| (params.cache_path.as_ref(), params.cache_size.as_ref()))
.unwrap();
- let cache_info = get_gpu_cache_info(cache_dir, cache_size, cfg.sandbox);
+ let cache_info = get_gpu_cache_info(cache_dir, cache_size, cfg.jail_config.is_some());
if let Some(dir) = cache_info.directory {
jail.mount_bind(dir, dir, true)?;
@@ -271,12 +271,12 @@
UnixSeqpacket::pair().context("failed to create render server socket")?;
let mut env = None;
- let jail = match gpu_jail(cfg, "gpu_render_server")? {
+ let jail = match gpu_jail(&cfg.jail_config, "gpu_render_server")? {
Some(mut jail) => {
let cache_info = get_gpu_cache_info(
render_server_parameters.cache_path.as_ref(),
render_server_parameters.cache_size.as_ref(),
- cfg.sandbox,
+ true,
);
if let Some(dir) = cache_info.directory {
diff --git a/src/linux/jail_helpers.rs b/src/linux/jail_helpers.rs
index 5309985..60dd5df 100644
--- a/src/linux/jail_helpers.rs
+++ b/src/linux/jail_helpers.rs
@@ -11,7 +11,7 @@
use base::*;
use minijail::{self, Minijail};
-use crate::Config;
+use crate::JailConfig;
pub(super) struct SandboxConfig<'a> {
pub(super) limit_caps: bool,
@@ -22,7 +22,7 @@
pub(super) remount_mode: Option<c_ulong>,
}
-pub(super) struct ScopedMinijail(pub Minijail);
+pub(crate) struct ScopedMinijail(pub Minijail);
impl Drop for ScopedMinijail {
fn drop(&mut self) {
@@ -109,27 +109,32 @@
Ok(j)
}
-pub(super) fn simple_jail(cfg: &Config, policy: &str) -> Result<Option<Minijail>> {
- if cfg.sandbox {
- let default_pivot_root: &str = option_env!("DEFAULT_PIVOT_ROOT").unwrap_or("/var/empty");
+pub(super) fn simple_jail(
+ jail_config: &Option<JailConfig>,
+ policy: &str,
+) -> Result<Option<Minijail>> {
+ if let Some(jail_config) = jail_config {
// A directory for a jailed device's pivot root.
- let root_path = cfg
- .pivot_root
- .as_deref()
- .unwrap_or_else(|| Path::new(default_pivot_root));
- if !root_path.exists() {
- bail!("{:?} doesn't exist, can't jail devices", root_path);
+ if !jail_config.pivot_root.exists() {
+ bail!(
+ "{:?} doesn't exist, can't jail devices",
+ jail_config.pivot_root
+ );
}
- let policy_path: PathBuf = cfg.seccomp_policy_dir.join(policy);
+ let policy_path: PathBuf = jail_config.seccomp_policy_dir.join(policy);
let config = SandboxConfig {
limit_caps: true,
- log_failures: cfg.seccomp_log_failures,
+ log_failures: jail_config.seccomp_log_failures,
seccomp_policy: &policy_path,
uid_map: None,
gid_map: None,
remount_mode: None,
};
- Ok(Some(create_base_minijail(root_path, None, Some(&config))?))
+ Ok(Some(create_base_minijail(
+ &jail_config.pivot_root,
+ None,
+ Some(&config),
+ )?))
} else {
Ok(None)
}
diff --git a/src/linux/mod.rs b/src/linux/mod.rs
index 1d19a50..444d8c9 100644
--- a/src/linux/mod.rs
+++ b/src/linux/mod.rs
@@ -15,6 +15,7 @@
use std::os::unix::net::UnixStream;
use std::os::unix::prelude::OpenOptionsExt;
use std::path::Path;
+use std::str::FromStr;
use std::sync::{mpsc, Arc, Barrier};
use std::time::Duration;
@@ -22,6 +23,7 @@
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use std::thread;
+use devices::virtio::vhost::vsock::{VhostVsockConfig, VhostVsockDeviceParameter};
use libc;
use acpi_tables::sdt::SDT;
@@ -77,17 +79,20 @@
mod device_helpers;
use device_helpers::*;
-mod jail_helpers;
+pub(crate) mod jail_helpers;
use jail_helpers::*;
mod vcpu;
#[cfg(feature = "gpu")]
-mod gpu;
+pub(crate) mod gpu;
#[cfg(feature = "gpu")]
pub use gpu::GpuRenderServerParameters;
#[cfg(feature = "gpu")]
use gpu::*;
+#[cfg(target_os = "android")]
+mod android;
+
// gpu_device_tube is not used when GPU support is disabled.
#[cfg_attr(not(feature = "gpu"), allow(unused_variables))]
fn create_virtio_devices(
@@ -107,6 +112,7 @@
fs_device_tubes: &mut Vec<Tube>,
#[cfg(feature = "gpu")] render_server_fd: Option<SafeDescriptor>,
vvu_proxy_device_tubes: &mut Vec<Tube>,
+ vvu_proxy_max_sibling_mem_size: u64,
) -> DeviceResult<Vec<VirtioDeviceStub>> {
let mut devs = Vec::new();
@@ -127,6 +133,7 @@
cfg,
opt,
vvu_proxy_device_tubes.remove(0),
+ vvu_proxy_max_sibling_mem_size,
)?);
}
@@ -203,7 +210,7 @@
.context("failed to set up mouse device")?;
devs.push(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
});
event_devices.push(EventDevice::touchscreen(event_device_socket));
}
@@ -220,7 +227,7 @@
.context("failed to set up keyboard device")?;
devs.push(VirtioDeviceStub {
dev: Box::new(dev),
- jail: simple_jail(cfg, "input_device")?,
+ jail: simple_jail(&cfg.jail_config, "input_device")?,
});
event_devices.push(EventDevice::keyboard(event_device_socket));
}
@@ -281,7 +288,7 @@
#[cfg(feature = "tpm")]
{
if cfg.software_tpm {
- devs.push(create_tpm_device(cfg)?);
+ devs.push(create_software_tpm_device(cfg)?);
}
}
@@ -399,7 +406,14 @@
}
if let Some(cid) = cfg.cid {
- devs.push(create_vhost_vsock_device(cfg, cid)?);
+ let vhost_config = VhostVsockConfig {
+ device: cfg
+ .vhost_vsock_device
+ .clone()
+ .unwrap_or(VhostVsockDeviceParameter::default()),
+ cid,
+ };
+ devs.push(create_vhost_vsock_device(cfg, &vhost_config)?);
}
for vhost_user_fs in &cfg.vhost_user_fs {
@@ -468,6 +482,7 @@
map_request: Arc<Mutex<Option<ExternalMapping>>>,
#[cfg(feature = "gpu")] render_server_fd: Option<SafeDescriptor>,
vvu_proxy_device_tubes: &mut Vec<Tube>,
+ vvu_proxy_max_sibling_mem_size: u64,
) -> DeviceResult<Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>> {
let mut devices: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)> = Vec::new();
let mut balloon_inflate_tube: Option<Tube> = None;
@@ -561,7 +576,7 @@
)
.context("failed to create coiommu device")?;
- devices.push((Box::new(dev), simple_jail(cfg, "coiommu")?));
+ devices.push((Box::new(dev), simple_jail(&cfg.jail_config, "coiommu")?));
}
}
@@ -583,6 +598,7 @@
#[cfg(feature = "gpu")]
render_server_fd,
vvu_proxy_device_tubes,
+ vvu_proxy_max_sibling_mem_size,
)?;
for stub in stubs {
@@ -598,7 +614,7 @@
for ac97_param in &cfg.ac97_parameters {
let dev = Ac97Dev::try_new(vm.get_memory().clone(), ac97_param.clone())
.context("failed to create ac97 device")?;
- let jail = simple_jail(cfg, dev.minijail_policy())?;
+ let jail = simple_jail(&cfg.jail_config, dev.minijail_policy())?;
devices.push((Box::new(dev), jail));
}
@@ -606,7 +622,7 @@
if cfg.usb {
// Create xhci controller.
let usb_controller = Box::new(XhciController::new(vm.get_memory().clone(), usb_provider));
- devices.push((usb_controller, simple_jail(cfg, "xhci")?));
+ devices.push((usb_controller, simple_jail(&cfg.jail_config, "xhci")?));
}
for params in &cfg.stub_pci_devices {
@@ -680,7 +696,9 @@
devices: &mut Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
hp_vec: &mut Vec<Arc<Mutex<dyn HotPlugBus>>>,
hp_endpoints_ranges: &mut Vec<RangeInclusive<u32>>,
- gpe_notify_devs: &mut Vec<(u32, Arc<Mutex<dyn GpeNotify>>)>,
+ // TODO(b/228627457): clippy is incorrectly warning about this Vec, which needs to be a Vec so
+ // we can push into it
+ #[allow(clippy::ptr_arg)] gpe_notify_devs: &mut Vec<(u32, Arc<Mutex<dyn GpeNotify>>)>,
) -> Result<()> {
if host_pcie_rp.is_empty() {
// user doesn't specify host pcie root port which link to this virtual pcie rp,
@@ -951,6 +969,12 @@
guest_mem.set_memory_policy(mem_policy);
let kvm = Kvm::new_with_path(&cfg.kvm_device_path).context("failed to create kvm")?;
let vm = KvmVm::new(&kvm, guest_mem, components.protected_vm).context("failed to create vm")?;
+
+ if !cfg.userspace_msr.is_empty() {
+ vm.enable_userspace_msr()
+ .context("failed to enable userspace MSR handling, do you have kernel 5.10 or later")?;
+ }
+
// Check that the VM was actually created in protected mode as expected.
if cfg.protected_vm != ProtectionType::Unprotected && !vm.check_capability(VmCap::Protected) {
bail!("Failed to create protected VM");
@@ -1013,7 +1037,7 @@
Vcpu: VcpuArch + 'static,
V: VmArch + 'static,
{
- if cfg.sandbox {
+ if cfg.jail_config.is_some() {
// Printing something to the syslog before entering minijail so that libc's syslogger has a
// chance to open files necessary for its operation, like `/etc/localtime`. After jailing,
// access to those files will not be possible.
@@ -1114,7 +1138,7 @@
let battery = if cfg.battery_type.is_some() {
#[cfg_attr(not(feature = "power-monitor-powerd"), allow(clippy::manual_map))]
- let jail = match simple_jail(&cfg, "battery")? {
+ let jail = match simple_jail(&cfg.jail_config, "battery")? {
#[cfg_attr(not(feature = "power-monitor-powerd"), allow(unused_mut))]
Some(mut jail) => {
// Setup a bind mount to the system D-Bus socket if the powerd monitor is used.
@@ -1217,16 +1241,20 @@
if !sys_allocator.reserve_irq(*irq) {
warn!("irq {} already reserved.", irq);
}
- let trigger = Event::new().context("failed to create event")?;
- let resample = Event::new().context("failed to create event")?;
- irq_chip
- .register_irq_event(*irq, &trigger, Some(&resample))
- .unwrap();
- let direct_irq = devices::DirectIrq::new(trigger, Some(resample))
+ let irq_evt = devices::IrqLevelEvent::new().context("failed to create event")?;
+ irq_chip.register_level_irq_event(*irq, &irq_evt).unwrap();
+ let direct_irq = devices::DirectIrq::new_level(&irq_evt)
.context("failed to enable interrupt forwarding")?;
direct_irq
.irq_enable(*irq)
.context("failed to enable interrupt forwarding")?;
+
+ if cfg.direct_wake_irq.contains(&irq) {
+ direct_irq
+ .irq_wake_enable(*irq)
+ .context("failed to enable interrupt wake")?;
+ }
+
irqs.push(direct_irq);
}
@@ -1235,13 +1263,20 @@
if !sys_allocator.reserve_irq(*irq) {
warn!("irq {} already reserved.", irq);
}
- let trigger = Event::new().context("failed to create event")?;
- irq_chip.register_irq_event(*irq, &trigger, None).unwrap();
- let direct_irq = devices::DirectIrq::new(trigger, None)
+ let irq_evt = devices::IrqEdgeEvent::new().context("failed to create event")?;
+ irq_chip.register_edge_irq_event(*irq, &irq_evt).unwrap();
+ let direct_irq = devices::DirectIrq::new_edge(&irq_evt)
.context("failed to enable interrupt forwarding")?;
direct_irq
.irq_enable(*irq)
.context("failed to enable interrupt forwarding")?;
+
+ if cfg.direct_wake_irq.contains(&irq) {
+ direct_irq
+ .irq_wake_enable(*irq)
+ .context("failed to enable interrupt wake")?;
+ }
+
irqs.push(direct_irq);
}
@@ -1269,6 +1304,7 @@
#[cfg(feature = "gpu")]
render_server_fd,
&mut vvu_proxy_device_tubes,
+ components.memory_size,
)?;
let mut hp_endpoints_ranges: Vec<RangeInclusive<u32>> = Vec::new();
@@ -1352,7 +1388,7 @@
&reset_evt,
&mut sys_allocator,
&cfg.serial_parameters,
- simple_jail(&cfg, "serial")?,
+ simple_jail(&cfg.jail_config, "serial")?,
battery,
vm,
ramoops_region,
@@ -1452,8 +1488,7 @@
let host_str = host_os_str
.to_str()
.ok_or_else(|| anyhow!("failed to parse or find vfio path"))?;
- let host_addr =
- PciAddress::from_string(host_str).context("failed to parse vfio pci address")?;
+ let host_addr = PciAddress::from_str(host_str).context("failed to parse vfio pci address")?;
let (hp_bus, bus_num) = get_hp_bus(linux, host_addr)?;
@@ -1520,8 +1555,7 @@
let host_str = host_os_str
.to_str()
.ok_or_else(|| anyhow!("failed to parse or find vfio path"))?;
- let host_addr =
- PciAddress::from_string(host_str).context("failed to parse vfio pci address")?;
+ let host_addr = PciAddress::from_str(host_str).context("failed to parse vfio pci address")?;
let host_key = HostHotPlugKey::Vfio { host_addr };
for hp_bus in linux.hotplug_bus.iter() {
let mut hp_bus_lock = hp_bus.lock();
@@ -1655,7 +1689,7 @@
.context("failed to add descriptor to wait context")?;
}
- if cfg.sandbox {
+ if cfg.jail_config.is_some() {
// Before starting VCPUs, in case we started with some capabilities, drop them all.
drop_capabilities().context("failed to drop process capabilities")?;
}
@@ -1699,6 +1733,10 @@
Some(f)
}
};
+
+ #[cfg(target_os = "android")]
+ android::set_process_profiles(&cfg.task_profiles)?;
+
for (cpu_id, vcpu) in vcpus.into_iter().enumerate() {
let (to_vcpu_channel, from_main_channel) = mpsc::channel();
let vcpu_affinity = match linux.vcpu_affinity.clone() {
@@ -1742,6 +1780,7 @@
.context("failed to clone vcpu cgroup tasks file")?,
),
},
+ cfg.userspace_msr.clone(),
)?;
vcpu_handles.push((handle, to_vcpu_channel));
}
@@ -1965,9 +2004,10 @@
let irq_chip = &mut linux.irq_chip;
request.execute(
|setup| match setup {
- IrqSetup::Event(irq, ev) => {
+ IrqSetup::Event(irq, ev, _, _, _) => {
+ let irq_evt = devices::IrqEdgeEvent::from_event(ev.try_clone()?);
if let Some(event_index) = irq_chip
- .register_irq_event(irq, ev, None)?
+ .register_edge_irq_event(irq, &irq_evt)?
{
match wait_ctx.add(
ev,
@@ -1988,7 +2028,10 @@
}
}
IrqSetup::Route(route) => irq_chip.route_irq(route),
- IrqSetup::UnRegister(irq, ev) => irq_chip.unregister_irq_event(irq, ev),
+ IrqSetup::UnRegister(irq, ev) => {
+ let irq_evt = devices::IrqEdgeEvent::from_event(ev.try_clone()?);
+ irq_chip.unregister_edge_irq_event(irq, &irq_evt)
+ }
},
&mut sys_allocator,
)
diff --git a/src/linux/vcpu.rs b/src/linux/vcpu.rs
index 56c9bbf..562b528 100644
--- a/src/linux/vcpu.rs
+++ b/src/linux/vcpu.rs
@@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::fs::File;
+use std::collections::{BTreeMap, BTreeSet};
+use std::fs::{File, OpenOptions};
use std::io::prelude::*;
+use std::os::unix::fs::FileExt;
+use std::rc::Rc;
use std::sync::{mpsc, Arc, Barrier};
use std::thread;
@@ -236,8 +239,6 @@
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn handle_s2idle_request(privileged_vm: bool) {
- use std::fs::OpenOptions;
-
const POWER_STATE_FREEZE: &[u8] = b"freeze";
// For non privileged guests, we silently ignore the suspend request
@@ -277,6 +278,7 @@
mpsc::Sender<VcpuDebugStatusMessage>,
>,
#[cfg(all(target_arch = "x86_64", feature = "gdb"))] guest_mem: GuestMemory,
+ msr_handlers: MsrHandlers,
) -> ExitState
where
V: VcpuArch + 'static,
@@ -435,6 +437,14 @@
}) => {
mmio_bus.write(address, &data[..size]);
}
+ Ok(VcpuExit::RdMsr { index }) => {
+ if let Some(data) = msr_handlers.read(index) {
+ let _ = vcpu.set_data(&data.to_ne_bytes());
+ }
+ }
+ Ok(VcpuExit::WrMsr { .. }) => {
+ // TODO(b/215297064): implement MSR write
+ }
Ok(VcpuExit::IoapicEoi { vector }) => {
if let Err(e) = irq_chip.broadcast_eoi(vector) {
error!(
@@ -514,6 +524,67 @@
}
}
+trait MsrHandling {
+ fn read(&self, index: u32) -> Result<u64>;
+ fn write(&self, index: u32, data: u64) -> Result<()>;
+}
+
+struct ReadPassthrough {
+ dev_msr: std::fs::File,
+}
+
+impl MsrHandling for ReadPassthrough {
+ fn read(&self, index: u32) -> Result<u64> {
+ let mut data = [0; 8];
+ self.dev_msr.read_exact_at(&mut data, index.into())?;
+ Ok(u64::from_ne_bytes(data))
+ }
+
+ fn write(&self, _index: u32, _data: u64) -> Result<()> {
+ // TODO(b/215297064): implement MSR write
+ unimplemented!();
+ }
+}
+
+impl ReadPassthrough {
+ fn new() -> Result<Self> {
+ // TODO(b/215297064): Support reading from other CPUs than 0, should match running CPU.
+ let filename = "/dev/cpu/0/msr";
+ let dev_msr = OpenOptions::new()
+ .read(true)
+ .open(&filename)
+ .context("Cannot open /dev/cpu/0/msr, are you root?")?;
+ Ok(ReadPassthrough { dev_msr })
+ }
+}
+
+/// MSR handler configuration. Per-cpu.
+struct MsrHandlers {
+ handler: BTreeMap<u32, Rc<Box<dyn MsrHandling>>>,
+}
+
+impl MsrHandlers {
+ fn new() -> Self {
+ MsrHandlers {
+ handler: BTreeMap::new(),
+ }
+ }
+
+ fn read(&self, index: u32) -> Option<u64> {
+ if let Some(handler) = self.handler.get(&index) {
+ match handler.read(index) {
+ Ok(data) => Some(data),
+ Err(e) => {
+ error!("MSR host read failed {:#x} {:?}", index, e);
+ None
+ }
+ }
+ } else {
+ None
+ }
+ }
+}
+
pub fn run_vcpu<V>(
cpu_id: usize,
kvm_vcpu_id: usize,
@@ -542,6 +613,7 @@
host_cpu_topology: bool,
privileged_vm: bool,
vcpu_cgroup_tasks_file: Option<File>,
+ userspace_msr: BTreeSet<u32>,
) -> Result<JoinHandle<()>>
where
V: VcpuArch + 'static,
@@ -554,6 +626,24 @@
// anything happens before we get to writing the final event.
let scoped_exit_evt = ScopedEvent::from(exit_evt);
+ let mut msr_handlers = MsrHandlers::new();
+ if !userspace_msr.is_empty() {
+ let read_passthrough: Rc<Box<dyn MsrHandling>> = match ReadPassthrough::new() {
+ Ok(r) => Rc::new(Box::new(r)),
+ Err(e) => {
+ error!(
+ "failed to create MSR read passthrough handler for vcpu {}: {:#}",
+ cpu_id, e
+ );
+ return;
+ }
+ };
+
+ userspace_msr.iter().for_each(|&index| {
+ msr_handlers.handler.insert(index, read_passthrough.clone());
+ });
+ }
+
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
let guest_mem = vm.get_memory().clone();
let runnable_vcpu = runnable_vcpu(
@@ -612,6 +702,7 @@
to_gdb_tube,
#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
guest_mem,
+ msr_handlers,
);
let exit_evt = scoped_exit_evt.into();
diff --git a/src/main.rs b/src/main.rs
index a210335..c910065 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -30,7 +30,7 @@
argument::{self, print_help, set_arguments, Argument},
platform, BindMount, Config, Executable, FileBackedMappingParameters, GidMap, SharedDir,
TouchDeviceOption, VfioCommand, VhostUserFsOption, VhostUserOption, VhostUserWlOption,
- VhostVsockDeviceParameter, VvuOption,
+ VvuOption,
};
use devices::serial_device::{SerialHardware, SerialParameters};
use devices::virtio::block::block::DiskOption;
@@ -42,6 +42,7 @@
run_block_device, run_console_device, run_fs_device, run_net_device, run_vsock_device,
run_wl_device,
};
+use devices::virtio::vhost::vsock::VhostVsockDeviceParameter;
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
use devices::virtio::VideoBackendType;
#[cfg(feature = "gpu")]
@@ -483,8 +484,13 @@
];
match s {
- #[cfg(feature = "libvda")]
- None => Ok(VideoBackendType::Libvda),
+ None => {
+ cfg_if::cfg_if! {
+ if #[cfg(feature = "libvda")] {
+ Ok(VideoBackendType::Libvda)
+ }
+ }
+ }
#[cfg(feature = "libvda")]
Some("libvda") => Ok(VideoBackendType::Libvda),
#[cfg(feature = "libvda")]
@@ -691,6 +697,41 @@
Ok(ac97_params)
}
+enum MsrAction {
+ Invalid,
+ /// Read MSR value from host CPU0 regardless of current vcpu.
+ ReadFromCPU0,
+}
+
+fn parse_userspace_msr_options(value: &str) -> argument::Result<u32> {
+ // TODO(b/215297064): Implement different type of operations, such
+ // as write or reading from the correct CPU.
+ let mut options = argument::parse_key_value_options("userspace-msr", value, ',');
+ let index: u32 = options
+ .next()
+ .ok_or(argument::Error::ExpectedValue(String::from(
+ "userspace-msr: expected index",
+ )))?
+ .key_numeric()?;
+ let mut msr_config = MsrAction::Invalid;
+ for opt in options {
+ match opt.key() {
+ "action" => match opt.value()? {
+ "r0" => msr_config = MsrAction::ReadFromCPU0,
+ _ => return Err(opt.invalid_value_err(String::from("bad action"))),
+ },
+ _ => return Err(opt.invalid_key_err()),
+ }
+ }
+
+ match msr_config {
+ MsrAction::ReadFromCPU0 => Ok(index),
+ _ => Err(argument::Error::UnknownArgument(
+ "userspace-msr action not specified".to_string(),
+ )),
+ }
+}
+
fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> {
let serial_setting: SerialParameters =
from_key_values(s).map_err(|e| argument::Error::ConfigParserError(e.to_string()))?;
@@ -913,7 +954,7 @@
)))?
.key();
let mut params = StubPciParameters {
- address: PciAddress::from_string(addr).map_err(|e| argument::Error::InvalidValue {
+ address: PciAddress::from_str(addr).map_err(|e| argument::Error::InvalidValue {
value: addr.to_owned(),
expected: format!("stub-pci-device: expected PCI address: {}", e),
})?,
@@ -1546,7 +1587,7 @@
cfg.balloon_control = Some(path);
}
"disable-sandbox" => {
- cfg.sandbox = false;
+ cfg.jail_config = None;
}
"cid" => {
if cfg.cid.is_some() {
@@ -1709,8 +1750,10 @@
cfg.shared_dirs.push(shared_dir);
}
"seccomp-policy-dir" => {
- // `value` is Some because we are in this match so it's safe to unwrap.
- cfg.seccomp_policy_dir = PathBuf::from(value.unwrap());
+ if let Some(jail_config) = &mut cfg.jail_config {
+ // `value` is Some because we are in this match so it's safe to unwrap.
+ jail_config.seccomp_policy_dir = PathBuf::from(value.unwrap());
+ }
}
"seccomp-log-failures" => {
// A side-effect of this flag is to force the use of .policy files
@@ -1730,7 +1773,9 @@
// or 2) do not use this command-line parameter and instead
// temporarily change the build by passing "log" rather than
// "trap" as the "--default-action" to compile_seccomp_policy.py.
- cfg.seccomp_log_failures = true;
+ if let Some(jail_config) = &mut cfg.jail_config {
+ jail_config.seccomp_log_failures = true;
+ }
}
"plugin" => {
if cfg.executable_path.is_some() {
@@ -2096,6 +2141,21 @@
);
}
#[cfg(feature = "direct")]
+ "direct-wake-irq" => {
+ cfg.direct_wake_irq
+ .push(
+ value
+ .unwrap()
+ .parse()
+ .map_err(|_| argument::Error::InvalidValue {
+ value: value.unwrap().to_owned(),
+ expected: String::from(
+ "this value for `direct-wake-irq` must be an unsigned integer",
+ ),
+ })?,
+ );
+ }
+ #[cfg(feature = "direct")]
"direct-gpe" => {
cfg.direct_gpe.push(value.unwrap().parse().map_err(|_| {
argument::Error::InvalidValue {
@@ -2130,6 +2190,10 @@
"no-legacy" => {
cfg.no_legacy = true;
}
+ "userspace-msr" => {
+ let index = parse_userspace_msr_options(value.unwrap())?;
+ cfg.userspace_msr.insert(index);
+ }
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
"host-cpu-topology" => {
cfg.host_cpu_topology = true;
@@ -2161,7 +2225,7 @@
}
vvu_opt.addr =
- Some(PciAddress::from_string(pci_address).map_err(|e| {
+ Some(PciAddress::from_str(pci_address).map_err(|e| {
argument::Error::InvalidValue {
value: pci_address.to_string(),
expected: format!("vvu-proxy PCI address: {}", e),
@@ -2319,7 +2383,9 @@
});
}
"pivot-root" => {
- cfg.pivot_root = Some(PathBuf::from(value.unwrap()));
+ if let Some(jail_config) = &mut cfg.jail_config {
+ jail_config.pivot_root = PathBuf::from(value.unwrap());
+ }
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
"s2idle" => {
@@ -2357,6 +2423,12 @@
.collect();
cfg.mmio_address_ranges = ranges?;
}
+ #[cfg(target_os = "android")]
+ "task-profiles" => {
+ for name in value.unwrap().split(',') {
+ cfg.task_profiles.push(name.to_owned());
+ }
+ }
"help" => return Err(argument::Error::PrintHelp),
_ => unreachable!(),
}
@@ -2468,6 +2540,11 @@
!cfg.vhost_user_console.is_empty(),
);
+ // Remove jail configuration if it has not been enabled.
+ if !cfg.jail_enabled {
+ cfg.jail_config = None;
+ }
+
Ok(())
}
@@ -2715,9 +2792,14 @@
#[cfg(feature = "direct")]
Argument::value("direct-edge-irq", "irq", "Enable interrupt passthrough"),
#[cfg(feature = "direct")]
+ Argument::value("direct-wake-irq", "irq", "Enable wakeup interrupt for host"),
+#[cfg(feature = "direct")]
Argument::value("direct-gpe", "gpe", "Enable GPE interrupt and register access passthrough"),
Argument::value("dmi", "DIR", "Directory with smbios_entry_point/DMI files"),
Argument::flag("no-legacy", "Don't use legacy KBD/RTC devices emulation"),
+ Argument::value("userspace-msr", "INDEX,action=r0", "Userspace MSR handling. Takes INDEX of the MSR and how they are handled.
+ action=r0 - forward RDMSR to host kernel cpu0.
+"),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Argument::flag("host-cpu-topology", "Use mirror cpu topology of Host for Guest VM"),
Argument::flag("privileged-vm", "Grant this Guest VM certian privileges to manage Host resources, such as power management."),
@@ -2757,6 +2839,8 @@
"Ranges (inclusive) into which to limit guest mmio addresses. Note that
this this may cause mmio allocations to fail if the specified ranges are
incompatible with the default ranges calculated by crosvm."),
+ #[cfg(target_os = "android")]
+ Argument::value("task-profiles", "NAME[,...]", "Comma-separated names of the task profiles to apply to all threads in crosvm including the vCPU threads."),
Argument::short_flag('h', "help", "Print help message.")];
let mut cfg = Config::default();
@@ -4245,4 +4329,13 @@
assert_eq!(params.address, 0x3000);
assert_eq!(params.size, 0x2000);
}
+
+ #[test]
+ fn parse_userspace_msr_options_test() {
+ let index = parse_userspace_msr_options("0x10,action=r0").unwrap();
+ assert_eq!(index, 0x10);
+ assert!(parse_userspace_msr_options("0x10,action=none").is_err());
+ assert!(parse_userspace_msr_options("0x10").is_err());
+ assert!(parse_userspace_msr_options("hoge").is_err());
+ }
}
diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs
index 3ca7dda..32425b0 100644
--- a/src/plugin/mod.rs
+++ b/src/plugin/mod.rs
@@ -21,16 +21,16 @@
MS_RDONLY, O_NONBLOCK, SIGCHLD, SOCK_SEQPACKET,
};
+use anyhow::{anyhow, bail, Context, Result};
use protobuf::ProtobufError;
use remain::sorted;
use thiserror::Error;
-use anyhow::{anyhow, bail, Context, Result};
use base::{
add_fd_flags, block_signal, clear_signal, drop_capabilities, enable_core_scheduling, error,
getegid, geteuid, info, pipe, register_rt_signal_handler, validate_raw_descriptor, warn,
- AsRawDescriptor, Error as SysError, Event, FromRawDescriptor, Killable, MmapError, PollToken,
- Result as SysResult, SignalFd, WaitContext, SIGRTMIN,
+ AsRawDescriptor, Descriptor, Error as SysError, Event, FromRawDescriptor, Killable, MmapError,
+ PollToken, RawDescriptor, Result as SysResult, SignalFd, WaitContext, SIGRTMIN,
};
use kvm::{Cap, Datamatch, IoeventAddress, Kvm, Vcpu, VcpuExit, Vm};
use minijail::{self, Minijail};
@@ -43,6 +43,7 @@
const MAX_DATAGRAM_SIZE: usize = 4096;
const MAX_VCPU_DATAGRAM_SIZE: usize = 0x40000;
+const CROSVM_GPU_SERVER_FD_ENV: &str = "CROSVM_GPU_SERVER_FD";
/// An error that occurs when communicating with the plugin process.
#[sorted]
@@ -498,7 +499,44 @@
add_fd_flags(stderr_rd.as_raw_descriptor(), O_NONBLOCK)
.context("error marking stderr nonblocking")?;
- let jail = if cfg.sandbox {
+ #[allow(unused_mut)]
+ let mut env_fds: Vec<(String, Descriptor)> = Vec::default();
+
+ let _default_render_server_params = crate::platform::GpuRenderServerParameters {
+ path: std::path::PathBuf::from("/usr/libexec/virgl_render_server"),
+ cache_path: None,
+ cache_size: None,
+ };
+
+ #[cfg(feature = "gpu")]
+ let gpu_render_server_parameters = if let Some(parameters) = &cfg.gpu_render_server_parameters {
+ Some(parameters)
+ } else {
+ if cfg!(feature = "plugin-render-server") {
+ Some(&_default_render_server_params)
+ } else {
+ None
+ }
+ };
+
+ #[cfg(feature = "gpu")]
+ // Hold on to the render server jail so it keeps running until we exit run_config()
+ let (_render_server_jail, _render_server_fd) =
+ if let Some(parameters) = &gpu_render_server_parameters {
+ let (jail, fd) = crate::platform::gpu::start_gpu_render_server(&cfg, parameters)?;
+ env_fds.push((
+ CROSVM_GPU_SERVER_FD_ENV.to_string(),
+ Descriptor(fd.as_raw_descriptor()),
+ ));
+ (
+ Some(crate::platform::jail_helpers::ScopedMinijail(jail)),
+ Some(fd),
+ )
+ } else {
+ (None, None)
+ };
+
+ let jail = if let Some(jail_config) = &cfg.jail_config {
// An empty directory for jailed plugin pivot root.
let root_path = match &cfg.plugin_root {
Some(dir) => dir,
@@ -517,8 +555,9 @@
bail!("specified root directory is not a directory");
}
- let policy_path = cfg.seccomp_policy_dir.join("plugin");
- let mut jail = create_plugin_jail(root_path, cfg.seccomp_log_failures, &policy_path)?;
+ let policy_path = jail_config.seccomp_policy_dir.join("plugin");
+ let mut jail =
+ create_plugin_jail(root_path, jail_config.seccomp_log_failures, &policy_path)?;
// Update gid map of the jail if caller provided supplemental groups.
if !cfg.plugin_gid_maps.is_empty() {
@@ -607,7 +646,14 @@
.context("failed to create kvm irqchip")?;
vm.create_pit().context("failed to create kvm PIT")?;
- let mut plugin = Process::new(vcpu_count, plugin_path, &plugin_args, jail, stderr_wr)?;
+ let mut plugin = Process::new(
+ vcpu_count,
+ plugin_path,
+ &plugin_args,
+ jail,
+ stderr_wr,
+ env_fds,
+ )?;
// Now that the jail for the plugin has been created and we had a chance to adjust gids there,
// we can drop all our capabilities in case we had any.
drop_capabilities().context("failed to drop process capabilities")?;
diff --git a/src/plugin/process.rs b/src/plugin/process.rs
index bfe13d4..88d078f 100644
--- a/src/plugin/process.rs
+++ b/src/plugin/process.rs
@@ -24,9 +24,8 @@
use protobuf::Message;
use base::{
- error, AsRawDescriptor, Error as SysError, Event, IntoRawDescriptor, Killable,
- MemoryMappingBuilder, RawDescriptor, Result as SysResult, ScmSocket, SharedMemory,
- SharedMemoryUnix, SIGRTMIN,
+ error, AsRawDescriptor, Descriptor, Error as SysError, Event, IntoRawDescriptor, Killable,
+ MemoryMappingBuilder, Result as SysResult, ScmSocket, SharedMemory, SharedMemoryUnix, SIGRTMIN,
};
use kvm::{dirty_log_bitmap_size, Datamatch, IoeventAddress, IrqRoute, IrqSource, PicId, Vm};
use kvm_sys::{kvm_clock_data, kvm_ioapic_state, kvm_pic_state, kvm_pit_state2};
@@ -52,6 +51,8 @@
struct VmClockState(kvm_clock_data);
unsafe impl DataInit for VmClockState {}
+const CROSVM_SOCKET_ENV: &str = "CROSVM_SOCKET";
+
fn get_vm_state(vm: &Vm, state_set: MainRequest_StateSet) -> SysResult<Vec<u8>> {
Ok(match state_set {
MainRequest_StateSet::PIC0 => VmPicState(vm.get_pic_state(PicId::Primary)?)
@@ -141,12 +142,23 @@
/// Set the `jail` argument to spawn the plugin process within the preconfigured jail.
/// Due to an API limitation in libminijail necessitating that this function set an environment
/// variable, this function is not thread-safe.
+ ///
+ /// Arguments:
+ ///
+ /// * `cpu_count`: number of vcpus
+ /// * `cmd`: path to plugin executable
+ /// * `args`: arguments to plugin executable
+ /// * `jail`: jail to launch plugin in. If None plugin will just be spawned as a child
+ /// * `stderr`: File to redirect stderr of plugin process to
+ /// * `env_fds`: collection of (Name, FD) where FD will be inherited by spawned process
+ /// and added to child's environment as a variable Name
pub fn new(
cpu_count: u32,
cmd: &Path,
args: &[&str],
jail: Option<Minijail>,
stderr: File,
+ env_fds: Vec<(String, Descriptor)>,
) -> Result<Process> {
let (request_socket, child_socket) =
new_seqpacket_pair().context("error creating main request socket")?;
@@ -162,32 +174,52 @@
let plugin_pid = match jail {
Some(jail) => {
set_var(
- "CROSVM_SOCKET",
+ CROSVM_SOCKET_ENV,
child_socket.as_raw_descriptor().to_string(),
);
+ env_fds
+ .iter()
+ .for_each(|(k, fd)| set_var(k, fd.as_raw_descriptor().to_string()));
jail.run_remap(
cmd,
- &[
- (stderr.as_raw_descriptor(), STDERR_FILENO),
- (
- child_socket.as_raw_descriptor(),
- child_socket.as_raw_descriptor(),
- ),
- ],
+ &env_fds
+ .into_iter()
+ .map(|(_, fd)| (fd.as_raw_descriptor(), fd.as_raw_descriptor()))
+ .chain(
+ [
+ (stderr.as_raw_descriptor(), STDERR_FILENO),
+ (
+ child_socket.as_raw_descriptor(),
+ child_socket.as_raw_descriptor(),
+ ),
+ ]
+ .into_iter(),
+ )
+ .collect::<Vec<_>>(),
args,
)
.context("failed to run plugin jail")?
}
- None => Command::new(cmd)
- .args(args)
- .env(
- "CROSVM_SOCKET",
- child_socket.as_raw_descriptor().to_string(),
- )
- .stderr(stderr)
- .spawn()
- .context("failed to spawn plugin")?
- .id() as pid_t,
+ None => {
+ for (_, fd) in env_fds.iter() {
+ base::clear_descriptor_cloexec(fd)?;
+ }
+ Command::new(cmd)
+ .args(args)
+ .envs(
+ env_fds
+ .into_iter()
+ .map(|(k, fd)| (k, { fd.as_raw_descriptor().to_string() })),
+ )
+ .env(
+ CROSVM_SOCKET_ENV,
+ child_socket.as_raw_descriptor().to_string(),
+ )
+ .stderr(stderr)
+ .spawn()
+ .context("failed to spawn plugin")?
+ .id() as pid_t
+ }
};
Ok(Process {
diff --git a/tests/plugin_net_config.c b/tests/plugin_net_config.c
index c064c53..a31fe77 100644
--- a/tests/plugin_net_config.c
+++ b/tests/plugin_net_config.c
@@ -49,7 +49,8 @@
unsigned int features;
if (ioctl(net_config.tap_fd, TUNGETFEATURES, &features) < 0) {
fprintf(stderr,
- "failed to read tap features: %s\n",
+ "failed to read tap(fd: %d) features: %s\n",
+ net_config.tap_fd,
strerror(errno));
return 1;
}
diff --git a/tests/plugins.rs b/tests/plugins.rs
index 1cbb2fd..cb7afad 100644
--- a/tests/plugins.rs
+++ b/tests/plugins.rs
@@ -17,6 +17,13 @@
use base::{ioctl, AsRawDescriptor};
use tempfile::tempfile;
+lazy_static::lazy_static! {
+ static ref TAP_AVAILABLE: bool = {
+ use net_util::TapT;
+ net_util::Tap::new(true, false).is_ok()
+ };
+}
+
struct RemovePath(PathBuf);
impl Drop for RemovePath {
fn drop(&mut self) {
@@ -89,12 +96,6 @@
"run",
"-c",
"1",
- "--host_ip",
- "100.115.92.5",
- "--netmask",
- "255.255.255.252",
- "--mac",
- "de:21:e8:47:6b:6a",
"--seccomp-policy-dir",
"tests",
"--plugin",
@@ -104,6 +105,17 @@
.canonicalize()
.expect("failed to canonicalize plugin path"),
);
+
+ if *TAP_AVAILABLE {
+ cmd.args(&[
+ "--host_ip",
+ "100.115.92.5",
+ "--netmask",
+ "255.255.255.252",
+ "--mac",
+ "de:21:e8:47:6b:6a",
+ ]);
+ }
if !with_sandbox {
cmd.arg("--disable-sandbox");
}
@@ -286,7 +298,9 @@
#[test]
fn test_net_config() {
- test_plugin(include_str!("plugin_net_config.c"));
+ if *TAP_AVAILABLE {
+ test_plugin(include_str!("plugin_net_config.c"));
+ }
}
#[test]
diff --git a/third_party/vmm_vhost/src/dummy_slave.rs b/third_party/vmm_vhost/src/dummy_slave.rs
index cc9a9fb..658a1e7 100644
--- a/third_party/vmm_vhost/src/dummy_slave.rs
+++ b/third_party/vmm_vhost/src/dummy_slave.rs
@@ -38,6 +38,10 @@
}
impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
+ fn protocol(&self) -> Protocol {
+ Protocol::Regular
+ }
+
fn set_owner(&mut self) -> Result<()> {
if self.owned {
return Err(Error::InvalidOperation);
diff --git a/third_party/vmm_vhost/src/slave_req_handler.rs b/third_party/vmm_vhost/src/slave_req_handler.rs
index 1a1ba3b..eec3983 100644
--- a/third_party/vmm_vhost/src/slave_req_handler.rs
+++ b/third_party/vmm_vhost/src/slave_req_handler.rs
@@ -90,9 +90,7 @@
#[allow(missing_docs)]
pub trait VhostUserSlaveReqHandlerMut {
/// Returns the type of vhost-user protocol that the handler support.
- fn protocol(&self) -> Protocol {
- Protocol::Regular
- }
+ fn protocol(&self) -> Protocol;
fn set_owner(&mut self) -> Result<()>;
fn reset_owner(&mut self) -> Result<()>;
@@ -831,21 +829,22 @@
if size - mem::size_of::<VhostUserConfig>() != msg.size as usize {
return Err(Error::InvalidMessage);
}
- let flags: VhostUserConfigFlags;
- match VhostUserConfigFlags::from_bits(msg.flags) {
- Some(val) => flags = val,
+ let flags: VhostUserConfigFlags = match VhostUserConfigFlags::from_bits(msg.flags) {
+ Some(val) => val,
None => return Err(Error::InvalidMessage),
- }
+ };
self.backend.set_config(msg.offset, buf, flags)
}
fn set_slave_req_fd(&mut self, files: Option<Vec<File>>) -> Result<()> {
- #[cfg(windows)]
- unimplemented!();
- let file = take_single_file(files).ok_or(Error::InvalidMessage)?;
- self.backend.set_slave_req_fd(file);
- Ok(())
+ if cfg!(windows) {
+ unimplemented!();
+ } else {
+ let file = take_single_file(files).ok_or(Error::InvalidMessage)?;
+ self.backend.set_slave_req_fd(file);
+ Ok(())
+ }
}
fn handle_vring_fd_request(
diff --git a/tools/bindgen-all-the-things b/tools/bindgen-all-the-things
index 2d32350..edd7bdc 100755
--- a/tools/bindgen-all-the-things
+++ b/tools/bindgen-all-the-things
@@ -23,7 +23,10 @@
devices/src/virtio/gpu
kernel_loader
kvm_sys
- libvda
+ media/libvda
+ net_sys
+ vfio_sys
+ virtio_sys
)
for d in "${dirs[@]}"; do
diff --git a/tools/clippy b/tools/clippy
index 558d9d0..d3ae380 100755
--- a/tools/clippy
+++ b/tools/clippy
@@ -9,28 +9,54 @@
# To fix violations where possible:
# $ ./tools/clippy --fix
+import os
+import sys
+
+sys.path.append(os.path.join(sys.path[0], "impl"))
from impl.common import CROSVM_ROOT, cwd, run_main, cmd, chdir
+from impl.test_runner import get_workspace_excludes
clippy = cmd("cargo clippy")
+if os.name == "posix":
+ EXCLUDED_CRATES: list[str] = []
+ EXCLUDED_CRATES_ARGS: list[str] = []
+ FEATURES: str = "--features=all-linux"
+
+elif os.name == "nt":
+ EXCLUDED_CRATES: list[str] = list(get_workspace_excludes("win64"))
+ EXCLUDED_CRATES_ARGS: list[str] = [f"--exclude={crate}" for crate in EXCLUDED_CRATES]
+ FEATURES: str = ""
+
+else:
+ raise Exception(f"Unsupported build target: {os.name}")
+
+
+def is_crate_excluded(crate: str) -> bool:
+ return crate in EXCLUDED_CRATES
+
+
def main(fix: bool = False):
chdir(CROSVM_ROOT)
# Note: Clippy checks are configured in .cargo/config.toml
- clippy_args = [
+ common_args = [
"--fix" if fix else None,
"--all-targets",
"--",
"-Dwarnings",
]
print("Clippy crosvm workspace")
- clippy("--workspace", "--features=all-linux", *clippy_args).fg()
+ clippy("--workspace", FEATURES, *EXCLUDED_CRATES_ARGS, *common_args).fg()
for crate in CROSVM_ROOT.glob("common/*/Cargo.toml"):
- print("Clippy", crate.parent.relative_to(CROSVM_ROOT))
- with cwd(crate.parent):
- clippy("--all-features", *clippy_args).fg()
+ if not is_crate_excluded(crate.parent.name):
+ print("Clippy", crate.parent.relative_to(CROSVM_ROOT))
+ with cwd(crate.parent):
+ clippy("--all-features", *common_args).fg()
+ else:
+ print("Skipping crate", crate.parent.relative_to(CROSVM_ROOT))
run_main(main)
diff --git a/tools/impl/dev_container/Dockerfile b/tools/impl/dev_container/Dockerfile
index 3e2beae..215cf04 100644
--- a/tools/impl/dev_container/Dockerfile
+++ b/tools/impl/dev_container/Dockerfile
@@ -25,8 +25,13 @@
# Delete build artifacts from 'cargo install' to save space in layer.
&& rm -rf /scratch/cargo_target/*
+# Prepare wine64
+RUN ln -sf /usr/bin/wine64-stable /usr/bin/wine64 \
+ && wine64 wineboot
+
# Install cross-compilation dependencies.
COPY tools/install-aarch64-deps tools/install-armhf-deps /tools/
+
RUN apt-get update \
&& /tools/install-aarch64-deps \
&& /tools/install-armhf-deps \
diff --git a/tools/impl/dev_container/version b/tools/impl/dev_container/version
index 5aed675..fa0363b 100644
--- a/tools/impl/dev_container/version
+++ b/tools/impl/dev_container/version
@@ -1 +1 @@
-r0007
+r0008
diff --git a/tools/impl/test_config.py b/tools/impl/test_config.py
index 84874ca..b85107d 100755
--- a/tools/impl/test_config.py
+++ b/tools/impl/test_config.py
@@ -12,6 +12,7 @@
DO_NOT_BUILD_AARCH64 = "do_not_build_aarch64"
DO_NOT_BUILD_ARMHF = "do_not_build_armhf"
DO_NOT_BUILD_X86_64 = "do_not_build_x86_64"
+ DO_NOT_BUILD_WIN64 = "do_not_build_win64"
# Build tests, but do not run for all, or just some platforms.
DO_NOT_RUN = "do_not_run"
@@ -32,119 +33,119 @@
# This test needs longer than usual to run.
LARGE = "large"
-
# Configuration to restrict how and where tests of a certain crate can
# be build and run.
#
# Please add a bug number when restricting a tests.
-if os.name == "posix":
- CRATE_OPTIONS: dict[str, list[TestOption]] = {
- "base": [TestOption.SINGLE_THREADED, TestOption.LARGE],
- "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,
- TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
- ],
- "disk": [TestOption.DO_NOT_RUN_AARCH64, TestOption.DO_NOT_RUN_ARMHF], # b/202294155
- "crosvm-fuzz": [TestOption.DO_NOT_BUILD], # b/194499769
- "fuzz": [TestOption.DO_NOT_BUILD],
- "hypervisor": [
- TestOption.DO_NOT_RUN_AARCH64,
- TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
- ], # b/181672912
- "integration_tests": [ # b/180196508
- TestOption.SINGLE_THREADED,
- TestOption.LARGE,
- TestOption.DO_NOT_RUN_AARCH64,
- TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
- ],
- "io_uring": [TestOption.DO_NOT_RUN], # b/202294403
- "kvm_sys": [TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL],
- "kvm": [
- TestOption.DO_NOT_RUN_AARCH64,
- TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
- ], # b/181674144
- "libvda": [TestOption.DO_NOT_BUILD], # b/202293971
- "sys_util": [TestOption.SINGLE_THREADED],
- "sys_util_core": [TestOption.SINGLE_THREADED],
- "rutabaga_gfx": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
- "vhost": [TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL],
- "vm_control": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
- "libcrosvm_control": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
- }
- BUILD_FEATURES: dict[str, str] = {
- "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],
- "audio_streams": [TestOption.DO_NOT_BUILD],
- "balloon_control": [],
- "base": [TestOption.SINGLE_THREADED, TestOption.LARGE],
- "bit_field_derive": [TestOption.DO_NOT_BUILD],
- "bit_field": [TestOption.DO_NOT_BUILD],
- "cros_async": [TestOption.DO_NOT_BUILD],
- "cros_asyncv2": [TestOption.DO_NOT_BUILD],
- "cros-fuzz": [TestOption.DO_NOT_BUILD],
- "crosvm_control": [TestOption.DO_NOT_BUILD],
- "crosvm_plugin": [TestOption.DO_NOT_BUILD],
- "crosvm-fuzz": [TestOption.DO_NOT_BUILD],
- "crosvm": [TestOption.DO_NOT_BUILD],
- "devices": [TestOption.DO_NOT_BUILD],
- "disk": [TestOption.DO_NOT_BUILD],
- "ffi": [TestOption.DO_NOT_BUILD],
- "fuse": [TestOption.DO_NOT_BUILD],
- "fuzz": [TestOption.DO_NOT_BUILD],
- "gpu_display": [TestOption.DO_NOT_BUILD],
- "hypervisor": [TestOption.DO_NOT_BUILD],
- "integration_tests": [TestOption.DO_NOT_BUILD],
- "io_uring": [TestOption.DO_NOT_BUILD],
- "kernel_cmdline": [TestOption.DO_NOT_BUILD],
- "kernel_loader": [TestOption.DO_NOT_BUILD],
- "kvm_sys": [TestOption.DO_NOT_BUILD],
- "kvm": [TestOption.DO_NOT_BUILD],
- "libcras_stub": [TestOption.DO_NOT_BUILD],
- "libvda": [TestOption.DO_NOT_BUILD],
- "linux_input_sys": [TestOption.DO_NOT_BUILD],
- "minijail-sys": [TestOption.DO_NOT_BUILD],
- "minijail": [TestOption.DO_NOT_BUILD],
- "net_sys": [TestOption.DO_NOT_BUILD],
- "net_util": [TestOption.DO_NOT_BUILD],
- "p9": [TestOption.DO_NOT_BUILD],
- "poll_token_derive": [],
- "power_monitor": [TestOption.DO_NOT_BUILD],
- "protos": [TestOption.DO_NOT_BUILD],
- "qcow_utils": [TestOption.DO_NOT_BUILD],
- "resources": [TestOption.DO_NOT_BUILD],
- "rutabaga_gfx": [TestOption.DO_NOT_BUILD],
- "rutabaga_gralloc": [TestOption.DO_NOT_BUILD],
- "sync": [TestOption.DO_NOT_BUILD],
- "sys_util": [TestOption.DO_NOT_BUILD],
- "sys_util_core": [],
- "system_api_stub": [TestOption.DO_NOT_BUILD],
- "tpm2-sys": [TestOption.DO_NOT_BUILD],
- "tpm2": [TestOption.DO_NOT_BUILD],
- "usb_sys": [TestOption.DO_NOT_BUILD],
- "usb_util": [TestOption.DO_NOT_BUILD],
- "vfio_sys": [TestOption.DO_NOT_BUILD],
- "vhost": [TestOption.DO_NOT_BUILD],
- "virtio_sys": [TestOption.DO_NOT_BUILD],
- "vm_control": [TestOption.DO_NOT_BUILD],
- "vm_memory": [TestOption.DO_NOT_BUILD],
- "wire_format_derive": [TestOption.DO_NOT_BUILD],
- "x86_64": [TestOption.DO_NOT_BUILD],
- }
+# This is just too big to keep in main list for now
+WIN64_DISABLED_CRATES = [
+ "aarch64",
+ "acpi_tables",
+ "arch",
+ "assertions",
+ "audio_streams",
+ "bit_field_derive",
+ "bit_field",
+ "cros_async",
+ "cros_asyncv2",
+ "cros-fuzz",
+ "crosvm_control",
+ "crosvm_plugin",
+ "crosvm-fuzz",
+ "crosvm",
+ "data_model",
+ "devices",
+ "disk",
+ "ffi",
+ "fuse",
+ "fuzz",
+ "gpu_display",
+ "hypervisor",
+ "integration_tests",
+ "io_uring",
+ "kernel_cmdline",
+ "kernel_loader",
+ "kvm_sys",
+ "kvm",
+ "libcras_stub",
+ "libvda",
+ "linux_input_sys",
+ "minijail-sys",
+ "minijail",
+ "net_sys",
+ "net_util",
+ "p9",
+ "power_monitor",
+ "protos",
+ "qcow_utils",
+ "resources",
+ "rutabaga_gfx",
+ "rutabaga_gralloc",
+ "sync",
+ "sys_util",
+ "system_api_stub",
+ "tpm2-sys",
+ "tpm2",
+ "usb_sys",
+ "usb_util",
+ "vfio_sys",
+ "vhost",
+ "virtio_sys",
+ "vm_control",
+ "vm_memory",
+ "vmm_vhost",
+ "wire_format_derive",
+ "x86_64",
+ ]
- BUILD_FEATURES: dict[str, str] = {
- "x86_64": "",
- }
-else:
- raise Exception(f"Unsupported build target: {os.name}")
+CRATE_OPTIONS: dict[str, list[TestOption]] = {
+ "base": [TestOption.SINGLE_THREADED, TestOption.LARGE],
+ "cros_async": [TestOption.LARGE],
+ "crosvm": [TestOption.SINGLE_THREADED],
+ "crosvm_plugin": [
+ TestOption.DO_NOT_BUILD_AARCH64,
+ TestOption.DO_NOT_BUILD_ARMHF,
+ ],
+ "crosvm-fuzz": [TestOption.DO_NOT_BUILD], # b/194499769
+ "devices": [
+ TestOption.SINGLE_THREADED,
+ TestOption.LARGE,
+ TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
+ ],
+ "disk": [TestOption.DO_NOT_RUN_AARCH64, TestOption.DO_NOT_RUN_ARMHF], # b/202294155
+ "fuzz": [TestOption.DO_NOT_BUILD],
+ "hypervisor": [
+ TestOption.DO_NOT_RUN_AARCH64,
+ TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
+ ], # b/181672912
+ "integration_tests": [ # b/180196508
+ TestOption.SINGLE_THREADED,
+ TestOption.LARGE,
+ TestOption.DO_NOT_RUN_AARCH64,
+ TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
+ ],
+ "io_uring": [TestOption.DO_NOT_RUN], # b/202294403
+ "kvm_sys": [TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL],
+ "kvm": [
+ TestOption.DO_NOT_RUN_AARCH64,
+ TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
+ ], # b/181674144
+ "libcrosvm_control": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
+ "libvda": [TestOption.DO_NOT_BUILD], # b/202293971
+ "rutabaga_gfx": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
+ "sys_util": [TestOption.SINGLE_THREADED],
+ "sys_util_core": [TestOption.SINGLE_THREADED],
+ "vhost": [TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL],
+ "vm_control": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
+}
+
+for name in WIN64_DISABLED_CRATES:
+ CRATE_OPTIONS[name] = CRATE_OPTIONS.get(name, []) + [TestOption.DO_NOT_BUILD_WIN64]
+
+BUILD_FEATURES: dict[str, str] = {
+ "x86_64": "linux-x86_64",
+ "aarch64": "linux-aarch64",
+ "armhf": "linux-armhf",
+ "win64": "win64",
+}
diff --git a/tools/impl/test_runner.py b/tools/impl/test_runner.py
index 8a6750d..6cadf54 100644
--- a/tools/impl/test_runner.py
+++ b/tools/impl/test_runner.py
@@ -21,7 +21,6 @@
from test_config import CRATE_OPTIONS, TestOption, BUILD_FEATURES
from check_code_hygiene import (
has_platform_dependent_code,
- is_sys_util_independent,
has_crlf_line_endings,
)
@@ -111,6 +110,8 @@
yield crate
elif TestOption.DO_NOT_BUILD_ARMHF in options and target_arch == "armhf":
yield crate
+ elif TestOption.DO_NOT_BUILD_WIN64 in options and target_arch == "win64":
+ yield crate
def should_run_executable(executable: Executable, target_arch: Arch):
@@ -283,6 +284,13 @@
if TestOption.SINGLE_THREADED in options:
args += ["--test-threads=1"]
+ binary_path = executable.binary_path
+
+ if executable.arch == "win64" and executable.kind != "proc-macro" and os.name != "nt":
+ args.insert(0, binary_path)
+ binary_path = "wine64"
+
+
# proc-macros and their tests are executed on the host.
if executable.kind == "proc-macro":
target = TestTarget("host")
@@ -293,7 +301,7 @@
# Pipe stdout/err to be printed in the main process if needed.
test_process = test_target.exec_file_on_target(
target,
- executable.binary_path,
+ binary_path,
args=args,
timeout=get_test_timeout(target, executable),
stdout=subprocess.PIPE,
diff --git a/tools/impl/test_target.py b/tools/impl/test_target.py
index f01d867..e6098c1 100755
--- a/tools/impl/test_target.py
+++ b/tools/impl/test_target.py
@@ -44,7 +44,7 @@
TARGET_DIR = testvm.cargo_target_dir().joinpath("crosvm_tools")
ENVRC_PATH = SCRIPT_DIR.parent.parent.joinpath(".envrc")
-Arch = Literal["x86_64", "aarch64", "armhf"]
+Arch = Literal["x86_64", "aarch64", "armhf", "win64"]
# Enviroment variables needed for building with cargo
BUILD_ENV = {
@@ -182,10 +182,15 @@
if os.name == "posix":
if arch == "armhf":
return "armv7-unknown-linux-gnueabihf"
+ elif arch == "win64":
+ return "x86_64-pc-windows-gnu"
else:
return f"{arch}-unknown-linux-gnu"
elif os.name == "nt":
- return f"{arch}-pc-windows-msvc"
+ if arch == "win64":
+ return f"x86_64-pc-windows-msvc"
+ else:
+ return f"{arch}-pc-windows-msvc"
else:
raise Exception(f"Unsupported build target: {os.name}")
diff --git a/tools/install-aarch64-deps b/tools/install-aarch64-deps
index a97eee6..7627482 100755
--- a/tools/install-aarch64-deps
+++ b/tools/install-aarch64-deps
@@ -5,7 +5,6 @@
set -ex
sudo apt-get install --yes --no-install-recommends \
- g++-aarch64-linux-gnu \
gcc-aarch64-linux-gnu \
ipxe-qemu \
libc-dev:arm64 \
diff --git a/tools/install-armhf-deps b/tools/install-armhf-deps
index 4758a5a..250fab1 100755
--- a/tools/install-armhf-deps
+++ b/tools/install-armhf-deps
@@ -5,7 +5,6 @@
set -ex
sudo apt-get install --yes --no-install-recommends \
- g++-arm-linux-gnueabihf \
gcc-arm-linux-gnueabihf \
libc-dev:armhf \
libcap-dev:armhf \
diff --git a/tools/install-deps b/tools/install-deps
index 5045e74..23aa211 100755
--- a/tools/install-deps
+++ b/tools/install-deps
@@ -7,12 +7,10 @@
sudo apt-get update
sudo apt-get install --yes --no-install-recommends \
ca-certificates \
- clang \
cloud-image-utils \
curl \
dpkg-dev \
expect \
- g++ \
gcc \
git \
jq \
@@ -37,6 +35,8 @@
qemu-system-x86 \
rsync \
screen \
+ wine64 \
+ gcc-mingw-w64-x86-64-win32 \
wayland-protocols
# Install meson for rutabaga_gfx
@@ -51,6 +51,8 @@
rustup component add clippy
rustup component add rustfmt
+rustup target add x86_64-pc-windows-gnu
+
# The bindgen tool is required to build a crosvm dependency.
cargo install bindgen
diff --git a/tools/presubmit b/tools/presubmit
index 458d656..91ab4a4 100755
--- a/tools/presubmit
+++ b/tools/presubmit
@@ -100,12 +100,14 @@
commands+=(
"$(aarch64_wrapper) ./tools/run_tests --target=vm:aarch64"
"$(aarch64_wrapper) ./tools/run_tests --target=vm:aarch64 --arch=armhf"
+ "./tools/run_tests --target=host --arch=win64 --build-only"
"cargo build --verbose --no-default-features"
)
elif [ "$QUICK" != true ]; then
commands+=(
# Test via user-space emulation for faster, but less complete results.
"$(aarch64_wrapper) ./tools/run_tests --target=host --arch=aarch64"
+ "./tools/run_tests --target=host --arch=win64 --build-only"
)
fi
diff --git a/vfio_sys/Android.bp b/vfio_sys/Android.bp
index 487a88a..46f97c4 100644
--- a/vfio_sys/Android.bp
+++ b/vfio_sys/Android.bp
@@ -21,5 +21,6 @@
edition: "2021",
rustlibs: [
"libbase_rust",
+ "libdata_model",
],
}
diff --git a/vfio_sys/Cargo.toml b/vfio_sys/Cargo.toml
index 866eeb7..8890f55 100644
--- a/vfio_sys/Cargo.toml
+++ b/vfio_sys/Cargo.toml
@@ -6,3 +6,4 @@
[dependencies]
base = { path = "../base" }
+data_model = { path = "../common/data_model" }
diff --git a/vfio_sys/bindgen.sh b/vfio_sys/bindgen.sh
new file mode 100755
index 0000000..1233380
--- /dev/null
+++ b/vfio_sys/bindgen.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+# Copyright 2022 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.
+#
+# Regenerate vfio_sys bindgen bindings.
+
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+
+source tools/impl/bindgen-common.sh
+
+# VFIO_TYPE is translated as a u8 since it is a char constant, but it needs to be u32 for use in
+# ioctl macros.
+fix_vfio_type() {
+ sed -E -e 's/^pub const VFIO_TYPE: u8 = (.*)u8;/pub const VFIO_TYPE: u32 = \1;/'
+}
+
+VFIO_EXTRA="// Added by vfio_sys/bindgen.sh
+use data_model::DataInit;
+
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct vfio_region_info_with_cap {
+ pub region_info: vfio_region_info,
+ pub cap_info: __IncompleteArrayField<u8>,
+}
+
+// vfio_iommu_type1_info_cap_iova_range minus the incomplete iova_ranges
+// array, so that Copy/DataInit can be implemented.
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_iommu_type1_info_cap_iova_range_header {
+ pub header: vfio_info_cap_header,
+ pub nr_iovas: u32,
+ pub reserved: u32,
+}
+
+// Safe because it only has data and no implicit padding.
+unsafe impl DataInit for vfio_info_cap_header {}
+
+// Safe because it only has data and no implicit padding.
+unsafe impl DataInit for vfio_iommu_type1_info_cap_iova_range_header {}
+
+// Safe because it only has data and no implicit padding.
+unsafe impl DataInit for vfio_iova_range {}"
+
+bindgen_generate \
+ --raw-line "${VFIO_EXTRA}" \
+ --allowlist-var='VFIO_.*' \
+ --blocklist-item='VFIO_DEVICE_API_.*_STRING' \
+ --allowlist-type='vfio_.*' \
+ "${BINDGEN_LINUX}/include/uapi/linux/vfio.h" \
+ -- \
+ -D__user= \
+ | replace_linux_int_types | fix_vfio_type \
+ > vfio_sys/src/vfio.rs
diff --git a/vfio_sys/src/lib.rs b/vfio_sys/src/lib.rs
index ad7e147..a8849a5 100644
--- a/vfio_sys/src/lib.rs
+++ b/vfio_sys/src/lib.rs
@@ -47,6 +47,12 @@
);
ioctl_io_nr!(
+ PLAT_IRQ_WAKE_SET,
+ PLAT_IRQ_FORWARD_TYPE,
+ PLAT_IRQ_FORWARD_BASE + 1
+);
+
+ioctl_io_nr!(
ACPI_GPE_FORWARD_SET,
PLAT_IRQ_FORWARD_TYPE,
GPE_FORWARD_BASE
diff --git a/vfio_sys/src/plat.rs b/vfio_sys/src/plat.rs
index ee79d2e..680eac9 100644
--- a/vfio_sys/src/plat.rs
+++ b/vfio_sys/src/plat.rs
@@ -68,6 +68,8 @@
pub const PLAT_IRQ_FORWARD_SET_EDGE_TRIGGER: u32 = 4;
pub const PLAT_IRQ_FORWARD_SET_LEVEL_SCI_FOR_GPE_TRIGGER_EVENTFD: u32 = 8;
pub const PLAT_IRQ_FORWARD_SET_LEVEL_SCI_FOR_GPE_UNMASK_EVENTFD: u32 = 16;
+pub const PLAT_IRQ_WAKE_ENABLE: u32 = 1;
+pub const PLAT_IRQ_WAKE_DISABLE: u32 = 2;
pub const ACPI_GPE_FORWARD_SET_TRIGGER: u32 = 1;
pub const ACPI_GPE_FORWARD_CLEAR_TRIGGER: u32 = 2;
pub type __s8 = ::std::os::raw::c_schar;
@@ -138,6 +140,13 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
+pub struct plat_irq_wake_set {
+ pub argsz: __u32,
+ pub action_flags: __u32,
+ pub irq_number_host: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct gpe_forward_set {
pub argsz: __u32,
pub action_flags: __u32,
diff --git a/vfio_sys/src/vfio.rs b/vfio_sys/src/vfio.rs
index 315ba50..401722f 100644
--- a/vfio_sys/src/vfio.rs
+++ b/vfio_sys/src/vfio.rs
@@ -1,9 +1,38 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-/* automatically generated by bindgen /usr/include/linux/vfio.h --constified-enum '*'
- * --with-derive-default --no-doc-comments --no-layout-tests */
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
+
+// Added by vfio_sys/bindgen.sh
+use data_model::DataInit;
+
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct vfio_region_info_with_cap {
+ pub region_info: vfio_region_info,
+ pub cap_info: __IncompleteArrayField<u8>,
+}
+
+// vfio_iommu_type1_info_cap_iova_range minus the incomplete iova_ranges
+// array, so that Copy/DataInit can be implemented.
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_iommu_type1_info_cap_iova_range_header {
+ pub header: vfio_info_cap_header,
+ pub nr_iovas: u32,
+ pub reserved: u32,
+}
+
+// Safe because it only has data and no implicit padding.
+unsafe impl DataInit for vfio_info_cap_header {}
+
+// Safe because it only has data and no implicit padding.
+unsafe impl DataInit for vfio_iommu_type1_info_cap_iova_range_header {}
+
+// Safe because it only has data and no implicit padding.
+unsafe impl DataInit for vfio_iova_range {}
#[repr(C)]
#[derive(Default)]
@@ -14,12 +43,12 @@
__IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
- pub unsafe fn as_ptr(&self) -> *const T {
- ::std::mem::transmute(self)
+ pub fn as_ptr(&self) -> *const T {
+ self as *const _ as *const T
}
#[inline]
- pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
- ::std::mem::transmute(self)
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as *mut T
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
@@ -35,34 +64,6 @@
fmt.write_str("__IncompleteArrayField")
}
}
-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
-}
-pub const __BITS_PER_LONG: u32 = 64;
-pub const __FD_SETSIZE: u32 = 1024;
-pub const _IOC_NRBITS: u32 = 8;
-pub const _IOC_TYPEBITS: u32 = 8;
-pub const _IOC_SIZEBITS: u32 = 14;
-pub const _IOC_DIRBITS: u32 = 2;
-pub const _IOC_NRMASK: u32 = 255;
-pub const _IOC_TYPEMASK: u32 = 255;
-pub const _IOC_SIZEMASK: u32 = 16383;
-pub const _IOC_DIRMASK: u32 = 3;
-pub const _IOC_NRSHIFT: u32 = 0;
-pub const _IOC_TYPESHIFT: u32 = 8;
-pub const _IOC_SIZESHIFT: u32 = 16;
-pub const _IOC_DIRSHIFT: u32 = 30;
-pub const _IOC_NONE: u32 = 0;
-pub const _IOC_WRITE: u32 = 1;
-pub const _IOC_READ: u32 = 2;
-pub const IOC_IN: u32 = 1073741824;
-pub const IOC_OUT: u32 = 2147483648;
-pub const IOC_INOUT: u32 = 3221225472;
-pub const IOCSIZE_MASK: u32 = 1073676288;
-pub const IOCSIZE_SHIFT: u32 = 16;
pub const VFIO_API_VERSION: u32 = 0;
pub const VFIO_TYPE1_IOMMU: u32 = 1;
pub const VFIO_SPAPR_TCE_IOMMU: u32 = 2;
@@ -81,22 +82,44 @@
pub const VFIO_DEVICE_FLAGS_PLATFORM: u32 = 4;
pub const VFIO_DEVICE_FLAGS_AMBA: u32 = 8;
pub const VFIO_DEVICE_FLAGS_CCW: u32 = 16;
-pub const VFIO_DEVICE_API_PCI_STRING: &[u8; 9usize] = b"vfio-pci\0";
-pub const VFIO_DEVICE_API_PLATFORM_STRING: &[u8; 14usize] = b"vfio-platform\0";
-pub const VFIO_DEVICE_API_AMBA_STRING: &[u8; 10usize] = b"vfio-amba\0";
-pub const VFIO_DEVICE_API_CCW_STRING: &[u8; 9usize] = b"vfio-ccw\0";
+pub const VFIO_DEVICE_FLAGS_AP: u32 = 32;
+pub const VFIO_DEVICE_FLAGS_FSL_MC: u32 = 64;
+pub const VFIO_DEVICE_FLAGS_CAPS: u32 = 128;
+pub const VFIO_DEVICE_INFO_CAP_ZPCI_BASE: u32 = 1;
+pub const VFIO_DEVICE_INFO_CAP_ZPCI_GROUP: u32 = 2;
+pub const VFIO_DEVICE_INFO_CAP_ZPCI_UTIL: u32 = 3;
+pub const VFIO_DEVICE_INFO_CAP_ZPCI_PFIP: u32 = 4;
pub const VFIO_REGION_INFO_FLAG_READ: u32 = 1;
pub const VFIO_REGION_INFO_FLAG_WRITE: u32 = 2;
pub const VFIO_REGION_INFO_FLAG_MMAP: u32 = 4;
pub const VFIO_REGION_INFO_FLAG_CAPS: u32 = 8;
pub const VFIO_REGION_INFO_CAP_SPARSE_MMAP: u32 = 1;
pub const VFIO_REGION_INFO_CAP_TYPE: u32 = 2;
-pub const VFIO_REGION_INFO_CAP_MSIX_MAPPABLE: u32 = 3;
pub const VFIO_REGION_TYPE_PCI_VENDOR_TYPE: u32 = 2147483648;
pub const VFIO_REGION_TYPE_PCI_VENDOR_MASK: u32 = 65535;
+pub const VFIO_REGION_TYPE_GFX: u32 = 1;
+pub const VFIO_REGION_TYPE_CCW: u32 = 2;
+pub const VFIO_REGION_TYPE_MIGRATION: u32 = 3;
pub const VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION: u32 = 1;
pub const VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG: u32 = 2;
pub const VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG: u32 = 3;
+pub const VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM: u32 = 1;
+pub const VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD: u32 = 1;
+pub const VFIO_REGION_SUBTYPE_GFX_EDID: u32 = 1;
+pub const VFIO_DEVICE_GFX_LINK_STATE_UP: u32 = 1;
+pub const VFIO_DEVICE_GFX_LINK_STATE_DOWN: u32 = 2;
+pub const VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD: u32 = 1;
+pub const VFIO_REGION_SUBTYPE_CCW_SCHIB: u32 = 2;
+pub const VFIO_REGION_SUBTYPE_CCW_CRW: u32 = 3;
+pub const VFIO_REGION_SUBTYPE_MIGRATION: u32 = 1;
+pub const VFIO_DEVICE_STATE_STOP: u32 = 0;
+pub const VFIO_DEVICE_STATE_RUNNING: u32 = 1;
+pub const VFIO_DEVICE_STATE_SAVING: u32 = 2;
+pub const VFIO_DEVICE_STATE_RESUMING: u32 = 4;
+pub const VFIO_DEVICE_STATE_MASK: u32 = 7;
+pub const VFIO_REGION_INFO_CAP_MSIX_MAPPABLE: u32 = 3;
+pub const VFIO_REGION_INFO_CAP_NVLINK2_SSATGT: u32 = 4;
+pub const VFIO_REGION_INFO_CAP_NVLINK2_LNKSPD: u32 = 5;
pub const VFIO_IRQ_INFO_EVENTFD: u32 = 1;
pub const VFIO_IRQ_INFO_MASKABLE: u32 = 2;
pub const VFIO_IRQ_INFO_AUTOMASKED: u32 = 4;
@@ -117,9 +140,22 @@
pub const VFIO_DEVICE_IOEVENTFD_32: u32 = 4;
pub const VFIO_DEVICE_IOEVENTFD_64: u32 = 8;
pub const VFIO_DEVICE_IOEVENTFD_SIZE_MASK: u32 = 15;
+pub const VFIO_DEVICE_FEATURE_MASK: u32 = 65535;
+pub const VFIO_DEVICE_FEATURE_GET: u32 = 65536;
+pub const VFIO_DEVICE_FEATURE_SET: u32 = 131072;
+pub const VFIO_DEVICE_FEATURE_PROBE: u32 = 262144;
+pub const VFIO_DEVICE_FEATURE_PCI_VF_TOKEN: u32 = 0;
pub const VFIO_IOMMU_INFO_PGSIZES: u32 = 1;
+pub const VFIO_IOMMU_INFO_CAPS: u32 = 2;
+pub const VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE: u32 = 1;
+pub const VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION: u32 = 2;
+pub const VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL: u32 = 3;
pub const VFIO_DMA_MAP_FLAG_READ: u32 = 1;
pub const VFIO_DMA_MAP_FLAG_WRITE: u32 = 2;
+pub const VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP: u32 = 1;
+pub const VFIO_IOMMU_DIRTY_PAGES_FLAG_START: u32 = 1;
+pub const VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP: u32 = 2;
+pub const VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP: u32 = 4;
pub const VFIO_IOMMU_SPAPR_INFO_DDW: u32 = 1;
pub const VFIO_EEH_PE_DISABLE: u32 = 0;
pub const VFIO_EEH_PE_ENABLE: u32 = 1;
@@ -136,328 +172,388 @@
pub const VFIO_EEH_PE_RESET_FUNDAMENTAL: u32 = 7;
pub const VFIO_EEH_PE_CONFIGURE: u32 = 8;
pub const VFIO_EEH_PE_INJECT_ERR: u32 = 9;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_info_cap_header {
- pub id: __u16,
- pub version: __u16,
- pub next: __u32,
+ pub id: u16,
+ pub version: u16,
+ pub next: u32,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_group_status {
- pub argsz: __u32,
- pub flags: __u32,
+ pub argsz: u32,
+ pub flags: u32,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_device_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub num_regions: __u32,
- pub num_irqs: __u32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub num_regions: u32,
+ pub num_irqs: u32,
+ pub cap_offset: u32,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_region_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub index: __u32,
- pub cap_offset: __u32,
- pub size: __u64,
- pub offset: __u64,
-}
-#[repr(C)]
-#[derive(Debug, Default)]
-pub struct vfio_region_info_with_cap {
- pub region_info: vfio_region_info,
- pub cap_info: __IncompleteArrayField<u8>,
+ pub argsz: u32,
+ pub flags: u32,
+ pub index: u32,
+ pub cap_offset: u32,
+ pub size: u64,
+ pub offset: u64,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_region_sparse_mmap_area {
- pub offset: __u64,
- pub size: __u64,
+ pub offset: u64,
+ pub size: u64,
}
#[repr(C)]
-#[repr(align(8))]
#[derive(Debug, Default)]
pub struct vfio_region_info_cap_sparse_mmap {
pub header: vfio_info_cap_header,
- pub nr_areas: __u32,
- pub reserved: __u32,
+ pub nr_areas: u32,
+ pub reserved: u32,
pub areas: __IncompleteArrayField<vfio_region_sparse_mmap_area>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_region_info_cap_type {
pub header: vfio_info_cap_header,
- pub type_: __u32,
- pub subtype: __u32,
+ pub type_: u32,
+ pub subtype: u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_region_gfx_edid {
+ pub edid_offset: u32,
+ pub edid_max_size: u32,
+ pub edid_size: u32,
+ pub max_xres: u32,
+ pub max_yres: u32,
+ pub link_state: u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_device_migration_info {
+ pub device_state: u32,
+ pub reserved: u32,
+ pub pending_bytes: u64,
+ pub data_offset: u64,
+ pub data_size: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_region_info_cap_nvlink2_ssatgt {
+ pub header: vfio_info_cap_header,
+ pub tgt: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_region_info_cap_nvlink2_lnkspd {
+ pub header: vfio_info_cap_header,
+ pub link_speed: u32,
+ pub __pad: u32,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_irq_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub index: __u32,
- pub count: __u32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub index: u32,
+ pub count: u32,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct vfio_irq_set {
- pub argsz: __u32,
- pub flags: __u32,
- pub index: __u32,
- pub start: __u32,
- pub count: __u32,
- pub data: __IncompleteArrayField<__u8>,
+ pub argsz: u32,
+ pub flags: u32,
+ pub index: u32,
+ pub start: u32,
+ pub count: u32,
+ pub data: __IncompleteArrayField<u8>,
}
-pub const VFIO_PCI_BAR0_REGION_INDEX: _bindgen_ty_1 = 0;
-pub const VFIO_PCI_BAR1_REGION_INDEX: _bindgen_ty_1 = 1;
-pub const VFIO_PCI_BAR2_REGION_INDEX: _bindgen_ty_1 = 2;
-pub const VFIO_PCI_BAR3_REGION_INDEX: _bindgen_ty_1 = 3;
-pub const VFIO_PCI_BAR4_REGION_INDEX: _bindgen_ty_1 = 4;
-pub const VFIO_PCI_BAR5_REGION_INDEX: _bindgen_ty_1 = 5;
-pub const VFIO_PCI_ROM_REGION_INDEX: _bindgen_ty_1 = 6;
-pub const VFIO_PCI_CONFIG_REGION_INDEX: _bindgen_ty_1 = 7;
-pub const VFIO_PCI_VGA_REGION_INDEX: _bindgen_ty_1 = 8;
-pub const VFIO_PCI_NUM_REGIONS: _bindgen_ty_1 = 9;
-pub type _bindgen_ty_1 = u32;
-pub const VFIO_PCI_INTX_IRQ_INDEX: _bindgen_ty_2 = 0;
-pub const VFIO_PCI_MSI_IRQ_INDEX: _bindgen_ty_2 = 1;
-pub const VFIO_PCI_MSIX_IRQ_INDEX: _bindgen_ty_2 = 2;
-pub const VFIO_PCI_ERR_IRQ_INDEX: _bindgen_ty_2 = 3;
-pub const VFIO_PCI_REQ_IRQ_INDEX: _bindgen_ty_2 = 4;
-pub const VFIO_PCI_NUM_IRQS: _bindgen_ty_2 = 5;
-pub type _bindgen_ty_2 = u32;
-pub const VFIO_CCW_CONFIG_REGION_INDEX: _bindgen_ty_3 = 0;
-pub const VFIO_CCW_NUM_REGIONS: _bindgen_ty_3 = 1;
-pub type _bindgen_ty_3 = u32;
-pub const VFIO_CCW_IO_IRQ_INDEX: _bindgen_ty_4 = 0;
-pub const VFIO_CCW_NUM_IRQS: _bindgen_ty_4 = 1;
-pub type _bindgen_ty_4 = u32;
+pub const VFIO_PCI_BAR0_REGION_INDEX: ::std::os::raw::c_uint = 0;
+pub const VFIO_PCI_BAR1_REGION_INDEX: ::std::os::raw::c_uint = 1;
+pub const VFIO_PCI_BAR2_REGION_INDEX: ::std::os::raw::c_uint = 2;
+pub const VFIO_PCI_BAR3_REGION_INDEX: ::std::os::raw::c_uint = 3;
+pub const VFIO_PCI_BAR4_REGION_INDEX: ::std::os::raw::c_uint = 4;
+pub const VFIO_PCI_BAR5_REGION_INDEX: ::std::os::raw::c_uint = 5;
+pub const VFIO_PCI_ROM_REGION_INDEX: ::std::os::raw::c_uint = 6;
+pub const VFIO_PCI_CONFIG_REGION_INDEX: ::std::os::raw::c_uint = 7;
+pub const VFIO_PCI_VGA_REGION_INDEX: ::std::os::raw::c_uint = 8;
+pub const VFIO_PCI_NUM_REGIONS: ::std::os::raw::c_uint = 9;
+pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
+pub const VFIO_PCI_INTX_IRQ_INDEX: ::std::os::raw::c_uint = 0;
+pub const VFIO_PCI_MSI_IRQ_INDEX: ::std::os::raw::c_uint = 1;
+pub const VFIO_PCI_MSIX_IRQ_INDEX: ::std::os::raw::c_uint = 2;
+pub const VFIO_PCI_ERR_IRQ_INDEX: ::std::os::raw::c_uint = 3;
+pub const VFIO_PCI_REQ_IRQ_INDEX: ::std::os::raw::c_uint = 4;
+pub const VFIO_PCI_NUM_IRQS: ::std::os::raw::c_uint = 5;
+pub type _bindgen_ty_2 = ::std::os::raw::c_uint;
+pub const VFIO_CCW_CONFIG_REGION_INDEX: ::std::os::raw::c_uint = 0;
+pub const VFIO_CCW_NUM_REGIONS: ::std::os::raw::c_uint = 1;
+pub type _bindgen_ty_3 = ::std::os::raw::c_uint;
+pub const VFIO_CCW_IO_IRQ_INDEX: ::std::os::raw::c_uint = 0;
+pub const VFIO_CCW_CRW_IRQ_INDEX: ::std::os::raw::c_uint = 1;
+pub const VFIO_CCW_NUM_IRQS: ::std::os::raw::c_uint = 2;
+pub type _bindgen_ty_4 = ::std::os::raw::c_uint;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_pci_dependent_device {
- pub group_id: __u32,
- pub segment: __u16,
- pub bus: __u8,
- pub devfn: __u8,
+ pub group_id: u32,
+ pub segment: u16,
+ pub bus: u8,
+ pub devfn: u8,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct vfio_pci_hot_reset_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub count: __u32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub count: u32,
pub devices: __IncompleteArrayField<vfio_pci_dependent_device>,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct vfio_pci_hot_reset {
- pub argsz: __u32,
- pub flags: __u32,
- pub count: __u32,
- pub group_fds: __IncompleteArrayField<__s32>,
+ pub argsz: u32,
+ pub flags: u32,
+ pub count: u32,
+ pub group_fds: __IncompleteArrayField<i32>,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct vfio_device_gfx_plane_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub drm_plane_type: __u32,
- pub drm_format: __u32,
- pub drm_format_mod: __u64,
- pub width: __u32,
- pub height: __u32,
- pub stride: __u32,
- pub size: __u32,
- pub x_pos: __u32,
- pub y_pos: __u32,
- pub x_hot: __u32,
- pub y_hot: __u32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub drm_plane_type: u32,
+ pub drm_format: u32,
+ pub drm_format_mod: u64,
+ pub width: u32,
+ pub height: u32,
+ pub stride: u32,
+ pub size: u32,
+ pub x_pos: u32,
+ pub y_pos: u32,
+ pub x_hot: u32,
+ pub y_hot: u32,
pub __bindgen_anon_1: vfio_device_gfx_plane_info__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union vfio_device_gfx_plane_info__bindgen_ty_1 {
- pub region_index: __u32,
- pub dmabuf_id: __u32,
- _bindgen_union_align: u32,
+ pub region_index: u32,
+ pub dmabuf_id: u32,
}
impl Default for vfio_device_gfx_plane_info__bindgen_ty_1 {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
impl Default for vfio_device_gfx_plane_info {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_device_ioeventfd {
- pub argsz: __u32,
- pub flags: __u32,
- pub offset: __u64,
- pub data: __u64,
- pub fd: __s32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub offset: u64,
+ pub data: u64,
+ pub fd: i32,
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct vfio_device_feature {
+ pub argsz: u32,
+ pub flags: u32,
+ pub data: __IncompleteArrayField<u8>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_type1_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub iova_pgsizes: __u64,
+ pub argsz: u32,
+ pub flags: u32,
+ pub iova_pgsizes: u64,
+ pub cap_offset: u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_iova_range {
+ pub start: u64,
+ pub end: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct vfio_iommu_type1_info_cap_iova_range {
+ pub header: vfio_info_cap_header,
+ pub nr_iovas: u32,
+ pub reserved: u32,
+ pub iova_ranges: __IncompleteArrayField<vfio_iova_range>,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_iommu_type1_info_cap_migration {
+ pub header: vfio_info_cap_header,
+ pub flags: u32,
+ pub pgsize_bitmap: u64,
+ pub max_dirty_bitmap_size: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vfio_iommu_type1_info_dma_avail {
+ pub header: vfio_info_cap_header,
+ pub avail: u32,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_type1_dma_map {
- pub argsz: __u32,
- pub flags: __u32,
- pub vaddr: __u64,
- pub iova: __u64,
- pub size: __u64,
+ pub argsz: u32,
+ pub flags: u32,
+ pub vaddr: u64,
+ pub iova: u64,
+ pub size: u64,
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
+pub struct vfio_bitmap {
+ pub pgsize: u64,
+ pub size: u64,
+ pub data: *mut u64,
+}
+impl Default for vfio_bitmap {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default)]
pub struct vfio_iommu_type1_dma_unmap {
- pub argsz: __u32,
- pub flags: __u32,
- pub iova: __u64,
- pub size: __u64,
+ pub argsz: u32,
+ pub flags: u32,
+ pub iova: u64,
+ pub size: u64,
+ pub data: __IncompleteArrayField<u8>,
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct vfio_iommu_type1_dirty_bitmap {
+ pub argsz: u32,
+ pub flags: u32,
+ pub data: __IncompleteArrayField<u8>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct vfio_iommu_type1_dirty_bitmap_get {
+ pub iova: u64,
+ pub size: u64,
+ pub bitmap: vfio_bitmap,
+}
+impl Default for vfio_iommu_type1_dirty_bitmap_get {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_spapr_tce_ddw_info {
- pub pgsizes: __u64,
- pub max_dynamic_windows_supported: __u32,
- pub levels: __u32,
+ pub pgsizes: u64,
+ pub max_dynamic_windows_supported: u32,
+ pub levels: u32,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_spapr_tce_info {
- pub argsz: __u32,
- pub flags: __u32,
- pub dma32_window_start: __u32,
- pub dma32_window_size: __u32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub dma32_window_start: u32,
+ pub dma32_window_size: u32,
pub ddw: vfio_iommu_spapr_tce_ddw_info,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_eeh_pe_err {
- pub type_: __u32,
- pub func: __u32,
- pub addr: __u64,
- pub mask: __u64,
+ pub type_: u32,
+ pub func: u32,
+ pub addr: u64,
+ pub mask: u64,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct vfio_eeh_pe_op {
- pub argsz: __u32,
- pub flags: __u32,
- pub op: __u32,
+ pub argsz: u32,
+ pub flags: u32,
+ pub op: u32,
pub __bindgen_anon_1: vfio_eeh_pe_op__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union vfio_eeh_pe_op__bindgen_ty_1 {
pub err: vfio_eeh_pe_err,
- _bindgen_union_align: [u64; 3usize],
}
impl Default for vfio_eeh_pe_op__bindgen_ty_1 {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
impl Default for vfio_eeh_pe_op {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_spapr_register_memory {
- pub argsz: __u32,
- pub flags: __u32,
- pub vaddr: __u64,
- pub size: __u64,
+ pub argsz: u32,
+ pub flags: u32,
+ pub vaddr: u64,
+ pub size: u64,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_spapr_tce_create {
- pub argsz: __u32,
- pub flags: __u32,
- pub page_shift: __u32,
- pub __resv1: __u32,
- pub window_size: __u64,
- pub levels: __u32,
- pub __resv2: __u32,
- pub start_addr: __u64,
+ pub argsz: u32,
+ pub flags: u32,
+ pub page_shift: u32,
+ pub __resv1: u32,
+ pub window_size: u64,
+ pub levels: u32,
+ pub __resv2: u32,
+ pub start_addr: u64,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_iommu_spapr_tce_remove {
- pub argsz: __u32,
- pub flags: __u32,
- pub start_addr: __u64,
+ pub argsz: u32,
+ pub flags: u32,
+ pub start_addr: u64,
}
diff --git a/vhost/src/lib.rs b/vhost/src/lib.rs
index e1f2355..4b947e3 100644
--- a/vhost/src/lib.rs
+++ b/vhost/src/lib.rs
@@ -329,7 +329,7 @@
fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- event: event.as_raw_descriptor() as i32,
+ fd: event.as_raw_descriptor(),
};
// This ioctl is called on a valid vhost_net descriptor and has its
@@ -349,7 +349,7 @@
fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- event: event.as_raw_descriptor() as i32,
+ fd: event.as_raw_descriptor(),
};
// This ioctl is called on a valid vhost_net fd and has its
@@ -370,7 +370,7 @@
fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- event: event.as_raw_descriptor() as i32,
+ fd: event.as_raw_descriptor(),
};
// This ioctl is called on a valid vhost_net descriptor and has its
diff --git a/vhost/src/net.rs b/vhost/src/net.rs
index 9d03dd7..47af749 100644
--- a/vhost/src/net.rs
+++ b/vhost/src/net.rs
@@ -61,7 +61,7 @@
fn set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- event: event.map_or(-1, |event| event.as_raw_descriptor()),
+ fd: event.map_or(-1, |event| event.as_raw_descriptor()),
};
// This ioctl is called on a valid vhost_net descriptor and has its
diff --git a/virtio_sys/Android.bp b/virtio_sys/Android.bp
index 15d257e..6c726ef 100644
--- a/virtio_sys/Android.bp
+++ b/virtio_sys/Android.bp
@@ -23,22 +23,3 @@
"libbase_rust",
],
}
-
-rust_test {
- name: "virtio_sys_test_src_lib",
- defaults: ["crosvm_defaults"],
- host_supported: true,
- crate_name: "virtio_sys",
- cargo_env_compat: true,
- cargo_pkg_version: "0.1.0",
- srcs: ["src/lib.rs"],
- test_suites: ["general-tests"],
- auto_gen_config: true,
- test_options: {
- unit_test: true,
- },
- edition: "2021",
- rustlibs: [
- "libbase_rust",
- ],
-}
diff --git a/virtio_sys/bindgen.sh b/virtio_sys/bindgen.sh
new file mode 100755
index 0000000..d22d82b
--- /dev/null
+++ b/virtio_sys/bindgen.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+# Copyright 2022 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.
+#
+# Regenerate virtio_sys bindgen bindings.
+
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+
+source tools/impl/bindgen-common.sh
+
+bindgen_generate \
+ --allowlist-type='vhost_.*' \
+ --allowlist-var='VHOST_.*' \
+ --allowlist-var='VIRTIO_.*' \
+ "${BINDGEN_LINUX_X86_HEADERS}/include/linux/vhost.h" \
+ -- \
+ -isystem "${BINDGEN_LINUX_X86_HEADERS}/include" \
+ | replace_linux_int_types \
+ > virtio_sys/src/vhost.rs
+
+bindgen_generate \
+ --allowlist-var='VIRTIO_NET_.*' \
+ --allowlist-type='virtio_net_.*' \
+ --blocklist-type='virtio_net_ctrl_mac' \
+ "${BINDGEN_LINUX_X86_HEADERS}/include/linux/virtio_net.h" \
+ -- \
+ -isystem "${BINDGEN_LINUX_X86_HEADERS}/include" \
+ | replace_linux_int_types \
+ > virtio_sys/src/virtio_net.rs
+
+bindgen_generate \
+ --allowlist-var='VRING_.*' \
+ --allowlist-var='VIRTIO_RING_.*' \
+ --allowlist-type='vring.*' \
+ "${BINDGEN_LINUX_X86_HEADERS}/include/linux/virtio_ring.h" \
+ -- \
+ -isystem "${BINDGEN_LINUX_X86_HEADERS}/include" \
+ | replace_linux_int_types \
+ > virtio_sys/src/virtio_ring.rs
diff --git a/virtio_sys/src/vhost.rs b/virtio_sys/src/vhost.rs
index 92895bf..3121cac 100644
--- a/virtio_sys/src/vhost.rs
+++ b/virtio_sys/src/vhost.rs
@@ -1,26 +1,25 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-#![allow(warnings)]
-
-/* automatically generated by rust-bindgen */
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
#[repr(C)]
#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
- pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData)
+ pub const fn new() -> Self {
+ __IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
- pub unsafe fn as_ptr(&self) -> *const T {
- ::std::mem::transmute(self)
+ pub fn as_ptr(&self) -> *const T {
+ self as *const _ as *const T
}
#[inline]
- pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
- ::std::mem::transmute(self)
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as *mut T
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
@@ -32,864 +31,184 @@
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
-}
-impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
-pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
-pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
-pub const _IOC_NRBITS: ::std::os::raw::c_uint = 8;
-pub const _IOC_TYPEBITS: ::std::os::raw::c_uint = 8;
-pub const _IOC_SIZEBITS: ::std::os::raw::c_uint = 14;
-pub const _IOC_DIRBITS: ::std::os::raw::c_uint = 2;
-pub const _IOC_NRMASK: ::std::os::raw::c_uint = 255;
-pub const _IOC_TYPEMASK: ::std::os::raw::c_uint = 255;
-pub const _IOC_SIZEMASK: ::std::os::raw::c_uint = 16383;
-pub const _IOC_DIRMASK: ::std::os::raw::c_uint = 3;
-pub const _IOC_NRSHIFT: ::std::os::raw::c_uint = 0;
-pub const _IOC_TYPESHIFT: ::std::os::raw::c_uint = 8;
-pub const _IOC_SIZESHIFT: ::std::os::raw::c_uint = 16;
-pub const _IOC_DIRSHIFT: ::std::os::raw::c_uint = 30;
-pub const _IOC_NONE: ::std::os::raw::c_uint = 0;
-pub const _IOC_WRITE: ::std::os::raw::c_uint = 1;
-pub const _IOC_READ: ::std::os::raw::c_uint = 2;
-pub const IOC_IN: ::std::os::raw::c_uint = 1073741824;
-pub const IOC_OUT: ::std::os::raw::c_uint = 2147483648;
-pub const IOC_INOUT: ::std::os::raw::c_uint = 3221225472;
-pub const IOCSIZE_MASK: ::std::os::raw::c_uint = 1073676288;
-pub const IOCSIZE_SHIFT: ::std::os::raw::c_uint = 16;
-pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_CONFIG_S_DRIVER: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_CONFIG_S_DRIVER_OK: ::std::os::raw::c_uint = 4;
-pub const VIRTIO_CONFIG_S_FEATURES_OK: ::std::os::raw::c_uint = 8;
-pub const VIRTIO_CONFIG_S_FAILED: ::std::os::raw::c_uint = 128;
-pub const VIRTIO_TRANSPORT_F_START: ::std::os::raw::c_uint = 28;
-pub const VIRTIO_TRANSPORT_F_END: ::std::os::raw::c_uint = 33;
-pub const VIRTIO_F_NOTIFY_ON_EMPTY: ::std::os::raw::c_uint = 24;
-pub const VIRTIO_F_ANY_LAYOUT: ::std::os::raw::c_uint = 27;
-pub const VIRTIO_F_VERSION_1: ::std::os::raw::c_uint = 32;
-pub const _STDINT_H: ::std::os::raw::c_uint = 1;
-pub const _FEATURES_H: ::std::os::raw::c_uint = 1;
-pub const _DEFAULT_SOURCE: ::std::os::raw::c_uint = 1;
-pub const __USE_ISOC11: ::std::os::raw::c_uint = 1;
-pub const __USE_ISOC99: ::std::os::raw::c_uint = 1;
-pub const __USE_ISOC95: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX_IMPLICITLY: ::std::os::raw::c_uint = 1;
-pub const _POSIX_SOURCE: ::std::os::raw::c_uint = 1;
-pub const _POSIX_C_SOURCE: ::std::os::raw::c_uint = 200809;
-pub const __USE_POSIX: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX2: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX199309: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX199506: ::std::os::raw::c_uint = 1;
-pub const __USE_XOPEN2K: ::std::os::raw::c_uint = 1;
-pub const __USE_XOPEN2K8: ::std::os::raw::c_uint = 1;
-pub const _ATFILE_SOURCE: ::std::os::raw::c_uint = 1;
-pub const __USE_MISC: ::std::os::raw::c_uint = 1;
-pub const __USE_ATFILE: ::std::os::raw::c_uint = 1;
-pub const __USE_FORTIFY_LEVEL: ::std::os::raw::c_uint = 0;
-pub const _STDC_PREDEF_H: ::std::os::raw::c_uint = 1;
-pub const __STDC_IEC_559__: ::std::os::raw::c_uint = 1;
-pub const __STDC_IEC_559_COMPLEX__: ::std::os::raw::c_uint = 1;
-pub const __STDC_ISO_10646__: ::std::os::raw::c_uint = 201505;
-pub const __STDC_NO_THREADS__: ::std::os::raw::c_uint = 1;
-pub const __GNU_LIBRARY__: ::std::os::raw::c_uint = 6;
-pub const __GLIBC__: ::std::os::raw::c_uint = 2;
-pub const __GLIBC_MINOR__: ::std::os::raw::c_uint = 23;
-pub const _SYS_CDEFS_H: ::std::os::raw::c_uint = 1;
-pub const __WORDSIZE: ::std::os::raw::c_uint = 64;
-pub const __WORDSIZE_TIME64_COMPAT32: ::std::os::raw::c_uint = 1;
-pub const __SYSCALL_WORDSIZE: ::std::os::raw::c_uint = 64;
-pub const _BITS_WCHAR_H: ::std::os::raw::c_uint = 1;
-pub const INT8_MIN: ::std::os::raw::c_int = -128;
-pub const INT16_MIN: ::std::os::raw::c_int = -32768;
-pub const INT32_MIN: ::std::os::raw::c_int = -2147483648;
-pub const INT8_MAX: ::std::os::raw::c_uint = 127;
-pub const INT16_MAX: ::std::os::raw::c_uint = 32767;
-pub const INT32_MAX: ::std::os::raw::c_uint = 2147483647;
-pub const UINT8_MAX: ::std::os::raw::c_uint = 255;
-pub const UINT16_MAX: ::std::os::raw::c_uint = 65535;
-pub const UINT32_MAX: ::std::os::raw::c_uint = 4294967295;
-pub const INT_LEAST8_MIN: ::std::os::raw::c_int = -128;
-pub const INT_LEAST16_MIN: ::std::os::raw::c_int = -32768;
-pub const INT_LEAST32_MIN: ::std::os::raw::c_int = -2147483648;
-pub const INT_LEAST8_MAX: ::std::os::raw::c_uint = 127;
-pub const INT_LEAST16_MAX: ::std::os::raw::c_uint = 32767;
-pub const INT_LEAST32_MAX: ::std::os::raw::c_uint = 2147483647;
-pub const UINT_LEAST8_MAX: ::std::os::raw::c_uint = 255;
-pub const UINT_LEAST16_MAX: ::std::os::raw::c_uint = 65535;
-pub const UINT_LEAST32_MAX: ::std::os::raw::c_uint = 4294967295;
-pub const INT_FAST8_MIN: ::std::os::raw::c_int = -128;
-pub const INT_FAST16_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const INT_FAST32_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const INT_FAST8_MAX: ::std::os::raw::c_uint = 127;
-pub const INT_FAST16_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const INT_FAST32_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const UINT_FAST8_MAX: ::std::os::raw::c_uint = 255;
-pub const UINT_FAST16_MAX: ::std::os::raw::c_int = -1;
-pub const UINT_FAST32_MAX: ::std::os::raw::c_int = -1;
-pub const INTPTR_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const INTPTR_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const UINTPTR_MAX: ::std::os::raw::c_int = -1;
-pub const PTRDIFF_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const PTRDIFF_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const SIG_ATOMIC_MIN: ::std::os::raw::c_int = -2147483648;
-pub const SIG_ATOMIC_MAX: ::std::os::raw::c_uint = 2147483647;
-pub const SIZE_MAX: ::std::os::raw::c_int = -1;
-pub const WINT_MIN: ::std::os::raw::c_uint = 0;
-pub const WINT_MAX: ::std::os::raw::c_uint = 4294967295;
-pub const VRING_DESC_F_NEXT: ::std::os::raw::c_uint = 1;
-pub const VRING_DESC_F_WRITE: ::std::os::raw::c_uint = 2;
-pub const VRING_DESC_F_INDIRECT: ::std::os::raw::c_uint = 4;
-pub const VRING_USED_F_NO_NOTIFY: ::std::os::raw::c_uint = 1;
-pub const VRING_AVAIL_F_NO_INTERRUPT: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_RING_F_INDIRECT_DESC: ::std::os::raw::c_uint = 28;
-pub const VIRTIO_RING_F_EVENT_IDX: ::std::os::raw::c_uint = 29;
-pub const VRING_AVAIL_ALIGN_SIZE: ::std::os::raw::c_uint = 2;
-pub const VRING_USED_ALIGN_SIZE: ::std::os::raw::c_uint = 4;
-pub const VRING_DESC_ALIGN_SIZE: ::std::os::raw::c_uint = 16;
-pub const VHOST_VRING_F_LOG: ::std::os::raw::c_uint = 0;
-pub const VHOST_PAGE_SIZE: ::std::os::raw::c_uint = 4096;
-pub const VHOST_VIRTIO: ::std::os::raw::c_uint = 175;
-pub const VHOST_VRING_LITTLE_ENDIAN: ::std::os::raw::c_uint = 0;
-pub const VHOST_VRING_BIG_ENDIAN: ::std::os::raw::c_uint = 1;
-pub const VHOST_F_LOG_ALL: ::std::os::raw::c_uint = 26;
-pub const VHOST_NET_F_VIRTIO_NET_HDR: ::std::os::raw::c_uint = 27;
-pub const VHOST_SCSI_ABI_VERSION: ::std::os::raw::c_uint = 1;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
+pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: u32 = 1;
+pub const VIRTIO_CONFIG_S_DRIVER: u32 = 2;
+pub const VIRTIO_CONFIG_S_DRIVER_OK: u32 = 4;
+pub const VIRTIO_CONFIG_S_FEATURES_OK: u32 = 8;
+pub const VIRTIO_CONFIG_S_NEEDS_RESET: u32 = 64;
+pub const VIRTIO_CONFIG_S_FAILED: u32 = 128;
+pub const VIRTIO_TRANSPORT_F_START: u32 = 28;
+pub const VIRTIO_TRANSPORT_F_END: u32 = 38;
+pub const VIRTIO_F_NOTIFY_ON_EMPTY: u32 = 24;
+pub const VIRTIO_F_ANY_LAYOUT: u32 = 27;
+pub const VIRTIO_F_VERSION_1: u32 = 32;
+pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33;
+pub const VIRTIO_F_IOMMU_PLATFORM: u32 = 33;
+pub const VIRTIO_F_RING_PACKED: u32 = 34;
+pub const VIRTIO_F_ORDER_PLATFORM: u32 = 36;
+pub const VIRTIO_F_SR_IOV: u32 = 37;
+pub const VIRTIO_RING_F_INDIRECT_DESC: u32 = 28;
+pub const VIRTIO_RING_F_EVENT_IDX: u32 = 29;
+pub const VHOST_VRING_F_LOG: u32 = 0;
+pub const VHOST_ACCESS_RO: u32 = 1;
+pub const VHOST_ACCESS_WO: u32 = 2;
+pub const VHOST_ACCESS_RW: u32 = 3;
+pub const VHOST_IOTLB_MISS: u32 = 1;
+pub const VHOST_IOTLB_UPDATE: u32 = 2;
+pub const VHOST_IOTLB_INVALIDATE: u32 = 3;
+pub const VHOST_IOTLB_ACCESS_FAIL: u32 = 4;
+pub const VHOST_IOTLB_BATCH_BEGIN: u32 = 5;
+pub const VHOST_IOTLB_BATCH_END: u32 = 6;
+pub const VHOST_IOTLB_MSG: u32 = 1;
+pub const VHOST_IOTLB_MSG_V2: u32 = 2;
+pub const VHOST_PAGE_SIZE: u32 = 4096;
+pub const VHOST_SCSI_ABI_VERSION: u32 = 1;
+pub const VHOST_F_LOG_ALL: u32 = 26;
+pub const VHOST_NET_F_VIRTIO_NET_HDR: u32 = 27;
+pub const VHOST_FILE_UNBIND: i32 = -1;
+pub const VHOST_VIRTIO: u32 = 175;
+pub const VHOST_VRING_LITTLE_ENDIAN: u32 = 0;
+pub const VHOST_VRING_BIG_ENDIAN: u32 = 1;
+pub const VHOST_BACKEND_F_IOTLB_MSG_V2: u32 = 1;
+pub const VHOST_BACKEND_F_IOTLB_BATCH: u32 = 2;
#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-#[test]
-#[ignore]
-fn bindgen_test_layout___kernel_fd_set() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fd_set>(),
- 128usize,
- concat!("Size of: ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fd_set>(),
- 8usize,
- concat!("Alignment of ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fd_set),
- "::",
- stringify!(fds_bits)
- )
- );
-}
-impl Clone for __kernel_fd_set {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-#[test]
-fn bindgen_test_layout___kernel_fsid_t() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fsid_t>(),
- 8usize,
- concat!("Size of: ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fsid_t>(),
- 4usize,
- concat!("Alignment of ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fsid_t),
- "::",
- stringify!(val)
- )
- );
-}
-impl Clone for __kernel_fsid_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
-pub type int_least8_t = ::std::os::raw::c_schar;
-pub type int_least16_t = ::std::os::raw::c_short;
-pub type int_least32_t = ::std::os::raw::c_int;
-pub type int_least64_t = ::std::os::raw::c_long;
-pub type uint_least8_t = ::std::os::raw::c_uchar;
-pub type uint_least16_t = ::std::os::raw::c_ushort;
-pub type uint_least32_t = ::std::os::raw::c_uint;
-pub type uint_least64_t = ::std::os::raw::c_ulong;
-pub type int_fast8_t = ::std::os::raw::c_schar;
-pub type int_fast16_t = ::std::os::raw::c_long;
-pub type int_fast32_t = ::std::os::raw::c_long;
-pub type int_fast64_t = ::std::os::raw::c_long;
-pub type uint_fast8_t = ::std::os::raw::c_uchar;
-pub type uint_fast16_t = ::std::os::raw::c_ulong;
-pub type uint_fast32_t = ::std::os::raw::c_ulong;
-pub type uint_fast64_t = ::std::os::raw::c_ulong;
-pub type intmax_t = ::std::os::raw::c_long;
-pub type uintmax_t = ::std::os::raw::c_ulong;
-pub type __virtio16 = __u16;
-pub type __virtio32 = __u32;
-pub type __virtio64 = __u64;
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct vring_desc {
- pub addr: __virtio64,
- pub len: __virtio32,
- pub flags: __virtio16,
- pub next: __virtio16,
-}
-#[test]
-fn bindgen_test_layout_vring_desc() {
- assert_eq!(
- ::std::mem::size_of::<vring_desc>(),
- 16usize,
- concat!("Size of: ", stringify!(vring_desc))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_desc>(),
- 8usize,
- concat!("Alignment of ", stringify!(vring_desc))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).addr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).len as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(len)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).flags as *const _ as usize },
- 12usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).next as *const _ as usize },
- 14usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(next)
- )
- );
-}
-impl Clone for vring_desc {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct vring_avail {
- pub flags: __virtio16,
- pub idx: __virtio16,
- pub ring: __IncompleteArrayField<__virtio16>,
-}
-#[test]
-fn bindgen_test_layout_vring_avail() {
- assert_eq!(
- ::std::mem::size_of::<vring_avail>(),
- 4usize,
- concat!("Size of: ", stringify!(vring_avail))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_avail>(),
- 2usize,
- concat!("Alignment of ", stringify!(vring_avail))
- );
-}
-impl Clone for vring_avail {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct vring_used_elem {
- pub id: __virtio32,
- pub len: __virtio32,
-}
-#[test]
-fn bindgen_test_layout_vring_used_elem() {
- assert_eq!(
- ::std::mem::size_of::<vring_used_elem>(),
- 8usize,
- concat!("Size of: ", stringify!(vring_used_elem))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_used_elem>(),
- 4usize,
- concat!("Alignment of ", stringify!(vring_used_elem))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_used_elem)).id as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_used_elem),
- "::",
- stringify!(id)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_used_elem)).len as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_used_elem),
- "::",
- stringify!(len)
- )
- );
-}
-impl Clone for vring_used_elem {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
-pub struct vring_used {
- pub flags: __virtio16,
- pub idx: __virtio16,
- pub ring: __IncompleteArrayField<vring_used_elem>,
- pub __bindgen_align: [u32; 0usize],
-}
-#[test]
-fn bindgen_test_layout_vring_used() {
- assert_eq!(
- ::std::mem::size_of::<vring_used>(),
- 4usize,
- concat!("Size of: ", stringify!(vring_used))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_used>(),
- 4usize,
- concat!("Alignment of ", stringify!(vring_used))
- );
-}
-impl Clone for vring_used {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct vring {
- pub num: ::std::os::raw::c_uint,
- pub desc: *mut vring_desc,
- pub avail: *mut vring_avail,
- pub used: *mut vring_used,
-}
-#[test]
-#[ignore]
-fn bindgen_test_layout_vring() {
- assert_eq!(
- ::std::mem::size_of::<vring>(),
- 32usize,
- concat!("Size of: ", stringify!(vring))
- );
- assert_eq!(
- ::std::mem::align_of::<vring>(),
- 8usize,
- concat!("Alignment of ", stringify!(vring))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).num as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(num)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).desc as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(desc)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).avail as *const _ as usize },
- 16usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(avail)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).used as *const _ as usize },
- 24usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(used)
- )
- );
-}
-impl Clone for vring {
- fn clone(&self) -> Self {
- *self
- }
-}
-impl Default for vring {
- fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
- }
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct vhost_vring_state {
pub index: ::std::os::raw::c_uint,
pub num: ::std::os::raw::c_uint,
}
-#[test]
-fn bindgen_test_layout_vhost_vring_state() {
- assert_eq!(
- ::std::mem::size_of::<vhost_vring_state>(),
- 8usize,
- concat!("Size of: ", stringify!(vhost_vring_state))
- );
- assert_eq!(
- ::std::mem::align_of::<vhost_vring_state>(),
- 4usize,
- concat!("Alignment of ", stringify!(vhost_vring_state))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_state)).index as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_state),
- "::",
- stringify!(index)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_state)).num as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_state),
- "::",
- stringify!(num)
- )
- );
-}
-impl Clone for vhost_vring_state {
- fn clone(&self) -> Self {
- *self
- }
-}
#[repr(C)]
-#[derive(Debug, Default, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct vhost_vring_file {
pub index: ::std::os::raw::c_uint,
- pub event: ::std::os::raw::c_int,
-}
-#[test]
-fn bindgen_test_layout_vhost_vring_file() {
- assert_eq!(
- ::std::mem::size_of::<vhost_vring_file>(),
- 8usize,
- concat!("Size of: ", stringify!(vhost_vring_file))
- );
- assert_eq!(
- ::std::mem::align_of::<vhost_vring_file>(),
- 4usize,
- concat!("Alignment of ", stringify!(vhost_vring_file))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_file)).index as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_file),
- "::",
- stringify!(index)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_file)).event as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_file),
- "::",
- stringify!(fd)
- )
- );
-}
-impl Clone for vhost_vring_file {
- fn clone(&self) -> Self {
- *self
- }
+ pub fd: ::std::os::raw::c_int,
}
#[repr(C)]
-#[derive(Debug, Default, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct vhost_vring_addr {
pub index: ::std::os::raw::c_uint,
pub flags: ::std::os::raw::c_uint,
- pub desc_user_addr: __u64,
- pub used_user_addr: __u64,
- pub avail_user_addr: __u64,
- pub log_guest_addr: __u64,
+ pub desc_user_addr: u64,
+ pub used_user_addr: u64,
+ pub avail_user_addr: u64,
+ pub log_guest_addr: u64,
}
-#[test]
-fn bindgen_test_layout_vhost_vring_addr() {
- assert_eq!(
- ::std::mem::size_of::<vhost_vring_addr>(),
- 40usize,
- concat!("Size of: ", stringify!(vhost_vring_addr))
- );
- assert_eq!(
- ::std::mem::align_of::<vhost_vring_addr>(),
- 8usize,
- concat!("Alignment of ", stringify!(vhost_vring_addr))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_addr)).index as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_addr),
- "::",
- stringify!(index)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_addr)).flags as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_addr),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_addr)).desc_user_addr as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_addr),
- "::",
- stringify!(desc_user_addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_addr)).used_user_addr as *const _ as usize },
- 16usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_addr),
- "::",
- stringify!(used_user_addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_addr)).avail_user_addr as *const _ as usize },
- 24usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_addr),
- "::",
- stringify!(avail_user_addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_addr)).log_guest_addr as *const _ as usize },
- 32usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_vring_addr),
- "::",
- stringify!(log_guest_addr)
- )
- );
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_iotlb_msg {
+ pub iova: u64,
+ pub size: u64,
+ pub uaddr: u64,
+ pub perm: u8,
+ pub type_: u8,
}
-impl Clone for vhost_vring_addr {
- fn clone(&self) -> Self {
- *self
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct vhost_msg {
+ pub type_: ::std::os::raw::c_int,
+ pub __bindgen_anon_1: vhost_msg__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union vhost_msg__bindgen_ty_1 {
+ pub iotlb: vhost_iotlb_msg,
+ pub padding: [u8; 64usize],
+}
+impl Default for vhost_msg__bindgen_ty_1 {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+impl Default for vhost_msg {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
-#[derive(Debug, Default, Copy)]
+#[derive(Copy, Clone)]
+pub struct vhost_msg_v2 {
+ pub type_: u32,
+ pub reserved: u32,
+ pub __bindgen_anon_1: vhost_msg_v2__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union vhost_msg_v2__bindgen_ty_1 {
+ pub iotlb: vhost_iotlb_msg,
+ pub padding: [u8; 64usize],
+}
+impl Default for vhost_msg_v2__bindgen_ty_1 {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+impl Default for vhost_msg_v2 {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct vhost_memory_region {
- pub guest_phys_addr: __u64,
- pub memory_size: __u64,
- pub userspace_addr: __u64,
- pub flags_padding: __u64,
-}
-#[test]
-fn bindgen_test_layout_vhost_memory_region() {
- assert_eq!(
- ::std::mem::size_of::<vhost_memory_region>(),
- 32usize,
- concat!("Size of: ", stringify!(vhost_memory_region))
- );
- assert_eq!(
- ::std::mem::align_of::<vhost_memory_region>(),
- 8usize,
- concat!("Alignment of ", stringify!(vhost_memory_region))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory_region)).guest_phys_addr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory_region),
- "::",
- stringify!(guest_phys_addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory_region)).memory_size as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory_region),
- "::",
- stringify!(memory_size)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory_region)).userspace_addr as *const _ as usize },
- 16usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory_region),
- "::",
- stringify!(userspace_addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory_region)).flags_padding as *const _ as usize },
- 24usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory_region),
- "::",
- stringify!(flags_padding)
- )
- );
-}
-impl Clone for vhost_memory_region {
- fn clone(&self) -> Self {
- *self
- }
+ pub guest_phys_addr: u64,
+ pub memory_size: u64,
+ pub userspace_addr: u64,
+ pub flags_padding: u64,
}
#[repr(C)]
-#[derive(Debug, Default, Copy)]
+#[derive(Debug, Default)]
pub struct vhost_memory {
- pub nregions: __u32,
- pub padding: __u32,
+ pub nregions: u32,
+ pub padding: u32,
pub regions: __IncompleteArrayField<vhost_memory_region>,
- pub __force_alignment: [u64; 0],
-}
-#[test]
-fn bindgen_test_layout_vhost_memory() {
- assert_eq!(
- ::std::mem::size_of::<vhost_memory>(),
- 8usize,
- concat!("Size of: ", stringify!(vhost_memory))
- );
- assert_eq!(
- ::std::mem::align_of::<vhost_memory>(),
- 8usize,
- concat!("Alignment of ", stringify!(vhost_memory))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory)).nregions as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory),
- "::",
- stringify!(nregions)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory)).padding as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory),
- "::",
- stringify!(padding)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_memory)).regions as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_memory),
- "::",
- stringify!(regions)
- )
- );
-}
-impl Clone for vhost_memory {
- fn clone(&self) -> Self {
- *self
- }
}
#[repr(C)]
+#[derive(Debug, Copy, Clone)]
pub struct vhost_scsi_target {
pub abi_version: ::std::os::raw::c_int,
pub vhost_wwpn: [::std::os::raw::c_char; 224usize],
pub vhost_tpgt: ::std::os::raw::c_ushort,
pub reserved: ::std::os::raw::c_ushort,
}
-#[test]
-fn bindgen_test_layout_vhost_scsi_target() {
- assert_eq!(
- ::std::mem::size_of::<vhost_scsi_target>(),
- 232usize,
- concat!("Size of: ", stringify!(vhost_scsi_target))
- );
- assert_eq!(
- ::std::mem::align_of::<vhost_scsi_target>(),
- 4usize,
- concat!("Alignment of ", stringify!(vhost_scsi_target))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_scsi_target)).abi_version as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_scsi_target),
- "::",
- stringify!(abi_version)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_scsi_target)).vhost_wwpn as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_scsi_target),
- "::",
- stringify!(vhost_wwpn)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_scsi_target)).vhost_tpgt as *const _ as usize },
- 228usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_scsi_target),
- "::",
- stringify!(vhost_tpgt)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vhost_scsi_target)).reserved as *const _ as usize },
- 230usize,
- concat!(
- "Alignment of field: ",
- stringify!(vhost_scsi_target),
- "::",
- stringify!(reserved)
- )
- );
-}
impl Default for vhost_scsi_target {
fn default() -> Self {
- unsafe { ::std::mem::zeroed() }
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct vhost_vdpa_config {
+ pub off: u32,
+ pub len: u32,
+ pub buf: __IncompleteArrayField<u8>,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_vdpa_iova_range {
+ pub first: u64,
+ pub last: u64,
+}
diff --git a/virtio_sys/src/virtio_net.rs b/virtio_sys/src/virtio_net.rs
index 05556d8..0c879cd 100644
--- a/virtio_sys/src/virtio_net.rs
+++ b/virtio_sys/src/virtio_net.rs
@@ -1,26 +1,25 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-#![allow(warnings)]
-
-/* automatically generated by rust-bindgen */
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
#[repr(C)]
#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
- pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData)
+ pub const fn new() -> Self {
+ __IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
- pub unsafe fn as_ptr(&self) -> *const T {
- ::std::mem::transmute(self)
+ pub fn as_ptr(&self) -> *const T {
+ self as *const _ as *const T
}
#[inline]
- pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
- ::std::mem::transmute(self)
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as *mut T
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
@@ -32,751 +31,223 @@
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
-}
-impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
-pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
-pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
-pub const VIRTIO_ID_NET: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_ID_BLOCK: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_ID_CONSOLE: ::std::os::raw::c_uint = 3;
-pub const VIRTIO_ID_RNG: ::std::os::raw::c_uint = 4;
-pub const VIRTIO_ID_BALLOON: ::std::os::raw::c_uint = 5;
-pub const VIRTIO_ID_RPMSG: ::std::os::raw::c_uint = 7;
-pub const VIRTIO_ID_SCSI: ::std::os::raw::c_uint = 8;
-pub const VIRTIO_ID_9P: ::std::os::raw::c_uint = 9;
-pub const VIRTIO_ID_RPROC_SERIAL: ::std::os::raw::c_uint = 11;
-pub const VIRTIO_ID_CAIF: ::std::os::raw::c_uint = 12;
-pub const VIRTIO_ID_GPU: ::std::os::raw::c_uint = 16;
-pub const VIRTIO_ID_INPUT: ::std::os::raw::c_uint = 18;
-pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_CONFIG_S_DRIVER: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_CONFIG_S_DRIVER_OK: ::std::os::raw::c_uint = 4;
-pub const VIRTIO_CONFIG_S_FEATURES_OK: ::std::os::raw::c_uint = 8;
-pub const VIRTIO_CONFIG_S_FAILED: ::std::os::raw::c_uint = 128;
-pub const VIRTIO_TRANSPORT_F_START: ::std::os::raw::c_uint = 28;
-pub const VIRTIO_TRANSPORT_F_END: ::std::os::raw::c_uint = 33;
-pub const VIRTIO_F_NOTIFY_ON_EMPTY: ::std::os::raw::c_uint = 24;
-pub const VIRTIO_F_ANY_LAYOUT: ::std::os::raw::c_uint = 27;
-pub const VIRTIO_F_VERSION_1: ::std::os::raw::c_uint = 32;
-pub const ETH_ALEN: ::std::os::raw::c_uint = 6;
-pub const ETH_HLEN: ::std::os::raw::c_uint = 14;
-pub const ETH_ZLEN: ::std::os::raw::c_uint = 60;
-pub const ETH_DATA_LEN: ::std::os::raw::c_uint = 1500;
-pub const ETH_FRAME_LEN: ::std::os::raw::c_uint = 1514;
-pub const ETH_FCS_LEN: ::std::os::raw::c_uint = 4;
-pub const ETH_P_LOOP: ::std::os::raw::c_uint = 96;
-pub const ETH_P_PUP: ::std::os::raw::c_uint = 512;
-pub const ETH_P_PUPAT: ::std::os::raw::c_uint = 513;
-pub const ETH_P_TSN: ::std::os::raw::c_uint = 8944;
-pub const ETH_P_IP: ::std::os::raw::c_uint = 2048;
-pub const ETH_P_X25: ::std::os::raw::c_uint = 2053;
-pub const ETH_P_ARP: ::std::os::raw::c_uint = 2054;
-pub const ETH_P_BPQ: ::std::os::raw::c_uint = 2303;
-pub const ETH_P_IEEEPUP: ::std::os::raw::c_uint = 2560;
-pub const ETH_P_IEEEPUPAT: ::std::os::raw::c_uint = 2561;
-pub const ETH_P_BATMAN: ::std::os::raw::c_uint = 17157;
-pub const ETH_P_DEC: ::std::os::raw::c_uint = 24576;
-pub const ETH_P_DNA_DL: ::std::os::raw::c_uint = 24577;
-pub const ETH_P_DNA_RC: ::std::os::raw::c_uint = 24578;
-pub const ETH_P_DNA_RT: ::std::os::raw::c_uint = 24579;
-pub const ETH_P_LAT: ::std::os::raw::c_uint = 24580;
-pub const ETH_P_DIAG: ::std::os::raw::c_uint = 24581;
-pub const ETH_P_CUST: ::std::os::raw::c_uint = 24582;
-pub const ETH_P_SCA: ::std::os::raw::c_uint = 24583;
-pub const ETH_P_TEB: ::std::os::raw::c_uint = 25944;
-pub const ETH_P_RARP: ::std::os::raw::c_uint = 32821;
-pub const ETH_P_ATALK: ::std::os::raw::c_uint = 32923;
-pub const ETH_P_AARP: ::std::os::raw::c_uint = 33011;
-pub const ETH_P_8021Q: ::std::os::raw::c_uint = 33024;
-pub const ETH_P_IPX: ::std::os::raw::c_uint = 33079;
-pub const ETH_P_IPV6: ::std::os::raw::c_uint = 34525;
-pub const ETH_P_PAUSE: ::std::os::raw::c_uint = 34824;
-pub const ETH_P_SLOW: ::std::os::raw::c_uint = 34825;
-pub const ETH_P_WCCP: ::std::os::raw::c_uint = 34878;
-pub const ETH_P_MPLS_UC: ::std::os::raw::c_uint = 34887;
-pub const ETH_P_MPLS_MC: ::std::os::raw::c_uint = 34888;
-pub const ETH_P_ATMMPOA: ::std::os::raw::c_uint = 34892;
-pub const ETH_P_PPP_DISC: ::std::os::raw::c_uint = 34915;
-pub const ETH_P_PPP_SES: ::std::os::raw::c_uint = 34916;
-pub const ETH_P_LINK_CTL: ::std::os::raw::c_uint = 34924;
-pub const ETH_P_ATMFATE: ::std::os::raw::c_uint = 34948;
-pub const ETH_P_PAE: ::std::os::raw::c_uint = 34958;
-pub const ETH_P_AOE: ::std::os::raw::c_uint = 34978;
-pub const ETH_P_8021AD: ::std::os::raw::c_uint = 34984;
-pub const ETH_P_802_EX1: ::std::os::raw::c_uint = 34997;
-pub const ETH_P_TIPC: ::std::os::raw::c_uint = 35018;
-pub const ETH_P_8021AH: ::std::os::raw::c_uint = 35047;
-pub const ETH_P_MVRP: ::std::os::raw::c_uint = 35061;
-pub const ETH_P_1588: ::std::os::raw::c_uint = 35063;
-pub const ETH_P_PRP: ::std::os::raw::c_uint = 35067;
-pub const ETH_P_FCOE: ::std::os::raw::c_uint = 35078;
-pub const ETH_P_TDLS: ::std::os::raw::c_uint = 35085;
-pub const ETH_P_FIP: ::std::os::raw::c_uint = 35092;
-pub const ETH_P_80221: ::std::os::raw::c_uint = 35095;
-pub const ETH_P_LOOPBACK: ::std::os::raw::c_uint = 36864;
-pub const ETH_P_QINQ1: ::std::os::raw::c_uint = 37120;
-pub const ETH_P_QINQ2: ::std::os::raw::c_uint = 37376;
-pub const ETH_P_QINQ3: ::std::os::raw::c_uint = 37632;
-pub const ETH_P_EDSA: ::std::os::raw::c_uint = 56026;
-pub const ETH_P_AF_IUCV: ::std::os::raw::c_uint = 64507;
-pub const ETH_P_802_3_MIN: ::std::os::raw::c_uint = 1536;
-pub const ETH_P_802_3: ::std::os::raw::c_uint = 1;
-pub const ETH_P_AX25: ::std::os::raw::c_uint = 2;
-pub const ETH_P_ALL: ::std::os::raw::c_uint = 3;
-pub const ETH_P_802_2: ::std::os::raw::c_uint = 4;
-pub const ETH_P_SNAP: ::std::os::raw::c_uint = 5;
-pub const ETH_P_DDCMP: ::std::os::raw::c_uint = 6;
-pub const ETH_P_WAN_PPP: ::std::os::raw::c_uint = 7;
-pub const ETH_P_PPP_MP: ::std::os::raw::c_uint = 8;
-pub const ETH_P_LOCALTALK: ::std::os::raw::c_uint = 9;
-pub const ETH_P_CAN: ::std::os::raw::c_uint = 12;
-pub const ETH_P_CANFD: ::std::os::raw::c_uint = 13;
-pub const ETH_P_PPPTALK: ::std::os::raw::c_uint = 16;
-pub const ETH_P_TR_802_2: ::std::os::raw::c_uint = 17;
-pub const ETH_P_MOBITEX: ::std::os::raw::c_uint = 21;
-pub const ETH_P_CONTROL: ::std::os::raw::c_uint = 22;
-pub const ETH_P_IRDA: ::std::os::raw::c_uint = 23;
-pub const ETH_P_ECONET: ::std::os::raw::c_uint = 24;
-pub const ETH_P_HDLC: ::std::os::raw::c_uint = 25;
-pub const ETH_P_ARCNET: ::std::os::raw::c_uint = 26;
-pub const ETH_P_DSA: ::std::os::raw::c_uint = 27;
-pub const ETH_P_TRAILER: ::std::os::raw::c_uint = 28;
-pub const ETH_P_PHONET: ::std::os::raw::c_uint = 245;
-pub const ETH_P_IEEE802154: ::std::os::raw::c_uint = 246;
-pub const ETH_P_CAIF: ::std::os::raw::c_uint = 247;
-pub const ETH_P_XDSA: ::std::os::raw::c_uint = 248;
-pub const VIRTIO_NET_F_CSUM: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_F_GUEST_CSUM: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_NET_F_MTU: ::std::os::raw::c_uint = 3;
-pub const VIRTIO_NET_F_MAC: ::std::os::raw::c_uint = 5;
-pub const VIRTIO_NET_F_GUEST_TSO4: ::std::os::raw::c_uint = 7;
-pub const VIRTIO_NET_F_GUEST_TSO6: ::std::os::raw::c_uint = 8;
-pub const VIRTIO_NET_F_GUEST_ECN: ::std::os::raw::c_uint = 9;
-pub const VIRTIO_NET_F_GUEST_UFO: ::std::os::raw::c_uint = 10;
-pub const VIRTIO_NET_F_HOST_TSO4: ::std::os::raw::c_uint = 11;
-pub const VIRTIO_NET_F_HOST_TSO6: ::std::os::raw::c_uint = 12;
-pub const VIRTIO_NET_F_HOST_ECN: ::std::os::raw::c_uint = 13;
-pub const VIRTIO_NET_F_HOST_UFO: ::std::os::raw::c_uint = 14;
-pub const VIRTIO_NET_F_MRG_RXBUF: ::std::os::raw::c_uint = 15;
-pub const VIRTIO_NET_F_STATUS: ::std::os::raw::c_uint = 16;
-pub const VIRTIO_NET_F_CTRL_VQ: ::std::os::raw::c_uint = 17;
-pub const VIRTIO_NET_F_CTRL_RX: ::std::os::raw::c_uint = 18;
-pub const VIRTIO_NET_F_CTRL_VLAN: ::std::os::raw::c_uint = 19;
-pub const VIRTIO_NET_F_CTRL_RX_EXTRA: ::std::os::raw::c_uint = 20;
-pub const VIRTIO_NET_F_GUEST_ANNOUNCE: ::std::os::raw::c_uint = 21;
-pub const VIRTIO_NET_F_MQ: ::std::os::raw::c_uint = 22;
-pub const VIRTIO_NET_F_CTRL_MAC_ADDR: ::std::os::raw::c_uint = 23;
-pub const VIRTIO_NET_F_GSO: ::std::os::raw::c_uint = 6;
-pub const VIRTIO_NET_S_LINK_UP: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_S_ANNOUNCE: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_NET_HDR_F_NEEDS_CSUM: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_HDR_F_DATA_VALID: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_NET_HDR_GSO_NONE: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_HDR_GSO_TCPV4: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_HDR_GSO_UDP: ::std::os::raw::c_uint = 3;
-pub const VIRTIO_NET_HDR_GSO_TCPV6: ::std::os::raw::c_uint = 4;
-pub const VIRTIO_NET_HDR_GSO_ECN: ::std::os::raw::c_uint = 128;
-pub const VIRTIO_NET_OK: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_ERR: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_CTRL_RX: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_CTRL_RX_PROMISC: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_CTRL_RX_ALLMULTI: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_CTRL_RX_ALLUNI: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_NET_CTRL_RX_NOMULTI: ::std::os::raw::c_uint = 3;
-pub const VIRTIO_NET_CTRL_RX_NOUNI: ::std::os::raw::c_uint = 4;
-pub const VIRTIO_NET_CTRL_RX_NOBCAST: ::std::os::raw::c_uint = 5;
-pub const VIRTIO_NET_CTRL_MAC: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_CTRL_MAC_TABLE_SET: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_CTRL_MAC_ADDR_SET: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_CTRL_VLAN: ::std::os::raw::c_uint = 2;
-pub const VIRTIO_NET_CTRL_VLAN_ADD: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_CTRL_VLAN_DEL: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_CTRL_ANNOUNCE: ::std::os::raw::c_uint = 3;
-pub const VIRTIO_NET_CTRL_ANNOUNCE_ACK: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_CTRL_MQ: ::std::os::raw::c_uint = 4;
-pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: ::std::os::raw::c_uint = 0;
-pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX: ::std::os::raw::c_uint = 32768;
-pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS: ::std::os::raw::c_uint = 5;
-pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET: ::std::os::raw::c_uint = 0;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
-#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-#[test]
-#[ignore]
-fn bindgen_test_layout___kernel_fd_set() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fd_set>(),
- 128usize,
- concat!("Size of: ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fd_set>(),
- 8usize,
- concat!("Alignment of ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fd_set),
- "::",
- stringify!(fds_bits)
- )
- );
-}
-impl Clone for __kernel_fd_set {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-#[test]
-fn bindgen_test_layout___kernel_fsid_t() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fsid_t>(),
- 8usize,
- concat!("Size of: ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fsid_t>(),
- 4usize,
- concat!("Alignment of ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fsid_t),
- "::",
- stringify!(val)
- )
- );
-}
-impl Clone for __kernel_fsid_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
-pub type __virtio16 = __u16;
-pub type __virtio32 = __u32;
-pub type __virtio64 = __u64;
+pub const VIRTIO_NET_F_CSUM: u32 = 0;
+pub const VIRTIO_NET_F_GUEST_CSUM: u32 = 1;
+pub const VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: u32 = 2;
+pub const VIRTIO_NET_F_MTU: u32 = 3;
+pub const VIRTIO_NET_F_MAC: u32 = 5;
+pub const VIRTIO_NET_F_GUEST_TSO4: u32 = 7;
+pub const VIRTIO_NET_F_GUEST_TSO6: u32 = 8;
+pub const VIRTIO_NET_F_GUEST_ECN: u32 = 9;
+pub const VIRTIO_NET_F_GUEST_UFO: u32 = 10;
+pub const VIRTIO_NET_F_HOST_TSO4: u32 = 11;
+pub const VIRTIO_NET_F_HOST_TSO6: u32 = 12;
+pub const VIRTIO_NET_F_HOST_ECN: u32 = 13;
+pub const VIRTIO_NET_F_HOST_UFO: u32 = 14;
+pub const VIRTIO_NET_F_MRG_RXBUF: u32 = 15;
+pub const VIRTIO_NET_F_STATUS: u32 = 16;
+pub const VIRTIO_NET_F_CTRL_VQ: u32 = 17;
+pub const VIRTIO_NET_F_CTRL_RX: u32 = 18;
+pub const VIRTIO_NET_F_CTRL_VLAN: u32 = 19;
+pub const VIRTIO_NET_F_CTRL_RX_EXTRA: u32 = 20;
+pub const VIRTIO_NET_F_GUEST_ANNOUNCE: u32 = 21;
+pub const VIRTIO_NET_F_MQ: u32 = 22;
+pub const VIRTIO_NET_F_CTRL_MAC_ADDR: u32 = 23;
+pub const VIRTIO_NET_F_HASH_REPORT: u32 = 57;
+pub const VIRTIO_NET_F_RSS: u32 = 60;
+pub const VIRTIO_NET_F_RSC_EXT: u32 = 61;
+pub const VIRTIO_NET_F_STANDBY: u32 = 62;
+pub const VIRTIO_NET_F_SPEED_DUPLEX: u32 = 63;
+pub const VIRTIO_NET_F_GSO: u32 = 6;
+pub const VIRTIO_NET_S_LINK_UP: u32 = 1;
+pub const VIRTIO_NET_S_ANNOUNCE: u32 = 2;
+pub const VIRTIO_NET_RSS_HASH_TYPE_IPv4: u32 = 1;
+pub const VIRTIO_NET_RSS_HASH_TYPE_TCPv4: u32 = 2;
+pub const VIRTIO_NET_RSS_HASH_TYPE_UDPv4: u32 = 4;
+pub const VIRTIO_NET_RSS_HASH_TYPE_IPv6: u32 = 8;
+pub const VIRTIO_NET_RSS_HASH_TYPE_TCPv6: u32 = 16;
+pub const VIRTIO_NET_RSS_HASH_TYPE_UDPv6: u32 = 32;
+pub const VIRTIO_NET_RSS_HASH_TYPE_IP_EX: u32 = 64;
+pub const VIRTIO_NET_RSS_HASH_TYPE_TCP_EX: u32 = 128;
+pub const VIRTIO_NET_RSS_HASH_TYPE_UDP_EX: u32 = 256;
+pub const VIRTIO_NET_HDR_F_NEEDS_CSUM: u32 = 1;
+pub const VIRTIO_NET_HDR_F_DATA_VALID: u32 = 2;
+pub const VIRTIO_NET_HDR_F_RSC_INFO: u32 = 4;
+pub const VIRTIO_NET_HDR_GSO_NONE: u32 = 0;
+pub const VIRTIO_NET_HDR_GSO_TCPV4: u32 = 1;
+pub const VIRTIO_NET_HDR_GSO_UDP: u32 = 3;
+pub const VIRTIO_NET_HDR_GSO_TCPV6: u32 = 4;
+pub const VIRTIO_NET_HDR_GSO_ECN: u32 = 128;
+pub const VIRTIO_NET_HASH_REPORT_NONE: u32 = 0;
+pub const VIRTIO_NET_HASH_REPORT_IPv4: u32 = 1;
+pub const VIRTIO_NET_HASH_REPORT_TCPv4: u32 = 2;
+pub const VIRTIO_NET_HASH_REPORT_UDPv4: u32 = 3;
+pub const VIRTIO_NET_HASH_REPORT_IPv6: u32 = 4;
+pub const VIRTIO_NET_HASH_REPORT_TCPv6: u32 = 5;
+pub const VIRTIO_NET_HASH_REPORT_UDPv6: u32 = 6;
+pub const VIRTIO_NET_HASH_REPORT_IPv6_EX: u32 = 7;
+pub const VIRTIO_NET_HASH_REPORT_TCPv6_EX: u32 = 8;
+pub const VIRTIO_NET_HASH_REPORT_UDPv6_EX: u32 = 9;
+pub const VIRTIO_NET_OK: u32 = 0;
+pub const VIRTIO_NET_ERR: u32 = 1;
+pub const VIRTIO_NET_CTRL_RX: u32 = 0;
+pub const VIRTIO_NET_CTRL_RX_PROMISC: u32 = 0;
+pub const VIRTIO_NET_CTRL_RX_ALLMULTI: u32 = 1;
+pub const VIRTIO_NET_CTRL_RX_ALLUNI: u32 = 2;
+pub const VIRTIO_NET_CTRL_RX_NOMULTI: u32 = 3;
+pub const VIRTIO_NET_CTRL_RX_NOUNI: u32 = 4;
+pub const VIRTIO_NET_CTRL_RX_NOBCAST: u32 = 5;
+pub const VIRTIO_NET_CTRL_MAC: u32 = 1;
+pub const VIRTIO_NET_CTRL_MAC_TABLE_SET: u32 = 0;
+pub const VIRTIO_NET_CTRL_MAC_ADDR_SET: u32 = 1;
+pub const VIRTIO_NET_CTRL_VLAN: u32 = 2;
+pub const VIRTIO_NET_CTRL_VLAN_ADD: u32 = 0;
+pub const VIRTIO_NET_CTRL_VLAN_DEL: u32 = 1;
+pub const VIRTIO_NET_CTRL_ANNOUNCE: u32 = 3;
+pub const VIRTIO_NET_CTRL_ANNOUNCE_ACK: u32 = 0;
+pub const VIRTIO_NET_CTRL_MQ: u32 = 4;
+pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: u32 = 0;
+pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN: u32 = 1;
+pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX: u32 = 32768;
+pub const VIRTIO_NET_CTRL_MQ_RSS_CONFIG: u32 = 1;
+pub const VIRTIO_NET_CTRL_MQ_HASH_CONFIG: u32 = 2;
+pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS: u32 = 5;
+pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET: u32 = 0;
+pub type __le16 = u16;
+pub type __le32 = u32;
+pub type __virtio16 = u16;
+pub type __virtio32 = u32;
#[repr(C, packed)]
-#[derive(Debug, Copy)]
-pub struct ethhdr {
- pub h_dest: [::std::os::raw::c_uchar; 6usize],
- pub h_source: [::std::os::raw::c_uchar; 6usize],
- pub h_proto: __be16,
-}
-#[test]
-fn bindgen_test_layout_ethhdr() {
- assert_eq!(
- ::std::mem::size_of::<ethhdr>(),
- 14usize,
- concat!("Size of: ", stringify!(ethhdr))
- );
- assert_eq!(
- ::std::mem::align_of::<ethhdr>(),
- 1usize,
- concat!("Alignment of ", stringify!(ethhdr))
- );
- assert_eq!(
- unsafe { &(*(0 as *const ethhdr)).h_dest as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(ethhdr),
- "::",
- stringify!(h_dest)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ethhdr)).h_source as *const _ as usize },
- 6usize,
- concat!(
- "Alignment of field: ",
- stringify!(ethhdr),
- "::",
- stringify!(h_source)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const ethhdr)).h_proto as *const _ as usize },
- 12usize,
- concat!(
- "Alignment of field: ",
- stringify!(ethhdr),
- "::",
- stringify!(h_proto)
- )
- );
-}
-impl Clone for ethhdr {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C, packed)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct virtio_net_config {
- pub mac: [__u8; 6usize],
- pub status: __u16,
- pub max_virtqueue_pairs: __u16,
- pub mtu: __u16,
-}
-#[test]
-fn bindgen_test_layout_virtio_net_config() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_config>(),
- 12usize,
- concat!("Size of: ", stringify!(virtio_net_config))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_config>(),
- 1usize,
- concat!("Alignment of ", stringify!(virtio_net_config))
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_config)).mac as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_config),
- "::",
- stringify!(mac)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_config)).status as *const _ as usize },
- 6usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_config),
- "::",
- stringify!(status)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_config)).max_virtqueue_pairs as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_config),
- "::",
- stringify!(max_virtqueue_pairs)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_config)).mtu as *const _ as usize },
- 10usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_config),
- "::",
- stringify!(mtu)
- )
- );
-}
-impl Clone for virtio_net_config {
- fn clone(&self) -> Self {
- *self
- }
+ pub mac: [u8; 6usize],
+ pub status: __virtio16,
+ pub max_virtqueue_pairs: __virtio16,
+ pub mtu: __virtio16,
+ pub speed: __le32,
+ pub duplex: u8,
+ pub rss_max_key_size: u8,
+ pub rss_max_indirection_table_length: __le16,
+ pub supported_hash_types: __le32,
}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Copy, Clone)]
pub struct virtio_net_hdr_v1 {
- pub flags: __u8,
- pub gso_type: __u8,
+ pub flags: u8,
+ pub gso_type: u8,
pub hdr_len: __virtio16,
pub gso_size: __virtio16,
- pub csum_start: __virtio16,
- pub csum_offset: __virtio16,
+ pub __bindgen_anon_1: virtio_net_hdr_v1__bindgen_ty_1,
pub num_buffers: __virtio16,
}
-#[test]
-fn bindgen_test_layout_virtio_net_hdr_v1() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_hdr_v1>(),
- 12usize,
- concat!("Size of: ", stringify!(virtio_net_hdr_v1))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_hdr_v1>(),
- 2usize,
- concat!("Alignment of ", stringify!(virtio_net_hdr_v1))
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).flags as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).gso_type as *const _ as usize },
- 1usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(gso_type)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).hdr_len as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(hdr_len)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).gso_size as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(gso_size)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).csum_start as *const _ as usize },
- 6usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(csum_start)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).csum_offset as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(csum_offset)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_v1)).num_buffers as *const _ as usize },
- 10usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_v1),
- "::",
- stringify!(num_buffers)
- )
- );
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union virtio_net_hdr_v1__bindgen_ty_1 {
+ pub __bindgen_anon_1: virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1,
+ pub csum: virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2,
+ pub rsc: virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3,
}
-impl Clone for virtio_net_hdr_v1 {
- fn clone(&self) -> Self {
- *self
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1 {
+ pub csum_start: __virtio16,
+ pub csum_offset: __virtio16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2 {
+ pub start: __virtio16,
+ pub offset: __virtio16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3 {
+ pub segments: __le16,
+ pub dup_acks: __le16,
+}
+impl Default for virtio_net_hdr_v1__bindgen_ty_1 {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+impl Default for virtio_net_hdr_v1 {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Copy, Clone)]
+pub struct virtio_net_hdr_v1_hash {
+ pub hdr: virtio_net_hdr_v1,
+ pub hash_value: __le32,
+ pub hash_report: __le16,
+ pub padding: __le16,
+}
+impl Default for virtio_net_hdr_v1_hash {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct virtio_net_hdr {
- pub flags: __u8,
- pub gso_type: __u8,
+ pub flags: u8,
+ pub gso_type: u8,
pub hdr_len: __virtio16,
pub gso_size: __virtio16,
pub csum_start: __virtio16,
pub csum_offset: __virtio16,
}
-#[test]
-fn bindgen_test_layout_virtio_net_hdr() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_hdr>(),
- 10usize,
- concat!("Size of: ", stringify!(virtio_net_hdr))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_hdr>(),
- 2usize,
- concat!("Alignment of ", stringify!(virtio_net_hdr))
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr)).flags as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr)).gso_type as *const _ as usize },
- 1usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr),
- "::",
- stringify!(gso_type)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr)).hdr_len as *const _ as usize },
- 2usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr),
- "::",
- stringify!(hdr_len)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr)).gso_size as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr),
- "::",
- stringify!(gso_size)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr)).csum_start as *const _ as usize },
- 6usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr),
- "::",
- stringify!(csum_start)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr)).csum_offset as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr),
- "::",
- stringify!(csum_offset)
- )
- );
-}
-impl Clone for virtio_net_hdr {
- fn clone(&self) -> Self {
- *self
- }
-}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct virtio_net_hdr_mrg_rxbuf {
pub hdr: virtio_net_hdr,
pub num_buffers: __virtio16,
}
-#[test]
-fn bindgen_test_layout_virtio_net_hdr_mrg_rxbuf() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_hdr_mrg_rxbuf>(),
- 12usize,
- concat!("Size of: ", stringify!(virtio_net_hdr_mrg_rxbuf))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_hdr_mrg_rxbuf>(),
- 2usize,
- concat!("Alignment of ", stringify!(virtio_net_hdr_mrg_rxbuf))
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_mrg_rxbuf)).hdr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_mrg_rxbuf),
- "::",
- stringify!(hdr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_hdr_mrg_rxbuf)).num_buffers as *const _ as usize },
- 10usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_hdr_mrg_rxbuf),
- "::",
- stringify!(num_buffers)
- )
- );
-}
-impl Clone for virtio_net_hdr_mrg_rxbuf {
- fn clone(&self) -> Self {
- *self
- }
-}
#[repr(C, packed)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct virtio_net_ctrl_hdr {
- pub class: __u8,
- pub cmd: __u8,
+ pub class: u8,
+ pub cmd: u8,
}
-#[test]
-fn bindgen_test_layout_virtio_net_ctrl_hdr() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_ctrl_hdr>(),
- 2usize,
- concat!("Size of: ", stringify!(virtio_net_ctrl_hdr))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_ctrl_hdr>(),
- 1usize,
- concat!("Alignment of ", stringify!(virtio_net_ctrl_hdr))
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_ctrl_hdr)).class as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_ctrl_hdr),
- "::",
- stringify!(class)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_ctrl_hdr)).cmd as *const _ as usize },
- 1usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_ctrl_hdr),
- "::",
- stringify!(cmd)
- )
- );
-}
-impl Clone for virtio_net_ctrl_hdr {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type virtio_net_ctrl_ack = __u8;
-#[repr(C, packed)]
-#[derive(Debug, Copy)]
-pub struct virtio_net_ctrl_mac {
- pub entries: __virtio32,
- pub macs: __IncompleteArrayField<[__u8; 6usize]>,
-}
-#[test]
-fn bindgen_test_layout_virtio_net_ctrl_mac() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_ctrl_mac>(),
- 4usize,
- concat!("Size of: ", stringify!(virtio_net_ctrl_mac))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_ctrl_mac>(),
- 1usize,
- concat!("Alignment of ", stringify!(virtio_net_ctrl_mac))
- );
-}
-impl Clone for virtio_net_ctrl_mac {
- fn clone(&self) -> Self {
- *self
- }
-}
+pub type virtio_net_ctrl_ack = u8;
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct virtio_net_ctrl_mq {
pub virtqueue_pairs: __virtio16,
}
-#[test]
-fn bindgen_test_layout_virtio_net_ctrl_mq() {
- assert_eq!(
- ::std::mem::size_of::<virtio_net_ctrl_mq>(),
- 2usize,
- concat!("Size of: ", stringify!(virtio_net_ctrl_mq))
- );
- assert_eq!(
- ::std::mem::align_of::<virtio_net_ctrl_mq>(),
- 2usize,
- concat!("Alignment of ", stringify!(virtio_net_ctrl_mq))
- );
- assert_eq!(
- unsafe { &(*(0 as *const virtio_net_ctrl_mq)).virtqueue_pairs as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(virtio_net_ctrl_mq),
- "::",
- stringify!(virtqueue_pairs)
- )
- );
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct virtio_net_rss_config {
+ pub hash_types: __le32,
+ pub indirection_table_mask: __le16,
+ pub unclassified_queue: __le16,
+ pub indirection_table: [__le16; 1usize],
+ pub max_tx_vq: __le16,
+ pub hash_key_length: u8,
+ pub hash_key_data: __IncompleteArrayField<u8>,
}
-impl Clone for virtio_net_ctrl_mq {
- fn clone(&self) -> Self {
- *self
- }
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct virtio_net_hash_config {
+ pub hash_types: __le32,
+ pub reserved: [__le16; 4usize],
+ pub hash_key_length: u8,
+ pub hash_key_data: __IncompleteArrayField<u8>,
}
diff --git a/virtio_sys/src/virtio_ring.rs b/virtio_sys/src/virtio_ring.rs
index eee59bc..e90b33e 100644
--- a/virtio_sys/src/virtio_ring.rs
+++ b/virtio_sys/src/virtio_ring.rs
@@ -1,26 +1,25 @@
-// Copyright 2019 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.
+/* automatically generated by tools/bindgen-all-the-things */
-#![allow(warnings)]
-
-/* automatically generated by rust-bindgen */
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
#[repr(C)]
#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
- pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData)
+ pub const fn new() -> Self {
+ __IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
- pub unsafe fn as_ptr(&self) -> *const T {
- ::std::mem::transmute(self)
+ pub fn as_ptr(&self) -> *const T {
+ self as *const _ as *const T
}
#[inline]
- pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
- ::std::mem::transmute(self)
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as *mut T
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
@@ -32,458 +31,92 @@
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
-}
-impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
-pub const _STDINT_H: ::std::os::raw::c_uint = 1;
-pub const _FEATURES_H: ::std::os::raw::c_uint = 1;
-pub const _DEFAULT_SOURCE: ::std::os::raw::c_uint = 1;
-pub const __USE_ISOC11: ::std::os::raw::c_uint = 1;
-pub const __USE_ISOC99: ::std::os::raw::c_uint = 1;
-pub const __USE_ISOC95: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX_IMPLICITLY: ::std::os::raw::c_uint = 1;
-pub const _POSIX_SOURCE: ::std::os::raw::c_uint = 1;
-pub const _POSIX_C_SOURCE: ::std::os::raw::c_uint = 200809;
-pub const __USE_POSIX: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX2: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX199309: ::std::os::raw::c_uint = 1;
-pub const __USE_POSIX199506: ::std::os::raw::c_uint = 1;
-pub const __USE_XOPEN2K: ::std::os::raw::c_uint = 1;
-pub const __USE_XOPEN2K8: ::std::os::raw::c_uint = 1;
-pub const _ATFILE_SOURCE: ::std::os::raw::c_uint = 1;
-pub const __USE_MISC: ::std::os::raw::c_uint = 1;
-pub const __USE_ATFILE: ::std::os::raw::c_uint = 1;
-pub const __USE_FORTIFY_LEVEL: ::std::os::raw::c_uint = 0;
-pub const _STDC_PREDEF_H: ::std::os::raw::c_uint = 1;
-pub const __STDC_IEC_559__: ::std::os::raw::c_uint = 1;
-pub const __STDC_IEC_559_COMPLEX__: ::std::os::raw::c_uint = 1;
-pub const __STDC_ISO_10646__: ::std::os::raw::c_uint = 201505;
-pub const __STDC_NO_THREADS__: ::std::os::raw::c_uint = 1;
-pub const __GNU_LIBRARY__: ::std::os::raw::c_uint = 6;
-pub const __GLIBC__: ::std::os::raw::c_uint = 2;
-pub const __GLIBC_MINOR__: ::std::os::raw::c_uint = 23;
-pub const _SYS_CDEFS_H: ::std::os::raw::c_uint = 1;
-pub const __WORDSIZE: ::std::os::raw::c_uint = 64;
-pub const __WORDSIZE_TIME64_COMPAT32: ::std::os::raw::c_uint = 1;
-pub const __SYSCALL_WORDSIZE: ::std::os::raw::c_uint = 64;
-pub const _BITS_WCHAR_H: ::std::os::raw::c_uint = 1;
-pub const INT8_MIN: ::std::os::raw::c_int = -128;
-pub const INT16_MIN: ::std::os::raw::c_int = -32768;
-pub const INT32_MIN: ::std::os::raw::c_int = -2147483648;
-pub const INT8_MAX: ::std::os::raw::c_uint = 127;
-pub const INT16_MAX: ::std::os::raw::c_uint = 32767;
-pub const INT32_MAX: ::std::os::raw::c_uint = 2147483647;
-pub const UINT8_MAX: ::std::os::raw::c_uint = 255;
-pub const UINT16_MAX: ::std::os::raw::c_uint = 65535;
-pub const UINT32_MAX: ::std::os::raw::c_uint = 4294967295;
-pub const INT_LEAST8_MIN: ::std::os::raw::c_int = -128;
-pub const INT_LEAST16_MIN: ::std::os::raw::c_int = -32768;
-pub const INT_LEAST32_MIN: ::std::os::raw::c_int = -2147483648;
-pub const INT_LEAST8_MAX: ::std::os::raw::c_uint = 127;
-pub const INT_LEAST16_MAX: ::std::os::raw::c_uint = 32767;
-pub const INT_LEAST32_MAX: ::std::os::raw::c_uint = 2147483647;
-pub const UINT_LEAST8_MAX: ::std::os::raw::c_uint = 255;
-pub const UINT_LEAST16_MAX: ::std::os::raw::c_uint = 65535;
-pub const UINT_LEAST32_MAX: ::std::os::raw::c_uint = 4294967295;
-pub const INT_FAST8_MIN: ::std::os::raw::c_int = -128;
-pub const INT_FAST16_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const INT_FAST32_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const INT_FAST8_MAX: ::std::os::raw::c_uint = 127;
-pub const INT_FAST16_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const INT_FAST32_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const UINT_FAST8_MAX: ::std::os::raw::c_uint = 255;
-pub const UINT_FAST16_MAX: ::std::os::raw::c_int = -1;
-pub const UINT_FAST32_MAX: ::std::os::raw::c_int = -1;
-pub const INTPTR_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const INTPTR_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const UINTPTR_MAX: ::std::os::raw::c_int = -1;
-pub const PTRDIFF_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
-pub const PTRDIFF_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
-pub const SIG_ATOMIC_MIN: ::std::os::raw::c_int = -2147483648;
-pub const SIG_ATOMIC_MAX: ::std::os::raw::c_uint = 2147483647;
-pub const SIZE_MAX: ::std::os::raw::c_int = -1;
-pub const WINT_MIN: ::std::os::raw::c_uint = 0;
-pub const WINT_MAX: ::std::os::raw::c_uint = 4294967295;
-pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
-pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
-pub const VRING_DESC_F_NEXT: ::std::os::raw::c_uint = 1;
-pub const VRING_DESC_F_WRITE: ::std::os::raw::c_uint = 2;
-pub const VRING_DESC_F_INDIRECT: ::std::os::raw::c_uint = 4;
-pub const VRING_USED_F_NO_NOTIFY: ::std::os::raw::c_uint = 1;
-pub const VRING_AVAIL_F_NO_INTERRUPT: ::std::os::raw::c_uint = 1;
-pub const VIRTIO_RING_F_INDIRECT_DESC: ::std::os::raw::c_uint = 28;
-pub const VIRTIO_RING_F_EVENT_IDX: ::std::os::raw::c_uint = 29;
-pub const VRING_AVAIL_ALIGN_SIZE: ::std::os::raw::c_uint = 2;
-pub const VRING_USED_ALIGN_SIZE: ::std::os::raw::c_uint = 4;
-pub const VRING_DESC_ALIGN_SIZE: ::std::os::raw::c_uint = 16;
-pub type int_least8_t = ::std::os::raw::c_schar;
-pub type int_least16_t = ::std::os::raw::c_short;
-pub type int_least32_t = ::std::os::raw::c_int;
-pub type int_least64_t = ::std::os::raw::c_long;
-pub type uint_least8_t = ::std::os::raw::c_uchar;
-pub type uint_least16_t = ::std::os::raw::c_ushort;
-pub type uint_least32_t = ::std::os::raw::c_uint;
-pub type uint_least64_t = ::std::os::raw::c_ulong;
-pub type int_fast8_t = ::std::os::raw::c_schar;
-pub type int_fast16_t = ::std::os::raw::c_long;
-pub type int_fast32_t = ::std::os::raw::c_long;
-pub type int_fast64_t = ::std::os::raw::c_long;
-pub type uint_fast8_t = ::std::os::raw::c_uchar;
-pub type uint_fast16_t = ::std::os::raw::c_ulong;
-pub type uint_fast32_t = ::std::os::raw::c_ulong;
-pub type uint_fast64_t = ::std::os::raw::c_ulong;
-pub type intmax_t = ::std::os::raw::c_long;
-pub type uintmax_t = ::std::os::raw::c_ulong;
-pub type __s8 = ::std::os::raw::c_schar;
-pub type __u8 = ::std::os::raw::c_uchar;
-pub type __s16 = ::std::os::raw::c_short;
-pub type __u16 = ::std::os::raw::c_ushort;
-pub type __s32 = ::std::os::raw::c_int;
-pub type __u32 = ::std::os::raw::c_uint;
-pub type __s64 = ::std::os::raw::c_longlong;
-pub type __u64 = ::std::os::raw::c_ulonglong;
+pub const VRING_DESC_F_NEXT: u32 = 1;
+pub const VRING_DESC_F_WRITE: u32 = 2;
+pub const VRING_DESC_F_INDIRECT: u32 = 4;
+pub const VRING_PACKED_DESC_F_AVAIL: u32 = 7;
+pub const VRING_PACKED_DESC_F_USED: u32 = 15;
+pub const VRING_USED_F_NO_NOTIFY: u32 = 1;
+pub const VRING_AVAIL_F_NO_INTERRUPT: u32 = 1;
+pub const VRING_PACKED_EVENT_FLAG_ENABLE: u32 = 0;
+pub const VRING_PACKED_EVENT_FLAG_DISABLE: u32 = 1;
+pub const VRING_PACKED_EVENT_FLAG_DESC: u32 = 2;
+pub const VRING_PACKED_EVENT_F_WRAP_CTR: u32 = 15;
+pub const VIRTIO_RING_F_INDIRECT_DESC: u32 = 28;
+pub const VIRTIO_RING_F_EVENT_IDX: u32 = 29;
+pub const VRING_AVAIL_ALIGN_SIZE: u32 = 2;
+pub const VRING_USED_ALIGN_SIZE: u32 = 4;
+pub const VRING_DESC_ALIGN_SIZE: u32 = 16;
+pub type __le16 = u16;
+pub type __le32 = u32;
+pub type __le64 = u64;
+pub type __virtio16 = u16;
+pub type __virtio32 = u32;
+pub type __virtio64 = u64;
#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct __kernel_fd_set {
- pub fds_bits: [::std::os::raw::c_ulong; 16usize],
-}
-#[test]
-#[ignore]
-fn bindgen_test_layout___kernel_fd_set() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fd_set>(),
- 128usize,
- concat!("Size of: ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fd_set>(),
- 8usize,
- concat!("Alignment of ", stringify!(__kernel_fd_set))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fd_set),
- "::",
- stringify!(fds_bits)
- )
- );
-}
-impl Clone for __kernel_fd_set {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_sighandler_t =
- ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
-pub type __kernel_key_t = ::std::os::raw::c_int;
-pub type __kernel_mqd_t = ::std::os::raw::c_int;
-pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
-pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
-pub type __kernel_long_t = ::std::os::raw::c_long;
-pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
-pub type __kernel_ino_t = __kernel_ulong_t;
-pub type __kernel_mode_t = ::std::os::raw::c_uint;
-pub type __kernel_pid_t = ::std::os::raw::c_int;
-pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
-pub type __kernel_uid_t = ::std::os::raw::c_uint;
-pub type __kernel_gid_t = ::std::os::raw::c_uint;
-pub type __kernel_suseconds_t = __kernel_long_t;
-pub type __kernel_daddr_t = ::std::os::raw::c_int;
-pub type __kernel_uid32_t = ::std::os::raw::c_uint;
-pub type __kernel_gid32_t = ::std::os::raw::c_uint;
-pub type __kernel_size_t = __kernel_ulong_t;
-pub type __kernel_ssize_t = __kernel_long_t;
-pub type __kernel_ptrdiff_t = __kernel_long_t;
-#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct __kernel_fsid_t {
- pub val: [::std::os::raw::c_int; 2usize],
-}
-#[test]
-fn bindgen_test_layout___kernel_fsid_t() {
- assert_eq!(
- ::std::mem::size_of::<__kernel_fsid_t>(),
- 8usize,
- concat!("Size of: ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- ::std::mem::align_of::<__kernel_fsid_t>(),
- 4usize,
- concat!("Alignment of ", stringify!(__kernel_fsid_t))
- );
- assert_eq!(
- unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(__kernel_fsid_t),
- "::",
- stringify!(val)
- )
- );
-}
-impl Clone for __kernel_fsid_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-pub type __kernel_off_t = __kernel_long_t;
-pub type __kernel_loff_t = ::std::os::raw::c_longlong;
-pub type __kernel_time_t = __kernel_long_t;
-pub type __kernel_clock_t = __kernel_long_t;
-pub type __kernel_timer_t = ::std::os::raw::c_int;
-pub type __kernel_clockid_t = ::std::os::raw::c_int;
-pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
-pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
-pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
-pub type __le16 = __u16;
-pub type __be16 = __u16;
-pub type __le32 = __u32;
-pub type __be32 = __u32;
-pub type __le64 = __u64;
-pub type __be64 = __u64;
-pub type __sum16 = __u16;
-pub type __wsum = __u32;
-pub type __virtio16 = __u16;
-pub type __virtio32 = __u32;
-pub type __virtio64 = __u64;
-#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct vring_desc {
pub addr: __virtio64,
pub len: __virtio32,
pub flags: __virtio16,
pub next: __virtio16,
}
-#[test]
-fn bindgen_test_layout_vring_desc() {
- assert_eq!(
- ::std::mem::size_of::<vring_desc>(),
- 16usize,
- concat!("Size of: ", stringify!(vring_desc))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_desc>(),
- 8usize,
- concat!("Alignment of ", stringify!(vring_desc))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).addr as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(addr)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).len as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(len)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).flags as *const _ as usize },
- 12usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_desc)).next as *const _ as usize },
- 14usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_desc),
- "::",
- stringify!(next)
- )
- );
-}
-impl Clone for vring_desc {
- fn clone(&self) -> Self {
- *self
- }
-}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default)]
pub struct vring_avail {
pub flags: __virtio16,
pub idx: __virtio16,
pub ring: __IncompleteArrayField<__virtio16>,
}
-#[test]
-fn bindgen_test_layout_vring_avail() {
- assert_eq!(
- ::std::mem::size_of::<vring_avail>(),
- 4usize,
- concat!("Size of: ", stringify!(vring_avail))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_avail>(),
- 2usize,
- concat!("Alignment of ", stringify!(vring_avail))
- );
-}
-impl Clone for vring_avail {
- fn clone(&self) -> Self {
- *self
- }
-}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct vring_used_elem {
pub id: __virtio32,
pub len: __virtio32,
}
-#[test]
-fn bindgen_test_layout_vring_used_elem() {
- assert_eq!(
- ::std::mem::size_of::<vring_used_elem>(),
- 8usize,
- concat!("Size of: ", stringify!(vring_used_elem))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_used_elem>(),
- 4usize,
- concat!("Alignment of ", stringify!(vring_used_elem))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_used_elem)).id as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_used_elem),
- "::",
- stringify!(id)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring_used_elem)).len as *const _ as usize },
- 4usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring_used_elem),
- "::",
- stringify!(len)
- )
- );
-}
-impl Clone for vring_used_elem {
- fn clone(&self) -> Self {
- *self
- }
-}
+pub type vring_used_elem_t = vring_used_elem;
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Debug, Default)]
pub struct vring_used {
pub flags: __virtio16,
pub idx: __virtio16,
- pub ring: __IncompleteArrayField<vring_used_elem>,
- pub __bindgen_align: [u32; 0usize],
+ pub ring: __IncompleteArrayField<vring_used_elem_t>,
}
-#[test]
-fn bindgen_test_layout_vring_used() {
- assert_eq!(
- ::std::mem::size_of::<vring_used>(),
- 4usize,
- concat!("Size of: ", stringify!(vring_used))
- );
- assert_eq!(
- ::std::mem::align_of::<vring_used>(),
- 4usize,
- concat!("Alignment of ", stringify!(vring_used))
- );
+pub type vring_desc_t = vring_desc;
+pub type vring_avail_t = vring_avail;
+pub type vring_used_t = vring_used;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct vring {
+ pub num: ::std::os::raw::c_uint,
+ pub desc: *mut vring_desc_t,
+ pub avail: *mut vring_avail_t,
+ pub used: *mut vring_used_t,
}
-impl Clone for vring_used {
- fn clone(&self) -> Self {
- *self
+impl Default for vring {
+ fn default() -> Self {
+ let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
}
}
#[repr(C)]
-#[derive(Debug, Copy)]
-pub struct vring {
- pub num: ::std::os::raw::c_uint,
- pub desc: *mut vring_desc,
- pub avail: *mut vring_avail,
- pub used: *mut vring_used,
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vring_packed_desc_event {
+ pub off_wrap: __le16,
+ pub flags: __le16,
}
-#[test]
-#[ignore]
-fn bindgen_test_layout_vring() {
- assert_eq!(
- ::std::mem::size_of::<vring>(),
- 32usize,
- concat!("Size of: ", stringify!(vring))
- );
- assert_eq!(
- ::std::mem::align_of::<vring>(),
- 8usize,
- concat!("Alignment of ", stringify!(vring))
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).num as *const _ as usize },
- 0usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(num)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).desc as *const _ as usize },
- 8usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(desc)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).avail as *const _ as usize },
- 16usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(avail)
- )
- );
- assert_eq!(
- unsafe { &(*(0 as *const vring)).used as *const _ as usize },
- 24usize,
- concat!(
- "Alignment of field: ",
- stringify!(vring),
- "::",
- stringify!(used)
- )
- );
-}
-impl Clone for vring {
- fn clone(&self) -> Self {
- *self
- }
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vring_packed_desc {
+ pub addr: __le64,
+ pub len: __le32,
+ pub id: __le16,
+ pub flags: __le16,
}
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index f920b51..b8499d6 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -36,7 +36,7 @@
use balloon_control::{BalloonTubeCommand, BalloonTubeResult};
use base::{
- error, with_as_descriptor, AsRawDescriptor, Error as SysError, Event, ExternalMapping, Fd,
+ error, with_as_descriptor, AsRawDescriptor, Error as SysError, Event, ExternalMapping,
FromRawDescriptor, IntoRawDescriptor, Killable, MappedRegion, MemoryMappingArena,
MemoryMappingBuilder, MemoryMappingBuilderUnix, MmapError, Protection, Result, SafeDescriptor,
SharedMemory, Tube, SIGRTMIN,
@@ -525,6 +525,9 @@
/// Allocate one gsi, and associate gsi to irqfd with register_irqfd()
AllocateOneMsi {
irqfd: Event,
+ device_id: u32,
+ queue_id: usize,
+ device_name: String,
},
/// Add one msi route entry into the IRQ chip.
AddMsiRoute {
@@ -543,7 +546,7 @@
/// VmIrqRequest::execute can't take an `IrqChip` argument, because of a dependency cycle between
/// devices and vm_control, so it takes a Fn that processes an `IrqSetup`.
pub enum IrqSetup<'a> {
- Event(u32, &'a Event),
+ Event(u32, &'a Event, u32, usize, String),
Route(IrqRoute),
UnRegister(u32, &'a Event),
}
@@ -563,9 +566,20 @@
{
use self::VmIrqRequest::*;
match *self {
- AllocateOneMsi { ref irqfd } => {
+ AllocateOneMsi {
+ ref irqfd,
+ device_id,
+ queue_id,
+ ref device_name,
+ } => {
if let Some(irq_num) = sys_allocator.allocate_irq() {
- match set_up_irq(IrqSetup::Event(irq_num, irqfd)) {
+ match set_up_irq(IrqSetup::Event(
+ irq_num,
+ irqfd,
+ device_id,
+ queue_id,
+ device_name.clone(),
+ )) {
Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
Err(e) => VmIrqResponse::Err(e),
}
@@ -922,13 +936,11 @@
prot,
mem_offset,
} => {
- let raw_fd: Fd = Fd(fd.as_raw_descriptor());
-
match vm.add_fd_mapping(
slot,
mem_offset,
size,
- &raw_fd,
+ fd,
file_offset,
Protection::from(prot as c_int & (libc::PROT_READ | libc::PROT_WRITE)),
) {
diff --git a/vm_memory/src/guest_address.rs b/vm_memory/src/guest_address.rs
index 457132e..a3af75c 100644
--- a/vm_memory/src/guest_address.rs
+++ b/vm_memory/src/guest_address.rs
@@ -115,12 +115,14 @@
#[test]
#[allow(clippy::eq_op)]
+ #[allow(clippy::nonminimal_bool)]
fn cmp() {
let a = GuestAddress(0x300);
let b = GuestAddress(0x301);
assert!(a < b);
assert!(b > a);
assert!(!(a < a));
+ assert!(a >= a);
}
#[test]
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index 489d1d1..577b47c 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -1327,28 +1327,18 @@
let pcie_vcfg = aml::Name::new("VCFG".into(), &Self::get_pcie_vcfg_mmio_base(mem));
pcie_vcfg.to_aml_bytes(&mut amls);
- let pm_sci_evt = Event::new().map_err(Error::CreateEvent)?;
- let pm_sci_evt_resample = Event::new().map_err(Error::CreateEvent)?;
+ let pm_sci_evt = devices::IrqLevelEvent::new().map_err(Error::CreateEvent)?;
irq_chip
- .register_irq_event(sci_irq, &pm_sci_evt, Some(&pm_sci_evt_resample))
+ .register_level_irq_event(sci_irq, &pm_sci_evt)
.map_err(Error::RegisterIrqfd)?;
#[cfg(feature = "direct")]
let direct_gpe_info = if direct_gpe.is_empty() {
None
} else {
- let direct_sci_evt = Event::new().map_err(Error::CreateEvent)?;
- let direct_sci_evt_resample = Event::new().map_err(Error::CreateEvent)?;
-
- let mut sci_devirq = devices::DirectIrq::new(
- direct_sci_evt.try_clone().map_err(Error::CloneEvent)?,
- Some(
- direct_sci_evt_resample
- .try_clone()
- .map_err(Error::CloneEvent)?,
- ),
- )
- .map_err(Error::CreateGpe)?;
+ let direct_sci_evt = devices::IrqLevelEvent::new().map_err(Error::CreateEvent)?;
+ let mut sci_devirq =
+ devices::DirectIrq::new_level(&direct_sci_evt).map_err(Error::CreateGpe)?;
sci_devirq.sci_irq_prepare().map_err(Error::CreateGpe)?;
@@ -1358,12 +1348,11 @@
.map_err(Error::CreateGpe)?;
}
- Some((direct_sci_evt, direct_sci_evt_resample, direct_gpe))
+ Some((direct_sci_evt, direct_gpe))
};
let mut pmresource = devices::ACPIPMResource::new(
pm_sci_evt,
- pm_sci_evt_resample,
#[cfg(feature = "direct")]
direct_gpe_info,
suspend_evt,
@@ -1454,24 +1443,24 @@
serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
serial_jail: Option<Minijail>,
) -> Result<()> {
- let com_evt_1_3 = Event::new().map_err(Error::CreateEvent)?;
- let com_evt_2_4 = Event::new().map_err(Error::CreateEvent)?;
+ let com_evt_1_3 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
+ let com_evt_2_4 = devices::IrqEdgeEvent::new().map_err(Error::CreateEvent)?;
arch::add_serial_devices(
protected_vm,
io_bus,
- &com_evt_1_3,
- &com_evt_2_4,
+ com_evt_1_3.get_trigger(),
+ com_evt_2_4.get_trigger(),
serial_parameters,
serial_jail,
)
.map_err(Error::CreateSerialDevices)?;
irq_chip
- .register_irq_event(X86_64_SERIAL_1_3_IRQ, &com_evt_1_3, None)
+ .register_edge_irq_event(X86_64_SERIAL_1_3_IRQ, &com_evt_1_3)
.map_err(Error::RegisterIrqfd)?;
irq_chip
- .register_irq_event(X86_64_SERIAL_2_4_IRQ, &com_evt_2_4, None)
+ .register_edge_irq_event(X86_64_SERIAL_2_4_IRQ, &com_evt_2_4)
.map_err(Error::RegisterIrqfd)?;
Ok(())