Files
k-os/crates/apps/spawntest/src/main.rs

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);
}