#![no_std] #![forbid(unsafe_code)] extern crate alloc; mod devices; mod factory; mod launch; mod load; mod manifest; mod output; mod selftest; mod session; mod spawn; mod supervise; 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: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x0180_0000); /// Boot loads storage before init and leaves its endpoint here. pub(crate) const STORAGE_EP: CapSlot = CapSlot::const_new(2); pub fn run() -> ! { libkos::start::set_console(devices::console()); let printer = output::start(); crate::outln!("init: started (pid={:#x})", syscall::get_process_id().raw()); if !printer { crate::outln!("init: no printer thread; output waits on the log server"); } // 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(); crate::outln!( "init: disk: {}", if disk { "handed to its driver" } else { "none" } ); let Ok(mut storage) = Storage::attach(STORAGE_EP, STORAGE_BUF_VA) else { crate::outln!("init: cannot reach storage, nothing to load"); idle(); }; // Storage has nothing to print with yet; init speaks for it. crate::outln!("init: storage: up"); let Some(scratch) = load::scratch() else { crate::outln!("init: no memory to load programs into"); idle(); }; let mut launcher = match launch::Launcher::new(&mut storage, scratch, found) { Ok(l) => l, Err(why) => { crate::outln!("init: {}", why); idle(); } }; launch_all(&mut launcher, manifest::SERVERS); give_storage_the_log(); if !launcher.watch_storage() { crate::outln!("init: cannot watch storage"); } // 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(); launcher.desktop = if storage .open(b"bin/smptest") .is_ok_and(|h| storage.close(h).is_ok()) { crate::outln!("init: running the SMP self-test"); selftest::run(storage, scratch); manifest::TESTS } else { manifest::DESKTOP }; // Nothing that touches a user's files starts before someone is in. if let Err(why) = session::sign_in(&mut launcher) { crate::outln!("init: STOP ({})", why); idle(); } crate::outln!("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: &'static [manifest::Program]) { for p in programs { crate::out!("init: loading {}... ", p.name); match launcher.run(p, false) { Ok(note) => crate::outln!("ok{}", note), Err(why) => crate::outln!("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.into()), ); 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(), } } }