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:
@@ -5,6 +5,7 @@ members = [
|
|||||||
"crates/apps/snake",
|
"crates/apps/snake",
|
||||||
"crates/domain",
|
"crates/domain",
|
||||||
"crates/elf",
|
"crates/elf",
|
||||||
|
"crates/init",
|
||||||
"crates/kernel",
|
"crates/kernel",
|
||||||
"crates/platform",
|
"crates/platform",
|
||||||
"crates/server-framework",
|
"crates/server-framework",
|
||||||
|
|||||||
8
crates/init/Cargo.toml
Normal file
8
crates/init/Cargo.toml
Normal 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
83
crates/init/src/boot.rs
Normal 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
6
crates/init/src/lib.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
pub mod boot;
|
||||||
|
pub mod manifest;
|
||||||
|
pub mod shutdown;
|
||||||
|
pub mod supervisor;
|
||||||
92
crates/init/src/manifest.rs
Normal file
92
crates/init/src/manifest.rs
Normal 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")],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
3
crates/init/src/shutdown.rs
Normal file
3
crates/init/src/shutdown.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn shutdown() -> ! {
|
||||||
|
userspace::syscall::exit();
|
||||||
|
}
|
||||||
7
crates/init/src/supervisor.rs
Normal file
7
crates/init/src/supervisor.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use crate::manifest::BootManifest;
|
||||||
|
|
||||||
|
pub fn supervise(_manifest: &BootManifest) -> ! {
|
||||||
|
loop {
|
||||||
|
userspace::syscall::yield_now();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
pub struct EntryPoint(usize);
|
pub struct EntryPoint(usize);
|
||||||
|
|
||||||
impl EntryPoint {
|
impl EntryPoint {
|
||||||
pub fn from_raw(addr: usize) -> Self {
|
pub const fn from_raw(addr: usize) -> Self {
|
||||||
Self(addr)
|
Self(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> usize {
|
pub const fn raw(&self) -> usize {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,11 +15,11 @@ impl EntryPoint {
|
|||||||
pub struct StackPointer(usize);
|
pub struct StackPointer(usize);
|
||||||
|
|
||||||
impl StackPointer {
|
impl StackPointer {
|
||||||
pub fn from_raw(addr: usize) -> Self {
|
pub const fn from_raw(addr: usize) -> Self {
|
||||||
Self(addr)
|
Self(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> usize {
|
pub const fn raw(&self) -> usize {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,11 +28,11 @@ impl StackPointer {
|
|||||||
pub struct VirtualAddress(usize);
|
pub struct VirtualAddress(usize);
|
||||||
|
|
||||||
impl VirtualAddress {
|
impl VirtualAddress {
|
||||||
pub fn from_raw(addr: usize) -> Self {
|
pub const fn from_raw(addr: usize) -> Self {
|
||||||
Self(addr)
|
Self(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> usize {
|
pub const fn raw(&self) -> usize {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,11 +41,11 @@ impl VirtualAddress {
|
|||||||
pub struct PhysicalAddress(usize);
|
pub struct PhysicalAddress(usize);
|
||||||
|
|
||||||
impl PhysicalAddress {
|
impl PhysicalAddress {
|
||||||
pub fn from_raw(addr: usize) -> Self {
|
pub const fn from_raw(addr: usize) -> Self {
|
||||||
Self(addr)
|
Self(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> usize {
|
pub const fn raw(&self) -> usize {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ macro_rules! kernel_id {
|
|||||||
pub struct $name($inner);
|
pub struct $name($inner);
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
pub fn from_raw(value: $inner) -> Self {
|
pub const fn from_raw(value: $inner) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> $inner {
|
pub const fn raw(&self) -> $inner {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,22 @@ pub fn request_pages(count: usize) -> usize {
|
|||||||
arch::syscall1(SYS_REQUEST_PAGES, count)
|
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 {
|
pub fn send(endpoint: usize, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
|
||||||
arch::syscall5(SYS_SEND, endpoint, w0, w1, w2, w3)
|
arch::syscall5(SYS_SEND, endpoint, w0, w1, w2, w3)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user