1use crate::addressing::{Kva, Pa};
18
19#[repr(transparent)]
21#[derive(Clone, Copy, Debug)]
22pub struct MmioAccessor<T, const R: bool, const W: bool>(pub *mut T);
23
24unsafe impl<T, const R: bool, const W: bool> Send for MmioAccessor<T, R, W> {}
25
26impl<T, const W: bool> MmioAccessor<T, true, W> {
27 #[inline(always)]
32 pub fn read(&self) -> T {
33 unsafe { core::ptr::read_volatile(self.0) }
34 }
35}
36
37impl<T, const R: bool> MmioAccessor<T, R, true> {
38 #[inline(always)]
43 pub fn write(&self, v: T) {
44 unsafe { core::ptr::write_volatile::<T>(self.0, v) }
45 }
46}
47
48#[derive(Clone, Copy, Debug)]
50pub struct MmioArrayAccessor<T, const R: bool, const W: bool, const SZ: usize>(
51 pub *mut T,
52 pub usize,
53);
54
55impl<T, const W: bool, const SZ: usize> MmioArrayAccessor<T, true, W, SZ> {
56 #[inline(always)]
61 pub fn read_at(&self, idx: usize) -> T {
62 unsafe {
63 core::assert!(idx < SZ);
64 core::ptr::read_volatile((self.0 as usize + idx * self.1) as *mut T)
65 }
66 }
67}
68
69impl<T, const R: bool, const SZ: usize> MmioArrayAccessor<T, R, true, SZ> {
70 #[inline(always)]
75 pub fn write_at(&self, idx: usize, v: T) {
76 core::assert!(idx < SZ);
77 unsafe { core::ptr::write_volatile::<T>((self.0 as usize + idx * self.1) as *mut T, v) }
78 }
79}
80
81#[repr(transparent)]
83#[derive(Debug)]
84pub struct MmioArea(pub core::ops::Range<Pa>);
85
86impl MmioArea {
87 #[inline(always)]
92 pub const unsafe fn new(n: core::ops::Range<Pa>) -> Self {
93 Self(n)
94 }
95
96 #[inline(always)]
98 pub const fn size(&self) -> usize {
99 self.0.end.into_usize() - self.0.start.into_usize()
100 }
101
102 #[inline(always)]
104 pub fn activate(self) -> ActiveMmioArea {
105 let core::ops::Range { start, end } = self.0;
106
107 ActiveMmioArea(start.into_kva()..end.into_kva())
108 }
109
110 pub unsafe fn clone(&self) -> Self {
115 Self(self.0.clone())
116 }
117
118 pub fn split_at(self, mid: usize) -> (Self, Self) {
128 assert!(mid <= self.size());
129 let core::ops::Range { start, end } = self.0;
130 let mid = start + mid;
131 (Self(start..mid), Self(mid..end))
132 }
133}
134
135#[repr(transparent)]
137#[derive(Debug)]
138pub struct ActiveMmioArea(core::ops::Range<Kva>);
139
140impl ActiveMmioArea {
141 #[inline]
143 pub fn start_end(&self) -> (usize, usize) {
144 (self.0.start.into_usize(), self.0.end.into_usize())
145 }
146
147 pub fn write_at<T: Copy>(&self, of: usize, t: T) {
149 unsafe {
150 assert!(
151 self.0.start.into_usize() + of * core::mem::size_of::<T>()
152 < self.0.end.into_usize()
153 );
154 core::ptr::write_volatile(
155 ((self.0.start.into_usize() + of * core::mem::size_of::<T>()) as *mut T)
156 .as_mut()
157 .unwrap(),
158 t,
159 );
160 }
161 }
162
163 pub fn read_at<T: Copy>(&self, of: usize) -> T {
165 unsafe {
166 assert!(
167 self.0.start.into_usize() + of * core::mem::size_of::<T>()
168 < self.0.end.into_usize()
169 );
170 core::ptr::read_volatile(
171 ((self.0.start.into_usize() + of * core::mem::size_of::<T>()) as *mut T)
172 .as_ref()
173 .unwrap(),
174 )
175 }
176 }
177}
178
179#[doc(hidden)]
180#[macro_export(local_inner_macros)]
181macro_rules! __mmio_mk_register {
182 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021 => R, $T:ty; $($t:tt)*) => {
183 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, $off, true, false);
184 __mmio_mk_register!($e, $($t)*);
185 };
186 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021 => W, $T:ty; $($t:tt)*) => {
187 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, $off, false, true);
188 __mmio_mk_register!($e, $($t)*);
189 };
190 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021 => RW, $T:ty; $($t:tt)*) => {
191 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, $off, true, true);
192 __mmio_mk_register!($e, $($t)*);
193 };
194
195 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021 => R, $T:ty, $sz:expr_2021; $($t:tt)*) => {
197 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, core::mem::size_of::<$T>(), $off, $sz, true, false);
198 __mmio_mk_register!($e, $($t)*);
199 };
200 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021 => W, $T:ty, $sz:expr_2021; $($t:tt)*) => {
201 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, core::mem::size_of::<$T>(), $off, $sz, false, true);
202 __mmio_mk_register!($e, $($t)*);
203 };
204 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021 => RW, $T:ty, $sz:expr_2021; $($t:tt)*) => {
205 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, core::mem::size_of::<$T>(), $off, $sz, true, true);
206 __mmio_mk_register!($e, $($t)*);
207 };
208
209 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021, $S:expr_2021 => R, $T:ty, $sz:expr_2021; $($t:tt)*) => {
211 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, $S, $off, $sz, true, false);
212 __mmio_mk_register!($e, $($t)*);
213 };
214 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021, $S:expr_2021 => W, $T:ty, $sz:expr_2021; $($t:tt)*) => {
215 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, $S, $off, $sz, false, true);
216 __mmio_mk_register!($e, $($t)*);
217 };
218 ($e:ident, $(#[$attr:meta])* $N:ident @ $off:expr_2021, $S:expr_2021 => RW, $T:ty, $sz:expr_2021; $($t:tt)*) => {
219 __mmio_mk_register!(@MAKE, $e, $(#[$attr])*, $N, $T, $S, $off, $sz, true, true);
220 __mmio_mk_register!($e, $($t)*);
221 };
222 (@MAKE, $e:ident, $(#[$attr:meta])*, $N:ident, $T: ty, $off:expr_2021, $r:expr_2021, $w:expr_2021) => {
223 impl $e {
224 $(#[$attr])*
225 #[inline(always)]
226 #[allow(non_snake_case)]
227 #[allow(dead_code)]
228 pub fn $N(&self) -> $crate::dev::mmio::MmioAccessor<$T, $r, $w> {
229 let core::ops::Range { start, end } = self.0;
230 core::assert!(
231 (start + $off) + core::mem::size_of::<$T>() <= end,
232 "{:x} {:x} {:x} {:x} {:?}",
233 start,
234 start + $off,
235 (start + $off) + core::mem::size_of::<$T>(),
236 end,
237 (start + $off) + core::mem::size_of::<$T>() <= end,
238 );
239 $crate::dev::mmio::MmioAccessor((start + $off) as *mut $T)
240 }
241 }
242 };
243 (@MAKE, $e:ident, $(#[$attr:meta])*, $N:ident, $T:ty, $S:expr_2021, $off:expr_2021, $sz:expr_2021, $r:expr_2021, $w:expr_2021) => {
244 impl $e {
245 $(#[$attr])*
246 #[inline(always)]
247 #[allow(non_snake_case)]
248 pub fn $N(&self) -> $crate::dev::mmio::MmioArrayAccessor<$T, $r, $w, $sz> {
249 let core::ops::Range { start, end } = self.0;
250 core::assert!(start + $off + $S * $sz - $sz < end);
251
252 $crate::dev::mmio::MmioArrayAccessor((start + $off) as *mut $T, $S)
253 }
254 }
255 };
256 ($e:expr_2021,) => ();
257}
258
259#[doc(hidden)]
260#[macro_export(local_inner_macros)]
261macro_rules! __mmio_mk_method {
262 ($N:ident) => {
263 impl $N {
264 pub fn new_from_mmio_area(area: $crate::dev::mmio::MmioArea) -> Self {
266 let core::ops::Range { start, end } = area.0;
267 Self(start.into_kva().into_usize()..end.into_kva().into_usize())
268 }
269
270 #[inline]
272 #[allow(dead_code)]
273 pub fn kva(&self) -> $crate::addressing::Kva {
274 $crate::addressing::Kva::new(self.0.start).unwrap()
275 }
276 }
277 };
278}
279
280#[macro_export]
282macro_rules! mmio {
283 ($(#[$attr:meta])* $N:ident: $($t:tt)*) => {
284 $(#[$attr])*
285 struct $N(core::ops::Range<usize>);
286
287 $crate::__mmio_mk_method!($N);
288 $crate::__mmio_mk_register!($N, $($t)*);
289 };
290
291 ($(#[$attr:meta])* pub $N:ident: $($t:tt)*) => {
292 $(#[$attr])*
293 pub struct $N(core::ops::Range<usize>);
294
295 $crate::__mmio_mk_method!($N);
296 $crate::__mmio_mk_register!($N, $($t)*);
297 };
298
299 ($(#[$attr:meta])* pub ($($vis:tt)+) $N:ident: $($t:tt)*) => {
300 $(#[$attr])*
301 #[allow(non_snake_case, dead_code)]
302 pub ($($vis:tt)+) struct $N(core::ops::Range<usize>);
303
304 $crate::__mmio_mk_method!($N);
305 $crate::__mmio_mk_register!($N, $($t)*);
306 };
307}