wip dynamic loading

This commit is contained in:
2025-09-05 17:27:15 -06:00
parent e2ff3740f3
commit 8dad3ce6bb
6 changed files with 110 additions and 28 deletions

View File

@@ -3,7 +3,16 @@ resolver = "3"
members = ["kernel", "abi", "shared", "user-apps/calculator"]
[profile.release]
debug = 2
debug = true
opt-level = "z"
lto = true
codegen-units = 1
[profile.release-binary]
inherits = "release"
lto = true
debug = false
opt-level = "s"
[profile.dev]
lto = true

View File

@@ -1,4 +1,4 @@
kernel: calculator
cargo run --bin kernel
calculator:
RUSTFLAGS="-C link-arg=--noinhibit-exec" cargo build --bin calculator --release
RUSTFLAGS="-C link-arg=--noinhibit-exec" cargo build --bin calculator --profile release-binary

View File

@@ -1,7 +1,7 @@
#![allow(static_mut_refs)]
use crate::abi;
use crate::{abi, storage::SDCARD};
use abi_sys::{CallAbiTable, EntryFn};
use alloc::boxed::Box;
use alloc::{boxed::Box, vec::Vec};
use core::{
alloc::Layout,
ffi::c_void,
@@ -10,8 +10,43 @@ use core::{
slice::from_raw_parts_mut,
task::{Context, Poll},
};
use embedded_sdmmc::ShortFileName;
use goblin::elf::{Elf, header::ET_DYN, program_header::PT_LOAD, sym};
pub async fn read_binary(name: &ShortFileName) -> Option<Vec<u8>> {
let mut guard = SDCARD.get().lock().await;
let sd = guard.as_mut()?;
let mut buf = Vec::new();
defmt::info!("sd closure");
sd.access_root_dir(|root_dir| {
// Try to open the file directly by name
defmt::info!("trying to open file: {:?}", name);
if let Ok(file) = root_dir.open_file_in_dir(name, embedded_sdmmc::Mode::ReadOnly) {
defmt::info!("opened");
let mut temp = [0u8; 512];
defmt::info!("caching binary");
loop {
match file.read(&mut temp) {
Ok(n) if n > 0 => buf.extend_from_slice(&temp[..n]),
_ => break,
}
}
defmt::info!("done");
let _ = file.close();
}
});
if buf.is_empty() {
return None;
}
Some(buf)
}
// userland ram region defined in memory.x
unsafe extern "C" {
static __userapp_start__: u8;

View File

@@ -30,6 +30,7 @@ use crate::{
ui::{SELECTIONS, ui_handler},
usb::usb_handler,
};
use abi_sys::EntryFn;
use alloc::vec::Vec;
use {defmt_rtt as _, panic_probe as _};
@@ -48,7 +49,7 @@ use embassy_rp::{
spi::{self, Spi},
usb as embassy_rp_usb,
};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, mutex::Mutex};
use embassy_time::{Delay, Timer};
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::SdCard as SdmmcSdCard;
@@ -66,7 +67,7 @@ static mut CORE1_STACK: Stack<16384> = Stack::new();
static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
static mut ARENA: [u8; 10000] = [0; 10000];
static mut ARENA: [u8; 10 * 1024] = [0; 10 * 1024];
#[global_allocator]
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
@@ -121,19 +122,30 @@ async fn main(_spawner: Spawner) {
executor0.run(|spawner| unwrap!(spawner.spawn(kernel_task(display, sd, mcu, p.USB))));
}
// One-slot channel to pass EntryFn from core1
static BINARY_CH: Channel<CriticalSectionRawMutex, EntryFn, 1> = Channel::new();
// runs dynamically loaded elf files
#[embassy_executor::task]
async fn userland_task() {
// DRIVERS_READY.wait().await;
let recv = BINARY_CH.receiver();
loop {
let entry = recv.receive().await;
// defmt::info!("Loading binary");
// let binary_data: &[u8] =
// include_bytes!("../../target/thumbv8m.main-none-eabihf/release/calculator");
// disable kernel ui
{
let mut state = TASK_STATE.lock().await;
*state = TaskState::Kernel;
}
// defmt::info!("Running binary");
// let entry = unsafe { load_binary(binary_data).unwrap() };
entry().await;
// entry().await;
// enable kernel ui
{
let mut state = TASK_STATE.lock().await;
*state = TaskState::Ui;
}
}
}
struct Display {
@@ -224,8 +236,8 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
SDCARD.get().lock().await.replace(SdCard::new(sdcard, det));
};
let usb = embassy_rp_usb::Driver::new(usb, Irqs);
let usb_fut = usb_handler(usb);
// let usb = embassy_rp_usb::Driver::new(usb, Irqs);
// let usb_fut = usb_handler(usb);
let key_abi_fut = async {
loop {

View File

@@ -8,11 +8,11 @@ use embassy_sync::lazy_lock::LazyLock;
use embassy_sync::mutex::Mutex;
use embassy_time::Delay;
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::LfnBuffer;
use embedded_sdmmc::{
Block, BlockCount, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource,
Timestamp, Volume, VolumeIdx, VolumeManager, sdcard::Error,
};
use embedded_sdmmc::{LfnBuffer, ShortFileName};
pub const MAX_DIRS: usize = 4;
pub const MAX_FILES: usize = 5;
@@ -34,6 +34,12 @@ impl TimeSource for DummyTimeSource {
}
}
#[derive(Clone, PartialEq)]
pub struct FileName {
pub long_name: String,
pub short_name: ShortFileName,
}
pub struct SdCard {
det: Input<'static>,
volume_mgr: VolMgr,
@@ -100,7 +106,7 @@ impl SdCard {
res.map_err(|_| ())
}
fn access_root_dir(&mut self, mut access: impl FnMut(Dir)) {
pub fn access_root_dir(&mut self, mut access: impl FnMut(Dir)) {
let volume0 = self.volume_mgr.open_volume(VolumeIdx(0)).unwrap();
let root_dir = volume0.open_root_dir().unwrap();
@@ -108,7 +114,7 @@ impl SdCard {
}
/// Returns a Vec of file names (long format) that match the given extension (e.g., "BIN")
pub fn list_files_by_extension(&mut self, ext: &str) -> Result<Vec<String>, ()> {
pub fn list_files_by_extension(&mut self, ext: &str) -> Result<Vec<FileName>, ()> {
let mut result = Vec::new();
// Only proceed if card is inserted
@@ -120,11 +126,14 @@ impl SdCard {
let mut lfn_buffer = LfnBuffer::new(&mut lfn_storage);
self.access_root_dir(|dir| {
dir.iterate_dir_lfn(&mut lfn_buffer, |_entry, name| {
dir.iterate_dir_lfn(&mut lfn_buffer, |entry, name| {
if let Some(name) = name {
let name = String::from_str(name).unwrap();
if name.contains(ext) {
result.push(name);
result.push(FileName {
long_name: name,
short_name: entry.name.clone(),
});
}
}
})

View File

@@ -1,8 +1,9 @@
use crate::{
TASK_STATE, TaskState,
BINARY_CH, TASK_STATE, TaskState,
display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH},
format,
peripherals::keyboard,
storage::FileName,
usb::RESTART_USB,
};
use alloc::{string::String, vec::Vec};
@@ -43,7 +44,7 @@ use embedded_text::TextBox;
use shared::keyboard::{KeyCode, KeyState};
pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
Mutex::new(SelectionList::new(Vec::new()));
Mutex::new(SelectionList::new());
pub async fn ui_handler() {
loop {
@@ -59,7 +60,22 @@ pub async fn ui_handler() {
let mut selections = SELECTIONS.lock().await;
selections.down();
}
KeyCode::Enter | KeyCode::JoyRight => (),
KeyCode::Enter | KeyCode::JoyRight => {
let selections = SELECTIONS.lock().await;
let selection = selections.selections
[selections.current_selection as usize - 1]
.clone();
defmt::info!(
"loading selected binary: {:?}",
&selection.long_name.as_str()
);
let bytes = crate::elf::read_binary(&selection.short_name)
.await
.unwrap();
let entry = unsafe { crate::elf::load_binary(&bytes).unwrap() };
BINARY_CH.send(entry).await;
}
_ => (),
}
}
@@ -71,7 +87,7 @@ pub async fn ui_handler() {
}
async fn draw_selection() {
let file_names: Vec<String> = {
let file_names: Vec<FileName> = {
let guard = SELECTIONS.lock().await;
guard.selections.clone()
};
@@ -104,7 +120,7 @@ async fn draw_selection() {
return;
};
let chain = Chain::new(Text::new(first, Point::zero(), text_style));
let chain = Chain::new(Text::new(&first.long_name, Point::zero(), text_style));
// for _ in 0..file_names.len() {
// let chain = chain.append(Text::new(
@@ -124,15 +140,16 @@ async fn draw_selection() {
}
}
#[derive(Clone)]
pub struct SelectionList {
current_selection: u16,
pub selections: Vec<String>,
pub selections: Vec<FileName>,
}
impl SelectionList {
pub const fn new(selections: Vec<String>) -> Self {
pub const fn new() -> Self {
Self {
selections,
selections: Vec::new(),
current_selection: 0,
}
}