use C abi for syscalls

This commit is contained in:
2025-09-26 23:39:19 -06:00
parent bf3b37783f
commit 7bd6012748
5 changed files with 61 additions and 52 deletions

View File

@@ -29,63 +29,49 @@ pub enum CallAbiTable {
GenRand = 5, GenRand = 5,
} }
pub type PrintAbi = extern "Rust" fn(msg: &str); pub type PrintAbi = extern "C" fn(ptr: *const u8, len: usize);
#[allow(unused)] #[allow(unused)]
pub fn print(msg: &str) { pub fn print(msg: &str) {
unsafe { let f: PrintAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Print as usize]) };
let ptr = CALL_ABI_TABLE[CallAbiTable::Print as usize]; f(msg.as_ptr(), msg.len());
let f: PrintAbi = core::mem::transmute(ptr);
f(msg);
}
} }
pub type SleepAbi = extern "Rust" fn(ms: u64); pub type SleepAbi = extern "C" fn(ms: u64);
#[allow(unused)] #[allow(unused)]
pub fn sleep(ms: u64) { pub fn sleep(ms: u64) {
unsafe { let f: SleepAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Sleep as usize]) };
let ptr = CALL_ABI_TABLE[CallAbiTable::Sleep as usize];
let f: SleepAbi = core::mem::transmute(ptr);
f(ms); f(ms);
}
} }
pub type LockDisplay = extern "Rust" fn(lock: bool); pub type LockDisplay = extern "C" fn(lock: bool);
#[allow(unused)] #[allow(unused)]
pub fn lock_display(lock: bool) { pub fn lock_display(lock: bool) {
unsafe { let f: LockDisplay =
let ptr = CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]; unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]) };
let f: LockDisplay = core::mem::transmute(ptr);
f(lock); f(lock);
}
} }
pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]); pub type DrawIterAbi = extern "C" fn(ptr: *const Pixel<Rgb565>, len: usize);
#[allow(unused)] #[allow(unused)]
pub fn draw_iter(pixels: &[Pixel<Rgb565>]) { pub fn draw_iter(pixels: &[Pixel<Rgb565>]) {
unsafe { let f: DrawIterAbi =
let ptr = CALL_ABI_TABLE[CallAbiTable::DrawIter as usize]; unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::DrawIter as usize]) };
let f: DrawIterAbi = core::mem::transmute(ptr); f(pixels.as_ptr(), pixels.len());
f(pixels);
}
} }
pub type GetKeyAbi = extern "Rust" fn() -> Option<KeyEvent>; pub type GetKeyAbi = extern "C" fn() -> KeyEvent;
#[allow(unused)] #[allow(unused)]
pub fn get_key() -> Option<KeyEvent> { pub fn get_key() -> KeyEvent {
unsafe { let f: GetKeyAbi =
let ptr = CALL_ABI_TABLE[CallAbiTable::GetKey as usize]; unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::GetKey as usize]) };
let f: GetKeyAbi = core::mem::transmute(ptr);
f() f()
}
} }
pub type GenRand = extern "Rust" fn(req: &mut RngRequest);
#[repr(C)] #[repr(C)]
pub enum RngRequest { pub enum RngRequest {
U32(u32), U32(u32),
@@ -93,6 +79,8 @@ pub enum RngRequest {
Bytes { ptr: *mut u8, len: usize }, Bytes { ptr: *mut u8, len: usize },
} }
pub type GenRand = extern "C" fn(req: &mut RngRequest);
#[allow(unused)] #[allow(unused)]
pub fn gen_rand(req: &mut RngRequest) { pub fn gen_rand(req: &mut RngRequest) {
unsafe { unsafe {

View File

@@ -1,4 +1,6 @@
use abi_sys::{DrawIterAbi, GetKeyAbi, LockDisplay, PrintAbi, RngRequest, SleepAbi}; use abi_sys::{
DrawIterAbi, GenRand, GetKeyAbi, LockDisplay, Modifiers, PrintAbi, RngRequest, SleepAbi,
};
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
use embassy_rp::clocks::{RoscRng, clk_sys_freq}; use embassy_rp::clocks::{RoscRng, clk_sys_freq};
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565}; use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
@@ -9,18 +11,20 @@ use crate::{
display::{FB_PAUSED, FRAMEBUFFER}, display::{FB_PAUSED, FRAMEBUFFER},
}; };
// ensure the abi and the kernel fn signatures are the same
const _: PrintAbi = print; const _: PrintAbi = print;
const _: SleepAbi = sleep; pub extern "C" fn print(ptr: *const u8, len: usize) {
const _: LockDisplay = lock_display; // SAFETY: caller guarantees `ptr` is valid for `len` bytes
const _: DrawIterAbi = draw_iter; let slice = unsafe { core::slice::from_raw_parts(ptr, len) };
const _: GetKeyAbi = get_key;
pub extern "Rust" fn print(msg: &str) { if let Ok(msg) = core::str::from_utf8(slice) {
defmt::info!("{:?}", msg); defmt::info!("print: {}", msg);
} else {
defmt::warn!("print: <invalid utf8>");
}
} }
pub extern "Rust" fn sleep(ms: u64) { const _: SleepAbi = sleep;
pub extern "C" fn sleep(ms: u64) {
let cycles_per_ms = clk_sys_freq() / 1000; let cycles_per_ms = clk_sys_freq() / 1000;
let total_cycles = ms * cycles_per_ms as u64; let total_cycles = ms * cycles_per_ms as u64;
@@ -29,20 +33,33 @@ pub extern "Rust" fn sleep(ms: u64) {
} }
} }
pub extern "Rust" fn lock_display(lock: bool) { const _: LockDisplay = lock_display;
pub extern "C" fn lock_display(lock: bool) {
FB_PAUSED.store(lock, Ordering::Relaxed); FB_PAUSED.store(lock, Ordering::Relaxed);
} }
const _: DrawIterAbi = draw_iter;
// TODO: maybe return result // TODO: maybe return result
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) { pub extern "C" fn draw_iter(pixels: *const Pixel<Rgb565>, len: usize) {
let pixels = unsafe { core::slice::from_raw_parts(pixels, len) };
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() } unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() }
} }
pub extern "Rust" fn get_key() -> Option<KeyEvent> { const _: GetKeyAbi = get_key;
unsafe { KEY_CACHE.dequeue() } pub extern "C" fn get_key() -> KeyEvent {
if let Some(event) = unsafe { KEY_CACHE.dequeue() } {
event
} else {
KeyEvent {
key: abi_sys::KeyCode::Unknown(0),
state: abi_sys::KeyState::Idle,
mods: Modifiers::empty(),
}
}
} }
pub extern "Rust" fn gen_rand(req: &mut RngRequest) { const _: GenRand = gen_rand;
pub extern "C" fn gen_rand(req: &mut RngRequest) {
let mut rng = RoscRng; let mut rng = RoscRng;
match req { match req {

View File

@@ -14,6 +14,7 @@ pub mod keyboard {
} }
#[derive(Debug)] #[derive(Debug)]
#[repr(C)]
pub struct KeyEvent { pub struct KeyEvent {
pub key: KeyCode, pub key: KeyCode,
pub state: KeyState, pub state: KeyState,
@@ -22,6 +23,7 @@ pub mod keyboard {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum KeyState { pub enum KeyState {
Idle = 0, Idle = 0,
Pressed = 1, Pressed = 1,

View File

@@ -2,7 +2,7 @@
#![no_main] #![no_main]
extern crate alloc; extern crate alloc;
use abi::{KeyCode, display::Display, get_key, lock_display, print}; use abi::{KeyCode, KeyState, display::Display, get_key, lock_display, print};
use alloc::{format, string::String, vec, vec::Vec}; use alloc::{format, string::String, vec, vec::Vec};
use core::panic::PanicInfo; use core::panic::PanicInfo;
use embedded_graphics::{ use embedded_graphics::{
@@ -105,7 +105,8 @@ pub fn main() {
lock_display(false); lock_display(false);
} }
if let Some(event) = get_key() { let event = get_key();
if event.state != KeyState::Idle {
match event.key { match event.key {
KeyCode::Char(ch) => { KeyCode::Char(ch) => {
input.push(ch); input.push(ch);

View File

@@ -3,7 +3,7 @@
extern crate alloc; extern crate alloc;
use abi::{ use abi::{
KeyCode, Rng, KeyCode, KeyState, Rng,
display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH}, display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH},
get_key, lock_display, print, sleep, get_key, lock_display, print, sleep,
}; };
@@ -46,7 +46,8 @@ pub fn main() {
); );
loop { loop {
if let Some(event) = get_key() { let event = get_key();
if event.state != KeyState::Idle {
let direction = match event.key { let direction = match event.key {
KeyCode::Up => Direction::Up, KeyCode::Up => Direction::Up,
KeyCode::Down => Direction::Down, KeyCode::Down => Direction::Down,
@@ -56,7 +57,7 @@ pub fn main() {
_ => Direction::None, _ => Direction::None,
}; };
game.set_direction(direction); game.set_direction(direction);
} };
// ensure all draws show up at once // ensure all draws show up at once
lock_display(true); lock_display(true);