[pvmfw][virtio] Refactor PCI initialisation

This cl refactors PCI initialisation by:

- Introducing a new error type specifically for PCI.
- Replacing the pvmfw-specific error type with the new PCIError
  to facilitate moving this module to vmbase for reuse later.
- Setting the static PCI_INFO before mapping the PCI CAM and
  BAR ranges.

Bug: 284462758
Test: m pvmfw_img
Change-Id: I66a653f4c9d404e7655919e89acf9bb93bb6aaaa
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 6a5151c..c6baf6d 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -98,7 +98,10 @@
     // Set up PCI bus for VirtIO devices.
     let pci_info = PciInfo::from_fdt(fdt).map_err(handle_pci_error)?;
     debug!("PCI: {:#x?}", pci_info);
-    let mut pci_root = pci::initialise(pci_info, MEMORY.lock().as_mut().unwrap())?;
+    let mut pci_root = pci::initialise(pci_info, MEMORY.lock().as_mut().unwrap()).map_err(|e| {
+        error!("Failed to initialise PCI: {e}");
+        RebootReason::InternalError
+    })?;
 
     let verified_boot_data = verify_payload(signed_kernel, ramdisk, PUBLIC_KEY).map_err(|e| {
         error!("Failed to verify the payload: {e}");
diff --git a/pvmfw/src/virtio/pci.rs b/pvmfw/src/virtio/pci.rs
index ad7cfbb..fd99c07 100644
--- a/pvmfw/src/virtio/pci.rs
+++ b/pvmfw/src/virtio/pci.rs
@@ -15,10 +15,10 @@
 //! Functions to scan the PCI bus for VirtIO devices.
 
 use super::hal::HalImpl;
-use crate::entry::RebootReason;
 use alloc::boxed::Box;
+use core::fmt;
 use fdtpci::PciInfo;
-use log::{debug, error};
+use log::debug;
 use once_cell::race::OnceBox;
 use virtio_drivers::{
     device::blk,
@@ -30,10 +30,33 @@
         DeviceType, Transport,
     },
 };
-use vmbase::memory::MemoryTracker;
+use vmbase::memory::{MemoryTracker, MemoryTrackerError};
 
 pub(super) static PCI_INFO: OnceBox<PciInfo> = OnceBox::new();
 
+/// PCI errors.
+#[derive(Debug, Clone)]
+pub enum PciError {
+    /// Attempted to initialize the PCI more than once.
+    DuplicateInitialization,
+    /// Failed to map PCI CAM.
+    CamMapFailed(MemoryTrackerError),
+    /// Failed to map PCI BAR.
+    BarMapFailed(MemoryTrackerError),
+}
+
+impl fmt::Display for PciError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::DuplicateInitialization => {
+                write!(f, "Attempted to initialize the PCI more than once.")
+            }
+            Self::CamMapFailed(e) => write!(f, "Failed to map PCI CAM: {e}"),
+            Self::BarMapFailed(e) => write!(f, "Failed to map PCI BAR: {e}"),
+        }
+    }
+}
+
 /// Prepares to use VirtIO PCI devices.
 ///
 /// In particular:
@@ -43,33 +66,18 @@
 /// 3. Creates and returns a `PciRoot`.
 ///
 /// This must only be called once; it will panic if it is called a second time.
-pub fn initialise(pci_info: PciInfo, memory: &mut MemoryTracker) -> Result<PciRoot, RebootReason> {
-    map_mmio(&pci_info, memory)?;
+pub fn initialise(pci_info: PciInfo, memory: &mut MemoryTracker) -> Result<PciRoot, PciError> {
+    PCI_INFO.set(Box::new(pci_info.clone())).map_err(|_| PciError::DuplicateInitialization)?;
 
-    PCI_INFO.set(Box::new(pci_info.clone())).expect("Tried to set PCI_INFO a second time");
+    memory.map_mmio_range(pci_info.cam_range.clone()).map_err(PciError::CamMapFailed)?;
+    let bar_range = pci_info.bar_range.start as usize..pci_info.bar_range.end as usize;
+    memory.map_mmio_range(bar_range).map_err(PciError::BarMapFailed)?;
 
     // Safety: This is the only place where we call make_pci_root, and `PCI_INFO.set` above will
     // panic if it is called a second time.
     Ok(unsafe { pci_info.make_pci_root() })
 }
 
-/// Maps the CAM and BAR range in the page table and MMIO guard.
-fn map_mmio(pci_info: &PciInfo, memory: &mut MemoryTracker) -> Result<(), RebootReason> {
-    memory.map_mmio_range(pci_info.cam_range.clone()).map_err(|e| {
-        error!("Failed to map PCI CAM: {}", e);
-        RebootReason::InternalError
-    })?;
-
-    memory
-        .map_mmio_range(pci_info.bar_range.start as usize..pci_info.bar_range.end as usize)
-        .map_err(|e| {
-            error!("Failed to map PCI MMIO range: {}", e);
-            RebootReason::InternalError
-        })?;
-
-    Ok(())
-}
-
 pub type VirtIOBlk = blk::VirtIOBlk<HalImpl, PciTransport>;
 
 pub struct VirtIOBlkIterator<'a> {