136 lines
4.1 KiB
Rust
136 lines
4.1 KiB
Rust
#![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(),
|
|
}
|
|
}
|
|
}
|