Skip to main content

strat9_bus_drivers/
probe.rs

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