WIP keyboard syscall
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user