strat9_bus_drivers/
mmio.rs1use core::sync::atomic::Ordering;
2
3pub struct MmioRegion {
4 base: usize,
5 size: usize,
6}
7
8impl MmioRegion {
9 pub const fn new() -> Self {
11 Self { base: 0, size: 0 }
12 }
13
14 pub fn init(&mut self, base: usize, size: usize) {
16 self.base = base;
17 self.size = size;
18 }
19
20 pub fn base(&self) -> usize {
22 self.base
23 }
24
25 pub fn is_valid(&self) -> bool {
27 self.base != 0
28 }
29
30 pub fn contains(&self, offset: usize, width: usize) -> bool {
38 if width == 0 {
39 return false;
40 }
41 match offset.checked_add(width) {
42 Some(end) => self.base != 0 && end <= self.size && offset % width == 0,
43 None => false,
44 }
45 }
46 pub fn check_user_offset(&self, offset: usize) -> Result<(), crate::BusError> {
50 if self.contains(offset, core::mem::size_of::<u32>()) {
51 Ok(())
52 } else {
53 Err(crate::BusError::InvalidAddress)
54 }
55 }
56
57 fn checked_addr(&self, offset: usize, width: usize) -> usize {
64 let base = self.base();
65 assert!(base != 0, "mmio access on uninitialized MmioRegion");
66 let end = offset.checked_add(width).expect("mmio offset overflow");
67 assert!(
68 end <= self.size,
69 "mmio access out of bounds (offset={:#x}, width={}, size={:#x})",
70 offset,
71 width,
72 self.size
73 );
74 assert!(
75 offset % width == 0,
76 "misaligned mmio access (offset={:#x}, width={})",
77 offset,
78 width
79 );
80 base.checked_add(offset).expect("mmio address overflow")
81 }
82
83 pub fn read8(&self, offset: usize) -> u8 {
85 let addr = self.checked_addr(offset, core::mem::size_of::<u8>());
86 unsafe { core::ptr::read_volatile(addr as *const u8) }
88 }
89
90 pub fn read16(&self, offset: usize) -> u16 {
92 let addr = self.checked_addr(offset, core::mem::size_of::<u16>());
93 unsafe { core::ptr::read_volatile(addr as *const u16) }
95 }
96
97 pub fn read32(&self, offset: usize) -> u32 {
99 let addr = self.checked_addr(offset, core::mem::size_of::<u32>());
100 unsafe { core::ptr::read_volatile(addr as *const u32) }
102 }
103
104 pub fn read64(&self, offset: usize) -> u64 {
106 let addr = self.checked_addr(offset, core::mem::size_of::<u64>());
107 unsafe { core::ptr::read_volatile(addr as *const u64) }
109 }
110
111 pub fn write8(&self, offset: usize, val: u8) {
113 let addr = self.checked_addr(offset, core::mem::size_of::<u8>());
114 unsafe { core::ptr::write_volatile(addr as *mut u8, val) }
116 }
117
118 pub fn write16(&self, offset: usize, val: u16) {
120 let addr = self.checked_addr(offset, core::mem::size_of::<u16>());
121 unsafe { core::ptr::write_volatile(addr as *mut u16, val) }
123 }
124
125 pub fn write32(&self, offset: usize, val: u32) {
127 let addr = self.checked_addr(offset, core::mem::size_of::<u32>());
128 unsafe { core::ptr::write_volatile(addr as *mut u32, val) }
130 }
131
132 pub fn write64(&self, offset: usize, val: u64) {
134 let addr = self.checked_addr(offset, core::mem::size_of::<u64>());
135 unsafe { core::ptr::write_volatile(addr as *mut u64, val) }
137 }
138
139 pub fn set_bits32(&self, offset: usize, bits: u32) {
141 let val = self.read32(offset);
142 self.write32(offset, val | bits);
143 }
144
145 pub fn clear_bits32(&self, offset: usize, bits: u32) {
147 let val = self.read32(offset);
148 self.write32(offset, val & !bits);
149 }
150
151 pub fn modify32(&self, offset: usize, clear: u32, set: u32) {
153 let val = self.read32(offset);
154 self.write32(offset, (val & !clear) | set);
155 }
156
157 pub fn read_field32(&self, offset: usize, mask: u32, shift: u32) -> u32 {
159 (self.read32(offset) & mask) >> shift
160 }
161
162 pub fn write_field32(&self, offset: usize, mask: u32, shift: u32, value: u32) {
169 let width_mask = mask >> shift;
170 let field = ((value & width_mask) << shift) & mask;
171 self.modify32(offset, mask, field);
172 }
173}
174
175unsafe impl Send for MmioRegion {}
179unsafe impl Sync for MmioRegion {}
180
181pub fn memory_barrier() {
183 core::sync::atomic::fence(Ordering::SeqCst);
184}