summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock79
-rw-r--r--Cargo.toml1
-rw-r--r--echo.S2
-rw-r--r--link.ld1
-rw-r--r--src/execload.rs67
-rw-r--r--src/main.rs24
6 files changed, 151 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8ff751b..11f7aa6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,12 +27,29 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -54,10 +71,72 @@ dependencies = [
]
[[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<P: AsRef<Path>>(path: P, ram: &mut [u8], ram_start: Addr) -> Result<Addr> {
+ 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<usize> {
- 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(())