feat(init): spawn service over IPC with per-client allowance refunded on child death; up to 4 death watchers; spawntest on test image

This commit is contained in:
2026-10-27 16:21:08 +01:00
parent 817a38993b
commit 8587661684
23 changed files with 564 additions and 28 deletions

View File

@@ -5,12 +5,14 @@ use libkos::device::Device as BoardDevice;
use libkos::fs::Storage;
use libkos::syscall;
use types::address::StackPointer;
use types::badge::Badge;
use types::bounded::CapSlot;
use types::permission::{Permission, PermissionSet};
use crate::devices::Devices;
use crate::load::{self, LoadedProcess};
use crate::manifest::{Device, Program};
use crate::spawn::Spawner;
const USER_STACK_TOP: StackPointer = StackPointer::from_raw(0x10000);
const MAX_SERVED: usize = 8;
@@ -25,11 +27,22 @@ pub(crate) struct Launcher<'a> {
devices: Devices,
/// The endpoint of every server started so far, by name.
served: [Option<(&'static str, CapSlot)>; MAX_SERVED],
/// Init's own endpoint, for the spawn service.
pub(crate) spawn_ep: CapSlot,
/// Bound to init's thread: spawned children's deaths, a bit each.
pub(crate) deaths: CapSlot,
pub(crate) spawner: Spawner,
}
impl<'a> Launcher<'a> {
pub(crate) fn new(storage: &'a mut Storage, scratch: &'a mut [u8], devices: Devices) -> Self {
Self { storage, scratch, devices, served: [None; MAX_SERVED] }
pub(crate) fn new(
storage: &'a mut Storage,
scratch: &'a mut [u8],
devices: Devices,
) -> Result<Self, &'static str> {
let spawn_ep = syscall::create_endpoint().ok_or("no spawn endpoint")?;
let deaths = syscall::create_notification().map_err(|_| "no death notification")?;
Ok(Self { storage, scratch, devices, served: [None; MAX_SERVED], spawn_ep, deaths, spawner: Spawner::new() })
}
pub(crate) fn storage(&mut self) -> (&mut Storage, &mut [u8]) {
@@ -61,6 +74,13 @@ impl<'a> Launcher<'a> {
let ep = self.endpoint(name).ok_or("needs a server that is not running")?;
syscall::delegate(ep, child, perms(&[Permission::Execute])).ok_or("cannot give an endpoint")?;
}
if let Some(allowance) = p.spawns {
self.give_spawn(child, allowance)?;
}
if p.system_control {
let control = crate::devices::system_control().ok_or("no SystemControl to give")?;
syscall::delegate(control, child, perms(&[Permission::Execute])).ok_or("cannot give SystemControl")?;
}
let console = libkos::start::console()
.filter(|_| p.console)
.and_then(|c| syscall::delegate(c, child, perms(&[Permission::Write])));
@@ -82,6 +102,17 @@ impl<'a> Launcher<'a> {
Ok(note)
}
/// A badged copy of init's endpoint: the badge names the client and so
/// its allowance.
fn give_spawn(&mut self, child: CapSlot, allowance: types::budget::Limits) -> Result<(), &'static str> {
let badge: Badge = self.spawner.add_client(allowance).ok_or("too many spawn clients")?;
let minted = perms(&[Permission::Execute, Permission::Delegate]);
let copy = syscall::mint(self.spawn_ep, badge, minted).map_err(|_| "cannot mint")?;
let given = syscall::delegate(copy, child, perms(&[Permission::Execute]));
syscall::drop_cap(copy);
given.map(|_| ()).ok_or("cannot give the spawn endpoint")
}
/// The driver waits for its device before serving, and runs without
/// one (headless) if the board has none.
fn give(&self, device: Device, ep: CapSlot) -> &'static str {