feat(userspace-rt): add runtime crate with entry point, panic handler, and allocator re-export
Snake and hello apps now use extern crate userspace_rt — no more boilerplate assembly or panic handlers in app code.
This commit is contained in:
@@ -38,6 +38,7 @@ members = [
|
|||||||
"crates/servers/user-manager",
|
"crates/servers/user-manager",
|
||||||
"crates/types",
|
"crates/types",
|
||||||
"crates/userspace",
|
"crates/userspace",
|
||||||
|
"crates/userspace-rt",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ platform = { path = "crates/platform" }
|
|||||||
kernel = { path = "crates/kernel" }
|
kernel = { path = "crates/kernel" }
|
||||||
server-framework = { path = "crates/server-framework" }
|
server-framework = { path = "crates/server-framework" }
|
||||||
userspace = { path = "crates/userspace" }
|
userspace = { path = "crates/userspace" }
|
||||||
|
userspace-rt = { path = "crates/userspace-rt" }
|
||||||
|
|
||||||
# servers
|
# servers
|
||||||
accessibility-server = { path = "crates/servers/accessibility-server" }
|
accessibility-server = { path = "crates/servers/accessibility-server" }
|
||||||
|
|||||||
@@ -9,11 +9,4 @@ test = false
|
|||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
userspace = { workspace = true }
|
userspace-rt = { workspace = true }
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
panic = "abort"
|
|
||||||
opt-level = "s"
|
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
panic = "abort"
|
|
||||||
|
|||||||
@@ -1,24 +1,9 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use core::arch::global_asm;
|
extern crate userspace_rt;
|
||||||
|
|
||||||
global_asm!(
|
|
||||||
r#"
|
|
||||||
.section .text.entry
|
|
||||||
.globl _start
|
|
||||||
_start:
|
|
||||||
call main
|
|
||||||
j _start
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main() -> ! {
|
extern "C" fn main() {
|
||||||
userspace::syscall::exit();
|
// The runtime handles _start, exit, and panic.
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ bench = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
types = { workspace = true }
|
types = { workspace = true }
|
||||||
userspace = { workspace = true }
|
userspace = { workspace = true }
|
||||||
|
userspace-rt = { workspace = true }
|
||||||
|
|||||||
@@ -1,48 +1,31 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
extern crate userspace_rt;
|
||||||
|
|
||||||
use snake::game::{Direction, GameState, Snake};
|
use snake::game::{Direction, GameState, Snake};
|
||||||
use snake::renderer::{render, RenderCommand};
|
use snake::renderer::{render, RenderCommand};
|
||||||
|
use userspace_rt::syscall;
|
||||||
|
|
||||||
const DISPLAY_EP: usize = 0;
|
const DISPLAY_EP: usize = 0;
|
||||||
const INPUT_EP: usize = 1;
|
const INPUT_EP: usize = 1;
|
||||||
const TICK_DELAY: usize = 2_000_000;
|
const TICK_DELAY: usize = 2_000_000;
|
||||||
const MAX_RENDER_COMMANDS: usize = 192;
|
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)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main() -> ! {
|
extern "C" fn main() {
|
||||||
run_game();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_game() -> ! {
|
|
||||||
let mut snake = Snake::new();
|
let mut snake = Snake::new();
|
||||||
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_COMMANDS];
|
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_COMMANDS];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
handle_input(&mut snake);
|
handle_input(&mut snake);
|
||||||
|
|
||||||
snake.tick();
|
snake.tick();
|
||||||
|
|
||||||
let count = render(&snake, &mut commands);
|
let count = render(&snake, &mut commands);
|
||||||
send_render_commands(&commands, count);
|
send_render_commands(&commands, count);
|
||||||
|
|
||||||
if snake.state() == GameState::GameOver {
|
if snake.state() == GameState::GameOver {
|
||||||
userspace::syscall::exit();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_tick();
|
wait_tick();
|
||||||
@@ -50,11 +33,9 @@ fn run_game() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_input(snake: &mut Snake) {
|
fn handle_input(snake: &mut Snake) {
|
||||||
// PollEvent request: tag=0
|
let _ = syscall::send(INPUT_EP, 0, 0, 0, 0);
|
||||||
let _ = userspace::syscall::send(INPUT_EP, 0, 0, 0, 0);
|
let (tag, kind, _, _) = syscall::receive(INPUT_EP);
|
||||||
let (tag, kind, _data, _) = userspace::syscall::receive(INPUT_EP);
|
|
||||||
|
|
||||||
// InputResponse::Event(KeyDown(key)): tag=1, key_kind in word 1
|
|
||||||
if tag == 1 {
|
if tag == 1 {
|
||||||
match kind {
|
match kind {
|
||||||
0 => snake.set_direction(Direction::Up),
|
0 => snake.set_direction(Direction::Up),
|
||||||
@@ -67,34 +48,25 @@ fn handle_input(snake: &mut Snake) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn send_render_commands(commands: &[RenderCommand], count: usize) {
|
fn send_render_commands(commands: &[RenderCommand], count: usize) {
|
||||||
// Clear: DisplayRequest tag=1
|
let _ = syscall::send(DISPLAY_EP, 1, 0, 0, 0);
|
||||||
let _ = userspace::syscall::send(DISPLAY_EP, 1, 0, 0, 0);
|
let _ = syscall::receive(DISPLAY_EP);
|
||||||
let _ = userspace::syscall::receive(DISPLAY_EP);
|
|
||||||
|
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let cmd = &commands[i];
|
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 xy = cmd.x as usize | ((cmd.y as usize) << 16);
|
||||||
let wh = cmd.w as usize | ((cmd.h 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 _ = syscall::send(DISPLAY_EP, 0, xy, wh, cmd.color as usize);
|
||||||
let _ = userspace::syscall::receive(DISPLAY_EP);
|
let _ = syscall::receive(DISPLAY_EP);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush: DisplayRequest tag=2
|
let _ = syscall::send(DISPLAY_EP, 2, 0, 0, 0);
|
||||||
let _ = userspace::syscall::send(DISPLAY_EP, 2, 0, 0, 0);
|
let _ = syscall::receive(DISPLAY_EP);
|
||||||
let _ = userspace::syscall::receive(DISPLAY_EP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_tick() {
|
fn wait_tick() {
|
||||||
let start = userspace::syscall::get_time();
|
let start = syscall::get_time();
|
||||||
let deadline = start + TICK_DELAY;
|
let deadline = start + TICK_DELAY;
|
||||||
while userspace::syscall::get_time() < deadline {
|
while syscall::get_time() < deadline {
|
||||||
userspace::syscall::yield_now();
|
syscall::yield_now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
|
||||||
userspace::syscall::exit();
|
|
||||||
}
|
|
||||||
|
|||||||
8
crates/userspace-rt/Cargo.toml
Normal file
8
crates/userspace-rt/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "userspace-rt"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
types = { workspace = true }
|
||||||
|
userspace = { workspace = true }
|
||||||
2
crates/userspace-rt/src/arch/mod.rs
Normal file
2
crates/userspace-rt/src/arch/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#[cfg(all(target_arch = "riscv64", target_os = "none"))]
|
||||||
|
mod riscv;
|
||||||
13
crates/userspace-rt/src/arch/riscv.rs
Normal file
13
crates/userspace-rt/src/arch/riscv.rs
Normal file
@@ -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
|
||||||
|
"#
|
||||||
|
);
|
||||||
12
crates/userspace-rt/src/lib.rs
Normal file
12
crates/userspace-rt/src/lib.rs
Normal file
@@ -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();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user