From 8ed4845d587eff7ba0252bedf34f98de8802153d Mon Sep 17 00:00:00 2001 From: taitep Date: Tue, 23 Dec 2025 19:56:42 +0100 Subject: ADD ELF SUPPORT --- src/execload.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 24 +++------------------ 2 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 src/execload.rs (limited to 'src') 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(()) -- cgit v1.2.3