//! Spinner half of init's SMP self-test: one thread per hart, each //! incrementing its own counter in the page given in slot 0. #![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; /// Counter page layout (words): 0 next free counter index, 1..=THREADS 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, 0); } 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 so a spinner sharing init's hart cannot starve it. for _ in 0..1024 { word(mine).fetch_add(1, Ordering::Relaxed); } syscall::yield_now(); } }