#![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(), } } }