summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2018-05-24 19:30:53 +0000
committerchrome-bot <chrome-bot@chromium.org>2018-07-11 12:12:55 -0700
commitcc08cdbd836cb280cebcb5f1d737da58aa3eff07 (patch)
tree3428306ebd481d55bc511c64d6ba35719023b1ab
parentb4e7ea300ade024f147812a6e6b7dd227c33e4bc (diff)
downloadcrosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.tar
crosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.tar.gz
crosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.tar.bz2
crosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.tar.lz
crosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.tar.xz
crosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.tar.zst
crosvm-cc08cdbd836cb280cebcb5f1d737da58aa3eff07.zip
devices: pci - Add PciDevice
The PciDevice trait represents any PciDevice. It provides access to
configuration registers and BAR space.

Change-Id: Ie18cb16b8bd97f9b70af05ebfebbfc612ce18494
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1072575
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Sonny Rao <sonnyrao@chromium.org>
-rw-r--r--devices/src/bus.rs7
-rw-r--r--devices/src/lib.rs2
-rw-r--r--devices/src/pci/mod.rs3
-rw-r--r--devices/src/pci/pci_device.rs114
4 files changed, 125 insertions, 1 deletions
diff --git a/devices/src/bus.rs b/devices/src/bus.rs
index 030694a..7b37c32 100644
--- a/devices/src/bus.rs
+++ b/devices/src/bus.rs
@@ -19,6 +19,13 @@ pub trait BusDevice: Send {
     fn read(&mut self, offset: u64, data: &mut [u8]) {}
     /// Writes at `offset` into this device
     fn write(&mut self, offset: u64, data: &[u8]) {}
+    /// Sets a register in the configuration space. Only used by PCI.
+    /// * `reg_idx` - The index of the config register to modify.
+    /// * `offset` - Offset in to the register.
+    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {}
+    /// Gets a register from the configuration space. Only used by PCI.
+    /// * `reg_idx` - The index of the config register to read.
+    fn config_register_read(&self, reg_idx: usize) -> u32 { 0 }
 }
 
 #[derive(Debug)]
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 3418baa..3a63577 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -30,7 +30,7 @@ pub use self::bus::{Bus, BusDevice};
 pub use self::cmos::Cmos;
 pub use self::pl030::Pl030;
 pub use self::i8042::I8042Device;
-pub use self::pci::PciInterruptPin;
+pub use self::pci::{PciDevice, PciInterruptPin};
 pub use self::proxy::ProxyDevice;
 pub use self::proxy::Error as ProxyError;
 pub use self::serial::Serial;
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index d997af0..afcad2c 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -5,6 +5,9 @@
 //! Implements pci devices and busses.
 
 mod pci_configuration;
+mod pci_device;
+
+pub use self::pci_device::PciDevice;
 
 /// PCI has four interrupt pins A->D.
 #[derive(Copy, Clone)]
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs
new file mode 100644
index 0000000..4af845c
--- /dev/null
+++ b/devices/src/pci/pci_device.rs
@@ -0,0 +1,114 @@
+// Copyright 2018 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 byteorder::{ByteOrder, LittleEndian};
+
+use std;
+
+use pci::pci_configuration::PciConfiguration;
+use pci::PciInterruptPin;
+use sys_util::EventFd;
+use resources::SystemAllocator;
+
+use BusDevice;
+
+#[derive(Debug)]
+pub enum Error {
+    /// Allocating space for an IO BAR failed.
+    IoAllocationFailed(u64),
+    /// Registering an IO BAR failed.
+    IoRegistrationFailed(u64),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+pub trait PciDevice: Send + Sync {
+    /// Assign a legacy PCI IRQ to this device.
+    fn assign_irq(&mut self, _irq_evt: EventFd, _irq_num: u32, _irq_pin: PciInterruptPin) {}
+    /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
+    /// returns an address. Returns a Vec of (address, length) tuples.
+    fn allocate_io_bars(
+        &mut self,
+        _resources: &mut SystemAllocator,
+    ) -> Result<Vec<(u64, u64)>> {
+        Ok(Vec::new())
+    }
+    /// Gets the configuration registers of the Pci Device.
+    fn config_registers(&self) -> &PciConfiguration; // TODO - remove these
+    /// Gets the configuration registers of the Pci Device for modification.
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration;
+    /// Reads from a BAR region mapped in to the device.
+    /// * `addr` - The guest address inside the BAR.
+    /// * `data` - Filled with the data from `addr`.
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]);
+    /// Writes to a BAR region mapped in to the device.
+    /// * `addr` - The guest address inside the BAR.
+    /// * `data` - The data to write.
+    fn write_bar(&mut self, addr: u64, data: &[u8]);
+}
+
+impl<T: PciDevice> BusDevice for T {
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        self.read_bar(offset, data)
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        self.write_bar(offset, data)
+    }
+
+    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
+        if offset as usize + data.len() > 4 {
+            return;
+        }
+
+        let regs = self.config_registers_mut();
+
+        match data.len() {
+            1 => regs.write_byte(reg_idx * 4 + offset as usize, data[0]),
+            2 => regs.write_word(
+                reg_idx * 4 + offset as usize,
+                (data[0] as u16) | (data[1] as u16) << 8,
+            ),
+            4 => regs.write_reg(reg_idx, LittleEndian::read_u32(data)),
+            _ => (),
+        }
+    }
+
+    fn config_register_read(&self, reg_idx: usize) -> u32 {
+        self.config_registers().read_reg(reg_idx)
+    }
+}
+
+impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
+    fn assign_irq(&mut self, irq_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin) {
+     (**self).assign_irq(irq_evt, irq_num, irq_pin)
+    }
+    /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
+    /// returns an address. Returns a Vec of (address, length) tuples.
+    fn allocate_io_bars(
+        &mut self,
+        resources: &mut SystemAllocator,
+    ) -> Result<Vec<(u64, u64)>> {
+        (**self).allocate_io_bars(resources)
+    }
+    /// Gets the configuration registers of the Pci Device.
+    fn config_registers(&self) -> &PciConfiguration {
+        (**self).config_registers()
+    }
+    /// Gets the configuration registers of the Pci Device for modification.
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
+        (**self).config_registers_mut()
+    }
+    /// Reads from a BAR region mapped in to the device.
+    /// * `addr` - The guest address inside the BAR.
+    /// * `data` - Filled with the data from `addr`.
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
+        (**self).read_bar(addr, data)
+    }
+    /// Writes to a BAR region mapped in to the device.
+    /// * `addr` - The guest address inside the BAR.
+    /// * `data` - The data to write.
+    fn write_bar(&mut self, addr: u64, data: &[u8]) {
+        (**self).write_bar(addr, data)
+    }
+}