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