[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> {