test: on-hardware SMP self-test (revoke/kill must stop every hart) + make test-qemu
This commit is contained in:
51
crates/apps/smptest/src/main.rs
Normal file
51
crates/apps/smptest/src/main.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user