summary refs log tree commit diff
path: root/devices/src/pci
diff options
context:
space:
mode:
authorGurchetan Singh <gurchetansingh@chromium.org>2019-02-20 16:30:48 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-03-01 01:08:27 -0800
commit036ba3390bfd31a3eeae07186cb9e4933fa5ddc3 (patch)
tree64aab291c5b555338297badfff30d7ebbaf6d263 /devices/src/pci
parent948a3ab6b5c67bd6fa46e6bdd9b49de59ccadf36 (diff)
downloadcrosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar
crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.gz
crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.bz2
crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.lz
crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.xz
crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.zst
crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.zip
devices: use PCI bar configuration when adding regions
This removes add_memory_region and add_io_region, and replaces
it with the add_pci_bar function.

BUG=chromium:924405
TEST=boot VM

Change-Id: Ifc637d174d3f8b1255cf13725a1a224b4cdf0a30
Reviewed-on: https://chromium-review.googlesource.com/1480741
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/pci')
-rw-r--r--devices/src/pci/ac97.rs15
-rw-r--r--devices/src/pci/pci_configuration.rs82
2 files changed, 59 insertions, 38 deletions
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs
index c8eb8ca..68dfe3c 100644
--- a/devices/src/pci/ac97.rs
+++ b/devices/src/pci/ac97.rs
@@ -9,7 +9,7 @@ use pci::ac97_bus_master::Ac97BusMaster;
 use pci::ac97_mixer::Ac97Mixer;
 use pci::ac97_regs::*;
 use pci::pci_configuration::{
-    PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass,
+    PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass,
 };
 use pci::pci_device::{self, PciDevice, Result};
 use pci::PciInterruptPin;
