89 lines
3.2 KiB
Rust
89 lines
3.2 KiB
Rust
//! The test image's last check, started by init with a spawn allowance:
|
|
//! programs run through init, the allowance holds, and it comes back when
|
|
//! a child dies. Reports the whole self-test and halts.
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
extern crate libkos;
|
|
|
|
use libkos::spawn::{SpawnError, spawn};
|
|
use libkos::syscall;
|
|
use types::bounded::CapSlot;
|
|
use types::budget::Limits;
|
|
|
|
/// Where init put them (see init's manifest: `uses`, the spawn endpoint,
|
|
/// then control).
|
|
const STORAGE: CapSlot = CapSlot::const_new(0);
|
|
const INIT: CapSlot = CapSlot::const_new(1);
|
|
const CONTROL: CapSlot = CapSlot::const_new(2);
|
|
/// Where storage's buffer is mapped.
|
|
const STORAGE_BUF_VA: usize = 0x0180_0000;
|
|
/// Read back from the disk image by scripts/test-qemu.sh.
|
|
const NOTE: &[u8] = b"written by k-os on ext4\n";
|
|
|
|
/// Over half the allowance (128 pages), so a second one fits only after
|
|
/// the first has died and its limits came back.
|
|
const HELLO: Limits = Limits { pages: 80, endpoints: 0, notifications: 0, regions: 0 };
|
|
|
|
/// Spawns hello, runs it, and waits for it to die.
|
|
fn run_hello(died: CapSlot) -> Result<(), &'static str> {
|
|
let child = spawn(INIT, b"hello.elf", HELLO).map_err(|_| "init would not spawn hello")?;
|
|
syscall::watch_death(child.process, died).map_err(|_| "cannot watch hello")?;
|
|
if !child.start() {
|
|
return Err("cannot start hello");
|
|
}
|
|
syscall::wait(died).map_err(|_| "wait failed")?;
|
|
Ok(())
|
|
}
|
|
|
|
/// A file written through storage, which the host then checks with e2fsck.
|
|
fn write_a_file() -> Result<(), &'static str> {
|
|
let mut fs = libkos::fs::Storage::attach(STORAGE, STORAGE_BUF_VA).map_err(|_| "cannot attach to storage")?;
|
|
let h = fs.create(b"selftest.txt").map_err(|_| "cannot create a file")?;
|
|
if fs.write(h, NOTE) != Ok(NOTE.len()) {
|
|
return Err("short write");
|
|
}
|
|
fs.close(h).map_err(|_| "close failed")?;
|
|
let h = fs.open(b"selftest.txt").map_err(|_| "cannot reopen the file")?;
|
|
let mut back = [0u8; 64];
|
|
let n = fs.read(h, &mut back).map_err(|_| "read failed")?;
|
|
fs.close(h).map_err(|_| "close failed")?;
|
|
if &back[..n] != NOTE {
|
|
return Err("read back something else");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn check() -> Result<(), &'static str> {
|
|
write_a_file()?;
|
|
libkos::println!("spawntest: a file written to ext4 reads back: ok");
|
|
|
|
let died = syscall::create_notification().map_err(|_| "no notification")?;
|
|
run_hello(died)?;
|
|
libkos::println!("spawntest: spawned program runs and its death is heard: ok");
|
|
|
|
let greedy = Limits { pages: 200, ..HELLO };
|
|
if spawn(INIT, b"hello.elf", greedy).err() != Some(SpawnError::OverAllowance) {
|
|
return Err("init spawned past the allowance");
|
|
}
|
|
let tiny = Limits { pages: 1, ..HELLO };
|
|
if spawn(INIT, b"nothere.elf", tiny).err() != Some(SpawnError::NotFound) {
|
|
return Err("a missing program was not reported");
|
|
}
|
|
libkos::println!("spawntest: allowance and missing files refused: ok");
|
|
|
|
run_hello(died)?;
|
|
libkos::println!("spawntest: allowance comes back when a child dies: ok");
|
|
Ok(())
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn main() {
|
|
match check() {
|
|
Ok(()) => libkos::println!("SMPTEST PASS"),
|
|
Err(why) => libkos::println!("SMPTEST FAIL: {}", why),
|
|
}
|
|
syscall::halt(CONTROL);
|
|
}
|