summary refs log tree commit diff
path: root/devices
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2020-05-08 15:27:56 +0000
committerAlyssa Ross <hi@alyssa.is>2020-05-10 02:39:28 +0000
commit2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b (patch)
treefefaf2c13796f8f2fa9a13b99b09c3b40ab5966b /devices
parent00c41c28bbc44b37fc8dcf5d2a5b4679f2aa4297 (diff)
parent03a54abf852984f696e7a101ff9590f05ebcba5b (diff)
downloadcrosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.tar
crosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.tar.gz
crosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.tar.bz2
crosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.tar.lz
crosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.tar.xz
crosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.tar.zst
crosvm-2f8d50adc97cc7fca6f710bd575b4f71ccb40f6b.zip
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'devices')
-rw-r--r--devices/src/lib.rs11
-rw-r--r--devices/src/pci/ac97.rs44
-rw-r--r--devices/src/pci/ac97_bus_master.rs1
-rw-r--r--devices/src/pci/mod.rs2
-rw-r--r--devices/src/pci/pci_device.rs11
-rw-r--r--devices/src/pci/pci_root.rs164
-rw-r--r--devices/src/pci/vfio_pci.rs32
-rw-r--r--devices/src/register_space/register.rs1
-rw-r--r--devices/src/serial.rs234
-rw-r--r--devices/src/serial_device.rs19
-rw-r--r--devices/src/usb/host_backend/host_device.rs29
-rw-r--r--devices/src/usb/xhci/event_ring.rs1
-rw-r--r--devices/src/usb/xhci/xhci_abi.rs2
-rw-r--r--devices/src/usb/xhci/xhci_controller.rs25
-rw-r--r--devices/src/virtio/balloon.rs1
-rw-r--r--devices/src/virtio/console.rs23
-rw-r--r--devices/src/virtio/descriptor_utils.rs10
-rw-r--r--devices/src/virtio/fs/filesystem.rs4
-rw-r--r--devices/src/virtio/fs/fuse.rs1
-rw-r--r--devices/src/virtio/fs/passthrough.rs110
-rw-r--r--devices/src/virtio/fs/server.rs13
-rw-r--r--devices/src/virtio/gpu/mod.rs11
-rw-r--r--devices/src/virtio/gpu/protocol.rs4
-rw-r--r--devices/src/virtio/input/constants.rs14
-rw-r--r--devices/src/virtio/net.rs1
-rw-r--r--devices/src/virtio/p9.rs1
-rw-r--r--devices/src/virtio/pmem.rs11
-rw-r--r--devices/src/virtio/rng.rs1
-rw-r--r--devices/src/virtio/tpm.rs1
-rw-r--r--devices/src/virtio/vhost/mod.rs1
-rw-r--r--devices/src/virtio/vhost/net.rs1
-rw-r--r--devices/src/virtio/virtio_device.rs4
-rw-r--r--devices/src/virtio/virtio_pci_device.rs41
-rw-r--r--devices/src/virtio/wl.rs11
34 files changed, 363 insertions, 477 deletions
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 9ed8417..01c2b46 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -17,6 +17,7 @@ mod proxy;
 mod register_space;
 pub mod acpi;
 mod serial;
+mod serial_device;
 pub mod split_irqchip_common;
 pub mod usb;
 mod utils;
@@ -30,18 +31,16 @@ pub use self::cmos::Cmos;
 pub use self::i8042::I8042Device;
 pub use self::ioapic::{Ioapic, IOAPIC_BASE_ADDRESS, IOAPIC_MEM_LENGTH_BYTES};
 pub use self::pci::{
-    Ac97Backend, Ac97Dev, Ac97Parameters, PciConfigIo, PciConfigMmio, PciDevice, PciDeviceError,
-    PciInterruptPin, PciRoot, VfioPciDevice,
+    Ac97Backend, Ac97Dev, Ac97Parameters, PciAddress, PciConfigIo, PciConfigMmio, PciDevice,
+    PciDeviceError, PciInterruptPin, PciRoot, VfioPciDevice,
 };
 pub use self::pic::Pic;
 pub use self::pit::{Pit, PitError};
 pub use self::pl030::Pl030;
 pub use self::proxy::Error as ProxyError;
 pub use self::proxy::ProxyDevice;
-pub use self::serial::Error as SerialError;
-pub use self::serial::{
-    get_serial_tty_string, Serial, SerialParameters, SerialType, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
-};
+pub use self::serial::Serial;
+pub use self::serial_device::SerialDevice;
 pub use self::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
 pub use self::usb::xhci::xhci_controller::XhciController;
 pub use self::vfio::{VfioContainer, VfioDevice};
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs
index d061746..8a6748d 100644
--- a/devices/src/pci/ac97.rs
+++ b/devices/src/pci/ac97.rs
@@ -12,7 +12,7 @@ use audio_streams::{
     shm_streams::{NullShmStreamSource, ShmStreamSource},
     StreamEffect,
 };
-use libcras::{CrasClient, CrasClientType};
+use libcras::{CrasClient, CrasClientType, CrasSocketType};
 use resources::{Alloc, MmioType, SystemAllocator};
 use sys_util::{error, EventFd, GuestMemory};
 
@@ -23,7 +23,7 @@ use crate::pci::pci_configuration::{
     PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass,
 };
 use crate::pci::pci_device::{self, PciDevice, Result};
-use crate::pci::PciInterruptPin;
+use crate::pci::{PciAddress, PciInterruptPin};
 
 // Use 82801AA because it's what qemu does.
 const PCI_DEVICE_ID_INTEL_82801AA_5: u16 = 0x2415;
