Files
k-os/crates/init/src/lib.rs

106 lines
3.5 KiB
Rust

#![no_std]
extern crate alloc;
mod devices;
mod launch;
mod load;
mod manifest;
mod selftest;
mod spawn;
use libkos::fs::Storage;
use libkos::syscall;
use types::badge::Badge;
use types::bounded::CapSlot;
use types::permission::{Permission, PermissionSet};
/// Where the buffer storage shares with init is mapped.
const STORAGE_BUF_VA: usize = 0x0180_0000;
/// Boot loads storage before init and leaves its endpoint here.
const STORAGE_EP: CapSlot = CapSlot::const_new(2);
pub fn run() -> ! {
libkos::start::set_console(devices::console());
libkos::println!("init: started (pid={:#x})", syscall::get_process_id().raw());
// Storage waits for its disk before serving, so this comes first.
let found = devices::discover();
let disk = libkos::device::give_device(STORAGE_EP, found.disk).is_ok() && found.disk.mmio.is_some();
libkos::println!("init: disk: {}", if disk { "handed to its driver" } else { "none" });
let Ok(mut storage) = Storage::attach(STORAGE_EP, STORAGE_BUF_VA) else {
libkos::println!("init: cannot reach storage, nothing to load");
idle();
};
// Storage has nothing to print with yet; init speaks for it.
libkos::println!("init: storage: up");
let Some(scratch) = load::scratch() else {
libkos::println!("init: no memory to load programs into");
idle();
};
let mut launcher = match launch::Launcher::new(&mut storage, scratch, found) {
Ok(l) => l,
Err(why) => {
libkos::println!("init: {}", why);
idle();
}
};
launch_all(&mut launcher, manifest::SERVERS);
give_storage_the_log();
// The test image carries the SMP self-test; it and the tests run
// instead of the desktop, and the last one halts the machine.
let (storage, scratch) = launcher.storage();
if storage.open(b"smptest.elf").is_ok_and(|h| storage.close(h).is_ok()) {
libkos::println!("init: running the SMP self-test");
selftest::run(storage, scratch);
launch_all(&mut launcher, manifest::TESTS);
} else {
launch_all(&mut launcher, manifest::APPS);
}
libkos::println!("init: all loaded, serving spawns");
let _ = syscall::bind_notification(launcher.deaths);
let ep = launcher.spawn_ep;
server_framework::serve(&mut launcher, ep)
}
fn launch_all(launcher: &mut launch::Launcher, programs: &[manifest::Program]) {
for p in programs {
libkos::print!("init: loading {}... ", p.name);
match launcher.launch(p) {
Ok(note) => libkos::println!("ok{}", note),
Err(why) => libkos::println!("SKIP ({})", why),
}
}
}
/// Storage started before the log server; it gets a call-only copy of
/// the log endpoint now (Delegate only to send it: transfer strips it).
fn give_storage_the_log() {
let Some(log) = libkos::start::log() else {
return;
};
let call_only = PermissionSet::empty().with(Permission::Execute).with(Permission::Delegate);
if let Ok(copy) = syscall::mint(log, Badge::NONE, call_only) {
let _ = syscall::call(STORAGE_EP, [types::storage::op::SET_LOG, 0, 0, 0], Some(copy));
syscall::drop_cap(copy);
}
}
/// Nothing to supervise yet: block on a notification nobody signals
/// rather than spin a core on Yield.
pub(crate) fn idle() -> ! {
let idle = syscall::create_notification();
loop {
match idle {
Ok(n) => {
let _ = syscall::wait(n);
}
Err(_) => syscall::yield_now(),
}
}
}