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,
}
pub type PrintAbi = extern "Rust" fn(msg: &str);
pub type PrintAbi = extern "C" fn(ptr: *const u8, len: usize);
#[allow(unused)]
pub fn print(msg: &str) {
unsafe {
let ptr = CALL_ABI_TABLE[CallAbiTable::Print as usize];
let f: PrintAbi = core::mem::transmute(ptr);
f(msg);
}
let f: PrintAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Print as usize]) };
f(msg.as_ptr(), msg.len());
}
pub type SleepAbi = extern "Rust" fn(ms: u64);
pub type SleepAbi = extern "C" fn(ms: u64);
#[allow(unused)]
pub fn sleep(ms: u64) {
unsafe {
let ptr = CALL_ABI_TABLE[CallAbiTable::Sleep as usize];
let f: SleepAbi = core::mem::transmute(ptr);
f(ms);
}
let f: SleepAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Sleep as usize]) };
f(ms);
}
pub type LockDisplay = extern "Rust" fn(lock: bool);
pub type LockDisplay = extern "C" fn(lock: bool);
#[allow(unused)]
pub fn lock_display(lock: bool) {
unsafe {
let ptr = CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize];
let f: LockDisplay = core::mem::transmute(ptr);
f(lock);
}
let f: LockDisplay =
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]) };
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)]
pub fn draw_iter(pixels: &[Pixel<Rgb565>]) {
unsafe {
let ptr = CALL_ABI_TABLE[CallAbiTable::DrawIter as usize];
let f: DrawIterAbi = core::mem::transmute(ptr);
f(pixels);
}
let f: DrawIterAbi =
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::DrawIter as usize]) };
f(pixels.as_ptr(), pixels.len());
}
pub type GetKeyAbi = extern "Rust" fn() -> Option<KeyEvent>;
pub type GetKeyAbi = extern "C" fn() -> KeyEvent;
#[allow(unused)]
pub fn get_key() -> Option<KeyEvent> {
unsafe {
let ptr = CALL_ABI_TABLE[CallAbiTable::GetKey as usize];
let f: GetKeyAbi = core::mem::transmute(ptr);
f()
}
pub fn get_key() -> KeyEvent {
let f: GetKeyAbi =
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::GetKey as usize]) };
f()
}
pub type GenRand = extern "Rust" fn(req: &mut RngRequest);
#[repr(C)]
pub enum RngRequest {
U32(u32),
@@ -93,6 +79,8 @@ pub enum RngRequest {
Bytes { ptr: *mut u8, len: usize },
}
pub type GenRand = extern "C" fn(req: &mut RngRequest);
#[allow(unused)]
pub fn gen_rand(req: &mut RngRequest) {
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 embassy_rp::clocks::{RoscRng, clk_sys_freq};
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
@@ -9,18 +11,20 @@ use crate::{
display::{FB_PAUSED, FRAMEBUFFER},
};
// ensure the abi and the kernel fn signatures are the same
const _: PrintAbi = print;
const _: SleepAbi = sleep;
const _: LockDisplay = lock_display;
const _: DrawIterAbi = draw_iter;
const _: GetKeyAbi = get_key;
pub extern "C" fn print(ptr: *const u8, len: usize) {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let slice = unsafe { core::slice::from_raw_parts(ptr, len) };
pub extern "Rust" fn print(msg: &str) {
defmt::info!("{:?}", msg);
if let Ok(msg) = core::str::from_utf8(slice) {
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 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);
}
const _: DrawIterAbi = draw_iter;
// 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() }
}
pub extern "Rust" fn get_key() -> Option<KeyEvent> {
unsafe { KEY_CACHE.dequeue() }
const _: GetKeyAbi = get_key;
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;
match req {

View File

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

View File

@@ -2,7 +2,7 @@
#![no_main]
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 core::panic::PanicInfo;
use embedded_graphics::{
@@ -105,7 +105,8 @@ pub fn main() {
lock_display(false);
}
if let Some(event) = get_key() {
let event = get_key();
if event.state != KeyState::Idle {
match event.key {
KeyCode::Char(ch) => {
input.push(ch);

View File

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