@@ -82,7 +82,7 @@ pub struct Ac97Parameters {
 
 pub struct Ac97Dev {
     config_regs: PciConfiguration,
-    pci_bus_dev: Option<(u8, u8)>,
+    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<EventFd>,
@@ -108,7 +108,7 @@ impl Ac97Dev {
 
         Ac97Dev {
             config_regs,
-            pci_bus_dev: None,
+            pci_address: None,
             irq_evt: None,
             irq_resample_evt: None,
             bus_master: Ac97BusMaster::new(mem, audio_server),
@@ -117,8 +117,10 @@ impl Ac97Dev {
     }
 
     fn create_cras_audio_device(params: Ac97Parameters, mem: GuestMemory) -> Result<Ac97Dev> {
-        let mut server =
-            Box::new(CrasClient::new().map_err(|e| pci_device::Error::CreateCrasClientFailed(e))?);
+        let mut server = Box::new(
+            CrasClient::with_type(CrasSocketType::Unified)
+                .map_err(|e| pci_device::Error::CreateCrasClientFailed(e))?,
+        );
         server.set_client_type(CrasClientType::CRAS_CLIENT_TYPE_CROSVM);
         if params.capture {
             server.enable_cras_capture();
@@ -214,8 +216,8 @@ impl PciDevice for Ac97Dev {
         "AC97".to_owned()
     }
 
-    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
-        self.pci_bus_dev = Some((bus, device));
+    fn assign_address(&mut self, address: PciAddress) {
+        self.pci_address = Some(address);
     }
 
     fn assign_irq(
@@ -231,15 +233,20 @@ impl PciDevice for Ac97Dev {
     }
 
     fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
-        let (bus, dev) = self
-            .pci_bus_dev
-            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        let address = self
+            .pci_address
+            .expect("assign_address must be called prior to allocate_io_bars");
         let mut ranges = Vec::new();
         let mixer_regs_addr = resources
             .mmio_allocator(MmioType::Low)
             .allocate_with_align(
                 MIXER_REGS_SIZE,
-                Alloc::PciBar { bus, dev, bar: 0 },
+                Alloc::PciBar {
+                    bus: address.bus,
+                    dev: address.dev,
+                    func: address.func,
+                    bar: 0,
+                },
                 "ac97-mixer_regs".to_string(),
                 MIXER_REGS_SIZE,
             )
@@ -257,7 +264,12 @@ impl PciDevice for Ac97Dev {
             .mmio_allocator(MmioType::Low)
             .allocate_with_align(
                 MASTER_REGS_SIZE,
-                Alloc::PciBar { bus, dev, bar: 1 },
+                Alloc::PciBar {
+                    bus: address.bus,
+                    dev: address.dev,
+                    func: address.func,
+                    bar: 1,
+                },
                 "ac97-master_regs".to_string(),
                 MASTER_REGS_SIZE,
             )
@@ -336,7 +348,11 @@ mod tests {
             .add_high_mmio_addresses(0x3000_0000, 0x1000_0000)
             .create_allocator(5, false)
             .unwrap();
-        ac97_dev.assign_bus_dev(0, 0);
+        ac97_dev.assign_address(PciAddress {
+            bus: 0,
+            dev: 0,
+            func: 0,
+        });
         assert!(ac97_dev.allocate_io_bars(&mut allocator).is_ok());
     }
 }
diff --git a/devices/src/pci/ac97_bus_master.rs b/devices/src/pci/ac97_bus_master.rs
index 809f31f..22f3c92 100644
--- a/devices/src/pci/ac97_bus_master.rs
+++ b/devices/src/pci/ac97_bus_master.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;
 use std::collections::VecDeque;
 use std::convert::AsRef;
 use std::convert::TryInto;
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index b9ebc19..0edc3b2 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -23,7 +23,7 @@ pub use self::pci_configuration::{
 };
 pub use self::pci_device::Error as PciDeviceError;
 pub use self::pci_device::PciDevice;
-pub use self::pci_root::{PciConfigIo, PciConfigMmio, PciRoot};
+pub use self::pci_root::{PciAddress, PciConfigIo, PciConfigMmio, PciRoot};
 pub use self::vfio_pci::VfioPciDevice;
 
 /// PCI has four interrupt pins A->D.
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs
index a1a3cca..244edbd 100644
--- a/devices/src/pci/pci_device.rs
+++ b/devices/src/pci/pci_device.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;
 use std::fmt::{self, Display};
 use std::os::unix::io::RawFd;
 
@@ -11,7 +10,7 @@ use resources::{Error as SystemAllocatorFaliure, SystemAllocator};
 use sys_util::EventFd;
 
 use crate::pci::pci_configuration;
-use crate::pci::PciInterruptPin;
+use crate::pci::{PciAddress, PciInterruptPin};
 use crate::BusDevice;
 
 #[derive(Debug)]
@@ -49,8 +48,8 @@ impl Display for Error {
 pub trait PciDevice: Send {
     /// Returns a label suitable for debug output.
     fn debug_label(&self) -> String;
-    /// Assign a unique bus and device number to this device.
-    fn assign_bus_dev(&mut self, _bus: u8, _device: u8 /*u5*/) {}
+    /// Assign a unique bus, device and function number to this device.
+    fn assign_address(&mut self, _address: PciAddress) {}
     /// A vector of device-specific file descriptors that must be kept open
     /// after jailing. Must be called before the process is jailed.
     fn keep_fds(&self) -> Vec<RawFd>;
@@ -149,8 +148,8 @@ impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
     fn debug_label(&self) -> String {
         (**self).debug_label()
     }
-    fn assign_bus_dev(&mut self, bus: u8, device: u8 /*u5*/) {
-        (**self).assign_bus_dev(bus, device)
+    fn assign_address(&mut self, address: PciAddress) {
+        (**self).assign_address(address)
     }
     fn keep_fds(&self) -> Vec<RawFd> {
         (**self).keep_fds()
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
index eef642e..91d6094 100644
--- a/devices/src/pci/pci_root.rs
+++ b/devices/src/pci/pci_root.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 std::collections::BTreeMap;
 use std::convert::TryInto;
+use std::fmt::{self, Display};
 use std::os::unix::io::RawFd;
 use std::sync::Arc;
 
@@ -39,12 +41,67 @@ impl PciDevice for PciRootConfiguration {
     fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
 }
 
+/// PCI Device Address, AKA Bus:Device.Function
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PciAddress {
+    pub bus: u8,
+    pub dev: u8,  /* u5 */
+    pub func: u8, /* u3 */
+}
+
+impl Display for PciAddress {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:04x}:{:02x}.{:0x}", self.bus, self.dev, self.func)
+    }
+}
+
+impl PciAddress {
+    const BUS_OFFSET: usize = 16;
+    const BUS_MASK: u32 = 0x00ff;
+    const DEVICE_OFFSET: usize = 11;
+    const DEVICE_MASK: u32 = 0x1f;
+    const FUNCTION_OFFSET: usize = 8;
+    const FUNCTION_MASK: u32 = 0x07;
+    const REGISTER_OFFSET: usize = 2;
+    const REGISTER_MASK: u32 = 0x3f;
+
+    /// Construct PciAddress and register tuple from CONFIG_ADDRESS value.
+    pub fn from_config_address(config_address: u32) -> (Self, usize) {
+        let bus = ((config_address >> Self::BUS_OFFSET) & Self::BUS_MASK) as u8;
+        let dev = ((config_address >> Self::DEVICE_OFFSET) & Self::DEVICE_MASK) as u8;
+        let func = ((config_address >> Self::FUNCTION_OFFSET) & Self::FUNCTION_MASK) as u8;
+        let register = ((config_address >> Self::REGISTER_OFFSET) & Self::REGISTER_MASK) as usize;
+
+        (PciAddress { bus, dev, func }, register)
+    }
+
+    /// Encode PciAddress into CONFIG_ADDRESS value.
+    pub fn to_config_address(&self, register: usize) -> u32 {
+        ((Self::BUS_MASK & self.bus as u32) << Self::BUS_OFFSET)
+            | ((Self::DEVICE_MASK & self.dev as u32) << Self::DEVICE_OFFSET)
+            | ((Self::FUNCTION_MASK & self.func as u32) << Self::FUNCTION_OFFSET)
+            | ((Self::REGISTER_MASK & register as u32) << Self::REGISTER_OFFSET)
+    }
+
+    /// Returns true if the address points to PCI root host-bridge.
+    fn is_root(&self) -> bool {
+        matches!(
+            &self,
+            PciAddress {
+                bus: 0,
+                dev: 0,
+                func: 0
+            }
+        )
+    }
+}
+
 /// Emulates the PCI Root bridge.
 pub struct PciRoot {
     /// Bus configuration for the root device.
     root_configuration: PciRootConfiguration,
     /// Devices attached to this bridge.
-    devices: Vec<Arc<Mutex<dyn BusDevice>>>,
+    devices: BTreeMap<PciAddress, Arc<Mutex<dyn BusDevice>>>,
 }
 
 const PCI_VENDOR_ID_INTEL: u16 = 0x8086;
@@ -66,44 +123,31 @@ impl PciRoot {
                     0,
                 ),
             },
-            devices: Vec::new(),
+            devices: BTreeMap::new(),
         }
     }
 
     /// Add a `device` to this root PCI bus.
-    pub fn add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>) {
-        self.devices.push(device);
-    }
-
-    pub fn config_space_read(
-        &self,
-        bus: usize,
-        device: usize,
-        _function: usize,
-        register: usize,
-    ) -> u32 {
-        // Only support one bus.
-        if bus != 0 {
-            return 0xffff_ffff;
+    pub fn add_device(&mut self, address: PciAddress, device: Arc<Mutex<dyn BusDevice>>) {
+        // Ignore attempt to replace PCI Root host bridge.
+        if !address.is_root() {
+            self.devices.insert(address, device);
         }
+    }
 
-        match device {
-            0 => {
-                // If bus and device are both zero, then read from the root config.
-                self.root_configuration.config_register_read(register)
-            }
-            dev_num => self
-                .devices
-                .get(dev_num - 1)
-                .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)),
+    pub fn config_space_read(&self, address: PciAddress, register: usize) -> u32 {
+        if address.is_root() {
+            self.root_configuration.config_register_read(register)
+        } else {
+            self.devices
+                .get(&address)
+                .map_or(0xffff_ffff, |d| d.lock().config_register_read(register))
         }
     }
 
     pub fn config_space_write(
         &mut self,
-        bus: usize,
-        device: usize,
-        _function: usize,
+        address: PciAddress,
         register: usize,
         offset: u64,
         data: &[u8],
@@ -111,24 +155,11 @@ impl PciRoot {
         if offset as usize + data.len() > 4 {
             return;
         }
-
-        // Only support one bus.
-        if bus != 0 {
-            return;
-        }
-
-        match device {
-            0 => {
-                // If bus and device are both zero, then read from the root config.
-                self.root_configuration
-                    .config_register_write(register, offset, data);
-            }
-            dev_num => {
-                // dev_num is 1-indexed here.
-                if let Some(d) = self.devices.get(dev_num - 1) {
-                    d.lock().config_register_write(register, offset, data);
-                }
-            }
+        if address.is_root() {
+            self.root_configuration
+                .config_register_write(register, offset, data);
+        } else if let Some(d) = self.devices.get(&address) {
+            d.lock().config_register_write(register, offset, data);
         }
     }
 }
@@ -155,10 +186,8 @@ impl PciConfigIo {
             return 0xffff_ffff;
         }
 
-        let (bus, device, function, register) =
-            parse_config_address(self.config_address & !0x8000_0000);
-        self.pci_root
-            .config_space_read(bus, device, function, register)
+        let (address, register) = PciAddress::from_config_address(self.config_address);
+        self.pci_root.config_space_read(address, register)
     }
 
     fn config_space_write(&mut self, offset: u64, data: &[u8]) {
@@ -167,10 +196,9 @@ impl PciConfigIo {
             return;
         }
 
-        let (bus, device, function, register) =
-            parse_config_address(self.config_address & !0x8000_0000);
+        let (address, register) = PciAddress::from_config_address(self.config_address);
         self.pci_root
-            .config_space_write(bus, device, function, register, offset, data)
+            .config_space_write(address, register, offset, data)
     }
 
     fn set_config_address(&mut self, offset: u64, data: &[u8]) {
@@ -242,15 +270,14 @@ impl PciConfigMmio {
     }
 
     fn config_space_read(&self, config_address: u32) -> u32 {
-        let (bus, device, function, register) = parse_config_address(config_address);
-        self.pci_root
-            .config_space_read(bus, device, function, register)
+        let (address, register) = PciAddress::from_config_address(config_address);
+        self.pci_root.config_space_read(address, register)
     }
 
     fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
-        let (bus, device, function, register) = parse_config_address(config_address);
+        let (address, register) = PciAddress::from_config_address(config_address);
         self.pci_root
-            .config_space_write(bus, device, function, register, offset, data)
+            .config_space_write(address, register, offset, data)
     }
 }
 
@@ -283,24 +310,3 @@ impl BusDevice for PciConfigMmio {
         self.config_space_write(offset as u32, offset % 4, data)
     }
 }
-
-// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
-fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
-    const BUS_NUMBER_OFFSET: usize = 16;
-    const BUS_NUMBER_MASK: u32 = 0x00ff;
-    const DEVICE_NUMBER_OFFSET: usize = 11;
-    const DEVICE_NUMBER_MASK: u32 = 0x1f;
-    const FUNCTION_NUMBER_OFFSET: usize = 8;
-    const FUNCTION_NUMBER_MASK: u32 = 0x07;
-    const REGISTER_NUMBER_OFFSET: usize = 2;
-    const REGISTER_NUMBER_MASK: u32 = 0x3f;
-
-    let bus_number = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as usize;
-    let device_number = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as usize;
-    let function_number =
-        ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as usize;
-    let register_number =
-        ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize;
-
-    (bus_number, device_number, function_number, register_number)
-}
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index 5c13d28..671e8cd 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -22,7 +22,7 @@ use crate::pci::msix::{
 };
 
 use crate::pci::pci_device::{Error as PciDeviceError, PciDevice};
-use crate::pci::{PciClassCode, PciInterruptPin};
+use crate::pci::{PciAddress, PciClassCode, PciInterruptPin};
 
 use crate::vfio::{VfioDevice, VfioIrqType};
 
@@ -457,7 +457,7 @@ enum DeviceData {
 pub struct VfioPciDevice {
     device: Arc<VfioDevice>,
     config: VfioPciConfig,
-    pci_bus_dev: Option<(u8, u8)>,
+    pci_address: Option<PciAddress>,
     interrupt_evt: Option<EventFd>,
     interrupt_resample_evt: Option<EventFd>,
     mmio_regions: Vec<MmioInfo>,
@@ -522,7 +522,7 @@ impl VfioPciDevice {
         VfioPciDevice {
             device: dev,
             config,
-            pci_bus_dev: None,
+            pci_address: None,
             interrupt_evt: None,
             interrupt_resample_evt: None,
             mmio_regions: Vec::new(),
@@ -776,8 +776,8 @@ impl PciDevice for VfioPciDevice {
         "vfio pci device".to_string()
     }
 
-    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
-        self.pci_bus_dev = Some((bus, device));
+    fn assign_address(&mut self, address: PciAddress) {
+        self.pci_address = Some(address);
     }
 
     fn keep_fds(&self) -> Vec<RawFd> {
@@ -816,9 +816,9 @@ impl PciDevice for VfioPciDevice {
     ) -> Result<Vec<(u64, u64)>, PciDeviceError> {
         let mut ranges = Vec::new();
         let mut i = VFIO_PCI_BAR0_REGION_INDEX;
-        let (bus, dev) = self
-            .pci_bus_dev
-            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        let address = self
+            .pci_address
+            .expect("assign_address must be called prior to allocate_io_bars");
 
         while i <= VFIO_PCI_ROM_REGION_INDEX {
             let mut low: u32 = 0xffffffff;
@@ -854,8 +854,9 @@ impl PciDevice for VfioPciDevice {
                     .allocate_with_align(
                         size,
                         Alloc::PciBar {
-                            bus,
-                            dev,
+                            bus: address.bus,
+                            dev: address.dev,
+                            func: address.func,
                             bar: i as u8,
                         },
                         "vfio_bar".to_string(),
@@ -914,16 +915,17 @@ impl PciDevice for VfioPciDevice {
             VFIO_REGION_TYPE_PCI_VENDOR_TYPE | (INTEL_VENDOR_ID as u32),
             VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION,
         ) {
-            let (bus, dev) = self
-                .pci_bus_dev
-                .expect("assign_bus_dev must be called prior to allocate_device_bars");
+            let address = self
+                .pci_address
+                .expect("assign_address must be called prior to allocate_device_bars");
             let bar_addr = resources
                 .mmio_allocator(MmioType::Low)
                 .allocate(
                     size,
                     Alloc::PciBar {
-                        bus,
-                        dev,
+                        bus: address.bus,
+                        dev: address.dev,
+                        func: address.func,
                         bar: (index * 4) as u8,
                     },
                     "vfio_bar".to_string(),
diff --git a/devices/src/register_space/register.rs b/devices/src/register_space/register.rs
index c2f5184..2a4f551 100644
--- a/devices/src/register_space/register.rs
+++ b/devices/src/register_space/register.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;
 use std::boxed::Box;
 use std::cmp::{max, min, Ord, Ordering, PartialOrd};
 use std::mem::size_of;
diff --git a/devices/src/serial.rs b/devices/src/serial.rs
index 6629d7e..2af988e 100644
--- a/devices/src/serial.rs
+++ b/devices/src/serial.rs
@@ -3,20 +3,16 @@
 // found in the LICENSE file.
 
 use std::collections::VecDeque;
-use std::fmt::{self, Display};
-use std::fs::File;
-use std::io::{self, stdin, stdout, Read, Write};
-use std::os::unix::io::{AsRawFd, RawFd};
-use std::path::PathBuf;
-use std::str::FromStr;
+use std::io::{self, Write};
+use std::os::unix::io::RawFd;
 use std::sync::atomic::{AtomicU8, Ordering};
 use std::sync::mpsc::{channel, Receiver, TryRecvError};
 use std::sync::Arc;
 use std::thread::{self};
 
-use sys_util::{error, read_raw_stdin, syslog, EventFd, Result};
+use sys_util::{error, EventFd, Result};
 
-use crate::BusDevice;
+use crate::{BusDevice, SerialDevice};
 
 const LOOP_SIZE: usize = 0x40;
 
@@ -62,187 +58,6 @@ const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
 const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
 const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
 
-#[derive(Debug)]
-pub enum Error {
-    CloneEventFd(sys_util::Error),
-    InvalidSerialType(String),
-    PathRequired,
-    FileError(std::io::Error),
-    Unimplemented(SerialType),
-}
-
-impl Display for Error {
-    #[remain::check]
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-
-        #[sorted]
-        match self {
-            CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
-            FileError(e) => write!(f, "Unable to open/create file: {}", e),
-            InvalidSerialType(e) => write!(f, "invalid serial type: {}", e),
-            PathRequired => write!(f, "serial device type file requires a path"),
-            Unimplemented(e) => write!(f, "serial device type {} not implemented", e.to_string()),
-        }
-    }
-}
-
-/// Enum for possible type of serial devices
-#[derive(Debug)]
-pub enum SerialType {
-    File,
-    Stdout,
-    Sink,
-    Syslog,
-    UnixSocket, // NOT IMPLEMENTED
-}
-
-impl Display for SerialType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let s = match &self {
-            SerialType::File => "File".to_string(),
-            SerialType::Stdout => "Stdout".to_string(),
-            SerialType::Sink => "Sink".to_string(),
-            SerialType::Syslog => "Syslog".to_string(),
-            SerialType::UnixSocket => "UnixSocket".to_string(),
-        };
-
-        write!(f, "{}", s)
-    }
-}
-
-impl FromStr for SerialType {
-    type Err = Error;
-    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
-        match s {
-            "file" | "File" => Ok(SerialType::File),
-            "stdout" | "Stdout" => Ok(SerialType::Stdout),
-            "sink" | "Sink" => Ok(SerialType::Sink),
-            "syslog" | "Syslog" => Ok(SerialType::Syslog),
-            "unix" | "UnixSocket" => Ok(SerialType::UnixSocket),
-            _ => Err(Error::InvalidSerialType(s.to_string())),
-        }
-    }
-}
-
-/// Holds the parameters for a serial device
-#[derive(Debug)]
-pub struct SerialParameters {
-    pub type_: SerialType,
-    pub path: Option<PathBuf>,
-    pub num: u8,
-    pub console: bool,
-    pub stdin: bool,
-}
-
-impl SerialParameters {
-    /// Helper function to create a serial device from the defined parameters.
-    ///
-    /// # Arguments
-    /// * `evt_fd` - eventfd used for interrupt events
-    /// * `keep_fds` - Vector of FDs required by this device if it were sandboxed in a child
-    ///                process. `evt_fd` will always be added to this vector by this function.
-    pub fn create_serial_device(
-        &self,
-        evt_fd: &EventFd,
-        keep_fds: &mut Vec<RawFd>,
-    ) -> std::result::Result<Serial, Error> {
-        let evt_fd = evt_fd.try_clone().map_err(Error::CloneEventFd)?;
-        keep_fds.push(evt_fd.as_raw_fd());
-        let input: Option<Box<dyn io::Read + Send>> = if self.stdin {
-            keep_fds.push(stdin().as_raw_fd());
-            // This wrapper is used in place of the libstd native version because we don't want
-            // buffering for stdin.
-            struct StdinWrapper;
-            impl io::Read for StdinWrapper {
-                fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
-                    read_raw_stdin(out).map_err(|e| e.into())
-                }
-            }
-            Some(Box::new(StdinWrapper))
-        } else {
-            None
-        };
-        match self.type_ {
-            SerialType::Stdout => {
-                keep_fds.push(stdout().as_raw_fd());
-                Ok(Serial::new(evt_fd, input, Some(Box::new(stdout()))))
-            }
-            SerialType::Sink => Ok(Serial::new(evt_fd, input, None)),
-            SerialType::Syslog => {
-                syslog::push_fds(keep_fds);
-                Ok(Serial::new(
-                    evt_fd,
-                    input,
-                    Some(Box::new(syslog::Syslogger::new(
-                        syslog::Priority::Info,
-                        syslog::Facility::Daemon,
-                    ))),
-                ))
-            }
-            SerialType::File => match &self.path {
-                None => Err(Error::PathRequired),
-                Some(path) => {
-                    let file = File::create(path.as_path()).map_err(Error::FileError)?;
-                    keep_fds.push(file.as_raw_fd());
-                    Ok(Serial::new(evt_fd, input, Some(Box::new(file))))
-                }
-            },
-            SerialType::UnixSocket => Err(Error::Unimplemented(SerialType::UnixSocket)),
-        }
-    }
-}
-
-// Structure for holding the default configuration of the serial devices.
-pub const DEFAULT_SERIAL_PARAMS: [SerialParameters; 4] = [
-    SerialParameters {
-        type_: SerialType::Stdout,
-        path: None,
-        num: 1,
-        console: true,
-        stdin: true,
-    },
-    SerialParameters {
-        type_: SerialType::Sink,
-        path: None,
-        num: 2,
-        console: false,
-        stdin: false,
-    },
-    SerialParameters {
-        type_: SerialType::Sink,
-        path: None,
-        num: 3,
-        console: false,
-        stdin: false,
-    },
-    SerialParameters {
-        type_: SerialType::Sink,
-        path: None,
-        num: 4,
-        console: false,
-        stdin: false,
-    },
-];
-
-/// Address for Serial ports in x86
-pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
-
-/// String representations of serial devices
-pub const SERIAL_TTY_STRINGS: [&str; 4] = ["ttyS0", "ttyS1", "ttyS2", "ttyS3"];
-
-/// Helper function to get the tty string of a serial device based on the port number. Will default
-///  to ttyS0 if an invalid number is given.
-pub fn get_serial_tty_string(stdio_serial_num: u8) -> String {
-    match stdio_serial_num {
-        1 => SERIAL_TTY_STRINGS[0].to_string(),
-        2 => SERIAL_TTY_STRINGS[1].to_string(),
-        3 => SERIAL_TTY_STRINGS[2].to_string(),
-        4 => SERIAL_TTY_STRINGS[3].to_string(),
-        _ => SERIAL_TTY_STRINGS[0].to_string(),
-    }
-}
-
 /// Emulates serial COM ports commonly seen on x86 I/O ports 0x3f8/0x2f8/0x3e8/0x2e8.
 ///
 /// This can optionally write the guest's output to a Write trait object. To send input to the
@@ -267,11 +82,12 @@ pub struct Serial {
     out: Option<Box<dyn io::Write + Send>>,
 }
 
-impl Serial {
+impl SerialDevice for Serial {
     fn new(
         interrupt_evt: EventFd,
         input: Option<Box<dyn io::Read + Send>>,
         out: Option<Box<dyn io::Write + Send>>,
+        _keep_fds: Vec<RawFd>,
     ) -> Serial {
         Serial {
             interrupt_enable: Default::default(),
@@ -289,28 +105,9 @@ impl Serial {
             out,
         }
     }
+}
 
-    /// Constructs a Serial port ready for input and output.
-    ///
-    /// The stream `input` should not block, instead returning 0 bytes if are no bytes available.
-    pub fn new_in_out(
-        interrupt_evt: EventFd,
-        input: Box<dyn io::Read + Send>,
-        out: Box<dyn io::Write + Send>,
-    ) -> Serial {
-        Self::new(interrupt_evt, Some(input), Some(out))
-    }
-
-    /// Constructs a Serial port ready for output but not input.
-    pub fn new_out(interrupt_evt: EventFd, out: Box<dyn io::Write + Send>) -> Serial {
-        Self::new(interrupt_evt, None, Some(out))
-    }
-
-    /// Constructs a Serial port with no connected input or output.
-    pub fn new_sink(interrupt_evt: EventFd) -> Serial {
-        Self::new(interrupt_evt, None, None)
-    }
-
+impl Serial {
     /// Queues raw bytes for the guest to read and signals the interrupt if the line status would
     /// change. These bytes will be read by the guest before any bytes from the input stream that
     /// have not already been queued.
@@ -611,7 +408,12 @@ mod tests {
         let intr_evt = EventFd::new().unwrap();
         let serial_out = SharedBuffer::new();
 
-        let mut serial = Serial::new_out(intr_evt, Box::new(serial_out.clone()));
+        let mut serial = Serial::new(
+            intr_evt,
+            None,
+            Some(Box::new(serial_out.clone())),
+            Vec::new(),
+        );
 
         serial.write(DATA as u64, &['a' as u8]);
         serial.write(DATA as u64, &['b' as u8]);
@@ -627,8 +429,12 @@ mod tests {
         let intr_evt = EventFd::new().unwrap();
         let serial_out = SharedBuffer::new();
 
-        let mut serial =
-            Serial::new_out(intr_evt.try_clone().unwrap(), Box::new(serial_out.clone()));
+        let mut serial = Serial::new(
+            intr_evt.try_clone().unwrap(),
+            None,
+            Some(Box::new(serial_out.clone())),
+            Vec::new(),
+        );
 
         serial.write(IER as u64, &[IER_RECV_BIT]);
         serial
diff --git a/devices/src/serial_device.rs b/devices/src/serial_device.rs
new file mode 100644
index 0000000..9377556
--- /dev/null
+++ b/devices/src/serial_device.rs
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::io;
+use std::os::unix::io::RawFd;
+
+use sys_util::EventFd;
+
+/// Abstraction over serial-like devices that can be created given an event and optional input and
+/// output streams.
+pub trait SerialDevice {
+    fn new(
+        interrupt_evt: EventFd,
+        input: Option<Box<dyn io::Read + Send>>,
+        output: Option<Box<dyn io::Write + Send>>,
+        keep_fds: Vec<RawFd>,
+    ) -> Self;
+}
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs
index 196fa50..8f8723d 100644
--- a/devices/src/usb/host_backend/host_device.rs
+++ b/devices/src/usb/host_backend/host_device.rs
@@ -140,30 +140,21 @@ impl HostDevice {
             return Ok(());
         }
 
-        // Default buffer size for control data transfer.
-        const CONTROL_DATA_BUFFER_SIZE: usize = 1024;
-
-        // Buffer type for control transfer. The first 8 bytes is a UsbRequestSetup struct.
-        #[derive(Copy, Clone)]
-        #[repr(C, packed)]
-        struct ControlTransferBuffer {
-            pub setup: UsbRequestSetup,
-            pub data: [u8; CONTROL_DATA_BUFFER_SIZE],
-        }
-
-        // Safe because it only has data and has no implicit padding.
-        unsafe impl DataInit for ControlTransferBuffer {}
+        // Allocate a buffer for the control transfer.
+        // This buffer will hold a UsbRequestSetup struct followed by the data.
+        let control_buffer_len =
+            mem::size_of::<UsbRequestSetup>() + self.control_request_setup.length as usize;
+        let mut control_buffer = vec![0u8; control_buffer_len];
 
-        let mut control_request = ControlTransferBuffer {
-            setup: self.control_request_setup,
-            data: [0; CONTROL_DATA_BUFFER_SIZE],
-        };
+        // Copy the control request header.
+        control_buffer[..mem::size_of::<UsbRequestSetup>()]
+            .copy_from_slice(self.control_request_setup.as_slice());
 
         let direction = self.control_request_setup.get_direction();
         let buffer = if direction == ControlRequestDataPhaseTransferDirection::HostToDevice {
             if let Some(buffer) = buffer {
                 buffer
-                    .read(&mut control_request.data)
+                    .read(&mut control_buffer[mem::size_of::<UsbRequestSetup>()..])
                     .map_err(Error::ReadBuffer)?;
             }
             // buffer is consumed here for HostToDevice transfers.
@@ -173,8 +164,6 @@ impl HostDevice {
             buffer
         };
 
-        let control_buffer = control_request.as_slice().to_vec();
-
         let mut control_transfer =
             Transfer::new_control(control_buffer).map_err(Error::CreateTransfer)?;
 
diff --git a/devices/src/usb/xhci/event_ring.rs b/devices/src/usb/xhci/event_ring.rs
index fcaff23..1742c77 100644
--- a/devices/src/usb/xhci/event_ring.rs
+++ b/devices/src/usb/xhci/event_ring.rs
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 use data_model::DataInit;
-use std;
 use std::fmt::{self, Display};
 use std::mem::size_of;
 use std::sync::atomic::{fence, Ordering};
diff --git a/devices/src/usb/xhci/xhci_abi.rs b/devices/src/usb/xhci/xhci_abi.rs
index 5a8748e..e9be3c3 100644
--- a/devices/src/usb/xhci/xhci_abi.rs
+++ b/devices/src/usb/xhci/xhci_abi.rs
@@ -8,8 +8,6 @@ use data_model::DataInit;
 use std::fmt::{self, Display};
 use sys_util::GuestAddress;
 
-use std;
-
 #[derive(Debug)]
 pub enum Error {
     UnknownTrbType(BitFieldError),
diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs
index b77a73a..e357ae3 100644
--- a/devices/src/usb/xhci/xhci_controller.rs
+++ b/devices/src/usb/xhci/xhci_controller.rs
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 use crate::pci::{
-    PciBarConfiguration, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType,
-    PciInterruptPin, PciProgrammingInterface, PciSerialBusSubClass,
+    PciAddress, PciBarConfiguration, PciClassCode, PciConfiguration, PciDevice, PciDeviceError,
+    PciHeaderType, PciInterruptPin, PciProgrammingInterface, PciSerialBusSubClass,
 };
 use crate::register_space::{Register, RegisterSpace};
 use crate::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
@@ -94,7 +94,7 @@ enum XhciControllerState {
 /// xHCI PCI interface implementation.
 pub struct XhciController {
     config_regs: PciConfiguration,
-    pci_bus_dev: Option<(u8, u8)>,
+    pci_address: Option<PciAddress>,
     mem: GuestMemory,
     state: XhciControllerState,
 }
@@ -114,7 +114,7 @@ impl XhciController {
         );
         XhciController {
             config_regs,
-            pci_bus_dev: None,
+            pci_address: None,
             mem,
             state: XhciControllerState::Created {
                 device_provider: usb_provider,
@@ -166,8 +166,8 @@ impl PciDevice for XhciController {
         "xhci controller".to_owned()
     }
 
-    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
-        self.pci_bus_dev = Some((bus, device));
+    fn assign_address(&mut self, address: PciAddress) {
+        self.pci_address = Some(address);
     }
 
     fn keep_fds(&self) -> Vec<RawFd> {
@@ -206,15 +206,20 @@ impl PciDevice for XhciController {
         &mut self,
         resources: &mut SystemAllocator,
     ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
-        let (bus, dev) = self
-            .pci_bus_dev
-            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        let address = self
+            .pci_address
+            .expect("assign_address must be called prior to allocate_io_bars");
         // xHCI spec 5.2.1.
         let bar0_addr = resources
             .mmio_allocator(MmioType::Low)
             .allocate_with_align(
                 XHCI_BAR0_SIZE,
-                Alloc::PciBar { bus, dev, bar: 0 },
+                Alloc::PciBar {
+                    bus: address.bus,
+                    dev: address.dev,
+                    func: address.func,
+                    bar: 0,
+                },
                 "xhci_bar0".to_string(),
                 XHCI_BAR0_SIZE,
             )
diff --git a/devices/src/virtio/balloon.rs b/devices/src/virtio/balloon.rs
index 3e6d602..b549258 100644
--- a/devices/src/virtio/balloon.rs
+++ b/devices/src/virtio/balloon.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;
 use std::fmt::{self, Display};
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::sync::atomic::{AtomicUsize, Ordering};
diff --git a/devices/src/virtio/console.rs b/devices/src/virtio/console.rs
index 38f5bf1..50a5a76 100644
--- a/devices/src/virtio/console.rs
+++ b/devices/src/virtio/console.rs
@@ -13,6 +13,7 @@ use sys_util::{error, EventFd, GuestMemory, PollContext, PollToken};
 use super::{
     copy_config, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_CONSOLE, VIRTIO_F_VERSION_1,
 };
+use crate::SerialDevice;
 
 const QUEUE_SIZE: u16 = 256;
 
@@ -303,8 +304,9 @@ pub struct Console {
     keep_fds: Vec<RawFd>,
 }
 
-impl Console {
+impl SerialDevice for Console {
     fn new(
+        _evt_fd: EventFd,
         input: Option<Box<dyn io::Read + Send>>,
         output: Option<Box<dyn io::Write + Send>>,
         keep_fds: Vec<RawFd>,
@@ -317,25 +319,6 @@ impl Console {
             keep_fds,
         }
     }
-
-    /// Constructs a console with input and output streams.
-    pub fn new_in_out(
-        input: Box<dyn io::Read + Send>,
-        out: Box<dyn io::Write + Send>,
-        keep_fds: Vec<RawFd>,
-    ) -> Console {
-        Self::new(Some(input), Some(out), keep_fds)
-    }
-
-    /// Constructs a console with an output stream but no input.
-    pub fn new_out(out: Box<dyn io::Write + Send>, keep_fds: Vec<RawFd>) -> Console {
-        Self::new(None, Some(out), keep_fds)
-    }
-
-    /// Constructs a console with no connected input or output.
-    pub fn new_sink() -> Console {
-        Self::new(None, None, Vec::new())
-    }
 }
 
 impl Drop for Console {
diff --git a/devices/src/virtio/descriptor_utils.rs b/devices/src/virtio/descriptor_utils.rs
index 990f147..f90264a 100644
--- a/devices/src/virtio/descriptor_utils.rs
+++ b/devices/src/virtio/descriptor_utils.rs
@@ -467,9 +467,17 @@ impl<'a> Writer<'a> {
         self.write_all(val.as_slice())
     }
 
+    /// Writes all objects produced by `iter` into the descriptor chain buffer. Unlike `consume`,
+    /// this doesn't require the values to be stored in an intermediate collection first. It also
+    /// allows callers to choose which elements in a collection to write, for example by using the
+    /// `filter` or `take` methods of the `Iterator` trait.
+    pub fn write_iter<T: DataInit, I: Iterator<Item = T>>(&mut self, iter: I) -> io::Result<()> {
+        iter.map(|v| self.write_obj(v)).collect()
+    }
+
     /// Writes a collection of objects into the descriptor chain buffer.
     pub fn consume<T: DataInit, C: IntoIterator<Item = T>>(&mut self, vals: C) -> io::Result<()> {
-        vals.into_iter().map(|v| self.write_obj(v)).collect()
+        self.write_iter(vals.into_iter())
     }
 
     /// Returns number of bytes available for writing.  May return an error if the combined
diff --git a/devices/src/virtio/fs/filesystem.rs b/devices/src/virtio/fs/filesystem.rs
index eb9726c..474a278 100644
--- a/devices/src/virtio/fs/filesystem.rs
+++ b/devices/src/virtio/fs/filesystem.rs
@@ -9,8 +9,6 @@ use std::io;
 use std::mem;
 use std::time::Duration;
 
-use libc;
-
 use crate::virtio::fs::fuse;
 
 pub use fuse::{FsOptions, IoctlFlags, IoctlIovec, OpenOptions, SetattrValid, ROOT_ID};
@@ -77,7 +75,7 @@ pub struct DirEntry<'a> {
 
     /// The name of this directory entry. There are no requirements for the contents of this field
     /// and any sequence of bytes is considered valid.
-    pub name: &'a [u8],
+    pub name: &'a CStr,
 }
 
 /// A reply to a `getxattr` method call.
diff --git a/devices/src/virtio/fs/fuse.rs b/devices/src/virtio/fs/fuse.rs
index 5c531cf..981596b 100644
--- a/devices/src/virtio/fs/fuse.rs
+++ b/devices/src/virtio/fs/fuse.rs
@@ -7,7 +7,6 @@ use std::mem;
 use bitflags::bitflags;
 use data_model::DataInit;
 use enumn::N;
-use libc;
 
 /// Version number of this interface.
 pub const KERNEL_VERSION: u32 = 7;
diff --git a/devices/src/virtio/fs/passthrough.rs b/devices/src/virtio/fs/passthrough.rs
index d2034ba..bcc7c5d 100644
--- a/devices/src/virtio/fs/passthrough.rs
+++ b/devices/src/virtio/fs/passthrough.rs
@@ -15,7 +15,6 @@ use std::sync::Arc;
 use std::time::Duration;
 
 use data_model::DataInit;
-use libc;
 use sync::Mutex;
 use sys_util::{error, ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ptr, ioctl_with_ptr};
 
@@ -26,8 +25,6 @@ use crate::virtio::fs::filesystem::{
 use crate::virtio::fs::fuse;
 use crate::virtio::fs::multikey::MultikeyBTreeMap;
 
-const CURRENT_DIR_CSTR: &[u8] = b".\0";
-const PARENT_DIR_CSTR: &[u8] = b"..\0";
 const EMPTY_CSTR: &[u8] = b"\0";
 const ROOT_CSTR: &[u8] = b"/\0";
 const PROC_CSTR: &[u8] = b"/proc\0";
@@ -199,6 +196,20 @@ fn stat(f: &File) -> io::Result<libc::stat64> {
     }
 }
 
+// Like `CStr::from_bytes_with_nul` but strips any bytes after the first '\0'-byte. Panics if `b`
+// doesn't contain any '\0' bytes.
+fn strip_padding(b: &[u8]) -> &CStr {
+    // It would be nice if we could use memchr here but that's locked behind an unstable gate.
+    let pos = b
+        .iter()
+        .position(|&c| c == 0)
+        .expect("`b` doesn't contain any nul bytes");
+
+    // Safe because we are creating this string with the first nul-byte we found so we can
+    // guarantee that it is nul-terminated and doesn't contain any interior nuls.
+    unsafe { CStr::from_bytes_with_nul_unchecked(&b[..pos + 1]) }
+}
+
 /// The caching policy that the file system should report to the FUSE client. By default the FUSE
 /// protocol uses close-to-open consistency. This means that any cached contents of the file are
 /// invalidated the next time that file is opened.
@@ -576,19 +587,15 @@ impl PassthroughFs {
             let namelen = dirent64.d_reclen as usize - size_of::<LinuxDirent64>();
             debug_assert!(namelen <= back.len(), "back is smaller than `namelen`");
 
-            let name = &back[..namelen];
-            let res = if name.starts_with(CURRENT_DIR_CSTR) || name.starts_with(PARENT_DIR_CSTR) {
-                // We don't want to report the "." and ".." entries. However, returning `Ok(0)` will
-                // break the loop so return `Ok` with a non-zero value instead.
-                Ok(1)
-            } else {
-                add_entry(DirEntry {
-                    ino: dirent64.d_ino,
-                    offset: dirent64.d_off as u64,
-                    type_: dirent64.d_ty as u32,
-                    name,
-                })
-            };
+            // The kernel will pad the name with additional nul bytes until it is 8-byte aligned so
+            // we need to strip those off here.
+            let name = strip_padding(&back[..namelen]);
+            let res = add_entry(DirEntry {
+                ino: dirent64.d_ino,
+                offset: dirent64.d_off as u64,
+                type_: dirent64.d_ty as u32,
+                name,
+            });
 
             debug_assert!(
                 rem.len() >= dirent64.d_reclen as usize,
@@ -806,7 +813,8 @@ impl FileSystem for PassthroughFs {
             }),
         );
 
-        let mut opts = FsOptions::DO_READDIRPLUS | FsOptions::READDIRPLUS_AUTO;
+        let mut opts =
+            FsOptions::DO_READDIRPLUS | FsOptions::READDIRPLUS_AUTO | FsOptions::EXPORT_SUPPORT;
         if self.cfg.writeback && capable.contains(FsOptions::WRITEBACK_CACHE) {
             opts |= FsOptions::WRITEBACK_CACHE;
             self.writeback.store(true, Ordering::Relaxed);
@@ -933,16 +941,38 @@ impl FileSystem for PassthroughFs {
         F: FnMut(DirEntry, Entry) -> io::Result<usize>,
     {
         self.do_readdir(inode, handle, size, offset, |dir_entry| {
-            // Safe because the kernel guarantees that the buffer is nul-terminated. Additionally,
-            // the kernel will pad the name with '\0' bytes up to 8-byte alignment and there's no
-            // way for us to know exactly how many padding bytes there are. This would cause
-            // `CStr::from_bytes_with_nul` to return an error because it would think there are
-            // interior '\0' bytes. We trust the kernel to provide us with properly formatted data
-            // so we'll just skip the checks here.
-            let name = unsafe { CStr::from_bytes_with_nul_unchecked(dir_entry.name) };
-            let entry = self.do_lookup(inode, name)?;
-
-            add_entry(dir_entry, entry)
+            let name = dir_entry.name.to_bytes();
+            let entry = if name == b"." || name == b".." {
+                // Don't do lookups on the current directory or the parent directory. Safe because
+                // this only contains integer fields and any value is valid.
+                let mut attr = unsafe { MaybeUninit::<libc::stat64>::zeroed().assume_init() };
+                attr.st_ino = dir_entry.ino;
+                attr.st_mode = dir_entry.type_;
+
+                // We use 0 for the inode value to indicate a negative entry.
+                Entry {
+                    inode: 0,
+                    generation: 0,
+                    attr,
+                    attr_timeout: Duration::from_secs(0),
+                    entry_timeout: Duration::from_secs(0),
+                }
+            } else {
+                self.do_lookup(inode, dir_entry.name)?
+            };
+
+            let entry_inode = entry.inode;
+            add_entry(dir_entry, entry).map_err(|e| {
+                if entry_inode != 0 {
+                    // Undo the `do_lookup` for this inode since we aren't going to report it to
+                    // the kernel. If `entry_inode` was 0 then that means this was the "." or
+                    // ".." entry and there wasn't a lookup in the first place.
+                    let mut inodes = self.inodes.lock();
+                    forget_one(&mut inodes, entry_inode, 1);
+                }
+
+                e
+            })
         })
     }
 
@@ -1747,3 +1777,29 @@ impl FileSystem for PassthroughFs {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn padded_cstrings() {
+        assert_eq!(strip_padding(b".\0\0\0\0\0\0\0").to_bytes(), b".");
+        assert_eq!(strip_padding(b"..\0\0\0\0\0\0").to_bytes(), b"..");
+        assert_eq!(
+            strip_padding(b"normal cstring\0").to_bytes(),
+            b"normal cstring"
+        );
+        assert_eq!(strip_padding(b"\0\0\0\0").to_bytes(), b"");
+        assert_eq!(
+            strip_padding(b"interior\0nul bytes\0\0\0").to_bytes(),
+            b"interior"
+        );
+    }
+
+    #[test]
+    #[should_panic(expected = "`b` doesn't contain any nul bytes")]
+    fn no_nul_byte() {
+        strip_padding(b"no nul bytes in string");
+    }
+}
diff --git a/devices/src/virtio/fs/server.rs b/devices/src/virtio/fs/server.rs
index c9025f2..33b7c98 100644
--- a/devices/src/virtio/fs/server.rs
+++ b/devices/src/virtio/fs/server.rs
@@ -8,7 +8,6 @@ use std::io::{self, Read, Write};
 use std::mem::size_of;
 
 use data_model::DataInit;
-use libc;
 use sys_util::error;
 
 use crate::virtio::fs::filesystem::{
@@ -19,7 +18,7 @@ use crate::virtio::fs::fuse::*;
 use crate::virtio::fs::{Error, Result};
 use crate::virtio::{Reader, Writer};
 
-const MAX_BUFFER_SIZE: u32 = (1 << 20);
+const MAX_BUFFER_SIZE: u32 = 1 << 20;
 const DIRENT_PADDING: [u8; 8] = [0; 8];
 
 struct ZCReader<'a>(Reader<'a>);
@@ -1369,12 +1368,14 @@ fn add_dirent(
     d: DirEntry,
     entry: Option<Entry>,
 ) -> io::Result<usize> {
-    if d.name.len() > ::std::u32::MAX as usize {
+    // Strip the trailing '\0'.
+    let name = d.name.to_bytes();
+    if name.len() > ::std::u32::MAX as usize {
         return Err(io::Error::from_raw_os_error(libc::EOVERFLOW));
     }
 
     let dirent_len = size_of::<Dirent>()
-        .checked_add(d.name.len())
+        .checked_add(name.len())
         .ok_or_else(|| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
 
     // Directory entries must be padded to 8-byte alignment.  If adding 7 causes
@@ -1402,12 +1403,12 @@ fn add_dirent(
         let dirent = Dirent {
             ino: d.ino,
             off: d.offset,
-            namelen: d.name.len() as u32,
+            namelen: name.len() as u32,
             type_: d.type_,
         };
 
         cursor.write_all(dirent.as_slice())?;
-        cursor.write_all(d.name)?;
+        cursor.write_all(name)?;
 
         // We know that `dirent_len` <= `padded_dirent_len` due to the check above
         // so there's no need for checked arithmetic.
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index fec2904..b305089 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -42,7 +42,9 @@ use self::virtio_2d_backend::Virtio2DBackend;
 use self::virtio_3d_backend::Virtio3DBackend;
 #[cfg(feature = "gfxstream")]
 use self::virtio_gfxstream_backend::VirtioGfxStreamBackend;
-use crate::pci::{PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability};
+use crate::pci::{
+    PciAddress, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability,
+};
 
 use vm_control::VmMemoryControlRequestSocket;
 
@@ -1203,10 +1205,11 @@ impl VirtioDevice for Gpu {
     }
 
     // Require 1 BAR for mapping 3D buffers
-    fn get_device_bars(&mut self, bus: u8, dev: u8) -> Vec<PciBarConfiguration> {
+    fn get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration> {
         self.pci_bar = Some(Alloc::PciBar {
-            bus,
-            dev,
+            bus: address.bus,
+            dev: address.dev,
+            func: address.func,
             bar: GPU_BAR_NUM,
         });
         vec![PciBarConfiguration::new(
diff --git a/devices/src/virtio/gpu/protocol.rs b/devices/src/virtio/gpu/protocol.rs
index 3df6975..5605dd3 100644
--- a/devices/src/virtio/gpu/protocol.rs
+++ b/devices/src/virtio/gpu/protocol.rs
@@ -137,7 +137,7 @@ pub fn virtio_gpu_cmd_str(cmd: u32) -> &'static str {
     }
 }
 
-pub const VIRTIO_GPU_FLAG_FENCE: u32 = (1 << 0);
+pub const VIRTIO_GPU_FLAG_FENCE: u32 = 1 << 0;
 
 #[derive(Copy, Clone, Debug, Default)]
 #[repr(C)]
@@ -336,7 +336,7 @@ pub struct virtio_gpu_transfer_host_3d {
 unsafe impl DataInit for virtio_gpu_transfer_host_3d {}
 
 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
-pub const VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP: u32 = (1 << 0);
+pub const VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP: u32 = 1 << 0;
 #[derive(Copy, Clone, Debug, Default)]
 #[repr(C)]
 pub struct virtio_gpu_resource_create_3d {
diff --git a/devices/src/virtio/input/constants.rs b/devices/src/virtio/input/constants.rs
index 84799b2..7973312 100644
--- a/devices/src/virtio/input/constants.rs
+++ b/devices/src/virtio/input/constants.rs
@@ -12,7 +12,7 @@ pub const INPUT_PROP_POINTING_STICK: u16 = 0x05;
 pub const INPUT_PROP_ACCELEROMETER: u16 = 0x06;
 
 pub const INPUT_PROP_MAX: u16 = 0x1f;
-pub const INPUT_PROP_CNT: u16 = (INPUT_PROP_MAX + 1);
+pub const INPUT_PROP_CNT: u16 = INPUT_PROP_MAX + 1;
 
 pub const EV_SYN: u16 = 0x00;
 pub const EV_KEY: u16 = 0x01;
@@ -638,7 +638,7 @@ pub const BTN_TRIGGER_HAPPY40: u16 = 0x2e7;
 
 pub const KEY_MIN_INTERESTING: u16 = KEY_MUTE;
 pub const KEY_MAX: u16 = 0x2ff;
-pub const KEY_CNT: u16 = (KEY_MAX + 1);
+pub const KEY_CNT: u16 = KEY_MAX + 1;
 
 pub const REL_X: u16 = 0x00;
 pub const REL_Y: u16 = 0x01;
@@ -651,7 +651,7 @@ pub const REL_DIAL: u16 = 0x07;
 pub const REL_WHEEL: u16 = 0x08;
 pub const REL_MISC: u16 = 0x09;
 pub const REL_MAX: u16 = 0x0f;
-pub const REL_CNT: u16 = (REL_MAX + 1);
+pub const REL_CNT: u16 = REL_MAX + 1;
 
 pub const ABS_X: u16 = 0x00;
 pub const ABS_Y: u16 = 0x01;
@@ -699,7 +699,7 @@ pub const ABS_MT_TOOL_X: u16 = 0x3c;
 pub const ABS_MT_TOOL_Y: u16 = 0x3d;
 
 pub const ABS_MAX: u16 = 0x3f;
-pub const ABS_CNT: u16 = (ABS_MAX + 1);
+pub const ABS_CNT: u16 = ABS_MAX + 1;
 
 pub const MSC_SERIAL: u16 = 0x00;
 pub const MSC_PULSELED: u16 = 0x01;
@@ -708,7 +708,7 @@ pub const MSC_RAW: u16 = 0x03;
 pub const MSC_SCAN: u16 = 0x04;
 pub const MSC_TIMESTAMP: u16 = 0x05;
 pub const MSC_MAX: u16 = 0x07;
-pub const MSC_CNT: u16 = (MSC_MAX + 1);
+pub const MSC_CNT: u16 = MSC_MAX + 1;
 
 pub const LED_NUML: u16 = 0x00;
 pub const LED_CAPSL: u16 = 0x01;
@@ -722,12 +722,12 @@ pub const LED_MISC: u16 = 0x08;
 pub const LED_MAIL: u16 = 0x09;
 pub const LED_CHARGING: u16 = 0x0a;
 pub const LED_MAX: u16 = 0x0f;
-pub const LED_CNT: u16 = (LED_MAX + 1);
+pub const LED_CNT: u16 = LED_MAX + 1;
 
 pub const REP_DELAY: u16 = 0x00;
 pub const REP_PERIOD: u16 = 0x01;
 pub const REP_MAX: u16 = 0x01;
-pub const REP_CNT: u16 = (REP_MAX + 1);
+pub const REP_CNT: u16 = REP_MAX + 1;
 
 // Should match linux/virtio_input.h
 pub const VIRTIO_INPUT_CFG_UNSET: u8 = 0x00;
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index a15ab03..8e9aa9e 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -13,7 +13,6 @@ use std::sync::Arc;
 use std::thread;
 
 use data_model::{DataInit, Le16, Le64};
-use net_sys;
 use net_util::{Error as TapError, MacAddress, TapT};
 use sys_util::Error as SysError;
 use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken, WatchingEvents};
diff --git a/devices/src/virtio/p9.rs b/devices/src/virtio/p9.rs
index 5e483c3..7854c39 100644
--- a/devices/src/virtio/p9.rs
+++ b/devices/src/virtio/p9.rs
@@ -10,7 +10,6 @@ use std::path::{Path, PathBuf};
 use std::result;
 use std::thread;
 
-use p9;
 use sys_util::{error, warn, Error as SysError, EventFd, GuestMemory, PollContext, PollToken};
 use virtio_sys::vhost::VIRTIO_F_VERSION_1;
 
diff --git a/devices/src/virtio/pmem.rs b/devices/src/virtio/pmem.rs
index 499e110..cbeecc3 100644
--- a/devices/src/virtio/pmem.rs
+++ b/devices/src/virtio/pmem.rs
@@ -8,8 +8,8 @@ use std::io;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::thread;
 
-use sys_util::Result as SysResult;
 use sys_util::{error, EventFd, GuestAddress, GuestMemory, PollContext, PollToken};
+use sys_util::{Error as SysError, Result as SysResult};
 
 use data_model::{DataInit, Le32, Le64};
 
@@ -89,6 +89,7 @@ struct Worker {
     memory: GuestMemory,
     pmem_device_socket: VmMsyncRequestSocket,
     mapping_arena_slot: u32,
+    mapping_size: usize,
 }
 
 impl Worker {
@@ -98,6 +99,7 @@ impl Worker {
                 let request = VmMsyncRequest::MsyncArena {
                     slot: self.mapping_arena_slot,
                     offset: 0, // The pmem backing file is always at offset 0 in the arena.
+                    size: self.mapping_size,
                 };
 
                 if let Err(e) = self.pmem_device_socket.send(&request) {
@@ -235,6 +237,10 @@ impl Pmem {
         mapping_size: u64,
         pmem_device_socket: Option<VmMsyncRequestSocket>,
     ) -> SysResult<Pmem> {
+        if mapping_size > usize::max_value() as u64 {
+            return Err(SysError::new(libc::EOVERFLOW));
+        }
+
         Ok(Pmem {
             kill_event: None,
             worker_thread: None,
@@ -308,6 +314,8 @@ impl VirtioDevice for Pmem {
         let queue_event = queue_events.remove(0);
 
         let mapping_arena_slot = self.mapping_arena_slot;
+        // We checked that this fits in a usize in `Pmem::new`.
+        let mapping_size = self.mapping_size as usize;
 
         if let Some(pmem_device_socket) = self.pmem_device_socket.take() {
             let (self_kill_event, kill_event) =
@@ -329,6 +337,7 @@ impl VirtioDevice for Pmem {
                         queue,
                         pmem_device_socket,
                         mapping_arena_slot,
+                        mapping_size,
                     };
                     worker.run(queue_event, kill_event);
                 });
diff --git a/devices/src/virtio/rng.rs b/devices/src/virtio/rng.rs
index 9ce8dae..3897ee3 100644
--- a/devices/src/virtio/rng.rs
+++ b/devices/src/virtio/rng.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;
 use std::fmt::{self, Display};
 use std::fs::File;
 use std::io;
diff --git a/devices/src/virtio/tpm.rs b/devices/src/virtio/tpm.rs
index 95f7092..727c634 100644
--- a/devices/src/virtio/tpm.rs
+++ b/devices/src/virtio/tpm.rs
@@ -12,7 +12,6 @@ use std::path::PathBuf;
 use std::thread;
 
 use sys_util::{error, EventFd, GuestMemory, PollContext, PollToken};
-use tpm2;
 
 use super::{
     DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_TPM,
diff --git a/devices/src/virtio/vhost/mod.rs b/devices/src/virtio/vhost/mod.rs
index 86ed81e..4d7623f 100644
--- a/devices/src/virtio/vhost/mod.rs
+++ b/devices/src/virtio/vhost/mod.rs
@@ -4,7 +4,6 @@
 
 //! Implements vhost-based virtio devices.
 
-use std;
 use std::fmt::{self, Display};
 
 use net_util::Error as TapError;
diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs
index 681cfe8..ce13226 100644
--- a/devices/src/virtio/vhost/net.rs
+++ b/devices/src/virtio/vhost/net.rs
@@ -7,7 +7,6 @@ use std::net::Ipv4Addr;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::thread;
 
-use net_sys;
 use net_util::{MacAddress, TapT};
 
 use sys_util::{error, warn, EventFd, GuestMemory};
diff --git a/devices/src/virtio/virtio_device.rs b/devices/src/virtio/virtio_device.rs
index 6eb5548..7c07651 100644
--- a/devices/src/virtio/virtio_device.rs
+++ b/devices/src/virtio/virtio_device.rs
@@ -7,7 +7,7 @@ use std::os::unix::io::RawFd;
 use sys_util::{EventFd, GuestMemory};
 
 use super::*;
-use crate::pci::{MsixStatus, PciBarConfiguration, PciCapability};
+use crate::pci::{MsixStatus, PciAddress, PciBarConfiguration, PciCapability};
 
 /// Trait for virtio devices to be driven by a virtio transport.
 ///
@@ -75,7 +75,7 @@ pub trait VirtioDevice: Send {
     }
 
     /// Returns any additional BAR configuration required by the device.
-    fn get_device_bars(&mut self, _bus: u8, _dev: u8) -> Vec<PciBarConfiguration> {
+    fn get_device_bars(&mut self, _address: PciAddress) -> Vec<PciBarConfiguration> {
         Vec::new()
     }
 
diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs
index e63abe9..eb91e58 100644
--- a/devices/src/virtio/virtio_pci_device.rs
+++ b/devices/src/virtio/virtio_pci_device.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;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::Arc;
@@ -16,10 +15,10 @@ use sys_util::{warn, EventFd, GuestMemory, Result};
 
 use super::*;
 use crate::pci::{
-    MsixCap, MsixConfig, PciBarConfiguration, PciCapability, PciCapabilityID, PciClassCode,
-    PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciInterruptPin, PciSubclass,
+    MsixCap, MsixConfig, PciAddress, PciBarConfiguration, PciCapability, PciCapabilityID,
+    PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciInterruptPin,
+    PciSubclass,
 };
-
 use vm_control::VmIrqRequestSocket;
 
 use self::virtio_pci_common_config::VirtioPciCommonConfig;
@@ -212,7 +211,7 @@ const VIRTIO_PCI_DEVICE_ID_BASE: u16 = 0x1040; // Add to device type to get devi
 /// transport for virtio devices.
 pub struct VirtioPciDevice {
     config_regs: PciConfiguration,
-    pci_bus_dev: Option<(u8, u8)>,
+    pci_address: Option<PciAddress>,
 
     device: Box<dyn VirtioDevice>,
     device_activated: bool,
@@ -270,7 +269,7 @@ impl VirtioPciDevice {
 
         Ok(VirtioPciDevice {
             config_regs,
-            pci_bus_dev: None,
+            pci_address: None,
             device,
             device_activated: false,
             interrupt_status: Arc::new(AtomicUsize::new(0)),
@@ -393,8 +392,8 @@ impl PciDevice for VirtioPciDevice {
         format!("virtio-pci ({})", self.device.debug_label())
     }
 
-    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
-        self.pci_bus_dev = Some((bus, device));
+    fn assign_address(&mut self, address: PciAddress) {
+        self.pci_address = Some(address);
     }
 
     fn keep_fds(&self) -> Vec<RawFd> {
@@ -426,16 +425,21 @@ impl PciDevice for VirtioPciDevice {
         &mut self,
         resources: &mut SystemAllocator,
     ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
-        let (bus, dev) = self
-            .pci_bus_dev
-            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        let address = self
+            .pci_address
+            .expect("assign_address must be called prior to allocate_io_bars");
         // Allocate one bar for the structures pointed to by the capability structures.
         let mut ranges = Vec::new();
         let settings_config_addr = resources
             .mmio_allocator(MmioType::Low)
             .allocate_with_align(
                 CAPABILITY_BAR_SIZE,
-                Alloc::PciBar { bus, dev, bar: 0 },
+                Alloc::PciBar {
+                    bus: address.bus,
+                    dev: address.dev,
+                    func: address.func,
+                    bar: 0,
+                },
                 format!(
                     "virtio-{}-cap_bar",
                     type_to_str(self.device.device_type()).unwrap_or("?")
@@ -464,18 +468,19 @@ impl PciDevice for VirtioPciDevice {
         &mut self,
         resources: &mut SystemAllocator,
     ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
-        let (bus, dev) = self
-            .pci_bus_dev
-            .expect("assign_bus_dev must be called prior to allocate_device_bars");
+        let address = self
+            .pci_address
+            .expect("assign_address must be called prior to allocate_device_bars");
         let mut ranges = Vec::new();
-        for config in self.device.get_device_bars(bus, dev) {
+        for config in self.device.get_device_bars(address) {
             let device_addr = resources
                 .mmio_allocator(MmioType::High)
                 .allocate_with_align(
                     config.get_size(),
                     Alloc::PciBar {
-                        bus,
-                        dev,
+                        bus: address.bus,
+                        dev: address.dev,
+                        func: address.func,
                         bar: config.get_register_index() as u8,
                     },
                     format!(
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index 95075b4..517a22e 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -47,7 +47,7 @@ use std::thread;
 use std::time::Duration;
 
 #[cfg(feature = "wl-dmabuf")]
-use libc::{dup, EBADF, EINVAL};
+use libc::{EBADF, EINVAL};
 
 use data_model::VolatileMemoryError;
 use data_model::*;
@@ -543,9 +543,6 @@ impl fmt::Debug for WlVfd {
 impl WlVfd {
     fn connect<P: AsRef<Path>>(path: P) -> WlResult<WlVfd> {
         let socket = UnixStream::connect(path).map_err(WlError::SocketConnect)?;
-        socket
-            .set_nonblocking(true)
-            .map_err(WlError::SocketNonBlock)?;
         let mut vfd = WlVfd::default();
         vfd.socket = Some(socket);
         Ok(vfd)
@@ -587,15 +584,13 @@ impl WlVfd {
             })?;
         match allocate_and_register_gpu_memory_response {
             VmMemoryResponse::AllocateAndRegisterGpuMemory {
-                fd,
+                fd: MaybeOwnedFd::Owned(file),
                 pfn,
                 slot,
                 desc,
             } => {
                 let mut vfd = WlVfd::default();
-                // Duplicate FD for shared memory instance.
-                let raw_fd = unsafe { File::from_raw_fd(dup(fd.as_raw_fd())) };
-                let vfd_shm = SharedMemory::from_raw_fd(raw_fd).map_err(WlError::NewAlloc)?;
+                let vfd_shm = SharedMemory::from_file(file).map_err(WlError::NewAlloc)?;
                 vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm.into()));
                 vfd.slot = Some((slot, pfn, vm));
                 vfd.is_dmabuf = true;