devices: PCI: use configuration callback

Not sure if adding the device addresses to the mmio bus
is the desired behavior, but it seems to work.

BUG=chromium:924405
TEST=boot VM

Change-Id: I7f6057b3e7d041a52b251af1203353ba7a0d3c22
Reviewed-on: https://chromium-review.googlesource.com/1480743
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>
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 74545a5..2560ff5 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -94,6 +94,8 @@
 pub enum DeviceRegistrationError {
     /// Could not allocate IO space for the device.
     AllocateIoAddrs(PciDeviceError),
+    /// Could not allocate device address space for the device.
+    AllocateDeviceAddrs(PciDeviceError),
     /// Could not allocate an IRQ number.
     AllocateIrq,
     /// Could not create the mmio device to wrap a VirtioDevice.
@@ -122,6 +124,9 @@
             DeviceRegistrationError::AllocateIoAddrs(e) => {
                 write!(f, "Allocating IO addresses: {}", e)
             }
+            DeviceRegistrationError::AllocateDeviceAddrs(e) => {
+                write!(f, "Allocating device addresses: {:?}", e)
+            }
             DeviceRegistrationError::AllocateIrq => write!(f, "Allocating IRQ number"),
             DeviceRegistrationError::CreateMmioDevice(e) => {
                 write!(f, "failed to create mmio device: {}", e)
@@ -187,6 +192,9 @@
         let ranges = device
             .allocate_io_bars(resources)
             .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
+        let device_ranges = device
+            .allocate_device_bars(resources)
+            .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
         for (event, addr, datamatch) in device.ioeventfds() {
             let io_addr = IoeventAddress::Mmio(addr);
             vm.register_ioevent(&event, io_addr, datamatch)
@@ -207,6 +215,12 @@
                 .insert(arced_dev.clone(), range.0, range.1, true)
                 .map_err(DeviceRegistrationError::MmioInsert)?;
         }
+
+        for range in &device_ranges {
+            mmio_bus
+                .insert(arced_dev.clone(), range.0, range.1, true)
+                .map_err(DeviceRegistrationError::MmioInsert)?;
+        }
     }
     Ok((root, pci_irqs, pid_labels))
 }
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs
index b27dc47..3b8b93e 100644
--- a/devices/src/pci/pci_device.rs
+++ b/devices/src/pci/pci_device.rs
@@ -60,6 +60,17 @@
     fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
         Ok(Vec::new())
     }
+
+    /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples.
+    /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits
+    /// - these BARs represent normal memory.
+    fn allocate_device_bars(
+        &mut self,
+        _resources: &mut SystemAllocator,
+    ) -> Result<Vec<(u64, u64)>> {
+        Ok(Vec::new())
+    }
+
     /// Gets a list of ioeventfds that should be registered with the running VM. The list is
     /// returned as a Vec of (eventfd, addr, datamatch) tuples.
     fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
@@ -141,6 +152,9 @@
     fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
         (**self).allocate_io_bars(resources)
     }
+    fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
+        (**self).allocate_device_bars(resources)
+    }
     fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
         (**self).ioeventfds()
     }
diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs
index bdd10c2..e764569 100644
--- a/devices/src/virtio/virtio_pci_device.rs
+++ b/devices/src/virtio/virtio_pci_device.rs
@@ -329,6 +329,31 @@
         Ok(ranges)
     }
 
+    fn allocate_device_bars(
+        &mut self,
+        resources: &mut SystemAllocator,
+    ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
+        let mut ranges = Vec::new();
+        let configs = self.device.get_device_bars();
+        match configs {
+            Some(configs) => {
+                for mut config in configs {
+                    let device_addr = resources
+                        .allocate_device_addresses(config.get_size())
+                        .ok_or(PciDeviceError::IoAllocationFailed(config.get_size()))?;
+                    config.set_address(device_addr);
+                    let _device_bar = self
+                        .config_regs
+                        .add_pci_bar(&config)
+                        .ok_or(PciDeviceError::IoRegistrationFailed(device_addr))?;
+                    ranges.push((device_addr, config.get_size()));
+                }
+            }
+            None => (),
+        };
+        Ok(ranges)
+    }
+
     fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
         let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
         let notify_base = bar0 + NOTIFICATION_BAR_OFFSET;