mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 07:45:28 +00:00
alloc user to access kernel backed heap (psram, if equiped)
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -20,8 +20,6 @@ dependencies = [
|
||||
"embedded-graphics",
|
||||
"embedded-sdmmc",
|
||||
"rand_core 0.9.3",
|
||||
"spin 0.10.0",
|
||||
"talc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1039,6 +1037,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "embedded-snake"
|
||||
version = "0.0.3"
|
||||
source = "git+https://github.com/LegitCamper/embedded-snake-rs#3986819c55819283dc5c1e89717d2a2f52e9b161"
|
||||
dependencies = [
|
||||
"embedded-graphics",
|
||||
"rand_core 0.9.3",
|
||||
|
||||
@@ -7,6 +7,4 @@ edition = "2024"
|
||||
embedded-sdmmc = { version = "0.9.0", default-features = false }
|
||||
embedded-graphics = "0.8.1"
|
||||
abi_sys = { path = "../abi_sys" }
|
||||
talc = "4.4.3"
|
||||
spin = "0.10.0"
|
||||
rand_core = "0.9.3"
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
#![no_std]
|
||||
|
||||
pub use abi_sys::keyboard;
|
||||
use abi_sys::{RngRequest, keyboard::KeyEvent};
|
||||
use rand_core::RngCore;
|
||||
use talc::*;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
static mut ARENA: [u8; 10000] = [0; 10000];
|
||||
pub use abi_sys::keyboard;
|
||||
use abi_sys::{RngRequest, alloc, dealloc, keyboard::KeyEvent};
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use rand_core::RngCore;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
||||
Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) })
|
||||
.lock();
|
||||
static ALLOC: Alloc = Alloc;
|
||||
|
||||
struct Alloc;
|
||||
|
||||
unsafe impl GlobalAlloc for Alloc {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
alloc(layout.into())
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
dealloc(ptr, layout.into());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(msg: &str) {
|
||||
abi_sys::print(msg.as_ptr(), msg.len());
|
||||
|
||||
@@ -4,7 +4,8 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["alloc"]
|
||||
alloc = []
|
||||
defmt = ["dep:defmt"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,42 +1,89 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::alloc::Layout;
|
||||
|
||||
use embedded_graphics::{
|
||||
Pixel,
|
||||
pixelcolor::{Rgb565, raw::RawU16},
|
||||
prelude::{IntoStorage, Point},
|
||||
};
|
||||
use embedded_sdmmc::DirEntry;
|
||||
use strum::EnumIter;
|
||||
|
||||
pub const ABI_CALL_TABLE_COUNT: usize = 10;
|
||||
|
||||
#[derive(Clone, Copy, EnumIter)]
|
||||
#[repr(u8)]
|
||||
pub enum CallAbiTable {
|
||||
PrintString = 0,
|
||||
SleepMs = 1,
|
||||
GetMs = 2,
|
||||
LockDisplay = 3,
|
||||
DrawIter = 4,
|
||||
GetKey = 5,
|
||||
GenRand = 6,
|
||||
ListDir = 7,
|
||||
ReadFile = 8,
|
||||
FileLen = 9,
|
||||
}
|
||||
use strum::{EnumCount, EnumIter};
|
||||
|
||||
pub type EntryFn = fn();
|
||||
|
||||
pub const ABI_CALL_TABLE_COUNT: usize = 12;
|
||||
const _: () = assert!(ABI_CALL_TABLE_COUNT == CallTable::COUNT);
|
||||
|
||||
#[derive(Clone, Copy, EnumIter, EnumCount)]
|
||||
#[repr(u8)]
|
||||
pub enum CallTable {
|
||||
Alloc = 0,
|
||||
Dealloc = 1,
|
||||
PrintString = 2,
|
||||
SleepMs = 3,
|
||||
GetMs = 4,
|
||||
LockDisplay = 5,
|
||||
DrawIter = 6,
|
||||
GetKey = 7,
|
||||
GenRand = 8,
|
||||
ListDir = 9,
|
||||
ReadFile = 10,
|
||||
FileLen = 11,
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[unsafe(link_section = ".syscall_table")]
|
||||
pub static mut CALL_ABI_TABLE: [usize; ABI_CALL_TABLE_COUNT] = [0; ABI_CALL_TABLE_COUNT];
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[repr(C)]
|
||||
pub struct CLayout {
|
||||
size: usize,
|
||||
alignment: usize,
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Into<Layout> for CLayout {
|
||||
fn into(self) -> Layout {
|
||||
unsafe { Layout::from_size_align_unchecked(self.size, self.alignment) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl From<Layout> for CLayout {
|
||||
fn from(value: Layout) -> Self {
|
||||
Self {
|
||||
size: value.size(),
|
||||
alignment: value.align(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type AllocAbi = extern "C" fn(layout: CLayout) -> *mut u8;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn alloc(layout: CLayout) -> *mut u8 {
|
||||
let f: AllocAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::Alloc as usize]) };
|
||||
f(layout)
|
||||
}
|
||||
|
||||
pub type DeallocAbi = extern "C" fn(ptr: *mut u8, layout: CLayout);
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn dealloc(ptr: *mut u8, layout: CLayout) {
|
||||
let f: DeallocAbi =
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::Dealloc as usize]) };
|
||||
f(ptr, layout)
|
||||
}
|
||||
|
||||
pub type PrintAbi = extern "C" fn(ptr: *const u8, len: usize);
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn print(ptr: *const u8, len: usize) {
|
||||
let f: PrintAbi =
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::PrintString as usize]) };
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::PrintString as usize]) };
|
||||
f(ptr, len);
|
||||
}
|
||||
|
||||
@@ -45,7 +92,7 @@ pub type SleepMsAbi = extern "C" fn(ms: u64);
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn sleep(ms: u64) {
|
||||
let f: SleepMsAbi =
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::SleepMs as usize]) };
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::SleepMs as usize]) };
|
||||
f(ms);
|
||||
}
|
||||
|
||||
@@ -53,7 +100,7 @@ pub type GetMsAbi = extern "C" fn() -> u64;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn get_ms() -> u64 {
|
||||
let f: GetMsAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::GetMs as usize]) };
|
||||
let f: GetMsAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::GetMs as usize]) };
|
||||
f()
|
||||
}
|
||||
|
||||
@@ -62,7 +109,7 @@ pub type LockDisplay = extern "C" fn(lock: bool);
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn lock_display(lock: bool) {
|
||||
let f: LockDisplay =
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]) };
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::LockDisplay as usize]) };
|
||||
f(lock);
|
||||
}
|
||||
|
||||
@@ -105,12 +152,12 @@ pub type DrawIterAbi = extern "C" fn(ptr: *const CPixel, len: usize);
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn draw_iter(ptr: *const CPixel, len: usize) {
|
||||
let f: DrawIterAbi =
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::DrawIter as usize]) };
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::DrawIter as usize]) };
|
||||
f(ptr, len);
|
||||
}
|
||||
|
||||
pub mod keyboard {
|
||||
use crate::{CALL_ABI_TABLE, CallAbiTable};
|
||||
use crate::{CALL_ABI_TABLE, CallTable};
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
@@ -333,7 +380,7 @@ pub mod keyboard {
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn get_key() -> KeyEventC {
|
||||
let f: GetKeyAbi =
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::GetKey as usize]) };
|
||||
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallTable::GetKey as usize]) };
|
||||
f()
|
||||
}
|
||||
}
|
||||
@@ -350,7 +397,7 @@ pub type GenRand = extern "C" fn(req: &mut RngRequest);
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn gen_rand(req: &mut RngRequest) {
|
||||
unsafe {
|
||||
let ptr = CALL_ABI_TABLE[CallAbiTable::GenRand as usize];
|
||||
let ptr = CALL_ABI_TABLE[CallTable::GenRand as usize];
|
||||
let f: GenRand = core::mem::transmute(ptr);
|
||||
f(req)
|
||||
}
|
||||
@@ -371,7 +418,7 @@ pub extern "C" fn list_dir(
|
||||
file_len: usize,
|
||||
) -> usize {
|
||||
unsafe {
|
||||
let ptr = CALL_ABI_TABLE[CallAbiTable::ListDir as usize];
|
||||
let ptr = CALL_ABI_TABLE[CallTable::ListDir as usize];
|
||||
let f: ListDir = core::mem::transmute(ptr);
|
||||
f(str, len, files, file_len)
|
||||
}
|
||||
@@ -394,7 +441,7 @@ pub extern "C" fn read_file(
|
||||
buf_len: usize,
|
||||
) -> usize {
|
||||
unsafe {
|
||||
let ptr = CALL_ABI_TABLE[CallAbiTable::ReadFile as usize];
|
||||
let ptr = CALL_ABI_TABLE[CallTable::ReadFile as usize];
|
||||
let f: ReadFile = core::mem::transmute(ptr);
|
||||
f(str, len, read_from, buf, buf_len)
|
||||
}
|
||||
@@ -405,7 +452,7 @@ pub type FileLen = extern "C" fn(str: *const u8, len: usize) -> usize;
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn file_len(str: *const u8, len: usize) -> usize {
|
||||
unsafe {
|
||||
let ptr = CALL_ABI_TABLE[CallAbiTable::FileLen as usize];
|
||||
let ptr = CALL_ABI_TABLE[CallTable::FileLen as usize];
|
||||
let f: FileLen = core::mem::transmute(ptr);
|
||||
f(str, len)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use abi_sys::{
|
||||
CPixel, DrawIterAbi, FileLen, GenRand, GetMsAbi, ListDir, LockDisplay, PrintAbi, ReadFile,
|
||||
RngRequest, SleepMsAbi, keyboard::*,
|
||||
AllocAbi, CLayout, CPixel, DeallocAbi, DrawIterAbi, FileLen, GenRand, GetMsAbi, ListDir,
|
||||
LockDisplay, PrintAbi, ReadFile, RngRequest, SleepMsAbi, keyboard::*,
|
||||
};
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use core::sync::atomic::Ordering;
|
||||
@@ -15,6 +15,18 @@ use crate::{
|
||||
storage::{Dir, File, SDCARD},
|
||||
};
|
||||
|
||||
const _: AllocAbi = alloc;
|
||||
pub extern "C" fn alloc(layout: CLayout) -> *mut u8 {
|
||||
// SAFETY: caller guarantees layout is valid
|
||||
unsafe { alloc::alloc::alloc(layout.into()) }
|
||||
}
|
||||
|
||||
const _: DeallocAbi = dealloc;
|
||||
pub extern "C" fn dealloc(ptr: *mut u8, layout: CLayout) {
|
||||
// SAFETY: caller guarantees ptr and layout are valid
|
||||
unsafe { alloc::alloc::dealloc(ptr, layout.into()) };
|
||||
}
|
||||
|
||||
const _: PrintAbi = print;
|
||||
pub extern "C" fn print(ptr: *const u8, len: usize) {
|
||||
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
|
||||
|
||||
@@ -21,7 +21,7 @@ type DISPLAY = ST7365P<
|
||||
pub const SCREEN_WIDTH: usize = 320;
|
||||
pub const SCREEN_HEIGHT: usize = 320;
|
||||
|
||||
pub static mut FRAMEBUFFER: AtomicFrameBuffer = AtomicFrameBuffer::new();
|
||||
pub static mut FRAMEBUFFER: AtomicFrameBuffer = AtomicFrameBuffer;
|
||||
pub static FB_PAUSED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub async fn init_display(
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{
|
||||
abi,
|
||||
storage::{File, SDCARD},
|
||||
};
|
||||
use abi_sys::CallAbiTable;
|
||||
use abi_sys::CallTable;
|
||||
use abi_sys::EntryFn;
|
||||
use alloc::{vec, vec::Vec};
|
||||
use bumpalo::Bump;
|
||||
@@ -194,18 +194,20 @@ fn patch_abi(
|
||||
unsafe { base.add((sym.st_value as usize) - min_vaddr as usize) }
|
||||
as *mut usize;
|
||||
|
||||
for (idx, call) in CallAbiTable::iter().enumerate() {
|
||||
for (idx, call) in CallTable::iter().enumerate() {
|
||||
let ptr = match call {
|
||||
CallAbiTable::PrintString => abi::print as usize,
|
||||
CallAbiTable::SleepMs => abi::sleep as usize,
|
||||
CallAbiTable::GetMs => abi::get_ms as usize,
|
||||
CallAbiTable::LockDisplay => abi::lock_display as usize,
|
||||
CallAbiTable::DrawIter => abi::draw_iter as usize,
|
||||
CallAbiTable::GetKey => abi::get_key as usize,
|
||||
CallAbiTable::GenRand => abi::gen_rand as usize,
|
||||
CallAbiTable::ListDir => abi::list_dir as usize,
|
||||
CallAbiTable::ReadFile => abi::read_file as usize,
|
||||
CallAbiTable::FileLen => abi::file_len as usize,
|
||||
CallTable::Alloc => abi::alloc as usize,
|
||||
CallTable::Dealloc => abi::dealloc as usize,
|
||||
CallTable::PrintString => abi::print as usize,
|
||||
CallTable::SleepMs => abi::sleep as usize,
|
||||
CallTable::GetMs => abi::get_ms as usize,
|
||||
CallTable::LockDisplay => abi::lock_display as usize,
|
||||
CallTable::DrawIter => abi::draw_iter as usize,
|
||||
CallTable::GetKey => abi::get_key as usize,
|
||||
CallTable::GenRand => abi::gen_rand as usize,
|
||||
CallTable::ListDir => abi::list_dir as usize,
|
||||
CallTable::ReadFile => abi::read_file as usize,
|
||||
CallTable::FileLen => abi::file_len as usize,
|
||||
};
|
||||
unsafe {
|
||||
table_base.add(idx as usize).write(ptr);
|
||||
|
||||
@@ -241,19 +241,21 @@ async fn setup_display(display: Display, spawner: Spawner) {
|
||||
spawner.spawn(display_handler(display)).unwrap();
|
||||
}
|
||||
|
||||
// psram is kind of useless on the pico calc
|
||||
// ive opted to use the pimoroni with on onboard xip psram instead
|
||||
async fn setup_psram(psram: Psram) {
|
||||
let psram = init_psram(
|
||||
psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2,
|
||||
)
|
||||
.await;
|
||||
// let psram = init_psram(
|
||||
// psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2,
|
||||
// )
|
||||
// .await;
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
defmt::info!("psram size: {}", psram.size);
|
||||
// #[cfg(feature = "defmt")]
|
||||
// defmt::info!("psram size: {}", psram.size);
|
||||
|
||||
if psram.size == 0 {
|
||||
#[cfg(feature = "defmt")]
|
||||
defmt::info!("\u{1b}[1mExternal PSRAM was NOT found!\u{1b}[0m");
|
||||
}
|
||||
// if psram.size == 0 {
|
||||
// #[cfg(feature = "defmt")]
|
||||
// defmt::info!("\u{1b}[1mExternal PSRAM was NOT found!\u{1b}[0m");
|
||||
// }
|
||||
|
||||
#[cfg(feature = "pimoroni2w")]
|
||||
{
|
||||
@@ -291,6 +293,7 @@ async fn kernel_task(
|
||||
setup_mcu(mcu).await;
|
||||
Timer::after_millis(250).await;
|
||||
setup_display(display, spawner).await;
|
||||
#[cfg(feature = "pimoroni2w")]
|
||||
setup_psram(psram).await;
|
||||
setup_sd(sd).await;
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
extern crate alloc;
|
||||
use abi::{
|
||||
display::{Display, lock_display},
|
||||
fs::read_file,
|
||||
fs::{file_len, read_file},
|
||||
get_key, get_ms,
|
||||
keyboard::{KeyCode, KeyState},
|
||||
print, sleep,
|
||||
};
|
||||
use alloc::format;
|
||||
use alloc::{format, vec::Vec};
|
||||
use core::panic::PanicInfo;
|
||||
use embedded_graphics::{image::ImageDrawable, pixelcolor::Rgb565};
|
||||
use tinygif::{Gif, Header};
|
||||
use tinygif::Gif;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
@@ -33,19 +33,20 @@ pub fn main() {
|
||||
print("Starting Gif app");
|
||||
let mut display = Display;
|
||||
|
||||
static mut BUF: [u8; 256] = [0_u8; 256];
|
||||
let size = file_len("/gifs/bad_apple.gif");
|
||||
let mut buf = Vec::with_capacity(size);
|
||||
let read = read_file("/gifs/bad_apple.gif", 0, &mut buf);
|
||||
assert!(read == size);
|
||||
|
||||
read_file("/gif/bad_apple.gif", 0, unsafe { &mut BUF[0..6] });
|
||||
|
||||
let gif_header = Header::parse(unsafe { &BUF[0..6] });
|
||||
|
||||
let image = Gif::<Rgb565>::from_slice().unwrap();
|
||||
let gif = Gif::<Rgb565>::from_slice(&buf).unwrap();
|
||||
|
||||
loop {
|
||||
for frame in image.frames() {
|
||||
for frame in gif.frames() {
|
||||
let start = get_ms();
|
||||
|
||||
lock_display(true);
|
||||
frame.draw(&mut display).unwrap();
|
||||
lock_display(false);
|
||||
|
||||
sleep(((frame.delay_centis as u64) * 10).saturating_sub(start));
|
||||
|
||||
@@ -56,9 +57,6 @@ pub fn main() {
|
||||
_ => (),
|
||||
};
|
||||
};
|
||||
|
||||
lock_display(true);
|
||||
lock_display(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ edition = "2024"
|
||||
[dependencies]
|
||||
abi = { path = "../../abi" }
|
||||
embedded-graphics = "0.8.1"
|
||||
embedded-snake = { path = "../../../embedded-snake-rs" }
|
||||
embedded-snake = { git = "https://github.com/LegitCamper/embedded-snake-rs" }
|
||||
rand = { version = "0.9.0", default-features = false }
|
||||
|
||||
Reference in New Issue
Block a user