diff --git a/Cargo.lock b/Cargo.lock index 8ff751b..11f7aa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,12 +26,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "goblin" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4db6758c546e6f81f265638c980e5e84dfbda80cfd8e89e02f83454c8e8124bd" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "libc" version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + [[package]] name = "memmap2" version = "0.9.8" @@ -53,11 +70,73 @@ dependencies = [ "libc", ] +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "trve" version = "0.0.0" dependencies = [ "anyhow", + "goblin", "memmap2", "nix", ] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" diff --git a/Cargo.toml b/Cargo.toml index c4c3ece..91b641a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,6 @@ edition = "2024" [dependencies] anyhow = "1.0.100" +goblin = "0.10.4" memmap2 = "0.9.8" nix = { version = "0.30.1", features = ["fs"] } diff --git a/echo.S b/echo.S index 664380e..7c29fec 100644 --- a/echo.S +++ b/echo.S @@ -1,4 +1,4 @@ -.section .text._start +.section .text .globl _start .equ UART_DATA, 0 diff --git a/link.ld b/link.ld index 93d3193..0e43104 100644 --- a/link.ld +++ b/link.ld @@ -6,7 +6,6 @@ MEMORY { SECTIONS { .text : ALIGN(4) { - *(.text._start) *(.text*) } > RAM diff --git a/src/execload.rs b/src/execload.rs new file mode 100644 index 0000000..12fe90d --- /dev/null +++ b/src/execload.rs @@ -0,0 +1,67 @@ +// Copyright (c) 2025 taitep +// SPDX-License-Identifier: MIT +// +// This file is part of TRVE (https://gitea.taitep.se/taitep/trve) +// See LICENSE file in the project root for full license text. + +use std::{fs, path::Path}; + +use anyhow::{Result, bail}; +use goblin::{ + Object, + elf::{ + header::{EM_RISCV, ET_EXEC}, + program_header::PT_LOAD, + }, +}; +use trve::consts::Addr; + +pub fn load>(path: P, ram: &mut [u8], ram_start: Addr) -> Result { + let buf = fs::read(path)?; + + match Object::parse(&buf)? { + Object::Elf(elf) => { + if elf.header.e_type != ET_EXEC { + bail!("Executable type incorrect, may not be an executable or may be dynamic"); + } + if elf.header.e_machine != EM_RISCV { + bail!("Executable architecture is not RISC-V"); + } + if !elf.is_64 { + bail!("Executable is not 64-bit"); + } + if !elf.little_endian { + bail!("Executable is not little-endian"); + } + + for ph in elf.program_headers { + if ph.p_type == PT_LOAD { + let start = (ph.p_vaddr - ram_start) as usize; + let end = start + ph.p_memsz as usize; + let file_end = start + ph.p_filesz as usize; + + if end > ram_start as usize + ram.len() { + bail!("Segment at 0x{:x} does not fit in RAM", ph.p_vaddr); + } + + ram[start..file_end].copy_from_slice( + &buf[ph.p_offset as usize..(ph.p_offset + ph.p_filesz) as usize], + ); + + ram[file_end..end].fill(0); + } + } + + Ok(elf.entry) + } + Object::Unknown(_) => { + eprintln!("Unrecognized executable format identifier, assuming raw binary"); + if buf.len() > ram.len() { + bail!("Program too large for RAM"); + } + ram[..buf.len()].copy_from_slice(&buf); + Ok(ram_start) + } + _ => bail!("Unsupported executable format"), + } +} diff --git a/src/main.rs b/src/main.rs index aeedcb2..26b6a2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,25 +22,7 @@ use anyhow::{Result, bail}; use crate::basic_uart::BasicUart; -fn read_file_to_buffer(path: &str, buffer: &mut [u8]) -> io::Result { - let mut file = File::open(path)?; - let mut total_read = 0; - - while total_read < buffer.len() { - let n = file.read(&mut buffer[total_read..])?; - if n == 0 { - return Ok(total_read); - } - total_read += n; - } - - let mut tmp = [0u8; 1]; - if file.read(&mut tmp)? != 0 { - return Err(io::Error::other("RAM too small for file")); - } - - Ok(total_read) -} +mod execload; fn main() -> Result<()> { let mut ram = Ram::try_new(16 * 1024 * 1024 / 4096)?; @@ -53,7 +35,7 @@ fn main() -> Result<()> { bail!("Wrong number of arguments"); } - read_file_to_buffer(&args[1], buf)?; + let entry_point = execload::load(&args[1], buf, 0x8000_0000)?; let uart = BasicUart::new(); let uart = uart.spawn_poller(Duration::from_millis(10)); @@ -76,7 +58,7 @@ fn main() -> Result<()> { }; let mut core = Core::new(mem_cfg); - core.reset(0x8000_0000); + core.reset(entry_point); core.run(); Ok(())