xref: /DragonOS/kernel/src/libs/volatile.rs (revision 7c28051e8c601312d3d0fd7bcb71bc71450d10c0)
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 #[derive(Default)]
69 #[repr(transparent)]
70 pub struct ReadOnly<T: Copy>(T);
71 
72 #[allow(dead_code)]
73 impl<T: Copy> ReadOnly<T> {
74     /// Construct a new instance for testing.
new(value: T) -> Self75     pub fn new(value: T) -> Self {
76         Self(value)
77     }
78 }
79 
80 /// 只写寄存器
81 #[derive(Default)]
82 #[repr(transparent)]
83 pub struct WriteOnly<T: Copy>(T);
84 
85 /// 写读寄存器
86 #[derive(Default)]
87 #[repr(transparent)]
88 pub struct Volatile<T: Copy>(T);
89 
90 #[allow(dead_code)]
91 impl<T: Copy> Volatile<T> {
92     /// Construct a new instance for testing.
new(value: T) -> Self93     pub fn new(value: T) -> Self {
94         Self(value)
95     }
96 }
97 
98 /// A trait implemented by MMIO registers which may be read from.
99 pub trait VolatileReadable<T> {
100     /// Performs a volatile read from the MMIO register.
vread(self) -> T101     unsafe fn vread(self) -> T;
102 }
103 
104 impl<T: Copy> VolatileReadable<T> for *const ReadOnly<T> {
vread(self) -> T105     unsafe fn vread(self) -> T {
106         self.read_volatile().0
107     }
108 }
109 
110 impl<T: Copy> VolatileReadable<T> for *const Volatile<T> {
vread(self) -> T111     unsafe fn vread(self) -> T {
112         self.read_volatile().0
113     }
114 }
115 
116 /// A trait implemented by MMIO registers which may be written to.
117 pub trait VolatileWritable<T> {
118     /// Performs a volatile write to the MMIO register.
vwrite(self, value: T)119     unsafe fn vwrite(self, value: T);
120 }
121 
122 impl<T: Copy> VolatileWritable<T> for *mut WriteOnly<T> {
vwrite(self, value: T)123     unsafe fn vwrite(self, value: T) {
124         (self as *mut T).write_volatile(value)
125     }
126 }
127 
128 impl<T: Copy> VolatileWritable<T> for *mut Volatile<T> {
vwrite(self, value: T)129     unsafe fn vwrite(self, value: T) {
130         (self as *mut T).write_volatile(value)
131     }
132 }
133 
134 /// Performs a volatile read from the given field of pointer to a struct representing an MMIO region.
135 ///
136 /// # Usage
137 /// ```compile_fail
138 /// # use core::ptr::NonNull;
139 /// # use virtio_drivers::volatile::{ReadOnly, volread};
140 /// struct MmioDevice {
141 ///   field: ReadOnly<u32>,
142 /// }
143 ///
144 /// let device: NonNull<MmioDevice> = NonNull::new(0x1234 as *mut MmioDevice).unwrap();
145 /// let value = unsafe { volread!(device, field) };
146 /// ```
147 macro_rules! volread {
148     ($nonnull:expr, $field:ident) => {
149         crate::libs::volatile::VolatileReadable::vread(core::ptr::addr_of!(
150             (*$nonnull.as_ptr()).$field
151         ))
152     };
153 }
154 
155 /// Performs a volatile write to the given field of pointer to a struct representing an MMIO region.
156 ///
157 /// # Usage
158 /// ```compile_fail
159 /// # use core::ptr::NonNull;
160 /// # use virtio_drivers::volatile::{WriteOnly, volread};
161 /// struct MmioDevice {
162 ///   field: WriteOnly<u32>,
163 /// }
164 ///
165 /// let device: NonNull<MmioDevice> = NonNull::new(0x1234 as *mut MmioDevice).unwrap();
166 /// unsafe { volwrite!(device, field, 42); }
167 /// ```
168 macro_rules! volwrite {
169     ($nonnull:expr, $field:ident, $value:expr) => {
170         crate::libs::volatile::VolatileWritable::vwrite(
171             core::ptr::addr_of_mut!((*$nonnull.as_ptr()).$field),
172             $value,
173         )
174     };
175 }
176 
177 pub(crate) use volread;
178 pub(crate) use volwrite;
179