can run entrypoint on user elf

syscalls via call_abi are still not working
This commit is contained in:
2025-08-03 18:55:26 -06:00
parent aa00e9728d
commit 6dcdd88a0f
10 changed files with 193 additions and 83 deletions

87
Cargo.lock generated
View File

@@ -422,17 +422,6 @@ dependencies = [
"defmt 0.3.100", "defmt 0.3.100",
] ]
[[package]]
name = "delegate"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6178a82cf56c836a3ba61a7935cdb1c49bfaa6fa4327cd5bf554a503087de26b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "diff" name = "diff"
version = "0.1.13" version = "0.1.13"
@@ -485,26 +474,6 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "elf"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
[[package]]
name = "elf_loader"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30a0da8db95cff71e500b3d7015c2441a4eb628e0df788b23d1b8d1243314342"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
"delegate",
"elf",
"portable-atomic",
"portable-atomic-util",
]
[[package]] [[package]]
name = "embassy-embedded-hal" name = "embassy-embedded-hal"
version = "0.3.1" version = "0.3.1"
@@ -662,7 +631,6 @@ dependencies = [
"nb 1.1.0", "nb 1.1.0",
"pio 0.3.0", "pio 0.3.0",
"rand_core", "rand_core",
"rp-binary-info",
"rp-pac", "rp-pac",
"rp2040-boot2", "rp2040-boot2",
"sha2-const-stable", "sha2-const-stable",
@@ -1065,6 +1033,17 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "goblin"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e961b33649994dcf69303af6b3a332c1228549e604d455d61ec5d2ab5e68d3a"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]] [[package]]
name = "half" name = "half"
version = "2.6.0" version = "2.6.0"
@@ -1456,13 +1435,13 @@ dependencies = [
"abi", "abi",
"bitflags 2.9.1", "bitflags 2.9.1",
"bt-hci", "bt-hci",
"bumpalo",
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"cyw43", "cyw43",
"cyw43-pio", "cyw43-pio",
"defmt 0.3.100", "defmt 0.3.100",
"defmt-rtt", "defmt-rtt",
"elf_loader",
"embassy-embedded-hal", "embassy-embedded-hal",
"embassy-executor", "embassy-executor",
"embassy-futures", "embassy-futures",
@@ -1476,6 +1455,7 @@ dependencies = [
"embedded-hal-bus", "embedded-hal-bus",
"embedded-layout", "embedded-layout",
"embedded-sdmmc", "embedded-sdmmc",
"goblin",
"heapless", "heapless",
"num_enum 0.7.4", "num_enum 0.7.4",
"panic-probe", "panic-probe",
@@ -1588,6 +1568,12 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]] [[package]]
name = "portable-atomic" name = "portable-atomic"
version = "1.11.1" version = "1.11.1"
@@ -1597,15 +1583,6 @@ dependencies = [
"critical-section", "critical-section",
] ]
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]] [[package]]
name = "precomputed-hash" name = "precomputed-hash"
version = "0.1.1" version = "0.1.1"
@@ -1752,12 +1729,6 @@ dependencies = [
"bytemuck", "bytemuck",
] ]
[[package]]
name = "rp-binary-info"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ed2051a0bf2c726df01cfce378ed8a367be2a6e402fc183857f429a346d429"
[[package]] [[package]]
name = "rp-pac" name = "rp-pac"
version = "7.0.0" version = "7.0.0"
@@ -1807,6 +1778,26 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scroll"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc4f90c27b57691bbaf11d8ecc7cfbfe98a4da6dbe60226115d322aa80c06e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "0.9.0" version = "0.9.0"

View File

@@ -3,9 +3,8 @@
use core::ffi::c_void; use core::ffi::c_void;
use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
unsafe extern "C" { #[unsafe(no_mangle)]
fn call_abi(call: *const Syscall); pub unsafe fn call_abi(_call: *const Syscall) {}
}
#[repr(C)] #[repr(C)]
pub enum Syscall { pub enum Syscall {

View File

@@ -41,7 +41,6 @@ embassy-rp = { version = "0.4.0", features = [
"critical-section-impl", "critical-section-impl",
"unstable-pac", "unstable-pac",
"time-driver", "time-driver",
"binary-info",
] } ] }
embassy-usb = "0.4.0" embassy-usb = "0.4.0"
embassy-futures = "0.1.1" embassy-futures = "0.1.1"
@@ -77,11 +76,12 @@ embedded-layout = "0.4.2"
static_cell = "2.1.1" static_cell = "2.1.1"
bitflags = "2.9.1" bitflags = "2.9.1"
talc = "4.4.3"
spin = "0.10.0"
heapless = "0.8.0" heapless = "0.8.0"
num_enum = { version = "0.7.4", default-features = false } num_enum = { version = "0.7.4", default-features = false }
elf_loader = {version ="0.12.0", default-features = false, features = ["portable-atomic"]} goblin = { version = "0.10.0", default-features = false, features = ["elf32", "elf64", "alloc", "endian_fd"] }
bumpalo = "3.19.0"
talc = "4.4.3"
spin = "0.10.0"
shared = { path = "../shared" } shared = { path = "../shared" }
abi = { path = "../abi" } abi = { path = "../abi" }

