[virtio] Move virtio module from pvmfw to vmbase

for reuse in both pvmfw and rialo.

No code change in this cl.

Bug: 284462758
Test: m pvmfw_img
Change-Id: I225b495a2f8c1a49cb63ea69d60f01949bab3f05
diff --git a/pvmfw/src/gpt.rs b/pvmfw/src/gpt.rs
index e0ffdc3..b553705 100644
--- a/pvmfw/src/gpt.rs
+++ b/pvmfw/src/gpt.rs
@@ -14,7 +14,6 @@
 
 //! Support for parsing GUID partition tables.
 
-use crate::virtio::pci::VirtIOBlk;
 use core::cmp::min;
 use core::fmt;
 use core::mem::size_of;
@@ -25,6 +24,7 @@
 use uuid::Uuid;
 use virtio_drivers::device::blk::SECTOR_SIZE;
 use vmbase::util::ceiling_div;
+use vmbase::virtio::pci::VirtIOBlk;
 use zerocopy::FromBytes;
 
 pub enum Error {
diff --git a/pvmfw/src/instance.rs b/pvmfw/src/instance.rs
index 9a6a6e4..b96ae1e 100644
--- a/pvmfw/src/instance.rs
+++ b/pvmfw/src/instance.rs
@@ -22,7 +22,6 @@
 use crate::gpt::Partition;
 use crate::gpt::Partitions;
 use crate::rand;
-use crate::virtio::pci::VirtIOBlkIterator;
 use core::fmt;
 use core::mem::size_of;
 use diced_open_dice::DiceMode;
@@ -32,6 +31,7 @@
 use uuid::Uuid;
 use virtio_drivers::transport::pci::bus::PciRoot;
 use vmbase::util::ceiling_div;
+use vmbase::virtio::pci::VirtIOBlkIterator;
 use zerocopy::AsBytes;
 use zerocopy::FromBytes;
 
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index c6baf6d..c826cd8 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -34,7 +34,6 @@
 mod instance;
 mod memory;
 mod rand;
-mod virtio;
 
 use crate::bcc::Bcc;
 use crate::dice::PartialInputs;
@@ -42,7 +41,6 @@
 use crate::fdt::modify_for_next_stage;
 use crate::helpers::GUEST_PAGE_SIZE;
 use crate::instance::get_or_generate_instance_salt;
-use crate::virtio::pci;
 use alloc::boxed::Box;
 use core::ops::Range;
 use diced_open_dice::{bcc_handover_parse, DiceArtifacts};
@@ -55,6 +53,7 @@
 use pvmfw_embedded_key::PUBLIC_KEY;
 use vmbase::memory::flush;
 use vmbase::memory::MEMORY;
+use vmbase::virtio::pci;
 
 const NEXT_BCC_SIZE: usize = GUEST_PAGE_SIZE;
 
diff --git a/pvmfw/src/virtio.rs b/pvmfw/src/virtio.rs
deleted file mode 100644
index df916bc..0000000
--- a/pvmfw/src/virtio.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2022, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Modules for working with VirtIO devices.
-
-mod hal;
-pub mod pci;
diff --git a/pvmfw/src/virtio/hal.rs b/pvmfw/src/virtio/hal.rs
deleted file mode 100644
index f223a7e..0000000
--- a/pvmfw/src/virtio/hal.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2023, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! HAL for the virtio_drivers crate.
-
-use super::pci::PCI_INFO;
-use core::alloc::Layout;
-use core::mem::size_of;
-use core::ptr::{copy_nonoverlapping, NonNull};
-use log::trace;
-use virtio_drivers::{BufferDirection, Hal, PhysAddr, PAGE_SIZE};
-use vmbase::memory::{alloc_shared, dealloc_shared, phys_to_virt, virt_to_phys};
-use vmbase::util::RangeExt as _;
-
-/// The alignment to use for the temporary buffers allocated by `HalImpl::share`. There doesn't seem
-/// to be any particular alignment required by VirtIO for these, so 16 bytes should be enough to
-/// allow appropriate alignment for whatever fields are accessed. `alloc_shared` will increase the
-/// alignment to the memory sharing granule size anyway.
-const SHARED_BUFFER_ALIGNMENT: usize = size_of::<u128>();
-
-pub struct HalImpl;
-
-/// # Safety
-///
-/// See the 'Implementation Safety' comments on methods below for how they fulfill the safety
-/// requirements of the unsafe `Hal` trait.
-unsafe impl Hal for HalImpl {
-    /// # Implementation Safety
-    ///
-    /// `dma_alloc` ensures the returned DMA buffer is not aliased with any other allocation or
-    /// reference in the program until it is deallocated by `dma_dealloc` by allocating a unique
-    /// block of memory using `alloc_shared`, which is guaranteed to allocate valid and unique
-    /// memory. We request an alignment of at least `PAGE_SIZE` from `alloc_shared`.
-    fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
-        let vaddr = alloc_shared(dma_layout(pages))
-            .expect("Failed to allocate and share VirtIO DMA range with host");
-        // TODO(ptosi): Move this zeroing to virtio_drivers, if it silently wants a zeroed region.
-        // SAFETY - vaddr points to a region allocated for the caller so is safe to access.
-        unsafe { core::ptr::write_bytes(vaddr.as_ptr(), 0, dma_layout(pages).size()) };
-        let paddr = virt_to_phys(vaddr);
-        (paddr, vaddr)
-    }
-
-    unsafe fn dma_dealloc(_paddr: PhysAddr, vaddr: NonNull<u8>, pages: usize) -> i32 {
-        // SAFETY - Memory was allocated by `dma_alloc` using `alloc_shared` with the same layout.
-        unsafe { dealloc_shared(vaddr, dma_layout(pages)) }
-            .expect("Failed to unshare VirtIO DMA range with host");
-        0
-    }
-
-    /// # Implementation Safety
-    ///
-    /// The returned pointer must be valid because the `paddr` describes a valid MMIO region, we
-    /// check that it is within the PCI MMIO range, and we previously mapped the entire PCI MMIO
-    /// range. It can't alias any other allocations because we previously validated in
-    /// `map_mmio_range` that the PCI MMIO range didn't overlap with any other memory ranges.
-    unsafe fn mmio_phys_to_virt(paddr: PhysAddr, size: usize) -> NonNull<u8> {
-        let pci_info = PCI_INFO.get().expect("VirtIO HAL used before PCI_INFO was initialised");
-        let bar_range = {
-            let start = pci_info.bar_range.start.try_into().unwrap();
-            let end = pci_info.bar_range.end.try_into().unwrap();
-
-            start..end
-        };
-        let mmio_range = paddr..paddr.checked_add(size).expect("PCI MMIO region end overflowed");
-
-        // Check that the region is within the PCI MMIO range that we read from the device tree. If
-        // not, the host is probably trying to do something malicious.
-        assert!(
-            mmio_range.is_within(&bar_range),
-            "PCI MMIO region was outside of expected BAR range.",
-        );
-
-        phys_to_virt(paddr)
-    }
-
-    unsafe fn share(buffer: NonNull<[u8]>, direction: BufferDirection) -> PhysAddr {
-        let size = buffer.len();
-
-        let bounce = alloc_shared(bb_layout(size))
-            .expect("Failed to allocate and share VirtIO bounce buffer with host");
-        let paddr = virt_to_phys(bounce);
-        if direction == BufferDirection::DriverToDevice {
-            let src = buffer.cast::<u8>().as_ptr().cast_const();
-            trace!("VirtIO bounce buffer at {bounce:?} (PA:{paddr:#x}) initialized from {src:?}");
-            // SAFETY - Both regions are valid, properly aligned, and don't overlap.
-            unsafe { copy_nonoverlapping(src, bounce.as_ptr(), size) };
-        }
-
-        paddr
-    }
-
-    unsafe fn unshare(paddr: PhysAddr, buffer: NonNull<[u8]>, direction: BufferDirection) {
-        let bounce = phys_to_virt(paddr);
-        let size = buffer.len();
-        if direction == BufferDirection::DeviceToDriver {
-            let dest = buffer.cast::<u8>().as_ptr();
-            trace!("VirtIO bounce buffer at {bounce:?} (PA:{paddr:#x}) copied back to {dest:?}");
-            // SAFETY - Both regions are valid, properly aligned, and don't overlap.
-            unsafe { copy_nonoverlapping(bounce.as_ptr(), dest, size) };
-        }
-
-        // SAFETY - Memory was allocated by `share` using `alloc_shared` with the same layout.
-        unsafe { dealloc_shared(bounce, bb_layout(size)) }
-            .expect("Failed to unshare and deallocate VirtIO bounce buffer");
-    }
-}
-
-fn dma_layout(pages: usize) -> Layout {
-    let size = pages.checked_mul(PAGE_SIZE).unwrap();
-    Layout::from_size_align(size, PAGE_SIZE).unwrap()
-}
-
-fn bb_layout(size: usize) -> Layout {
-    Layout::from_size_align(size, SHARED_BUFFER_ALIGNMENT).unwrap()
-}
diff --git a/pvmfw/src/virtio/pci.rs b/pvmfw/src/virtio/pci.rs
deleted file mode 100644
index fd99c07..0000000
--- a/pvmfw/src/virtio/pci.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2022, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Functions to scan the PCI bus for VirtIO devices.
-
-use super::hal::HalImpl;
-use alloc::boxed::Box;
-use core::fmt;
-use fdtpci::PciInfo;
-use log::debug;
-use once_cell::race::OnceBox;
-use virtio_drivers::{
-    device::blk,
-    transport::{
-        pci::{
-            bus::{BusDeviceIterator, PciRoot},
-            virtio_device_type, PciTransport,
-        },
-        DeviceType, Transport,
-    },
-};
-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:
-///
-/// 1. Maps the PCI CAM and BAR range in the page table and MMIO guard.
-/// 2. Stores the `PciInfo` for the VirtIO HAL to use later.
-/// 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, PciError> {
-    PCI_INFO.set(Box::new(pci_info.clone())).map_err(|_| PciError::DuplicateInitialization)?;
-
-    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() })
-}
-
-pub type VirtIOBlk = blk::VirtIOBlk<HalImpl, PciTransport>;
-
-pub struct VirtIOBlkIterator<'a> {
-    pci_root: &'a mut PciRoot,
-    bus: BusDeviceIterator,
-}
-
-impl<'a> VirtIOBlkIterator<'a> {
-    pub fn new(pci_root: &'a mut PciRoot) -> Self {
-        let bus = pci_root.enumerate_bus(0);
-        Self { pci_root, bus }
-    }
-}
-
-impl<'a> Iterator for VirtIOBlkIterator<'a> {
-    type Item = VirtIOBlk;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        loop {
-            let (device_function, info) = self.bus.next()?;
-            let (status, command) = self.pci_root.get_status_command(device_function);
-            debug!(
-                "Found PCI device {} at {}, status {:?} command {:?}",
-                info, device_function, status, command
-            );
-
-            let Some(virtio_type) = virtio_device_type(&info) else {
-                continue;
-            };
-            debug!("  VirtIO {:?}", virtio_type);
-
-            let mut transport =
-                PciTransport::new::<HalImpl>(self.pci_root, device_function).unwrap();
-            debug!(
-                "Detected virtio PCI device with device type {:?}, features {:#018x}",
-                transport.device_type(),
-                transport.read_device_features(),
-            );
-
-            if virtio_type == DeviceType::Block {
-                return Some(Self::Item::new(transport).expect("failed to create blk driver"));
-            }
-        }
-    }
-}