virtio_drivers/
volatile.rs

1/// An MMIO register which can only be read from.
2#[derive(Default)]
3#[repr(transparent)]
4pub struct ReadOnly<T: Copy>(pub(crate) T);
5
6impl<T: Copy> ReadOnly<T> {
7    /// Construct a new instance for testing.
8    pub const fn new(value: T) -> Self {
9        Self(value)
10    }
11}
12
13/// An MMIO register which can only be written to.
14#[derive(Default)]
15#[repr(transparent)]
16pub struct WriteOnly<T: Copy>(pub(crate) T);
17
18/// An MMIO register which may be both read and written.
19#[derive(Default)]
20#[repr(transparent)]
21pub struct Volatile<T: Copy>(T);
22
23impl<T: Copy> Volatile<T> {
24    /// Construct a new instance for testing.
25    pub const fn new(value: T) -> Self {
26        Self(value)
27    }
28}
29
30/// A trait implemented by MMIO registers which may be read from.
31pub trait VolatileReadable<T> {
32    /// Performs a volatile read from the MMIO register.
33    unsafe fn vread(self) -> T;
34}
35
36impl<T: Copy> VolatileReadable<T> for *const ReadOnly<T> {
37    unsafe fn vread(self) -> T {
38        self.read_volatile().0
39    }
40}
41
42impl<T: Copy> VolatileReadable<T> for *const Volatile<T> {
43    unsafe fn vread(self) -> T {
44        self.read_volatile().0
45    }
46}
47
48/// A trait implemented by MMIO registers which may be written to.
49pub trait VolatileWritable<T> {
50    /// Performs a volatile write to the MMIO register.
51    unsafe fn vwrite(self, value: T);
52}
53
54impl<T: Copy> VolatileWritable<T> for *mut WriteOnly<T> {
55    unsafe fn vwrite(self, value: T) {
56        (self as *mut T).write_volatile(value)
57    }
58}
59
60impl<T: Copy> VolatileWritable<T> for *mut Volatile<T> {
61    unsafe fn vwrite(self, value: T) {
62        (self as *mut T).write_volatile(value)
63    }
64}
65
66/// Performs a volatile read from the given field of pointer to a struct representing an MMIO region.
67///
68/// # Usage
69/// ```compile_fail
70/// # use core::ptr::NonNull;
71/// # use virtio_drivers::volatile::{ReadOnly, volread};
72/// struct MmioDevice {
73///   field: ReadOnly<u32>,
74/// }
75///
76/// let device: NonNull<MmioDevice> = NonNull::new(0x1234 as *mut MmioDevice).unwrap();
77/// let value = unsafe { volread!(device, field) };
78/// ```
79macro_rules! volread {
80    ($nonnull:expr, $field:ident) => {
81        $crate::volatile::VolatileReadable::vread(core::ptr::addr_of!((*$nonnull.as_ptr()).$field))
82    };
83}
84
85/// Performs a volatile write to the given field of pointer to a struct representing an MMIO region.
86///
87/// # Usage
88/// ```compile_fail
89/// # use core::ptr::NonNull;
90/// # use virtio_drivers::volatile::{WriteOnly, volread};
91/// struct MmioDevice {
92///   field: WriteOnly<u32>,
93/// }
94///
95/// let device: NonNull<MmioDevice> = NonNull::new(0x1234 as *mut MmioDevice).unwrap();
96/// unsafe { volwrite!(device, field, 42); }
97/// ```
98macro_rules! volwrite {
99    ($nonnull:expr, $field:ident, $value:expr) => {
100        $crate::volatile::VolatileWritable::vwrite(
101            core::ptr::addr_of_mut!((*$nonnull.as_ptr()).$field),
102            $value,
103        )
104    };
105}
106
107pub(crate) use volread;
108pub(crate) use volwrite;