Probe for VirtIO PCI devices and allocate BARs.

Bug: 237249346
Test: Ran vmbase example
Change-Id: I6ce254a5d5a5740011ddc8efecd4052f40a2a53c
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index bb64651..df81b2b 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -20,6 +20,7 @@
 
 mod exceptions;
 mod layout;
+mod pci;
 
 extern crate alloc;
 
@@ -27,17 +28,18 @@
     bionic_tls, dtb_range, print_addresses, rodata_range, stack_chk_guard, text_range,
     writable_region, DEVICE_REGION,
 };
-use aarch64_paging::{
-    idmap::IdMap,
-    paging::{Attributes, MemoryRegion},
-};
+use crate::pci::{check_pci, pci_node, PciMemory32Allocator};
+use aarch64_paging::{idmap::IdMap, paging::Attributes};
 use alloc::{vec, vec::Vec};
 use buddy_system_allocator::LockedHeap;
 use core::ffi::CStr;
 use libfdt::Fdt;
-use log::{info, LevelFilter};
+use log::{debug, info, LevelFilter};
 use vmbase::{logger, main, println};
 
+/// PCI MMIO configuration region size.
+const AARCH64_PCI_CFG_SIZE: u64 = 0x1000000;
+
 static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
 static mut ZEROED_DATA: [u32; 10] = [0; 10];
 static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
@@ -62,7 +64,27 @@
     assert_eq!(arg0, dtb_range().start.0 as u64);
     check_data();
     check_stack_guard();
-    check_fdt();
+
+    info!("Checking FDT...");
+    let fdt = dtb_range();
+    let fdt =
+        unsafe { core::slice::from_raw_parts_mut(fdt.start.0 as *mut u8, fdt.end.0 - fdt.start.0) };
+    let fdt = Fdt::from_mut_slice(fdt).unwrap();
+    info!("FDT passed verification.");
+    check_fdt(fdt);
+
+    let pci_node = pci_node(fdt);
+    // Parse reg property to find CAM.
+    let pci_reg = pci_node.reg().unwrap().unwrap().next().unwrap();
+    debug!("Found PCI CAM at {:#x}-{:#x}", pci_reg.addr, pci_reg.addr + pci_reg.size.unwrap());
+    // Check that the CAM is the size we expect, so we don't later try accessing it beyond its
+    // bounds. If it is a different size then something is very wrong and we shouldn't continue to
+    // access it; maybe there is some new version of PCI we don't know about.
+    assert_eq!(pci_reg.size.unwrap(), AARCH64_PCI_CFG_SIZE);
+    // Parse ranges property to find memory ranges from which to allocate PCI BARs.
+    let mut pci_allocator = PciMemory32Allocator::for_pci_ranges(&pci_node);
+
+    modify_fdt(fdt);
 
     unsafe {
         HEAP_ALLOCATOR.lock().init(HEAP.as_mut_ptr() as usize, HEAP.len());
@@ -93,6 +115,21 @@
             Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
         )
         .unwrap();
+    idmap
+        .map_range(
+            &dtb_range().into(),
+            Attributes::NORMAL
+                | Attributes::NON_GLOBAL
+                | Attributes::READ_ONLY
+                | Attributes::EXECUTE_NEVER,
+        )
+        .unwrap();
+    idmap
+        .map_range(
+            &pci_allocator.get_region(),
+            Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER,
+        )
+        .unwrap();
 
     info!("Activating IdMap...");
     info!("{:?}", idmap);
@@ -101,6 +138,8 @@
 
     check_data();
     check_dice();
+
+    check_pci(pci_reg, &mut pci_allocator);
 }
 
 fn check_stack_guard() {
@@ -144,13 +183,7 @@
     info!("Data looks good");
 }
 
-fn check_fdt() {
-    info!("Checking FDT...");
-    let fdt = MemoryRegion::from(layout::dtb_range());
-    let fdt = unsafe { core::slice::from_raw_parts_mut(fdt.start().0 as *mut u8, fdt.len()) };
-
-    let reader = Fdt::from_slice(fdt).unwrap();
-    info!("FDT passed verification.");
+fn check_fdt(reader: &Fdt) {
     for reg in reader.memory().unwrap().unwrap() {
         info!("memory @ {reg:#x?}");
     }
@@ -161,8 +194,9 @@
         let reg = c.reg().unwrap().unwrap().next().unwrap();
         info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
     }
+}
 
-    let writer = Fdt::from_mut_slice(fdt).unwrap();
+fn modify_fdt(writer: &mut Fdt) {
     writer.unpack().unwrap();
     info!("FDT successfully unpacked.");