1use crate::mmio::{MmioRegion, memory_barrier};
2use alloc::vec;
3
4const REGION_SIZE: usize = 4096;
5const REGION_WORDS: usize = REGION_SIZE / core::mem::size_of::<u64>();
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum ProbeMode {
9 Quick,
10 Full,
11}
12
13pub struct ProbeResult {
14 pub passed: u32,
15 pub failed: u32,
16}
17
18impl ProbeResult {
19 fn new() -> Self {
21 Self {
22 passed: 0,
23 failed: 0,
24 }
25 }
26
27 fn check(&mut self, ok: bool) {
29 if ok {
30 self.passed += 1;
31 } else {
32 self.failed += 1;
33 }
34 }
35
36 pub fn all_passed(&self) -> bool {
38 self.failed == 0 && self.passed > 0
39 }
40}
41
42fn zero_buf(buf: &mut [u64]) {
44 buf.fill(0);
45}
46
47pub fn run_mmio_probe() -> ProbeResult {
49 run_mmio_probe_with_mode(ProbeMode::Full)
50}
51
52pub fn run_mmio_probe_with_mode(mode: ProbeMode) -> ProbeResult {
54 let mut r = ProbeResult::new();
55 let mut buf = vec![0u64; REGION_WORDS];
56 let base = buf.as_mut_ptr() as usize;
57
58 match mode {
59 ProbeMode::Quick => {
60 probe_lifecycle(&mut r, base);
61 zero_buf(&mut buf);
62 probe_read_write_32(&mut r, base);
63 zero_buf(&mut buf);
64 probe_boundary_offsets(&mut r, base);
65 zero_buf(&mut buf);
66 probe_memory_barrier(&mut r, base);
67 }
68 ProbeMode::Full => {
69 probe_lifecycle(&mut r, base);
70 zero_buf(&mut buf);
71 probe_read_write_8(&mut r, base);
72 zero_buf(&mut buf);
73 probe_read_write_16(&mut r, base);
74 zero_buf(&mut buf);
75 probe_read_write_32(&mut r, base);
76 zero_buf(&mut buf);
77 probe_read_write_64(&mut r, base);
78 zero_buf(&mut buf);
79 probe_set_bits(&mut r, base);
80 zero_buf(&mut buf);
81 probe_clear_bits(&mut r, base);
82 zero_buf(&mut buf);
83 probe_modify32(&mut r, base);
84 zero_buf(&mut buf);
85 probe_read_field32(&mut r, base);
86 zero_buf(&mut buf);
87 probe_write_field32(&mut r, base);
88 zero_buf(&mut buf);
89 probe_boundary_offsets(&mut r, base);
90 zero_buf(&mut buf);
91 probe_multi_width_overlap(&mut r, base);
92 zero_buf(&mut buf);
93 probe_walking_ones_32(&mut r, base);
94 zero_buf(&mut buf);
95 probe_walking_ones_64(&mut r, base);
96 zero_buf(&mut buf);
97 probe_memory_barrier(&mut r, base);
98 zero_buf(&mut buf);
99 probe_reinit(&mut r, base);
100 }
101 }
102
103 r
104}
105
106fn make_region(base: usize) -> MmioRegion {
108 let mut reg = MmioRegion::new();
109 reg.init(base, REGION_SIZE);
110 reg
111}
112
113fn probe_lifecycle(r: &mut ProbeResult, base: usize) {
115 let uninit = MmioRegion::new();
116 r.check(!uninit.is_valid());
117 r.check(uninit.base() == 0);
118
119 let reg = make_region(base);
120 r.check(reg.is_valid());
121 r.check(reg.base() == base);
122}
123
124fn probe_read_write_8(r: &mut ProbeResult, base: usize) {
126 let reg = make_region(base);
127
128 reg.write8(0, 0xAB);
129 r.check(reg.read8(0) == 0xAB);
130
131 reg.write8(1, 0x00);
132 r.check(reg.read8(1) == 0x00);
133
134 reg.write8(2, 0xFF);
135 r.check(reg.read8(2) == 0xFF);
136
137 reg.write8(0, 0x12);
138 r.check(reg.read8(0) == 0x12);
139 r.check(reg.read8(2) == 0xFF);
140
141 for i in 0..16u8 {
142 reg.write8(i as usize, i.wrapping_mul(17));
143 }
144 for i in 0..16u8 {
145 r.check(reg.read8(i as usize) == i.wrapping_mul(17));
146 }
147}
148
149fn probe_read_write_16(r: &mut ProbeResult, base: usize) {
151 let reg = make_region(base);
152
153 reg.write16(0, 0xBEEF);
154 r.check(reg.read16(0) == 0xBEEF);
155
156 reg.write16(2, 0x0000);
157 r.check(reg.read16(2) == 0x0000);
158
159 reg.write16(4, 0xFFFF);
160 r.check(reg.read16(4) == 0xFFFF);
161
162 r.check(reg.read16(0) == 0xBEEF);
163
164 reg.write16(0, 0x1234);
165 reg.write16(2, 0x5678);
166 let combined = reg.read32(0);
167 let expected = 0x1234u32 | (0x5678u32 << 16);
168 r.check(combined == expected);
169}
170
171fn probe_read_write_32(r: &mut ProbeResult, base: usize) {
173 let reg = make_region(base);
174
175 reg.write32(0, 0xDEADBEEF);
176 r.check(reg.read32(0) == 0xDEADBEEF);
177
178 reg.write32(4, 0x00000000);
179 r.check(reg.read32(4) == 0x00000000);
180
181 reg.write32(8, 0xFFFFFFFF);
182 r.check(reg.read32(8) == 0xFFFFFFFF);
183
184 r.check(reg.read32(0) == 0xDEADBEEF);
185
186 reg.write32(0, 0x01020304);
187 r.check(reg.read8(0) == 0x04);
188 r.check(reg.read8(1) == 0x03);
189 r.check(reg.read8(2) == 0x02);
190 r.check(reg.read8(3) == 0x01);
191
192 for i in 0..32u32 {
193 let off = (i as usize) * 4;
194 if off + 4 > REGION_SIZE {
195 break;
196 }
197 reg.write32(off, i.wrapping_mul(0x11111111));
198 }
199 for i in 0..32u32 {
200 let off = (i as usize) * 4;
201 if off + 4 > REGION_SIZE {
202 break;
203 }
204 r.check(reg.read32(off) == i.wrapping_mul(0x11111111));
205 }
206}
207
208fn probe_read_write_64(r: &mut ProbeResult, base: usize) {
210 let reg = make_region(base);
211
212 reg.write64(0, 0xCAFEBABE_DEADBEEF);
213 r.check(reg.read64(0) == 0xCAFEBABE_DEADBEEF);
214
215 reg.write64(8, 0x0000000000000000);
216 r.check(reg.read64(8) == 0x0000000000000000);
217
218 reg.write64(16, 0xFFFFFFFFFFFFFFFF);
219 r.check(reg.read64(16) == 0xFFFFFFFFFFFFFFFF);
220
221 r.check(reg.read64(0) == 0xCAFEBABE_DEADBEEF);
222
223 r.check(reg.read32(0) == 0xDEADBEEF);
224 r.check(reg.read32(4) == 0xCAFEBABE);
225}
226
227fn probe_set_bits(r: &mut ProbeResult, base: usize) {
229 let reg = make_region(base);
230
231 reg.write32(0, 0x00000000);
232 reg.set_bits32(0, 0x0000000F);
233 r.check(reg.read32(0) == 0x0000000F);
234
235 reg.set_bits32(0, 0x000000F0);
236 r.check(reg.read32(0) == 0x000000FF);
237
238 reg.set_bits32(0, 0x000000FF);
239 r.check(reg.read32(0) == 0x000000FF);
240
241 reg.write32(0, 0x80000000);
242 reg.set_bits32(0, 0x00000001);
243 r.check(reg.read32(0) == 0x80000001);
244}
245
246fn probe_clear_bits(r: &mut ProbeResult, base: usize) {
248 let reg = make_region(base);
249
250 reg.write32(0, 0xFFFFFFFF);
251 reg.clear_bits32(0, 0x0000000F);
252 r.check(reg.read32(0) == 0xFFFFFFF0);
253
254 reg.clear_bits32(0, 0x000000F0);
255 r.check(reg.read32(0) == 0xFFFFFF00);
256
257 reg.clear_bits32(0, 0x00000000);
258 r.check(reg.read32(0) == 0xFFFFFF00);
259
260 reg.write32(0, 0x80000001);
261 reg.clear_bits32(0, 0x80000000);
262 r.check(reg.read32(0) == 0x00000001);
263}
264
265fn probe_modify32(r: &mut ProbeResult, base: usize) {
267 let reg = make_region(base);
268
269 reg.write32(0, 0xAABBCCDD);
270 reg.modify32(0, 0x0000FF00, 0x00001200);
271 r.check(reg.read32(0) == 0xAABB12DD);
272
273 reg.write32(0, 0xFFFFFFFF);
274 reg.modify32(0, 0xFFFFFFFF, 0x12345678);
275 r.check(reg.read32(0) == 0x12345678);
276
277 reg.write32(0, 0x00000000);
278 reg.modify32(0, 0x00000000, 0x00000000);
279 r.check(reg.read32(0) == 0x00000000);
280
281 reg.write32(0, 0x00FF00FF);
282 reg.modify32(0, 0x00FF0000, 0x00AB0000);
283 r.check(reg.read32(0) == 0x00AB00FF);
284}
285
286fn probe_read_field32(r: &mut ProbeResult, base: usize) {
288 let reg = make_region(base);
289
290 reg.write32(0, 0x12345678);
291
292 r.check(reg.read_field32(0, 0x000000FF, 0) == 0x78);
293 r.check(reg.read_field32(0, 0x0000FF00, 8) == 0x56);
294 r.check(reg.read_field32(0, 0x00FF0000, 16) == 0x34);
295 r.check(reg.read_field32(0, 0xFF000000, 24) == 0x12);
296
297 r.check(reg.read_field32(0, 0x0000000F, 0) == 0x08);
298 r.check(reg.read_field32(0, 0x000F0000, 16) == 0x04);
299
300 reg.write32(0, 0x00000000);
301 r.check(reg.read_field32(0, 0xFFFFFFFF, 0) == 0x00000000);
302
303 reg.write32(0, 0xFFFFFFFF);
304 r.check(reg.read_field32(0, 0xFFFFFFFF, 0) == 0xFFFFFFFF);
305}
306
307fn probe_write_field32(r: &mut ProbeResult, base: usize) {
309 let reg = make_region(base);
310
311 reg.write32(0, 0x00000000);
312 reg.write_field32(0, 0x000000FF, 0, 0xAB);
313 r.check(reg.read32(0) == 0x000000AB);
314
315 reg.write32(0, 0xFFFFFFFF);
316 reg.write_field32(0, 0x0000FF00, 8, 0x42);
317 r.check(reg.read32(0) == 0xFFFF42FF);
318
319 reg.write32(0, 0x12345678);
320 reg.write_field32(0, 0xFF000000, 24, 0x99);
321 r.check(reg.read32(0) == 0x99345678);
322
323 reg.write32(0, 0xAAAAAAAA);
324 reg.write_field32(0, 0x000F0000, 16, 0x05);
325 let val = reg.read32(0);
326 r.check((val & 0x000F0000) >> 16 == 0x05);
327 r.check((val & 0xFFF0FFFF) == 0xAAA0AAAA);
328}
329
330fn probe_boundary_offsets(r: &mut ProbeResult, base: usize) {
332 let reg = make_region(base);
333
334 reg.write8(0, 0x01);
335 r.check(reg.read8(0) == 0x01);
336
337 reg.write8(REGION_SIZE - 1, 0xFE);
338 r.check(reg.read8(REGION_SIZE - 1) == 0xFE);
339
340 reg.write16(REGION_SIZE - 2, 0xABCD);
341 r.check(reg.read16(REGION_SIZE - 2) == 0xABCD);
342
343 reg.write32(REGION_SIZE - 4, 0xDEADC0DE);
344 r.check(reg.read32(REGION_SIZE - 4) == 0xDEADC0DE);
345
346 reg.write64(REGION_SIZE - 8, 0x0102030405060708);
347 r.check(reg.read64(REGION_SIZE - 8) == 0x0102030405060708);
348}
349
350fn probe_multi_width_overlap(r: &mut ProbeResult, base: usize) {
352 let reg = make_region(base);
353
354 reg.write64(0, 0);
355 reg.write8(0, 0x11);
356 reg.write8(1, 0x22);
357 reg.write8(2, 0x33);
358 reg.write8(3, 0x44);
359 reg.write8(4, 0x55);
360 reg.write8(5, 0x66);
361 reg.write8(6, 0x77);
362 reg.write8(7, 0x88);
363 r.check(reg.read16(0) == 0x2211);
364 r.check(reg.read16(2) == 0x4433);
365 r.check(reg.read32(0) == 0x44332211);
366 r.check(reg.read32(4) == 0x88776655);
367 r.check(reg.read64(0) == 0x8877665544332211);
368
369 reg.write32(0, 0xAABBCCDD);
370 r.check(reg.read8(0) == 0xDD);
371 r.check(reg.read8(1) == 0xCC);
372 r.check(reg.read8(2) == 0xBB);
373 r.check(reg.read8(3) == 0xAA);
374 r.check(reg.read16(0) == 0xCCDD);
375 r.check(reg.read16(2) == 0xAABB);
376}
377
378fn probe_walking_ones_32(r: &mut ProbeResult, base: usize) {
380 let reg = make_region(base);
381
382 for bit in 0..32u32 {
383 let val = 1u32 << bit;
384 reg.write32(0, val);
385 r.check(reg.read32(0) == val);
386 }
387
388 reg.write32(0, 0);
389 for bit in 0..32u32 {
390 reg.set_bits32(0, 1u32 << bit);
391 }
392 r.check(reg.read32(0) == 0xFFFFFFFF);
393
394 for bit in 0..32u32 {
395 reg.clear_bits32(0, 1u32 << bit);
396 }
397 r.check(reg.read32(0) == 0x00000000);
398}
399
400fn probe_walking_ones_64(r: &mut ProbeResult, base: usize) {
402 let reg = make_region(base);
403
404 for bit in 0..64u32 {
405 let val = 1u64 << bit;
406 reg.write64(0, val);
407 r.check(reg.read64(0) == val);
408 }
409
410 reg.write64(0, 0xAAAAAAAAAAAAAAAA);
411 r.check(reg.read64(0) == 0xAAAAAAAAAAAAAAAA);
412
413 reg.write64(0, 0x5555555555555555);
414 r.check(reg.read64(0) == 0x5555555555555555);
415}
416
417fn probe_memory_barrier(r: &mut ProbeResult, base: usize) {
419 let reg = make_region(base);
420
421 reg.write32(0, 0x11111111);
422 memory_barrier();
423 r.check(reg.read32(0) == 0x11111111);
424
425 reg.write32(0, 0x22222222);
426 memory_barrier();
427 reg.write32(4, 0x33333333);
428 memory_barrier();
429 r.check(reg.read32(0) == 0x22222222);
430 r.check(reg.read32(4) == 0x33333333);
431
432 for i in 0..16u32 {
433 reg.write32((i as usize) * 4, i);
434 memory_barrier();
435 }
436 for i in 0..16u32 {
437 r.check(reg.read32((i as usize) * 4) == i);
438 }
439}
440
441fn probe_reinit(r: &mut ProbeResult, base: usize) {
443 let mut reg = MmioRegion::new();
444 r.check(!reg.is_valid());
445
446 reg.init(base, REGION_SIZE);
447 r.check(reg.is_valid());
448 r.check(reg.base() == base);
449 reg.write32(0, 0xABCD1234);
450 r.check(reg.read32(0) == 0xABCD1234);
451
452 let mut buf2 = vec![0u64; REGION_WORDS];
453 let base2 = buf2.as_mut_ptr() as usize;
454 reg.init(base2, REGION_SIZE);
455 r.check(reg.is_valid());
456 r.check(reg.base() == base2);
457 r.check(reg.base() != base);
458 r.check(reg.read32(0) == 0x00000000);
459
460 reg.write32(0, 0x99887766);
461 r.check(reg.read32(0) == 0x99887766);
462}