Skip to main content

axvirtio_common/
memory.rs

1//! Scoped guest-memory operations used by VirtIO queues.
2
3use ax_memory_addr::PhysAddr;
4use axaddrspace::GuestMemoryAccessor;
5use axdevice_base::{DeviceContext, DmaGrant};
6use axvm_types::GuestPhysAddr;
7
8use crate::{VirtioError, VirtioResult};
9
10/// The minimum guest-memory capability required by a VirtIO queue operation.
11pub trait GuestMemory {
12    /// Reads bytes starting at `guest_addr`.
13    fn read(&mut self, guest_addr: GuestPhysAddr, data: &mut [u8]) -> VirtioResult<()>;
14
15    /// Writes bytes starting at `guest_addr`.
16    fn write(&mut self, guest_addr: GuestPhysAddr, data: &[u8]) -> VirtioResult<()>;
17}
18
19/// Placeholder accessor for runtimes that provide guest memory only through
20/// a scoped [`GuestMemory`] capability at queue-processing time.
21#[derive(Clone, Copy, Debug, Default)]
22pub struct NoGuestMemoryAccessor;
23
24impl GuestMemoryAccessor for NoGuestMemoryAccessor {
25    fn translate_and_get_limit(&self, _guest_addr: GuestPhysAddr) -> Option<(PhysAddr, usize)> {
26        None
27    }
28}
29
30/// Adapter for existing address-space accessors used by host tests and
31/// standalone device-model users.
32pub struct AddressSpaceMemory<'a, T> {
33    accessor: &'a T,
34}
35
36impl<'a, T> AddressSpaceMemory<'a, T> {
37    /// Wraps one address-space accessor for a scoped queue operation.
38    pub const fn new(accessor: &'a T) -> Self {
39        Self { accessor }
40    }
41}
42
43impl<T: GuestMemoryAccessor> GuestMemory for AddressSpaceMemory<'_, T> {
44    fn read(&mut self, guest_addr: GuestPhysAddr, data: &mut [u8]) -> VirtioResult<()> {
45        self.accessor
46            .read_buffer(guest_addr, data)
47            .map_err(|_| VirtioError::InvalidAddress)
48    }
49
50    fn write(&mut self, guest_addr: GuestPhysAddr, data: &[u8]) -> VirtioResult<()> {
51        self.accessor
52            .write_buffer(guest_addr, data)
53            .map_err(|_| VirtioError::InvalidAddress)
54    }
55}
56
57/// Guest-memory capability adapter for a routed PCI endpoint callback.
58///
59/// The endpoint supplies its registration-time [`DmaGrant`]; the runtime still
60/// validates the grant and the current BME snapshot on every operation through
61/// [`DeviceContext`].
62pub struct DeviceContextMemory<'a> {
63    context: &'a mut dyn DeviceContext,
64    grant: &'a DmaGrant,
65}
66
67impl<'a> DeviceContextMemory<'a> {
68    /// Creates a scoped memory adapter for one endpoint callback.
69    pub fn new(context: &'a mut dyn DeviceContext, grant: &'a DmaGrant) -> Self {
70        Self { context, grant }
71    }
72}
73
74impl GuestMemory for DeviceContextMemory<'_> {
75    fn read(&mut self, guest_addr: GuestPhysAddr, data: &mut [u8]) -> VirtioResult<()> {
76        self.context
77            .read_guest_memory(self.grant, guest_addr, data)
78            .map_err(|_| VirtioError::MemoryError)
79    }
80
81    fn write(&mut self, guest_addr: GuestPhysAddr, data: &[u8]) -> VirtioResult<()> {
82        self.context
83            .write_guest_memory(self.grant, guest_addr, data)
84            .map_err(|_| VirtioError::MemoryError)
85    }
86}