68 lines
2.1 KiB
Rust
68 lines
2.1 KiB
Rust
// Copyright (c) 2025 taitep
|
|
// SPDX-License-Identifier: BSD-2-Clause
|
|
//
|
|
// 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, mem::RAM_START};
|
|
|
|
pub fn load<P: AsRef<Path>>(path: P, ram: &mut [u8]) -> 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"),
|
|
}
|
|
}
|