feat(init): add init crate with declarative boot manifest, boot sequence, supervisor and shutdown stubs

Also: make types from_raw/raw const fn, add create_process/kill/delegate/revoke to userspace syscall stubs.
This commit is contained in:
2026-10-18 03:21:17 +02:00
parent 962df75f85
commit a83b53d962
10 changed files with 226 additions and 10 deletions

View File

@@ -5,6 +5,7 @@ members = [
"crates/apps/snake",
"crates/domain",
"crates/elf",
"crates/init",
"crates/kernel",
"crates/platform",
"crates/server-framework",

8
crates/init/Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[package]
name = "init"
version = "0.1.0"
edition = "2024"
[dependencies]
types = { workspace = true }
userspace = { workspace = true }

83
crates/init/src/boot.rs Normal file
View File

@@ -0,0 +1,83 @@
use crate::manifest::{BootManifest, EndpointBinding, HardwareCap};
use types::bounded::CapSlot;
use userspace::syscall;
const MAX_ENDPOINTS: usize = 16;
struct EndpointEntry {
name: &'static str,
slot: CapSlot,
}
struct EndpointRegistry {
entries: [Option<EndpointEntry>; MAX_ENDPOINTS],
count: usize,
}
impl EndpointRegistry {
fn new() -> Self {
Self {
entries: [const { None }; MAX_ENDPOINTS],
count: 0,
}
}
fn register(&mut self, name: &'static str, slot: CapSlot) {
if self.count < MAX_ENDPOINTS {
self.entries[self.count] = Some(EndpointEntry { name, slot });
self.count += 1;
}
}
fn find(&self, name: &str) -> Option<CapSlot> {
for entry in &self.entries {
if let Some(e) = entry {
if e.name == name {
return Some(e.slot);
}
}
}
None
}
}
pub fn boot(manifest: &BootManifest, create_cap: CapSlot) {
let mut endpoints = EndpointRegistry::new();
for server in manifest.servers {
let _pid = syscall::create_process(create_cap.value() as usize);
for binding in server.endpoints {
if let EndpointBinding::Own { name } = binding {
// TODO: create endpoint syscall, get CapSlot back
// TODO: delegate endpoint cap to server process
if let Some(slot) = CapSlot::new(0) {
endpoints.register(name, slot);
}
}
}
for hw_cap in server.hardware_caps {
match hw_cap {
HardwareCap::Framebuffer { base: _, pages: _ } => {
// TODO: grant memory cap for framebuffer region
}
HardwareCap::Irq { irq: _ } => {
// TODO: grant interrupt cap
}
HardwareCap::Memory { base: _, pages: _ } => {
// TODO: grant memory cap
}
}
}
}
for app in manifest.apps {
let _pid = syscall::create_process(create_cap.value() as usize);
for (_server_name, endpoint_name) in app.connects_to {
let _ep = endpoints.find(endpoint_name);
// TODO: delegate endpoint cap to app process
}
}
}

6
crates/init/src/lib.rs Normal file
View File

@@ -0,0 +1,6 @@
#![no_std]
pub mod boot;
pub mod manifest;
pub mod shutdown;
pub mod supervisor;

View File

@@ -0,0 +1,92 @@
use types::address::PhysicalAddress;
use types::bounded::{CapSlot, Priority};
use types::id::IrqId;
#[derive(Debug, Clone, Copy)]
pub enum HardwareCap {
Framebuffer { base: PhysicalAddress, pages: usize },
Irq { irq: IrqId },
Memory { base: PhysicalAddress, pages: usize },
}
#[derive(Debug, Clone, Copy)]
pub enum EndpointBinding {
Own { name: &'static str },
ConnectTo { server: &'static str, endpoint: &'static str },
}
#[derive(Debug)]
pub struct ServerEntry {
pub name: &'static str,
pub priority: Priority,
pub memory_pages: usize,
pub hardware_caps: &'static [HardwareCap],
pub endpoints: &'static [EndpointBinding],
pub restartable: bool,
}
#[derive(Debug)]
pub struct AppEntry {
pub name: &'static str,
pub priority: Priority,
pub memory_pages: usize,
pub connects_to: &'static [(&'static str, &'static str)],
}
#[derive(Debug)]
pub struct BootManifest {
pub servers: &'static [ServerEntry],
pub apps: &'static [AppEntry],
}
pub static SNAKE_MANIFEST: BootManifest = BootManifest {
servers: &[
ServerEntry {
name: "log",
priority: Priority::DEFAULT,
memory_pages: 64,
hardware_caps: &[],
endpoints: &[EndpointBinding::Own { name: "log" }],
restartable: true,
},
ServerEntry {
name: "permission",
priority: Priority::DEFAULT,
memory_pages: 32,
hardware_caps: &[],
endpoints: &[EndpointBinding::Own { name: "permission" }],
restartable: true,
},
ServerEntry {
name: "display",
priority: Priority::DEFAULT,
memory_pages: 256,
hardware_caps: &[
HardwareCap::Framebuffer {
base: PhysicalAddress::from_raw(0x10008000),
pages: 75,
},
],
endpoints: &[EndpointBinding::Own { name: "display" }],
restartable: true,
},
ServerEntry {
name: "input",
priority: Priority::DEFAULT,
memory_pages: 32,
hardware_caps: &[
HardwareCap::Irq { irq: IrqId::from_raw(10) },
],
endpoints: &[EndpointBinding::Own { name: "input" }],
restartable: true,
},
],
apps: &[
AppEntry {
name: "snake",
priority: Priority::DEFAULT,
memory_pages: 64,
connects_to: &[("display", "display"), ("input", "input")],
},
],
};

View File

@@ -0,0 +1,3 @@
pub fn shutdown() -> ! {
userspace::syscall::exit();
}

View File

@@ -0,0 +1,7 @@
use crate::manifest::BootManifest;
pub fn supervise(_manifest: &BootManifest) -> ! {
loop {
userspace::syscall::yield_now();
}
}

View File

@@ -2,11 +2,11 @@
pub struct EntryPoint(usize);
impl EntryPoint {
pub fn from_raw(addr: usize) -> Self {
pub const fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
pub const fn raw(&self) -> usize {
self.0
}
}
@@ -15,11 +15,11 @@ impl EntryPoint {
pub struct StackPointer(usize);
impl StackPointer {
pub fn from_raw(addr: usize) -> Self {
pub const fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
pub const fn raw(&self) -> usize {
self.0
}
}
@@ -28,11 +28,11 @@ impl StackPointer {
pub struct VirtualAddress(usize);
impl VirtualAddress {
pub fn from_raw(addr: usize) -> Self {
pub const fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
pub const fn raw(&self) -> usize {
self.0
}
}
@@ -41,11 +41,11 @@ impl VirtualAddress {
pub struct PhysicalAddress(usize);
impl PhysicalAddress {
pub fn from_raw(addr: usize) -> Self {
pub const fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
pub const fn raw(&self) -> usize {
self.0
}

View File

@@ -4,11 +4,11 @@ macro_rules! kernel_id {
pub struct $name($inner);
impl $name {
pub fn from_raw(value: $inner) -> Self {
pub const fn from_raw(value: $inner) -> Self {
Self(value)
}
pub fn raw(&self) -> $inner {
pub const fn raw(&self) -> $inner {
self.0
}
}

View File

@@ -31,6 +31,22 @@ pub fn request_pages(count: usize) -> usize {
arch::syscall1(SYS_REQUEST_PAGES, count)
}
pub fn create_process(create_cap: usize) -> usize {
arch::syscall1(SYS_CREATE_PROCESS, create_cap)
}
pub fn kill(process_cap: usize) -> usize {
arch::syscall1(SYS_KILL, process_cap)
}
pub fn delegate(slot: usize, to: usize, permissions: usize) -> usize {
arch::syscall2(SYS_DELEGATE, slot, to)
}
pub fn revoke(slot: usize) -> usize {
arch::syscall1(SYS_REVOKE, slot)
}
pub fn send(endpoint: usize, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
arch::syscall5(SYS_SEND, endpoint, w0, w1, w2, w3)
}