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 fn checked_addr(&self, offset: usize, width: usize) -> usize {
32 let base = self.base();
33 assert!(base != 0);
34 let end = offset.checked_add(width).expect("mmio offset overflow");
35 assert!(end <= self.size);
36 base.checked_add(offset).expect("mmio address overflow")
37 }
38
39 pub fn read8(&self, offset: usize) -> u8 {
41 let addr = self.checked_addr(offset, core::mem::size_of::<u8>());
42 unsafe { core::ptr::read_volatile(addr as *const u8) }
44 }
45
46 pub fn read16(&self, offset: usize) -> u16 {
48 let addr = self.checked_addr(offset, core::mem::size_of::<u16>());
49 unsafe { core::ptr::read_volatile(addr as *const u16) }
51 }
52
53 pub fn read32(&self, offset: usize) -> u32 {
55 let addr = self.checked_addr(offset, core::mem::size_of::<u32>());
56 unsafe { core::ptr::read_volatile(addr as *const u32) }
58 }
59
60 pub fn read64(&self, offset: usize) -> u64 {
62 let addr = self.checked_addr(offset, core::mem::size_of::<u64>());
63 unsafe { core::ptr::read_volatile(addr as *const u64) }
65 }
66
67 pub fn write8(&self, offset: usize, val: u8) {
69 let addr = self.checked_addr(offset, core::mem::size_of::<u8>());
70 unsafe { core::ptr::write_volatile(addr as *mut u8, val) }
72 }
73
74 pub fn write16(&self, offset: usize, val: u16) {
76 let addr = self.checked_addr(offset, core::mem::size_of::<u16>());
77 unsafe { core::ptr::write_volatile(addr as *mut u16, val) }
79 }
80
81 pub fn write32(&self, offset: usize, val: u32) {
83 let addr = self.checked_addr(offset, core::mem::size_of::<u32>());
84 unsafe { core::ptr::write_volatile(addr as *mut u32, val) }
86 }
87
88 pub fn write64(&self, offset: usize, val: u64) {
90 let addr = self.checked_addr(offset, core::mem::size_of::<u64>());
91 unsafe { core::ptr::write_volatile(addr as *mut u64, val) }
93 }
94
95 pub fn set_bits32(&self, offset: usize, bits: u32) {
97 let val = self.read32(offset);
98 self.write32(offset, val | bits);
99 }
100
101 pub fn clear_bits32(&self, offset: usize, bits: u32) {
103 let val = self.read32(offset);
104 self.write32(offset, val & !bits);
105 }
106
107 pub fn modify32(&self, offset: usize, clear: u32, set: u32) {
109 let val = self.read32(offset);
110 self.write32(offset, (val & !clear) | set);
111 }
112
113 pub fn read_field32(&self, offset: usize, mask: u32, shift: u32) -> u32 {
115 (self.read32(offset) & mask) >> shift
116 }
117
118 pub fn write_field32(&self, offset: usize, mask: u32, shift: u32, value: u32) {
120 self.modify32(offset, mask, (value << shift) & mask);
121 }
122}
123
124unsafe impl Send for MmioRegion {}
128unsafe impl Sync for MmioRegion {}
129
130pub fn memory_barrier() {
132 core::sync::atomic::fence(Ordering::SeqCst);
133}