test: on-hardware SMP self-test (revoke/kill must stop every hart) + make test-qemu

This commit is contained in:
2026-10-27 12:54:42 +01:00
parent 909b3f0503
commit b814bd9570
10 changed files with 262 additions and 12 deletions

View File

@@ -0,0 +1,51 @@
//! The spinner half of init's SMP self-test (see init's `selftest`):
//! maps the counter page it was given in slot 0 and runs one thread per
//! hart, each incrementing its own counter for ever. Init watches the
//! counters through its own mapping of the same page.
#![no_std]
#![no_main]
extern crate libkos;
use core::sync::atomic::{AtomicUsize, Ordering};
use libkos::syscall;
use types::address::{EntryPoint, StackPointer, VirtualAddress};
use types::bounded::{CapSlot, PageCount};
use types::mapping::PagePerms;
/// Where the counter page is mapped. Layout (words): 0 the next free
/// counter index, 1..=THREADS the counters.
const COUNTERS_VA: usize = 0x0100_0000;
const THREADS: usize = 4;
#[unsafe(no_mangle)]
extern "C" fn main() {
let page = CapSlot::const_new(0);
if syscall::map_region(page, VirtualAddress::from_raw(COUNTERS_VA), PagePerms::ReadWrite).is_err() {
libkos::println!("smptest: cannot map the counter page");
syscall::exit();
}
for _ in 1..THREADS {
let Some(stack) = PageCount::new(1).and_then(syscall::request_pages) else {
break;
};
let top = StackPointer::from_raw(stack.raw() + 4096);
syscall::spawn_thread(EntryPoint::from_raw(spin as *const () as usize), top);
}
spin();
}
extern "C" fn spin() -> ! {
// SAFETY: COUNTERS_VA maps the counter page; every access is atomic.
let word = |i: usize| unsafe { &*((COUNTERS_VA + i * 8) as *const AtomicUsize) };
let mine = 1 + word(0).fetch_add(1, Ordering::Relaxed) % THREADS;
loop {
// Yield now and then: a spinner sharing init's hart would
// otherwise starve it until the next (1 s) timer tick.
for _ in 0..1024 {
word(mine).fetch_add(1, Ordering::Relaxed);
}
syscall::yield_now();
}
}