@@ -141,15 +141,24 @@ impl PciDevice for Ac97Dev {
         let mixer_regs_addr = resources
             .allocate_mmio_addresses(MIXER_REGS_SIZE)
             .ok_or(pci_device::Error::IoAllocationFailed(MIXER_REGS_SIZE))?;
+        let config: PciBarConfiguration = PciBarConfiguration::default()
+            .set_register_index(0)
+            .set_address(mixer_regs_addr)
+            .set_size(MIXER_REGS_SIZE);
         self.config_regs
-            .add_memory_region(mixer_regs_addr, MIXER_REGS_SIZE)
+            .add_pci_bar(&config)
             .ok_or_else(|| pci_device::Error::IoRegistrationFailed(mixer_regs_addr))?;
         ranges.push((mixer_regs_addr, MIXER_REGS_SIZE));
+
         let master_regs_addr = resources
             .allocate_mmio_addresses(MASTER_REGS_SIZE)
             .ok_or_else(|| pci_device::Error::IoAllocationFailed(MASTER_REGS_SIZE))?;
+        config
+            .set_register_index(1)
+            .set_address(master_regs_addr)
+            .set_size(MASTER_REGS_SIZE);
         self.config_regs
-            .add_memory_region(master_regs_addr, MASTER_REGS_SIZE)
+            .add_pci_bar(&config)
             .ok_or_else(|| pci_device::Error::IoRegistrationFailed(master_regs_addr))?;
         ranges.push((master_regs_addr, MASTER_REGS_SIZE));
         Ok(ranges)
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs
index b2bf90d..d93ae03 100644
--- a/devices/src/pci/pci_configuration.rs
+++ b/devices/src/pci/pci_configuration.rs
@@ -11,7 +11,6 @@ const STATUS_REG: usize = 1;
 const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
 const BAR0_REG: usize = 4;
 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
-const BAR_IO_BIT: u32 = 0x0000_0001;
 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
 const NUM_BAR_REGS: usize = 6;
 const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
@@ -167,13 +166,12 @@ pub trait PciCapability {
 pub struct PciConfiguration {
     registers: [u32; NUM_CONFIGURATION_REGISTERS],
     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
-    num_bars: usize,
+    bar_used: [bool; NUM_BAR_REGS],
     // Contains the byte offset and size of the last capability.
     last_capability: Option<(usize, usize)>,
 }
 
 /// See pci_regs.h in kernel
-#[allow(dead_code)]
 #[derive(Copy, Clone)]
 pub enum PciBarRegionType {
     Memory32BitRegion = 0,
@@ -181,14 +179,12 @@ pub enum PciBarRegionType {
     Memory64BitRegion = 0x04,
 }
 
-#[allow(dead_code)]
 #[derive(Copy, Clone)]
 pub enum PciBarPrefetchable {
     NotPrefetchable = 0,
     Prefetchable = 0x08,
 }
 
-#[allow(dead_code)]
 #[derive(Copy, Clone)]
 pub struct PciBarConfiguration {
     addr: u64,
@@ -239,7 +235,7 @@ impl PciConfiguration {
         PciConfiguration {
             registers,
             writable_bits,
-            num_bars: 0,
+            bar_used: [false; NUM_BAR_REGS],
             last_capability: None,
         }
     }
@@ -304,44 +300,61 @@ impl PciConfiguration {
         }
     }
 
-    // Add either an IO or memory region, depending on `mem_type` mask, which is ORed in to the
-    // value before saving it.
-    fn add_bar(&mut self, addr: u64, size: u64, addr_mask: u32, mem_type: u32) -> Option<usize> {
-        if self.num_bars >= NUM_BAR_REGS {
+    /// Adds a region specified by `config`.  Configures the specified BAR(s) to
+    /// report this region and size to the guest kernel.  Enforces a few constraints
+    /// (i.e, region size must be power of two, register not already used). Returns 'None' on
+    /// failure all, `Some(BarIndex)` on success.
+    pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Option<usize> {
+        if self.bar_used[config.reg_idx] {
             return None;
         }
-        if size.count_ones() != 1 {
+
+        if config.size.count_ones() != 1 {
             return None;
         }
 
-        // TODO(dgreid) Allow 64 bit address and size.
-        if addr.checked_add(size)? > u64::from(u32::max_value()) {
+        if config.reg_idx >= NUM_BAR_REGS {
             return None;
         }
 
-        let this_bar = self.num_bars;
-        let bar_idx = BAR0_REG + this_bar;
-
-        self.registers[bar_idx] = addr as u32 & addr_mask | mem_type;
-        // The first writable bit represents the size of the region.
-        self.writable_bits[bar_idx] = !(size - 1) as u32;
-
-        self.num_bars += 1;
-        Some(this_bar)
-    }
+        let bar_idx = BAR0_REG + config.reg_idx;
+        match config.region_type {
+            PciBarRegionType::Memory32BitRegion | PciBarRegionType::IORegion => {
+                if config.addr.checked_add(config.size)? > u64::from(u32::max_value()) {
+                    return None;
+                }
+            }
+            PciBarRegionType::Memory64BitRegion => {
+                if config.reg_idx + 1 >= NUM_BAR_REGS {
+                    return None;
+                }
+
+                if config.addr.checked_add(config.size)? > u64::max_value() {
+                    return None;
+                }
+
+                if self.bar_used[config.reg_idx + 1] {
+                    return None;
+                }
+
+                self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
+                self.writable_bits[bar_idx + 1] = !((config.size >> 32) - 1) as u32;
+                self.bar_used[config.reg_idx + 1] = true;
+            }
+        }
 
-    /// Adds a memory region of `size` at `addr`. Configures the next available BAR register to
-    /// report this region and size to the guest kernel. Returns 'None' if all BARs are full, or
-    /// `Some(BarIndex)` on success. `size` must be a power of 2.
-    pub fn add_memory_region(&mut self, addr: u64, size: u64) -> Option<usize> {
-        self.add_bar(addr, size, BAR_MEM_ADDR_MASK, 0)
-    }
+        let (mask, lower_bits) = match config.region_type {
+            PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
+                BAR_MEM_ADDR_MASK,
+                config.prefetchable as u32 | config.region_type as u32,
+            ),
+            PciBarRegionType::IORegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
+        };
 
-    /// Adds an IO region of `size` at `addr`. Configures the next available BAR register to
-    /// report this region and size to the guest kernel. Returns 'None' if all BARs are full, or
-    /// `Some(BarIndex)` on success. `size` must be a power of 2.
-    pub fn add_io_region(&mut self, addr: u64, size: u64) -> Option<usize> {
-        self.add_bar(addr, size, BAR_IO_ADDR_MASK, BAR_IO_BIT)
+        self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
+        self.writable_bits[bar_idx] = !(config.size - 1) as u32;
+        self.bar_used[config.reg_idx] = true;
+        Some(config.reg_idx)
     }
 
     /// Returns the address of the given BAR region.
@@ -407,7 +420,6 @@ impl Default for PciBarConfiguration {
     }
 }
 
-#[allow(dead_code)]
 impl PciBarConfiguration {
     pub fn new(
         reg_idx: usize,