WIP keyboard syscall
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -17,8 +17,11 @@ name = "abi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi_sys",
|
||||
"embassy-time 0.5.0",
|
||||
"embedded-graphics",
|
||||
"shared",
|
||||
"spin",
|
||||
"talc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -186,7 +189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f377753756ec12e76b52d2dd657437be0448cc9736402ffadd0b8b8b9602c8a1"
|
||||
dependencies = [
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embedded-io",
|
||||
"embedded-io-async",
|
||||
"futures-intrusive",
|
||||
@@ -320,7 +323,7 @@ dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-net-driver-channel",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-io-async",
|
||||
"futures",
|
||||
@@ -494,7 +497,7 @@ dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-hal-internal 0.3.0",
|
||||
"embassy-sync 0.7.0",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
@@ -588,7 +591,7 @@ dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-hal-internal 0.2.0",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embassy-usb-driver",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
@@ -626,7 +629,7 @@ dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-hal-internal 0.2.0",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embassy-time-driver",
|
||||
"embassy-time-queue-utils",
|
||||
"embassy-usb-driver",
|
||||
@@ -696,10 +699,26 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-time-driver"
|
||||
version = "0.2.0"
|
||||
name = "embassy-time"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d45f5d833b6d98bd2aab0c2de70b18bfaa10faf661a1578fd8e5dfb15eb7eba"
|
||||
checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
"document-features",
|
||||
"embassy-time-driver",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-time-driver"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6"
|
||||
dependencies = [
|
||||
"document-features",
|
||||
]
|
||||
@@ -1187,7 +1206,7 @@ dependencies = [
|
||||
"embassy-futures",
|
||||
"embassy-rp 0.4.0",
|
||||
"embassy-sync 0.7.0",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embassy-usb",
|
||||
"embedded-graphics",
|
||||
"embedded-hal 0.2.7",
|
||||
@@ -2086,7 +2105,7 @@ dependencies = [
|
||||
"bt-hci",
|
||||
"embassy-futures",
|
||||
"embassy-sync 0.6.2",
|
||||
"embassy-time",
|
||||
"embassy-time 0.4.0",
|
||||
"embedded-io",
|
||||
"futures",
|
||||
"heapless",
|
||||
|
||||
@@ -7,3 +7,6 @@ edition = "2024"
|
||||
embedded-graphics = "0.8.1"
|
||||
shared = { path = "../shared" }
|
||||
abi_sys = { path = "../abi_sys" }
|
||||
talc = "4.4.3"
|
||||
spin = "0.10.0"
|
||||
embassy-time = "0.5.0"
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#![no_std]
|
||||
|
||||
use abi_sys::{Syscall, call_abi};
|
||||
use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||
use abi_sys::draw_iter;
|
||||
pub use abi_sys::{get_key, print};
|
||||
pub use embassy_time;
|
||||
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||
use talc::*;
|
||||
|
||||
pub fn print(msg: &str) {
|
||||
let syscall = Syscall::Print {
|
||||
msg: msg.as_ptr(),
|
||||
len: msg.len(),
|
||||
};
|
||||
unsafe {
|
||||
call_abi(&syscall);
|
||||
}
|
||||
}
|
||||
static mut ARENA: [u8; 10000] = [0; 10000];
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
||||
Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) })
|
||||
.lock();
|
||||
|
||||
pub mod display {
|
||||
use crate::{Syscall, call_abi};
|
||||
use crate::draw_iter;
|
||||
use embedded_graphics::{
|
||||
Pixel,
|
||||
geometry::{Dimensions, Point},
|
||||
@@ -30,18 +30,6 @@ pub mod display {
|
||||
|
||||
pub struct Display;
|
||||
|
||||
impl Display {
|
||||
fn syscall_draw(&self, pixels: &[Pixel565]) {
|
||||
let syscall = Syscall::DrawIter {
|
||||
pixels: pixels.as_ptr(),
|
||||
len: pixels.len(),
|
||||
};
|
||||
unsafe {
|
||||
call_abi(&syscall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dimensions for Display {
|
||||
fn bounding_box(&self) -> Rectangle {
|
||||
Rectangle {
|
||||
@@ -71,13 +59,13 @@ pub mod display {
|
||||
count += 1;
|
||||
|
||||
if count == BUF_SIZE {
|
||||
self.syscall_draw(&buf[..count]);
|
||||
draw_iter(&buf[..count]);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
self.syscall_draw(&buf[..count]);
|
||||
draw_iter(&buf[..count]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use core::pin::Pin;
|
||||
pub use embedded_graphics::{
|
||||
Pixel,
|
||||
geometry::Point,
|
||||
@@ -7,26 +11,50 @@ pub use embedded_graphics::{
|
||||
};
|
||||
use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||
|
||||
// Instead of extern, declare a static pointer in a dedicated section
|
||||
pub type EntryFn = fn() -> Pin<Box<dyn Future<Output = ()>>>;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[unsafe(link_section = ".user_reloc")]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub static mut call_abi_ptr: usize = 0;
|
||||
#[unsafe(link_section = ".userapp")]
|
||||
pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable::COUNT];
|
||||
|
||||
// Helper to call it
|
||||
pub unsafe fn call_abi(call: *const Syscall) {
|
||||
let f: extern "C" fn(*const Syscall) = unsafe { core::mem::transmute(call_abi_ptr) };
|
||||
f(call);
|
||||
#[repr(usize)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CallAbiTable {
|
||||
Print = 0,
|
||||
DrawIter = 1,
|
||||
GetKey = 2,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum Syscall {
|
||||
DrawIter {
|
||||
pixels: *const Pixel<Rgb565>,
|
||||
len: usize,
|
||||
},
|
||||
Print {
|
||||
msg: *const u8,
|
||||
len: usize,
|
||||
},
|
||||
impl CallAbiTable {
|
||||
pub const COUNT: usize = 3;
|
||||
}
|
||||
|
||||
pub type PrintAbi = extern "Rust" fn(msg: &str);
|
||||
|
||||
pub fn print(msg: &str) {
|
||||
unsafe {
|
||||
let ptr = CALL_ABI_TABLE[CallAbiTable::Print as usize];
|
||||
let f: PrintAbi = core::mem::transmute(ptr);
|
||||
f(msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
pub type GetKeyAbi = extern "Rust" fn() -> Option<KeyEvent>;
|
||||
|
||||
pub fn get_key() -> Option<KeyEvent> {
|
||||
unsafe {
|
||||
let ptr = CALL_ABI_TABLE[CallAbiTable::GetKey as usize];
|
||||
let f: GetKeyAbi = core::mem::transmute(ptr);
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use abi_sys::Syscall;
|
||||
use core::pin::Pin;
|
||||
|
||||
use abi_sys::{DrawIterAbi, GetKeyAbi, Pixel, PrintAbi};
|
||||
use alloc::boxed::Box;
|
||||
use defmt::info;
|
||||
use embassy_futures::block_on;
|
||||
use embedded_graphics::{
|
||||
@@ -8,35 +11,30 @@ use embedded_graphics::{
|
||||
prelude::{Point, RgbColor, Size},
|
||||
primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
|
||||
};
|
||||
use shared::keyboard::KeyEvent;
|
||||
|
||||
use crate::display::FRAMEBUFFER;
|
||||
use crate::{KEY_CACHE, display::FRAMEBUFFER};
|
||||
|
||||
#[allow(unused)]
|
||||
pub extern "C" fn call_abi(call: *const Syscall) {
|
||||
info!("called abi");
|
||||
let call = unsafe { &*call };
|
||||
match call {
|
||||
Syscall::DrawIter { pixels, len } => {
|
||||
// SAFETY: we're trusting the user program here
|
||||
let slice = unsafe { core::slice::from_raw_parts(*pixels, *len) };
|
||||
// ensure the abi and the kernel fn signatures are the same
|
||||
const _: PrintAbi = print;
|
||||
const _: DrawIterAbi = draw_iter;
|
||||
const _: GetKeyAbi = get_key;
|
||||
|
||||
let framebuffer = block_on(FRAMEBUFFER.lock());
|
||||
framebuffer
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.draw_iter(slice.iter().copied())
|
||||
.unwrap();
|
||||
}
|
||||
Syscall::Print { msg, len } => {
|
||||
// SAFETY: we're trusting the user program here
|
||||
let slice = unsafe { core::slice::from_raw_parts(*msg, *len) };
|
||||
|
||||
if let Ok(str) = str::from_utf8(slice) {
|
||||
defmt::info!("{:?}", str);
|
||||
} else {
|
||||
defmt::error!("Failed to parse user print str")
|
||||
}
|
||||
}
|
||||
}
|
||||
pub extern "Rust" fn print(msg: &str) {
|
||||
defmt::info!("{:?}", msg);
|
||||
}
|
||||
|
||||
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
||||
let framebuffer = block_on(FRAMEBUFFER.lock());
|
||||
framebuffer
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.draw_iter(pixels.iter().copied())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub extern "Rust" fn get_key() -> Option<KeyEvent> {
|
||||
defmt::info!("get key called");
|
||||
unsafe { KEY_CACHE.dequeue() }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#![allow(static_mut_refs)]
|
||||
use core::{alloc::Layout, ffi::c_void, ptr::NonNull, slice::from_raw_parts_mut};
|
||||
use crate::abi;
|
||||
use abi_sys::{CallAbiTable, EntryFn};
|
||||
use alloc::boxed::Box;
|
||||
use core::{
|
||||
alloc::Layout,
|
||||
ffi::c_void,
|
||||
pin::Pin,
|
||||
ptr::NonNull,
|
||||
slice::from_raw_parts_mut,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use goblin::elf::{Elf, header::ET_DYN, program_header::PT_LOAD, sym};
|
||||
|
||||
// userland ram region defined in memory.x
|
||||
@@ -8,8 +18,6 @@ unsafe extern "C" {
|
||||
static __userapp_end__: u8;
|
||||
}
|
||||
|
||||
type EntryFn = extern "C" fn();
|
||||
|
||||
pub unsafe fn load_binary(bytes: &[u8]) -> Result<EntryFn, &str> {
|
||||
let elf = Elf::parse(&bytes).expect("Failed to parse ELF");
|
||||
|
||||
@@ -55,16 +63,22 @@ pub unsafe fn load_binary(bytes: &[u8]) -> Result<EntryFn, &str> {
|
||||
let call_abi_sym = elf
|
||||
.syms
|
||||
.iter()
|
||||
.find(|s| elf.strtab.get_at(s.st_name).unwrap() == "call_abi_ptr")
|
||||
.expect("call_abi_ptr not found");
|
||||
.find(|s| elf.strtab.get_at(s.st_name).unwrap() == "CALL_ABI_TABLE")
|
||||
.expect("syscall table not found");
|
||||
|
||||
// Virtual address inside user RAM
|
||||
let addr = call_abi_sym.st_value as *mut usize;
|
||||
let table_base = call_abi_sym.st_value as *mut usize;
|
||||
|
||||
// Patch it
|
||||
unsafe {
|
||||
core::ptr::write(addr, crate::abi::call_abi as usize);
|
||||
let entries: &[(CallAbiTable, usize)] = &[
|
||||
(CallAbiTable::Print, abi::print as usize),
|
||||
(CallAbiTable::DrawIter, abi::draw_iter as usize),
|
||||
(CallAbiTable::GetKey, abi::get_key as usize),
|
||||
];
|
||||
assert!(entries.len() == CallAbiTable::COUNT);
|
||||
|
||||
for &(abi_idx, func_ptr) in entries {
|
||||
unsafe {
|
||||
table_base.add(abi_idx as usize).write(func_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(unsafe { core::mem::transmute(elf.entry as u32) })
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(ascii_char)]
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![cfg_attr(not(test), no_main)]
|
||||
#![allow(static_mut_refs)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod abi;
|
||||
mod display;
|
||||
@@ -23,12 +27,13 @@ use crate::{
|
||||
storage::{SDCARD, SdCard},
|
||||
usb::{ENABLE_SCSI, usb_handler},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
use defmt::unwrap;
|
||||
use embassy_executor::{Executor, Spawner};
|
||||
use embassy_futures::join::join;
|
||||
use embassy_futures::join::{join, join3};
|
||||
use embassy_rp::{
|
||||
gpio::{Input, Level, Output, Pull},
|
||||
i2c::{self, I2c},
|
||||
@@ -40,10 +45,15 @@ use embassy_rp::{
|
||||
spi::{self, Spi},
|
||||
usb as embassy_rp_usb,
|
||||
};
|
||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{Mutex, raw::CriticalSectionRawMutex},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
||||
use heapless::spsc::Queue;
|
||||
use shared::keyboard::KeyEvent;
|
||||
use static_cell::StaticCell;
|
||||
use talc::*;
|
||||
|
||||
@@ -118,7 +128,7 @@ async fn userland_task() {
|
||||
defmt::info!("Running binary");
|
||||
let entry = unsafe { load_binary(binary_data).unwrap() };
|
||||
|
||||
entry();
|
||||
entry().await;
|
||||
}
|
||||
|
||||
struct Display {
|
||||
@@ -194,5 +204,21 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
|
||||
let usb_fut = usb_handler(usb);
|
||||
|
||||
ENABLE_SCSI.store(true, core::sync::atomic::Ordering::Relaxed);
|
||||
join(usb_fut, display_fut).await;
|
||||
join3(usb_fut, display_fut, async {
|
||||
loop {
|
||||
Timer::after_millis(100).await;
|
||||
get_keys().await
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
||||
|
||||
async fn get_keys() {
|
||||
if let Some(event) = read_keyboard_fifo().await {
|
||||
unsafe {
|
||||
let _ = KEY_CACHE.enqueue(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use abi::{display::Display, print};
|
||||
use core::panic::PanicInfo;
|
||||
extern crate alloc;
|
||||
use abi::{KeyCode, display::Display, embassy_time, get_key, print};
|
||||
use alloc::{boxed::Box, string::String, vec};
|
||||
use core::{panic::PanicInfo, pin::Pin};
|
||||
use embedded_graphics::{
|
||||
Drawable,
|
||||
geometry::{Dimensions, Point},
|
||||
@@ -17,21 +19,40 @@ fn panic(_info: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn _start() {
|
||||
print("Starting Calculator app");
|
||||
pub async fn main() {
|
||||
print("Starting Async Calculator app");
|
||||
let mut display = Display;
|
||||
|
||||
let character_style = MonoTextStyle::new(&FONT_6X10, Rgb565::RED);
|
||||
|
||||
// Draw centered text.
|
||||
let text = "embedded-graphics";
|
||||
Text::with_alignment(
|
||||
text,
|
||||
display.bounding_box().center() + Point::new(0, 15),
|
||||
character_style,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
let mut text = vec!['H', 'E', 'L', 'L', 'O'];
|
||||
|
||||
loop {
|
||||
Text::with_alignment(
|
||||
&text.iter().cloned().collect::<String>(),
|
||||
display.bounding_box().center() + Point::new(0, 15),
|
||||
character_style,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
|
||||
if let Some(event) = get_key() {
|
||||
print("User got event");
|
||||
match event.key {
|
||||
KeyCode::Char(ch) => {
|
||||
text.push(ch);
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
text.pop();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "Rust" fn _start() -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(async { main().await })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user