virtio_spec/
volatile.rs

1//! Volatile Pointer Types.
2
3use core::marker::PhantomData;
4
5use volatile::access::{Readable, Writable};
6use volatile::VolatilePtr;
7
8use crate::{be32, be64, le16, le32, le64, DeviceStatus, Id};
9
10/// A wide volatile pointer for 64-bit fields.
11///
12/// In virtio, 64-bit fields are to be treated as two 32-bit fields, with low 32 bit part followed by the high 32 bit part.
13/// This type mimics [`VolatilePtr`], and allows easy access to 64-bit fields.
14pub struct WideVolatilePtr<'a, T, A>
15where
16    T: ?Sized,
17{
18    low: VolatilePtr<'a, T, A>,
19    high: VolatilePtr<'a, T, A>,
20}
21
22impl<'a, T, A> Copy for WideVolatilePtr<'a, T, A> where T: ?Sized {}
23
24impl<'a, T, A> Clone for WideVolatilePtr<'a, T, A>
25where
26    T: ?Sized,
27{
28    fn clone(&self) -> Self {
29        *self
30    }
31}
32
33impl<'a, T, A> WideVolatilePtr<'a, T, A> {
34    /// Creates a new wide volatile pointer from pointers to the low and to the high part.
35    pub fn from_low_high(low: VolatilePtr<'a, T, A>, high: VolatilePtr<'a, T, A>) -> Self {
36        Self { low, high }
37    }
38}
39
40impl<'a, A> WideVolatilePtr<'a, le32, A> {
41    /// Performs a volatile read of the contained value.
42    ///
43    /// See [`VolatilePtr::read`].
44    pub fn read(self) -> le64
45    where
46        A: Readable,
47    {
48        let low = self.low.read();
49        let high = self.high.read();
50        le64::from([low, high])
51    }
52
53    /// Performs a volatile write, setting the contained value to the given `value`.
54    ///
55    /// See [`VolatilePtr::write`].
56    pub fn write(self, value: le64)
57    where
58        A: Writable,
59    {
60        let [low, high] = value.into();
61        self.low.write(low);
62        self.high.write(high);
63    }
64
65    /// Updates the contained value using the given closure and volatile instructions.
66    ///
67    /// See [`VolatilePtr::update`].
68    pub fn update(self, f: impl FnOnce(le64) -> le64)
69    where
70        A: Readable + Writable,
71    {
72        let new = f(self.read());
73        self.write(new);
74    }
75}
76
77impl<'a, A> WideVolatilePtr<'a, be32, A> {
78    /// Performs a volatile read of the contained value.
79    ///
80    /// See [`VolatilePtr::read`].
81    pub fn read(self) -> be64
82    where
83        A: Readable,
84    {
85        let low = self.low.read();
86        let high = self.high.read();
87        be64::from([low, high])
88    }
89
90    /// Performs a volatile write, setting the contained value to the given `value`.
91    ///
92    /// See [`VolatilePtr::write`].
93    pub fn write(self, value: be64)
94    where
95        A: Writable,
96    {
97        let [low, high] = value.into();
98        self.low.write(low);
99        self.high.write(high);
100    }
101
102    /// Updates the contained value using the given closure and volatile instructions.
103    ///
104    /// See [`VolatilePtr::update`].
105    pub fn update(self, f: impl FnOnce(be64) -> be64)
106    where
107        A: Readable + Writable,
108    {
109        let new = f(self.read());
110        self.write(new);
111    }
112}
113
114#[cfg(any(feature = "mmio", feature = "pci"))]
115macro_rules! impl_wide_field_access {
116    (
117        $(#[$outer:meta])*
118        $vis:vis trait $Trait:ident<'a, A>: $T:ty {
119            $(
120                $(#[doc = $doc:literal])*
121                $(#[doc(alias = $alias:literal)])?
122                #[access($Access:ty)]
123                $field:ident: $field_low:ident, $field_high:ident;
124            )*
125        }
126    ) => {
127        $(#[$outer])*
128        $vis trait $Trait<'a, A> {
129            $(
130                $(#[doc = $doc])*
131                $(#[doc(alias = $alias)])?
132                fn $field(self) -> WideVolatilePtr<'a, le32, A::Restricted>
133                where
134                    A: RestrictAccess<$Access>;
135            )*
136        }
137
138        impl<'a, A> $Trait<'a, A> for VolatilePtr<'a, $T, A> {
139            $(
140                fn $field(self) -> WideVolatilePtr<'a, le32, A::Restricted>
141                where
142                    A: RestrictAccess<$Access>,
143                {
144                    WideVolatilePtr::from_low_high(self.$field_low(), self.$field_high())
145                }
146            )*
147        }
148    };
149}
150
151/// An overaligned volatile pointer for fields that require wider access operations.
152///
153/// In virtio, some fields require wider access operations than their type indicate, such as for [`mmio::DeviceRegisters`].
154///
155/// [`mmio::DeviceRegisters`]: crate::mmio::DeviceRegisters
156pub struct OveralignedVolatilePtr<'a, T, F, A>
157where
158    T: ?Sized,
159    F: ?Sized,
160{
161    ptr: VolatilePtr<'a, F, A>,
162    ty: PhantomData<VolatilePtr<'a, T, A>>,
163}
164
165impl<'a, T, F, A> Copy for OveralignedVolatilePtr<'a, T, F, A>
166where
167    T: ?Sized,
168    F: ?Sized,
169{
170}
171
172impl<'a, T, F, A> Clone for OveralignedVolatilePtr<'a, T, F, A>
173where
174    T: ?Sized,
175    F: ?Sized,
176{
177    fn clone(&self) -> Self {
178        *self
179    }
180}
181
182impl<'a, T, F, A> OveralignedVolatilePtr<'a, T, F, A>
183where
184    T: OveralignedField<F>,
185    F: Copy,
186{
187    /// Creates a new overaligned volatile pointer.
188    pub fn new(ptr: VolatilePtr<'a, F, A>) -> Self {
189        Self {
190            ptr,
191            ty: PhantomData,
192        }
193    }
194
195    /// Performs a volatile read of the contained value.
196    ///
197    /// See [`VolatilePtr::read`].
198    pub fn read(self) -> T
199    where
200        A: Readable,
201    {
202        T::from_field(self.ptr.read())
203    }
204
205    /// Performs a volatile write, setting the contained value to the given `value`.
206    ///
207    /// See [`VolatilePtr::write`].
208    pub fn write(self, value: T)
209    where
210        A: Writable,
211    {
212        self.ptr.write(value.into_field())
213    }
214
215    /// Updates the contained value using the given closure and volatile instructions.
216    ///
217    /// See [`VolatilePtr::update`].
218    pub fn update(self, f: impl FnOnce(T) -> T)
219    where
220        A: Readable + Writable,
221    {
222        let new = f(self.read());
223        self.write(new);
224    }
225}
226
227/// A trait for fields that can be accessed via [`OveralignedVolatilePtr`].
228pub trait OveralignedField<F>: private::Sealed<F> {
229    /// Converts to this type from the overaligned field.
230    fn from_field(field: F) -> Self;
231
232    /// Converts this type into the overaligned field.
233    fn into_field(self) -> F;
234}
235
236impl OveralignedField<le32> for le16 {
237    fn from_field(field: le32) -> Self {
238        field.try_into().unwrap()
239    }
240
241    fn into_field(self) -> le32 {
242        self.into()
243    }
244}
245
246impl OveralignedField<le32> for bool {
247    fn from_field(field: le32) -> Self {
248        field.to_ne() == 1
249    }
250
251    fn into_field(self) -> le32 {
252        le32::from_ne(self as u32)
253    }
254}
255
256impl OveralignedField<le32> for u8 {
257    fn from_field(field: le32) -> Self {
258        field.to_ne().try_into().unwrap()
259    }
260
261    fn into_field(self) -> le32 {
262        le32::from_ne(self.into())
263    }
264}
265
266impl OveralignedField<le32> for Id {
267    fn from_field(field: le32) -> Self {
268        Self::from(u8::from_field(field))
269    }
270
271    fn into_field(self) -> le32 {
272        u8::from(self).into_field()
273    }
274}
275
276impl OveralignedField<le32> for DeviceStatus {
277    fn from_field(field: le32) -> Self {
278        Self::from_bits_retain(u8::from_field(field))
279    }
280
281    fn into_field(self) -> le32 {
282        self.bits().into_field()
283    }
284}
285
286#[cfg(feature = "mmio")]
287impl OveralignedField<le32> for crate::mmio::InterruptStatus {
288    fn from_field(field: le32) -> Self {
289        Self::from_bits_retain(u8::from_field(field))
290    }
291
292    fn into_field(self) -> le32 {
293        self.bits().into_field()
294    }
295}
296
297mod private {
298    use crate::{le16, le32, DeviceStatus, Id};
299
300    pub trait Sealed<T> {}
301
302    impl Sealed<le32> for bool {}
303    impl Sealed<le32> for u8 {}
304    impl Sealed<le32> for le16 {}
305    impl Sealed<le32> for Id {}
306    impl Sealed<le32> for DeviceStatus {}
307    #[cfg(feature = "mmio")]
308    impl Sealed<le32> for crate::mmio::InterruptStatus {}
309}