View File

@@ -19,7 +19,7 @@ fn main() {
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x")) File::create(out.join("memory.x"))
.unwrap() .unwrap()
.write_all(include_bytes!("../memory.x")) .write_all(include_bytes!("memory.x"))
.unwrap(); .unwrap();
println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rustc-link-search={}", out.display());

View File

@@ -1,4 +1,5 @@
use abi::Syscall; use abi::Syscall;
use defmt::info;
use embassy_futures::block_on; use embassy_futures::block_on;
use embedded_graphics::{ use embedded_graphics::{
Drawable, Drawable,
@@ -9,8 +10,9 @@ use embedded_graphics::{
use crate::display::FRAMEBUFFER; use crate::display::FRAMEBUFFER;
#[unsafe(no_mangle)] #[allow(unused)]
pub extern "C" fn call_abi(call: *const Syscall) { pub fn call_abi(call: *const Syscall) {
info!("called abi");
let call = unsafe { &*call }; let call = unsafe { &*call };
match call { match call {
Syscall::DrawPixel { x, y, color } => { Syscall::DrawPixel { x, y, color } => {
@@ -20,6 +22,7 @@ pub extern "C" fn call_abi(call: *const Syscall) {
} }
fn draw_pixel(x: u32, y: u32, color: u16) { fn draw_pixel(x: u32, y: u32, color: u16) {
info!("draw pixel abi called");
let framebuffer = block_on(FRAMEBUFFER.lock()); let framebuffer = block_on(FRAMEBUFFER.lock());
Rectangle::new(Point::new(x as i32, y as i32), Size::new(1, 1)) Rectangle::new(Point::new(x as i32, y as i32), Size::new(1, 1))
.draw_styled( .draw_styled(

85
kernel/src/elf.rs Normal file
View File

@@ -0,0 +1,85 @@
#![allow(static_mut_refs)]
use abi::Syscall;
use bumpalo::Bump;
use core::{alloc::Layout, ffi::c_void, ptr::NonNull, slice::from_raw_parts_mut};
use goblin::{
elf::{Elf, header::ET_DYN, program_header::PT_LOAD, sym},
elf32,
};
use crate::abi::call_abi;
pub fn load_elf(elf_bytes: &[u8], bump: &mut Bump) -> Result<extern "C" fn() -> !, ()> {
let elf = Elf::parse(elf_bytes).map_err(|_| ())?;
if elf.is_64
|| elf.is_lib
|| elf.is_object_file()
|| !elf.little_endian
|| elf.header.e_type != ET_DYN
|| elf.interpreter.is_some()
{
return Err(());
}
// Find base address (lowest virtual address of PT_LOAD segments)
let base_vaddr = elf
.program_headers
.iter()
.filter(|ph| ph.p_type == PT_LOAD)
.map(|ph| ph.p_vaddr)
.min()
.ok_or(())?;
// Determine total memory needed for all PT_LOAD segments
let total_size = elf
.program_headers
.iter()
.filter(|ph| ph.p_type == PT_LOAD)
.map(|ph| {
let start = ph.p_vaddr;
let end = ph.p_vaddr + ph.p_memsz;
end - base_vaddr
})
.max()
.unwrap_or(0) as usize;
// Allocate one big block from the bump heap
let layout = Layout::from_size_align(total_size, 0x1000).map_err(|_| ())?;
let base_ptr = bump.alloc_layout(layout).as_ptr();
for ph in &elf.program_headers {
if ph.p_type != PT_LOAD {
continue;
}
let file_offset = ph.p_offset as usize;
let file_size = ph.p_filesz as usize;
let mem_size = ph.p_memsz as usize;
let virt_offset = (ph.p_vaddr - base_vaddr) as usize;
let src = &elf_bytes[file_offset..file_offset + file_size];
let dst = unsafe { base_ptr.add(virt_offset) };
unsafe {
core::ptr::copy_nonoverlapping(src.as_ptr(), dst, file_size);
if mem_size > file_size {
core::ptr::write_bytes(dst.add(file_size), 0, mem_size - file_size);
}
}
}
// Patch `call_abi` symbol
for sym in elf.syms.iter() {
let name = elf.strtab.get_at(sym.st_name).ok_or(())?;
if name == "call_abi" && sym.st_bind() == sym::STB_GLOBAL {
let offset = (sym.st_value - base_vaddr) as usize;
let ptr = unsafe { base_ptr.add(offset) as *mut usize };
unsafe { *ptr = call_abi as usize };
}
}
// Compute relocated entry point
let relocated_entry = unsafe { base_ptr.add((elf.entry - base_vaddr) as usize) };
Ok(unsafe { core::mem::transmute(relocated_entry) })
}

View File

@@ -5,6 +5,7 @@
mod abi; mod abi;
mod display; mod display;
mod elf;
mod peripherals; mod peripherals;
mod scsi; mod scsi;
mod storage; mod storage;
@@ -14,6 +15,7 @@ mod utils;
use crate::{ use crate::{
display::{display_handler, init_display}, display::{display_handler, init_display},
elf::load_elf,
peripherals::{ peripherals::{
conf_peripherals, conf_peripherals,
keyboard::{KeyCode, KeyState, read_keyboard_fifo}, keyboard::{KeyCode, KeyState, read_keyboard_fifo},
@@ -22,24 +24,10 @@ use crate::{
usb::{ENABLE_SCSI, usb_handler}, usb::{ENABLE_SCSI, usb_handler},
}; };
use defmt::unwrap;
use elf_loader::{
Loader, load_exec,
mmap::MmapImpl,
object::{ElfBinary, ElfObject},
};
use static_cell::StaticCell;
use talc::*;
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();
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
use bumpalo::Bump;
use defmt::unwrap;
use embassy_executor::{Executor, Spawner}; use embassy_executor::{Executor, Spawner};
use embassy_futures::join::join; use embassy_futures::join::join;
use embassy_rp::{ use embassy_rp::{
@@ -56,16 +44,25 @@ use embassy_rp::{
use embassy_time::{Delay, Timer}; use embassy_time::{Delay, Timer};
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::SdCard as SdmmcSdCard; use embedded_sdmmc::SdCard as SdmmcSdCard;
use static_cell::StaticCell;
use talc::*;
embassy_rp::bind_interrupts!(struct Irqs { embassy_rp::bind_interrupts!(struct Irqs {
I2C1_IRQ => i2c::InterruptHandler<I2C1>; I2C1_IRQ => i2c::InterruptHandler<I2C1>;
USBCTRL_IRQ => embassy_rp_usb::InterruptHandler<USB>; USBCTRL_IRQ => embassy_rp_usb::InterruptHandler<USB>;
}); });
static mut CORE1_STACK: Stack<4096> = Stack::new(); static mut CORE1_STACK: Stack<16384> = Stack::new();
static EXECUTOR0: StaticCell<Executor> = StaticCell::new(); static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
static mut ARENA: [u8; 50_000] = [0; 50_000];
#[global_allocator]
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) })
.lock();
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
@@ -110,12 +107,14 @@ async fn main(_spawner: Spawner) {
// runs dynamically loaded elf files // runs dynamically loaded elf files
#[embassy_executor::task] #[embassy_executor::task]
async fn userland_task() { async fn userland_task() {
let binary_data: &[u8] = include_bytes!("../../example.bin"); let mut bump = Bump::with_capacity(25_000);
let bin = load_exec!("example", binary_data).unwrap();
let entry = bin.entry();
let entry_fn: extern "C" fn() = unsafe { core::mem::transmute(entry) }; let binary_data: &[u8] =
entry_fn(); // jump into user code include_bytes!("../../target/thumbv8m.main-none-eabihf/debug/calculator");
let entry = load_elf(binary_data, &mut bump).unwrap();
entry();
bump.reset(); // clear heap arena
} }
struct Display { struct Display {

View File

@@ -1,14 +1,26 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use abi::{Syscall, call_abi};
use core::panic::PanicInfo; use core::panic::PanicInfo;
#[panic_handler] #[panic_handler]
fn panic(_info: &PanicInfo) -> ! { fn panic(_info: &PanicInfo) -> ! {
loop {} // or call your ABI trap, or `abort()` loop {}
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
fn main() { pub extern "C" fn _start() -> ! {
loop {} loop {
for i in 0..300 {
for o in 0..300 {
let call = Syscall::DrawPixel {
x: i,
y: o,
color: 0,
};
unsafe { call_abi(&call) };
}
}
}
} }

21
user-apps/link.x Normal file
View File

@@ -0,0 +1,21 @@
MEMORY
{
RAM : ORIGIN = 0x00000000, LENGTH = 256K
}
SECTIONS
{
.text : {
*(.text .text.*);
*(.rodata .rodata.*);
} > RAM
.data : {
*(.data .data.*);
} > RAM
.bss : {
*(.bss .bss.*);
*(COMMON);
} > RAM
}