From 29434805a6b6c4b66e375e40e9e909e4091fe018 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 18 Oct 2026 04:04:52 +0200 Subject: [PATCH] feat(userspace-rt): add runtime crate with entry point, panic handler, and allocator re-export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Snake and hello apps now use extern crate userspace_rt — no more boilerplate assembly or panic handlers in app code. --- Cargo.toml | 2 + crates/apps/hello/Cargo.toml | 9 +--- crates/apps/hello/src/main.rs | 21 ++-------- crates/apps/snake/Cargo.toml | 1 + crates/apps/snake/src/main.rs | 60 +++++++-------------------- crates/userspace-rt/Cargo.toml | 8 ++++ crates/userspace-rt/src/arch/mod.rs | 2 + crates/userspace-rt/src/arch/riscv.rs | 13 ++++++ crates/userspace-rt/src/lib.rs | 12 ++++++ 9 files changed, 58 insertions(+), 70 deletions(-) create mode 100644 crates/userspace-rt/Cargo.toml create mode 100644 crates/userspace-rt/src/arch/mod.rs create mode 100644 crates/userspace-rt/src/arch/riscv.rs create mode 100644 crates/userspace-rt/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e4ce546..1ef30e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ members = [ "crates/servers/user-manager", "crates/types", "crates/userspace", + "crates/userspace-rt", ] resolver = "2" @@ -51,6 +52,7 @@ platform = { path = "crates/platform" } kernel = { path = "crates/kernel" } server-framework = { path = "crates/server-framework" } userspace = { path = "crates/userspace" } +userspace-rt = { path = "crates/userspace-rt" } # servers accessibility-server = { path = "crates/servers/accessibility-server" } diff --git a/crates/apps/hello/Cargo.toml b/crates/apps/hello/Cargo.toml index 117cce2..889ff7d 100644 --- a/crates/apps/hello/Cargo.toml +++ b/crates/apps/hello/Cargo.toml @@ -9,11 +9,4 @@ test = false bench = false [dependencies] -userspace = { workspace = true } - -[profile.release] -panic = "abort" -opt-level = "s" - -[profile.dev] -panic = "abort" +userspace-rt = { workspace = true } diff --git a/crates/apps/hello/src/main.rs b/crates/apps/hello/src/main.rs index 41cbbbd..afd92d4 100644 --- a/crates/apps/hello/src/main.rs +++ b/crates/apps/hello/src/main.rs @@ -1,24 +1,9 @@ #![no_std] #![no_main] -use core::arch::global_asm; - -global_asm!( - r#" -.section .text.entry -.globl _start -_start: - call main - j _start -"# -); +extern crate userspace_rt; #[unsafe(no_mangle)] -extern "C" fn main() -> ! { - userspace::syscall::exit(); -} - -#[panic_handler] -fn panic(_: &core::panic::PanicInfo) -> ! { - loop {} +extern "C" fn main() { + // The runtime handles _start, exit, and panic. } diff --git a/crates/apps/snake/Cargo.toml b/crates/apps/snake/Cargo.toml index 2b2a97c..5242f4c 100644 --- a/crates/apps/snake/Cargo.toml +++ b/crates/apps/snake/Cargo.toml @@ -11,3 +11,4 @@ bench = false [dependencies] types = { workspace = true } userspace = { workspace = true } +userspace-rt = { workspace = true } diff --git a/crates/apps/snake/src/main.rs b/crates/apps/snake/src/main.rs index da766c6..c39c775 100644 --- a/crates/apps/snake/src/main.rs +++ b/crates/apps/snake/src/main.rs @@ -1,48 +1,31 @@ #![no_std] #![no_main] +extern crate userspace_rt; + use snake::game::{Direction, GameState, Snake}; use snake::renderer::{render, RenderCommand}; +use userspace_rt::syscall; const DISPLAY_EP: usize = 0; const INPUT_EP: usize = 1; const TICK_DELAY: usize = 2_000_000; const MAX_RENDER_COMMANDS: usize = 192; -#[cfg(not(test))] -use core::arch::global_asm; - -#[cfg(not(test))] -global_asm!( - r#" -.section .text.entry -.globl _start -_start: - call main - j _start -"# -); - -#[cfg(not(test))] #[unsafe(no_mangle)] -extern "C" fn main() -> ! { - run_game(); -} - -fn run_game() -> ! { +extern "C" fn main() { let mut snake = Snake::new(); let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_COMMANDS]; loop { handle_input(&mut snake); - snake.tick(); let count = render(&snake, &mut commands); send_render_commands(&commands, count); if snake.state() == GameState::GameOver { - userspace::syscall::exit(); + return; } wait_tick(); @@ -50,11 +33,9 @@ fn run_game() -> ! { } fn handle_input(snake: &mut Snake) { - // PollEvent request: tag=0 - let _ = userspace::syscall::send(INPUT_EP, 0, 0, 0, 0); - let (tag, kind, _data, _) = userspace::syscall::receive(INPUT_EP); + let _ = syscall::send(INPUT_EP, 0, 0, 0, 0); + let (tag, kind, _, _) = syscall::receive(INPUT_EP); - // InputResponse::Event(KeyDown(key)): tag=1, key_kind in word 1 if tag == 1 { match kind { 0 => snake.set_direction(Direction::Up), @@ -67,34 +48,25 @@ fn handle_input(snake: &mut Snake) { } fn send_render_commands(commands: &[RenderCommand], count: usize) { - // Clear: DisplayRequest tag=1 - let _ = userspace::syscall::send(DISPLAY_EP, 1, 0, 0, 0); - let _ = userspace::syscall::receive(DISPLAY_EP); + let _ = syscall::send(DISPLAY_EP, 1, 0, 0, 0); + let _ = syscall::receive(DISPLAY_EP); for i in 0..count { let cmd = &commands[i]; - // DrawRect: DisplayRequest tag=0, xy packed, wh packed, color let xy = cmd.x as usize | ((cmd.y as usize) << 16); let wh = cmd.w as usize | ((cmd.h as usize) << 16); - let _ = userspace::syscall::send(DISPLAY_EP, 0, xy, wh, cmd.color as usize); - let _ = userspace::syscall::receive(DISPLAY_EP); + let _ = syscall::send(DISPLAY_EP, 0, xy, wh, cmd.color as usize); + let _ = syscall::receive(DISPLAY_EP); } - // Flush: DisplayRequest tag=2 - let _ = userspace::syscall::send(DISPLAY_EP, 2, 0, 0, 0); - let _ = userspace::syscall::receive(DISPLAY_EP); + let _ = syscall::send(DISPLAY_EP, 2, 0, 0, 0); + let _ = syscall::receive(DISPLAY_EP); } fn wait_tick() { - let start = userspace::syscall::get_time(); + let start = syscall::get_time(); let deadline = start + TICK_DELAY; - while userspace::syscall::get_time() < deadline { - userspace::syscall::yield_now(); + while syscall::get_time() < deadline { + syscall::yield_now(); } } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_: &core::panic::PanicInfo) -> ! { - userspace::syscall::exit(); -} diff --git a/crates/userspace-rt/Cargo.toml b/crates/userspace-rt/Cargo.toml new file mode 100644 index 0000000..4a75192 --- /dev/null +++ b/crates/userspace-rt/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "userspace-rt" +version = "0.1.0" +edition = "2024" + +[dependencies] +types = { workspace = true } +userspace = { workspace = true } diff --git a/crates/userspace-rt/src/arch/mod.rs b/crates/userspace-rt/src/arch/mod.rs new file mode 100644 index 0000000..963a1f1 --- /dev/null +++ b/crates/userspace-rt/src/arch/mod.rs @@ -0,0 +1,2 @@ +#[cfg(all(target_arch = "riscv64", target_os = "none"))] +mod riscv; diff --git a/crates/userspace-rt/src/arch/riscv.rs b/crates/userspace-rt/src/arch/riscv.rs new file mode 100644 index 0000000..169ba6d --- /dev/null +++ b/crates/userspace-rt/src/arch/riscv.rs @@ -0,0 +1,13 @@ +use core::arch::global_asm; + +global_asm!( + r#" +.section .text.entry +.globl _start +_start: + call main + li a7, 16 + ecall + j _start +"# +); diff --git a/crates/userspace-rt/src/lib.rs b/crates/userspace-rt/src/lib.rs new file mode 100644 index 0000000..f42c8b5 --- /dev/null +++ b/crates/userspace-rt/src/lib.rs @@ -0,0 +1,12 @@ +#![no_std] + +mod arch; + +pub use userspace::syscall; +pub use userspace::allocator::KosAllocator; + +#[cfg(target_os = "none")] +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + userspace::syscall::exit(); +}