From 6dcdd88a0feb74cc25c92a2bec0089525685de1a Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Sun, 3 Aug 2025 18:55:26 -0600 Subject: [PATCH] can run entrypoint on user elf syscalls via call_abi are still not working --- Cargo.lock | 87 ++++++++++++++------------------ abi/src/lib.rs | 5 +- kernel/Cargo.toml | 8 +-- kernel/build.rs | 2 +- memory.x => kernel/memory.x | 0 kernel/src/abi.rs | 7 ++- kernel/src/elf.rs | 85 +++++++++++++++++++++++++++++++ kernel/src/main.rs | 43 ++++++++-------- user-apps/calculator/src/main.rs | 18 +++++-- user-apps/link.x | 21 ++++++++ 10 files changed, 193 insertions(+), 83 deletions(-) rename memory.x => kernel/memory.x (100%) create mode 100644 kernel/src/elf.rs create mode 100644 user-apps/link.x diff --git a/Cargo.lock b/Cargo.lock index de4d866..8d737a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -422,17 +422,6 @@ dependencies = [ "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]] name = "diff" version = "0.1.13" @@ -485,26 +474,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "embassy-embedded-hal" version = "0.3.1" @@ -662,7 +631,6 @@ dependencies = [ "nb 1.1.0", "pio 0.3.0", "rand_core", - "rp-binary-info", "rp-pac", "rp2040-boot2", "sha2-const-stable", @@ -1065,6 +1033,17 @@ dependencies = [ "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]] name = "half" version = "2.6.0" @@ -1456,13 +1435,13 @@ dependencies = [ "abi", "bitflags 2.9.1", "bt-hci", + "bumpalo", "cortex-m", "cortex-m-rt", "cyw43", "cyw43-pio", "defmt 0.3.100", "defmt-rtt", - "elf_loader", "embassy-embedded-hal", "embassy-executor", "embassy-futures", @@ -1476,6 +1455,7 @@ dependencies = [ "embedded-hal-bus", "embedded-layout", "embedded-sdmmc", + "goblin", "heapless", "num_enum 0.7.4", "panic-probe", @@ -1588,6 +1568,12 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "portable-atomic" version = "1.11.1" @@ -1597,15 +1583,6 @@ dependencies = [ "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]] name = "precomputed-hash" version = "0.1.1" @@ -1752,12 +1729,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "rp-binary-info" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ed2051a0bf2c726df01cfce378ed8a367be2a6e402fc183857f429a346d429" - [[package]] name = "rp-pac" version = "7.0.0" @@ -1807,6 +1778,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "semver" version = "0.9.0" diff --git a/abi/src/lib.rs b/abi/src/lib.rs index 398e386..b39cd25 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -3,9 +3,8 @@ use core::ffi::c_void; use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; -unsafe extern "C" { - fn call_abi(call: *const Syscall); -} +#[unsafe(no_mangle)] +pub unsafe fn call_abi(_call: *const Syscall) {} #[repr(C)] pub enum Syscall { diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 39dcdca..d6d0173 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -41,7 +41,6 @@ embassy-rp = { version = "0.4.0", features = [ "critical-section-impl", "unstable-pac", "time-driver", - "binary-info", ] } embassy-usb = "0.4.0" embassy-futures = "0.1.1" @@ -77,11 +76,12 @@ embedded-layout = "0.4.2" static_cell = "2.1.1" bitflags = "2.9.1" -talc = "4.4.3" -spin = "0.10.0" heapless = "0.8.0" 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" } abi = { path = "../abi" } diff --git a/kernel/build.rs b/kernel/build.rs index e0ded4a..30691aa 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -19,7 +19,7 @@ fn main() { let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("memory.x")) .unwrap() - .write_all(include_bytes!("../memory.x")) + .write_all(include_bytes!("memory.x")) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); diff --git a/memory.x b/kernel/memory.x similarity index 100% rename from memory.x rename to kernel/memory.x diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 8bb55ec..5eba4df 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -1,4 +1,5 @@ use abi::Syscall; +use defmt::info; use embassy_futures::block_on; use embedded_graphics::{ Drawable, @@ -9,8 +10,9 @@ use embedded_graphics::{ use crate::display::FRAMEBUFFER; -#[unsafe(no_mangle)] -pub extern "C" fn call_abi(call: *const Syscall) { +#[allow(unused)] +pub fn call_abi(call: *const Syscall) { + info!("called abi"); let call = unsafe { &*call }; match call { 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) { + info!("draw pixel abi called"); let framebuffer = block_on(FRAMEBUFFER.lock()); Rectangle::new(Point::new(x as i32, y as i32), Size::new(1, 1)) .draw_styled( diff --git a/kernel/src/elf.rs b/kernel/src/elf.rs new file mode 100644 index 0000000..13943f2 --- /dev/null +++ b/kernel/src/elf.rs @@ -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 !, ()> { + 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) }) +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index fb64a01..d0b34f5 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -5,6 +5,7 @@ mod abi; mod display; +mod elf; mod peripherals; mod scsi; mod storage; @@ -14,6 +15,7 @@ mod utils; use crate::{ display::{display_handler, init_display}, + elf::load_elf, peripherals::{ conf_peripherals, keyboard::{KeyCode, KeyState, read_keyboard_fifo}, @@ -22,24 +24,10 @@ use crate::{ 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, 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 bumpalo::Bump; +use defmt::unwrap; use embassy_executor::{Executor, Spawner}; use embassy_futures::join::join; use embassy_rp::{ @@ -56,16 +44,25 @@ use embassy_rp::{ use embassy_time::{Delay, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_sdmmc::SdCard as SdmmcSdCard; +use static_cell::StaticCell; +use talc::*; embassy_rp::bind_interrupts!(struct Irqs { I2C1_IRQ => i2c::InterruptHandler; USBCTRL_IRQ => embassy_rp_usb::InterruptHandler; }); -static mut CORE1_STACK: Stack<4096> = Stack::new(); +static mut CORE1_STACK: Stack<16384> = Stack::new(); static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); +static mut ARENA: [u8; 50_000] = [0; 50_000]; + +#[global_allocator] +static ALLOCATOR: Talck, ClaimOnOom> = + Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) }) + .lock(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -110,12 +107,14 @@ async fn main(_spawner: Spawner) { // runs dynamically loaded elf files #[embassy_executor::task] async fn userland_task() { - let binary_data: &[u8] = include_bytes!("../../example.bin"); - let bin = load_exec!("example", binary_data).unwrap(); - let entry = bin.entry(); + let mut bump = Bump::with_capacity(25_000); - let entry_fn: extern "C" fn() = unsafe { core::mem::transmute(entry) }; - entry_fn(); // jump into user code + let binary_data: &[u8] = + 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 { diff --git a/user-apps/calculator/src/main.rs b/user-apps/calculator/src/main.rs index 4fc2132..3d219e5 100644 --- a/user-apps/calculator/src/main.rs +++ b/user-apps/calculator/src/main.rs @@ -1,14 +1,26 @@ #![no_std] #![no_main] +use abi::{Syscall, call_abi}; use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { - loop {} // or call your ABI trap, or `abort()` + loop {} } #[unsafe(no_mangle)] -fn main() { - loop {} +pub extern "C" fn _start() -> ! { + 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) }; + } + } + } } diff --git a/user-apps/link.x b/user-apps/link.x new file mode 100644 index 0000000..cdfc9f7 --- /dev/null +++ b/user-apps/link.x @@ -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 +}