1 macro_rules! volatile_read {
2     ($data: expr) => {
3         unsafe { core::ptr::read_volatile(core::ptr::addr_of!($data)) }
4     };
5 }
6 
7 macro_rules! volatile_write {
8     ($data: expr, $value: expr) => {
9         unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($data), $value) }
10     };
11 }
12 
13 /// @brief: 用于volatile设置某些bits
14 /// @param val: 设置这些位
15 /// @param flag: true表示设置这些位为1; false表示设置这些位为0;
16 macro_rules! volatile_set_bit {
17     ($data: expr, $val: expr, $flag: expr) => {
18         volatile_write!(
19             $data,
20             match $flag {
21                 true => core::ptr::read_volatile(core::ptr::addr_of!($data)) | $val,
22                 false => core::ptr::read_volatile(core::ptr::addr_of!($data)) & (!$val),
23             }
24         )
25     };
26 }
27 
28 /// @param data: volatile变量
29 /// @param bits: 置1的位才有效,表示写这些位
30 /// @param val: 要写的值
31 /// 比如: 写 x 的 2至8bit, 为 10, 可以这么写 volatile_write_bit(x, (1<<8)-(1<<2), 10<<2);
32 macro_rules! volatile_write_bit {
33     ($data: expr, $bits: expr, $val: expr) => {
34         volatile_set_bit!($data, $bits, false);
35         volatile_set_bit!($data, ($val) & ($bits), true);
36     };
37 }
38 
39 /// 以下代码来自于virtio-drivers 0.2.0
40 /// 在对已经MMIO映射对虚拟地址的寄存器的操作中,我们经常遇到有的寄存器是只读或可读写的
41 /// 那么我们就可以使用结构体ReadOnly WriteOnly Volatile对其进行区分
42 /// 例:
43 /// #[repr(C)]
44 /// struct CommonCfg {
45 ///     device_feature_select: Volatile<u32>,
46 ///     device_feature: ReadOnly<u32>,
47 ///     driver_feature_select: Volatile<u32>,
48 ///     driver_feature: Volatile<u32>,
49 ///     msix_config: Volatile<u16>,
50 ///     num_queues: ReadOnly<u16>,
51 ///     device_status: Volatile<u8>,
52 ///     config_generation: ReadOnly<u8>,
53 ///     queue_select: Volatile<u16>,
54 ///     queue_size: Volatile<u16>,
55 ///     queue_msix_vector: Volatile<u16>,
56 ///     queue_enable: Volatile<u16>,
57 ///     queue_notify_off: Volatile<u16>,
58 ///     queue_desc: Volatile<u64>,
59 ///     queue_driver: Volatile<u64>,
60 ///     queue_device: Volatile<u64>,
61 /// }
62 ///
63 /// 对CommonCfg里面的某个寄存器进行读写:
64 /// volwrite!(self.common_cfg, queue_enable, 0);
65 ///
66 /// 这样做不仅使代码的可读性提高了,也避免了对只读寄存器进行写入的误操作
67 
68 /// 只读寄存器
69 #[derive(Default)]
70 #[repr(transparent)]
71 pub struct ReadOnly<T: Copy>(T);
72 
73 #[allow(dead_code)]
74 impl<T: Copy> ReadOnly<T> {
75     /// Construct a new instance for testing.
new(value: T) -> Self76     pub fn new(value: T) -> Self {
77         Self(value)
78     }
79 }
80 
81 /// 只写寄存器
82 #[derive(Default)]
83 #[repr(transparent)]
84 pub struct WriteOnly<T: Copy>(T);
85 
86 /// 写读寄存器
87 #[derive(Default)]
88 #[repr(transparent)]
89 pub struct Volatile<T: Copy>(T);
90 
91 #[allow(dead_code)]
92 impl<T: Copy> Volatile<T> {
93     /// Construct a new instance for testing.
new(value: T) -> Self94     pub fn new(value: T) -> Self {
95         Self(value)
96     }
97 }
98 
99 /// A trait implemented by MMIO registers which may be read from.
100 pub trait VolatileReadable<T> {
101     /// Performs a volatile read from the MMIO register.
vread(self) -> T102     unsafe fn vread(self) -> T;
103 }
104 
105 impl<T: Copy> VolatileReadable<T> for *const ReadOnly<T> {
vread(self) -> T106     unsafe fn vread(self) -> T {
107         self.read_volatile().0
108     }
109 }
110 
111 impl<T: Copy> VolatileReadable<T> for *const Volatile<T> {
vread(self) -> T112     unsafe fn vread(self) -> T {
113         self.read_volatile().0
114     }
115 }
116 
117 /// A trait implemented by MMIO registers which may be written to.
118 pub trait VolatileWritable<T> {
119     /// Performs a volatile write to the MMIO register.
vwrite(self, value: T)120     unsafe fn vwrite(self, value: T);
121 }
122 
123 impl<T: Copy> VolatileWritable<T> for *mut WriteOnly<T> {
vwrite(self, value: T)124     unsafe fn vwrite(self, value: T) {
125         (self as *mut T).write_volatile(value)
126     }
127 }
128 
129 impl<T: Copy> VolatileWritable<T> for *mut Volatile<T> {
vwrite(self, value: T)130     unsafe fn vwrite(self, value: T) {
131         (self as *mut T).write_volatile(value)
132     }
133 }
134 
135 /// Performs a volatile read from the given field of pointer to a struct representing an MMIO region.
136 ///
137 /// # Usage
138 /// ```compile_fail
139 /// # use core::ptr::NonNull;
140 /// # use virtio_drivers::volatile::{ReadOnly, volread};
141 /// struct MmioDevice {
142 ///   field: ReadOnly<u32>,
143 /// }
144 ///
145 /// let device: NonNull<MmioDevice> = NonNull::new(0x1234 as *mut MmioDevice).unwrap();
146 /// let value = unsafe { volread!(device, field) };
147 /// ```
148 macro_rules! volread {
149     ($nonnull:expr, $field:ident) => {
150         VolatileReadable::vread(core::ptr::addr_of!((*$nonnull.as_ptr()).$field))
151     };
152 }
153 
154 /// Performs a volatile write to the given field of pointer to a struct representing an MMIO region.
155 ///
156 /// # Usage
157 /// ```compile_fail
158 /// # use core::ptr::NonNull;
159 /// # use virtio_drivers::volatile::{WriteOnly, volread};
160 /// struct MmioDevice {
161 ///   field: WriteOnly<u32>,
162 /// }
163 ///
164 /// let device: NonNull<MmioDevice> = NonNull::new(0x1234 as *mut MmioDevice).unwrap();
165 /// unsafe { volwrite!(device, field, 42); }
166 /// ```
167 macro_rules! volwrite {
168     ($nonnull:expr, $field:ident, $value:expr) => {
169         VolatileWritable::vwrite(core::ptr::addr_of_mut!((*$nonnull.as_ptr()).$field), $value)
170     };
171 }
172 
173 pub(crate) use volread;
174 pub(crate) use volwrite;
175