devices:pcie: Add and emulate pcie root port

Pcie root port implements pcie cap register, but it is wrapped as a pci
bridge to VM, the pci bridge implements PciDevice trait.

BUG=b:185084350
TEST=Boot a guest with pcie root port and check its status

Change-Id: I739e878846f4b35d58e4d213caafe30196a27ccb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2954676
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
diff --git a/src/linux.rs b/src/linux.rs
index f588382..4361020 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -45,8 +45,9 @@
 use devices::Ac97Dev;
 use devices::ProtectionType;
 use devices::{
-    self, HostHotPlugKey, IrqChip, IrqEventIndex, KvmKernelIrqChip, PciAddress, PciDevice,
-    VcpuRunState, VfioContainer, VfioDevice, VfioPciDevice, VirtioPciDevice,
+    self, HostHotPlugKey, IrqChip, IrqEventIndex, KvmKernelIrqChip, PciAddress, PciBridge,
+    PciDevice, PcieRootPort, VcpuRunState, VfioContainer, VfioDevice, VfioPciDevice,
+    VirtioPciDevice,
 };
 #[cfg(feature = "usb")]
 use devices::{HostBackendDeviceProvider, XhciController};
@@ -1569,6 +1570,14 @@
         pci_devices.push((usb_controller, simple_jail(&cfg, "xhci")?));
     }
 
+    // Create Pcie Root Port
+    let pcie_root_port = Box::new(PcieRootPort::new());
+    let (msi_host_tube, msi_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+    control_tubes.push(TaggedControlTube::VmIrq(msi_host_tube));
+    let pci_bridge = Box::new(PciBridge::new(pcie_root_port, msi_device_tube));
+    // pcie root port is used in hotplug process only, so disable sandbox for it
+    pci_devices.push((pci_bridge, None));
+
     if !cfg.vfio.is_empty() {
         let mut iommu_attached_endpoints: BTreeMap<u32, Arc<Mutex<VfioContainer>>> =
             BTreeMap::new();