mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 21:35:02 +01:00
This commit is contained in:
parent
0144740228
commit
e9a689aa1a
6 changed files with 449 additions and 193 deletions
91
src/elf.rs
91
src/elf.rs
|
|
@ -32,18 +32,30 @@ pub struct Header {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Phdr32 {
|
||||
pub struct Phdr {
|
||||
pub p_type: u32,
|
||||
pub p_offset: u32,
|
||||
pub p_vaddr: u32,
|
||||
pub p_paddr: u32,
|
||||
pub p_filesz: u32,
|
||||
pub p_memsz: u32,
|
||||
pub p_offset: Offset,
|
||||
pub p_vaddr: Addr,
|
||||
pub p_paddr: Addr,
|
||||
pub p_filesz: u64,
|
||||
pub p_memsz: u64,
|
||||
pub p_flags: u32,
|
||||
pub p_align: u32,
|
||||
pub p_align: u64,
|
||||
}
|
||||
|
||||
impl Elf<'_> {
|
||||
fn class(&self) -> Result<ElfClass> {
|
||||
let (_, class) = self.content.split_u32()?;
|
||||
let (class, _) = class.split_bytes(1)?;
|
||||
Ok(match class[0] {
|
||||
// ELFCLASS32
|
||||
1 => ElfClass::Elf32,
|
||||
// ELFCLASS64
|
||||
2 => ElfClass::Elf64,
|
||||
_ => bail!("not a ELF32 or ELF64 file (EI_CLASS={})", class[0]),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn header(&self) -> Result<Header> {
|
||||
let (ident, rest) = self.content.split_bytes(16)?;
|
||||
if ident[..4] != *b"\x7fELF" {
|
||||
|
|
@ -140,8 +152,9 @@ impl Elf<'_> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn segments_32(&self) -> Result<Vec<Phdr32>> {
|
||||
pub fn segments(&self) -> Result<Vec<Phdr>> {
|
||||
let header = self.header()?;
|
||||
let class = self.class()?;
|
||||
|
||||
let (_, phdrs) = self.content.split_bytes(header.e_phoff.0 as usize)?;
|
||||
let (mut phdrs, _) = phdrs.split_bytes((header.e_phentsize * header.e_phnum) as usize)?;
|
||||
|
|
@ -152,25 +165,51 @@ impl Elf<'_> {
|
|||
let phdr;
|
||||
(phdr, phdrs) = phdrs.split_bytes(header.e_phentsize as usize)?;
|
||||
|
||||
let (p_type, phdr) = phdr.split_u32()?;
|
||||
let (p_offset, phdr) = phdr.split_u32()?;
|
||||
let (p_vaddr, phdr) = phdr.split_u32()?;
|
||||
let (p_paddr, phdr) = phdr.split_u32()?;
|
||||
let (p_filesz, phdr) = phdr.split_u32()?;
|
||||
let (p_memsz, phdr) = phdr.split_u32()?;
|
||||
let (p_flags, phdr) = phdr.split_u32()?;
|
||||
let (p_align, _) = phdr.split_u32()?;
|
||||
let phdr = match class {
|
||||
ElfClass::Elf32 => {
|
||||
let (p_type, phdr) = phdr.split_u32()?;
|
||||
let (p_offset, phdr) = phdr.split_u32()?;
|
||||
let (p_vaddr, phdr) = phdr.split_u32()?;
|
||||
let (p_paddr, phdr) = phdr.split_u32()?;
|
||||
let (p_filesz, phdr) = phdr.split_u32()?;
|
||||
let (p_memsz, phdr) = phdr.split_u32()?;
|
||||
let (p_flags, phdr) = phdr.split_u32()?;
|
||||
let (p_align, _) = phdr.split_u32()?;
|
||||
|
||||
parsed_phdrs.push(Phdr32 {
|
||||
p_type,
|
||||
p_offset,
|
||||
p_vaddr,
|
||||
p_paddr,
|
||||
p_filesz,
|
||||
p_memsz,
|
||||
p_flags,
|
||||
p_align,
|
||||
});
|
||||
Phdr {
|
||||
p_type,
|
||||
p_offset: Offset(p_offset as u64),
|
||||
p_vaddr: Addr(p_vaddr as u64),
|
||||
p_paddr: Addr(p_paddr as u64),
|
||||
p_filesz: p_filesz as u64,
|
||||
p_memsz: p_memsz as u64,
|
||||
p_flags,
|
||||
p_align: p_align as u64,
|
||||
}
|
||||
}
|
||||
ElfClass::Elf64 => {
|
||||
let (p_type, phdr) = phdr.split_u32()?;
|
||||
let (p_flags, phdr) = phdr.split_u32()?;
|
||||
let (p_offset, phdr) = phdr.split_u64()?;
|
||||
let (p_vaddr, phdr) = phdr.split_u64()?;
|
||||
let (p_paddr, phdr) = phdr.split_u64()?;
|
||||
let (p_filesz, phdr) = phdr.split_u64()?;
|
||||
let (p_memsz, phdr) = phdr.split_u64()?;
|
||||
let (p_align, _) = phdr.split_u64()?;
|
||||
|
||||
Phdr {
|
||||
p_type,
|
||||
p_offset: Offset(p_offset),
|
||||
p_vaddr: Addr(p_vaddr),
|
||||
p_paddr: Addr(p_paddr),
|
||||
p_filesz,
|
||||
p_memsz,
|
||||
p_flags,
|
||||
p_align,
|
||||
}
|
||||
}
|
||||
};
|
||||
parsed_phdrs.push(phdr);
|
||||
}
|
||||
|
||||
Ok(parsed_phdrs)
|
||||
|
|
|
|||
271
src/emu.rs
271
src/emu.rs
|
|
@ -20,44 +20,50 @@ impl Memory {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
pub fn slice<XLEN: XLen>(&self, addr: XLEN, len: u32) -> Result<&[u8], Status> {
|
||||
pub fn slice<XLEN: XLen>(&self, addr: XLEN, len: XLEN) -> Result<&[u8], Status> {
|
||||
self.mem
|
||||
.get((addr.as_usize())..)
|
||||
.ok_or(Status::InvalidMemoryAccess(addr.as_usize()))?
|
||||
.get(..(len as usize))
|
||||
.get(..(len.as_usize()))
|
||||
.ok_or(Status::InvalidMemoryAccess(addr.as_usize()))
|
||||
}
|
||||
pub fn slice_mut<XLEN: XLen>(&mut self, addr: XLEN, len: u32) -> Result<&mut [u8], Status> {
|
||||
pub fn slice_mut<XLEN: XLen>(&mut self, addr: XLEN, len: XLEN) -> Result<&mut [u8], Status> {
|
||||
self.mem
|
||||
.get_mut((addr.as_usize())..)
|
||||
.ok_or(Status::InvalidMemoryAccess(addr.as_usize()))?
|
||||
.get_mut(..(len as usize))
|
||||
.get_mut(..(len.as_usize()))
|
||||
.ok_or(Status::InvalidMemoryAccess(addr.as_usize()))
|
||||
}
|
||||
|
||||
pub fn load_u8<XLEN: XLen>(&self, addr: XLEN) -> Result<u8, Status> {
|
||||
Ok(u8::from_le_bytes(self.slice(addr, 1)?.try_into().unwrap()))
|
||||
Ok(u8::from_le_bytes(
|
||||
self.slice(addr, XLEN::from_32_z(1))?.try_into().unwrap(),
|
||||
))
|
||||
}
|
||||
pub fn load_u16<XLEN: XLen>(&self, addr: XLEN) -> Result<u16, Status> {
|
||||
Ok(u16::from_le_bytes(self.slice(addr, 2)?.try_into().unwrap()))
|
||||
Ok(u16::from_le_bytes(
|
||||
self.slice(addr, XLEN::from_32_z(2))?.try_into().unwrap(),
|
||||
))
|
||||
}
|
||||
pub fn load_u32<XLEN: XLen>(&self, addr: XLEN) -> Result<u32, Status> {
|
||||
Ok(u32::from_le_bytes(self.slice(addr, 4)?.try_into().unwrap()))
|
||||
Ok(u32::from_le_bytes(
|
||||
self.slice(addr, XLEN::from_32_z(4))?.try_into().unwrap(),
|
||||
))
|
||||
}
|
||||
pub fn store_u8<XLEN: XLen>(&mut self, addr: XLEN, value: u8) -> Result<(), Status> {
|
||||
self.slice_mut(addr, 1)?
|
||||
self.slice_mut(addr, XLEN::from_32_z(1))?
|
||||
.copy_from_slice(&value.to_le_bytes());
|
||||
Ok(())
|
||||
}
|
||||
pub fn store_u16<XLEN: XLen>(&mut self, addr: XLEN, value: u16) -> Result<(), Status> {
|
||||
self.check_align(addr, 2)?;
|
||||
self.slice_mut(addr, 2)?
|
||||
self.slice_mut(addr, XLEN::from_32_z(2))?
|
||||
.copy_from_slice(&value.to_le_bytes());
|
||||
Ok(())
|
||||
}
|
||||
pub fn store_u32<XLEN: XLen>(&mut self, addr: XLEN, value: u32) -> Result<(), Status> {
|
||||
self.check_align(addr, 4)?;
|
||||
self.slice_mut(addr, 4)?
|
||||
self.slice_mut(addr, XLEN::from_32_z(4))?
|
||||
.copy_from_slice(&value.to_le_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -139,6 +145,28 @@ fn hash_color(value: usize) -> impl Display {
|
|||
}
|
||||
|
||||
impl<XLEN: XLen> Emulator<XLEN> {
|
||||
pub fn new(
|
||||
mem: Memory,
|
||||
start: XLEN,
|
||||
break_addr: XLEN,
|
||||
debug: bool,
|
||||
ecall_handler: Box<dyn FnMut(&mut Memory, &mut [XLEN; 32]) -> Result<(), Status>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
mem,
|
||||
xreg: [XLEN::ZERO; 32],
|
||||
xreg0_value: XLEN::ZERO,
|
||||
pc: start,
|
||||
reservation_set: None,
|
||||
|
||||
is_breaking: false,
|
||||
|
||||
break_pc: break_addr,
|
||||
debug,
|
||||
ecall_handler,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_linux(&mut self) -> Status {
|
||||
self.setup_linux_stack().unwrap();
|
||||
|
||||
|
|
@ -210,7 +238,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
|||
print!("0x{:x} ", self.pc.as_usize());
|
||||
}
|
||||
|
||||
let (inst, was_compressed) = Inst::decode(code)?;
|
||||
let (inst, was_compressed) = Inst::decode(code, XLEN::XLEN)?;
|
||||
|
||||
if self.debug {
|
||||
println!(
|
||||
|
|
@ -649,11 +677,21 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
|||
}
|
||||
|
||||
pub trait XLen: Copy + PartialEq + Eq {
|
||||
type Signed;
|
||||
type NextUnsigned;
|
||||
type NextSigned;
|
||||
|
||||
const XLEN: rvdc::Xlen;
|
||||
|
||||
const ZERO: Self;
|
||||
const SIGNED_MIN: Self;
|
||||
const MAX: Self;
|
||||
|
||||
fn from_bool(v: bool) -> Self;
|
||||
fn switch<R>(self, on_32: impl FnOnce(u32) -> R, on_64: impl FnOnce(u64) -> R) -> R;
|
||||
|
||||
fn from_bool(v: bool) -> Self {
|
||||
Self::from_32_z(v as u32)
|
||||
}
|
||||
fn from_8_z(v: u8) -> Self {
|
||||
Self::from_32_z(v as u32)
|
||||
}
|
||||
|
|
@ -704,14 +742,107 @@ pub trait XLen: Copy + PartialEq + Eq {
|
|||
fn unsigned_rem(self, other: Self) -> Self;
|
||||
}
|
||||
|
||||
impl XLen for u32 {
|
||||
const ZERO: Self = 0;
|
||||
const SIGNED_MIN: Self = i32::MIN as u32;
|
||||
const MAX: Self = u32::MAX;
|
||||
macro_rules! xlen_impl {
|
||||
() => {
|
||||
const ZERO: Self = 0;
|
||||
const SIGNED_MIN: Self = Self::Signed::MIN as Self;
|
||||
const MAX: Self = Self::MAX;
|
||||
|
||||
fn from_bool(v: bool) -> Self {
|
||||
v as u32
|
||||
fn as_usize(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
fn truncate32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
self.wrapping_add(other)
|
||||
}
|
||||
fn sub(self, other: Self) -> Self {
|
||||
self.wrapping_sub(other)
|
||||
}
|
||||
fn and(self, other: Self) -> Self {
|
||||
self & other
|
||||
}
|
||||
fn or(self, other: Self) -> Self {
|
||||
self | other
|
||||
}
|
||||
fn xor(self, other: Self) -> Self {
|
||||
self ^ other
|
||||
}
|
||||
fn signed_lt(self, other: Self) -> bool {
|
||||
(self as Self::Signed) < (other as Self::Signed)
|
||||
}
|
||||
fn unsigned_lt(self, other: Self) -> bool {
|
||||
self < other
|
||||
}
|
||||
fn signed_ge(self, other: Self) -> bool {
|
||||
(self as Self::Signed) >= (other as Self::Signed)
|
||||
}
|
||||
fn unsigned_ge(self, other: Self) -> bool {
|
||||
self >= other
|
||||
}
|
||||
fn shl(self, other: u32) -> Self {
|
||||
self.wrapping_shl(other)
|
||||
}
|
||||
fn unsigned_shr(self, other: u32) -> Self {
|
||||
self.wrapping_shr(other)
|
||||
}
|
||||
fn signed_shr(self, other: u32) -> Self {
|
||||
((self as Self::Signed).wrapping_shr(other)) as Self
|
||||
}
|
||||
fn signed_min(self, other: Self) -> Self {
|
||||
(self as Self::Signed).min(other as Self::Signed) as Self
|
||||
}
|
||||
fn unsigned_min(self, other: Self) -> Self {
|
||||
self.min(other)
|
||||
}
|
||||
fn signed_max(self, other: Self) -> Self {
|
||||
(self as Self::Signed).max(other as Self::Signed) as Self
|
||||
}
|
||||
fn unsigned_max(self, other: Self) -> Self {
|
||||
self.max(other)
|
||||
}
|
||||
fn mul_lower(self, other: Self) -> Self {
|
||||
(self as Self::Signed).wrapping_mul(other as Self::Signed) as Self
|
||||
}
|
||||
fn signed_mul_upper(self, other: Self) -> Self {
|
||||
let mul_result = (self as Self::Signed as Self::NextSigned)
|
||||
.wrapping_mul(other as Self::Signed as Self::NextSigned);
|
||||
let shifted = (mul_result as Self::NextUnsigned) >> Self::BITS;
|
||||
shifted as Self
|
||||
}
|
||||
fn unsigned_mul_upper(self, other: Self) -> Self {
|
||||
let shifted = ((self as Self::NextUnsigned).wrapping_mul(other as Self::NextUnsigned))
|
||||
>> Self::BITS;
|
||||
shifted as Self
|
||||
}
|
||||
fn signed_div(self, other: Self) -> Self {
|
||||
((self as Self::Signed) / (other as Self::Signed)) as Self
|
||||
}
|
||||
fn unsigned_div(self, other: Self) -> Self {
|
||||
self / other
|
||||
}
|
||||
fn signed_rem(self, other: Self) -> Self {
|
||||
((self as Self::Signed) % (other as Self::Signed)) as Self
|
||||
}
|
||||
fn unsigned_rem(self, other: Self) -> Self {
|
||||
self % other
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl XLen for u32 {
|
||||
type Signed = i32;
|
||||
type NextUnsigned = u64;
|
||||
type NextSigned = i64;
|
||||
|
||||
const XLEN: rvdc::Xlen = rvdc::Xlen::Rv32;
|
||||
|
||||
fn switch<R>(self, on_32: impl FnOnce(u32) -> R, _: impl FnOnce(u64) -> R) -> R {
|
||||
on_32(self)
|
||||
}
|
||||
|
||||
fn from_32_s(v: u32) -> Self {
|
||||
v
|
||||
}
|
||||
|
|
@ -721,84 +852,30 @@ impl XLen for u32 {
|
|||
fn from_imm(v: Imm) -> Self {
|
||||
v.as_u32()
|
||||
}
|
||||
fn as_usize(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
fn truncate32(self) -> u32 {
|
||||
self
|
||||
}
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
self.wrapping_add(other)
|
||||
}
|
||||
fn sub(self, other: Self) -> Self {
|
||||
self.wrapping_sub(other)
|
||||
}
|
||||
fn and(self, other: Self) -> Self {
|
||||
self & other
|
||||
}
|
||||
fn or(self, other: Self) -> Self {
|
||||
self | other
|
||||
}
|
||||
fn xor(self, other: Self) -> Self {
|
||||
self ^ other
|
||||
}
|
||||
fn signed_lt(self, other: Self) -> bool {
|
||||
(self as i32) < (other as i32)
|
||||
}
|
||||
fn unsigned_lt(self, other: Self) -> bool {
|
||||
self < other
|
||||
}
|
||||
fn signed_ge(self, other: Self) -> bool {
|
||||
(self as i32) >= (other as i32)
|
||||
}
|
||||
fn unsigned_ge(self, other: Self) -> bool {
|
||||
self >= other
|
||||
}
|
||||
fn shl(self, other: u32) -> Self {
|
||||
self.wrapping_shl(other)
|
||||
}
|
||||
fn unsigned_shr(self, other: u32) -> Self {
|
||||
self.wrapping_shr(other)
|
||||
}
|
||||
fn signed_shr(self, other: u32) -> Self {
|
||||
((self as i32).wrapping_shr(other)) as u32
|
||||
}
|
||||
fn signed_min(self, other: Self) -> Self {
|
||||
(self as i32).min(other as i32) as u32
|
||||
}
|
||||
fn unsigned_min(self, other: Self) -> Self {
|
||||
self.min(other)
|
||||
}
|
||||
fn signed_max(self, other: Self) -> Self {
|
||||
(self as i32).max(other as i32) as u32
|
||||
}
|
||||
fn unsigned_max(self, other: Self) -> Self {
|
||||
self.max(other)
|
||||
}
|
||||
fn mul_lower(self, other: Self) -> Self {
|
||||
(self as i32).wrapping_mul(other as i32) as u32
|
||||
}
|
||||
fn signed_mul_upper(self, other: Self) -> Self {
|
||||
let mul_result = (self as i32 as i64).wrapping_mul(other as i32 as i64);
|
||||
let shifted = (mul_result as u64) >> 32;
|
||||
shifted as u32
|
||||
}
|
||||
fn unsigned_mul_upper(self, other: Self) -> Self {
|
||||
let shifted = ((self as u64).wrapping_mul(other as u64)) >> 32;
|
||||
shifted as u32
|
||||
}
|
||||
fn signed_div(self, other: Self) -> Self {
|
||||
((self as i32) / (other as i32)) as u32
|
||||
}
|
||||
fn unsigned_div(self, other: Self) -> Self {
|
||||
self / other
|
||||
}
|
||||
fn signed_rem(self, other: Self) -> Self {
|
||||
((self as i32) % (other as i32)) as u32
|
||||
}
|
||||
fn unsigned_rem(self, other: Self) -> Self {
|
||||
self % other
|
||||
}
|
||||
xlen_impl!();
|
||||
}
|
||||
|
||||
impl XLen for u64 {
|
||||
type Signed = i64;
|
||||
type NextUnsigned = u128;
|
||||
type NextSigned = i128;
|
||||
|
||||
const XLEN: rvdc::Xlen = rvdc::Xlen::Rv64;
|
||||
|
||||
fn switch<R>(self, _: impl FnOnce(u32) -> R, on_64: impl FnOnce(u64) -> R) -> R {
|
||||
on_64(self)
|
||||
}
|
||||
|
||||
fn from_32_s(v: u32) -> Self {
|
||||
v as i32 as i64 as u64
|
||||
}
|
||||
fn from_32_z(v: u32) -> Self {
|
||||
v as u64
|
||||
}
|
||||
fn from_imm(v: Imm) -> Self {
|
||||
v.as_u64()
|
||||
}
|
||||
|
||||
xlen_impl!();
|
||||
}
|
||||
|
|
|
|||
38
src/lib.rs
38
src/lib.rs
|
|
@ -9,13 +9,14 @@ const MEMORY_SIZE: usize = 2 << 21;
|
|||
pub fn execute_linux_elf(
|
||||
elf: &[u8],
|
||||
debug: bool,
|
||||
break_addr: u32,
|
||||
ecall_handler: Box<dyn FnMut(&mut emu::Memory, &mut [u32; 32]) -> Result<(), emu::Status>>,
|
||||
break_addr: u64,
|
||||
ecall_handler32: Box<dyn FnMut(&mut emu::Memory, &mut [u32; 32]) -> Result<(), emu::Status>>,
|
||||
ecall_handler64: Box<dyn FnMut(&mut emu::Memory, &mut [u64; 32]) -> Result<(), emu::Status>>,
|
||||
) -> eyre::Result<emu::Status> {
|
||||
let elf = elf::Elf { content: elf };
|
||||
let header = elf.header()?;
|
||||
|
||||
let segments = elf.segments_32()?;
|
||||
let segments = elf.segments()?;
|
||||
|
||||
let mut mem = emu::Memory {
|
||||
mem: vec![0; MEMORY_SIZE],
|
||||
|
|
@ -30,13 +31,13 @@ pub fn execute_linux_elf(
|
|||
if phdr.p_filesz > 0 {
|
||||
let contents = &elf
|
||||
.content
|
||||
.get((phdr.p_offset as usize)..)
|
||||
.get((phdr.p_offset.0 as usize)..)
|
||||
.ok_or_eyre("invalid offset")?
|
||||
.get(..(phdr.p_filesz as usize))
|
||||
.ok_or_eyre("invalid offset")?;
|
||||
|
||||
mem.mem
|
||||
.get_mut((phdr.p_vaddr as usize)..)
|
||||
.get_mut((phdr.p_vaddr.0 as usize)..)
|
||||
.ok_or_eyre("invalid offset")?
|
||||
.get_mut(..(phdr.p_filesz as usize))
|
||||
.ok_or_eyre("invalid offset")?
|
||||
|
|
@ -61,19 +62,16 @@ pub fn execute_linux_elf(
|
|||
|
||||
let start = header.e_entry;
|
||||
|
||||
let mut emu = emu::Emulator {
|
||||
mem,
|
||||
xreg: [0; 32],
|
||||
xreg0_value: 0,
|
||||
pc: start.0 as u32,
|
||||
reservation_set: None,
|
||||
|
||||
is_breaking: false,
|
||||
|
||||
break_pc: break_addr,
|
||||
debug,
|
||||
ecall_handler,
|
||||
};
|
||||
|
||||
Ok(emu.start_linux())
|
||||
match header.class {
|
||||
elf::ElfClass::Elf32 => {
|
||||
let mut emu =
|
||||
emu::Emulator::<u32>::new(mem, start.0 as u32, break_addr as u32, debug, ecall_handler32);
|
||||
Ok(emu.start_linux())
|
||||
}
|
||||
elf::ElfClass::Elf64 => {
|
||||
let mut emu =
|
||||
emu::Emulator::<u64>::new(mem, start.0, break_addr, debug, ecall_handler64);
|
||||
Ok(emu.start_linux())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
64
src/main.rs
64
src/main.rs
|
|
@ -1,7 +1,7 @@
|
|||
use std::io::Write;
|
||||
use std::{cell::RefCell, io::Write, sync::Arc};
|
||||
|
||||
use eyre::eyre;
|
||||
use rustv32i::emu::{self, Memory};
|
||||
use rustv32i::emu::{self, Memory, XLen};
|
||||
use rvdc::Reg;
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
|
|
@ -12,22 +12,26 @@ fn main() -> eyre::Result<()> {
|
|||
.nth(1)
|
||||
.map(|addr| {
|
||||
if let Some(addr) = addr.strip_prefix("0x") {
|
||||
u32::from_str_radix(addr, 16)
|
||||
u64::from_str_radix(addr, 16)
|
||||
} else {
|
||||
u32::from_str_radix(&addr, 10)
|
||||
u64::from_str_radix(&addr, 10)
|
||||
}
|
||||
})
|
||||
.unwrap_or(Ok(0))?;
|
||||
|
||||
let debug = std::env::args().any(|arg| arg == "--debug");
|
||||
|
||||
let mut syscall_state = SyscallState { set_child_tid: 0 };
|
||||
let syscall_state = Arc::new(RefCell::new(SyscallState { set_child_tid: 0 }));
|
||||
let syscall_state64 = syscall_state.clone();
|
||||
|
||||
let status = rustv32i::execute_linux_elf(
|
||||
&content,
|
||||
debug,
|
||||
break_addr,
|
||||
Box::new(move |mem, xreg| ecall_handler(mem, xreg, &mut syscall_state)),
|
||||
Box::new(move |mem, xreg| ecall_handler::<u32>(mem, xreg, &mut syscall_state.borrow_mut())),
|
||||
Box::new(move |mem, xreg| {
|
||||
ecall_handler::<u64>(mem, xreg, &mut syscall_state64.borrow_mut())
|
||||
}),
|
||||
)?;
|
||||
|
||||
std::io::stdout().flush()?;
|
||||
|
|
@ -44,12 +48,12 @@ fn main() -> eyre::Result<()> {
|
|||
}
|
||||
|
||||
struct SyscallState {
|
||||
set_child_tid: u32,
|
||||
set_child_tid: u64,
|
||||
}
|
||||
|
||||
fn ecall_handler(
|
||||
fn ecall_handler<XLEN: Into<u64> + From<u32> + XLen>(
|
||||
mem: &mut Memory,
|
||||
xreg: &mut [u32; 32],
|
||||
xreg: &mut [XLEN; 32],
|
||||
syscall_state: &mut SyscallState,
|
||||
) -> Result<(), emu::Status> {
|
||||
let nr = xreg[Reg::A7.0 as usize];
|
||||
|
|
@ -60,22 +64,22 @@ fn ecall_handler(
|
|||
|
||||
// https://jborza.com/post/2021-05-11-riscv-linux-syscalls/
|
||||
// https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/unistd.h
|
||||
match nr {
|
||||
match nr.into() {
|
||||
// ioctl
|
||||
29 => {
|
||||
let fd = arg0;
|
||||
let request = arg1;
|
||||
|
||||
match request {
|
||||
match request.into() {
|
||||
// TIOCGWINSZ
|
||||
0x5413 => {
|
||||
let wsz_ptr = xreg[Reg::A2.0 as usize];
|
||||
let wsz_ptr = xreg[Reg::A2.0 as usize].into();
|
||||
|
||||
let mut wsz: libc::winsize = unsafe { std::mem::zeroed() };
|
||||
|
||||
let r = unsafe { libc::ioctl(fd as i32, libc::TIOCGWINSZ, &mut wsz) };
|
||||
let r = unsafe { libc::ioctl(fd.into() as i32, libc::TIOCGWINSZ, &mut wsz) };
|
||||
|
||||
xreg[Reg::A0.0 as usize] = r as u32;
|
||||
xreg[Reg::A0.0 as usize] = (r as u32).into();
|
||||
if r >= 0 {
|
||||
mem.store_u16(wsz_ptr, wsz.ws_row)?;
|
||||
mem.store_u16(wsz_ptr + 2, wsz.ws_col)?;
|
||||
|
|
@ -83,16 +87,16 @@ fn ecall_handler(
|
|||
mem.store_u16(wsz_ptr + 6, wsz.ws_ypixel)?;
|
||||
}
|
||||
}
|
||||
_ => todo!("unknown ioctl: {request}"),
|
||||
_ => todo!("unknown ioctl: {}", request.into()),
|
||||
}
|
||||
}
|
||||
// read
|
||||
63 => {
|
||||
let fd = arg0;
|
||||
let fd = arg0.into();
|
||||
let ptr = xreg[Reg::A1.0 as usize];
|
||||
let len = xreg[Reg::A2.0 as usize];
|
||||
|
||||
let buf = mem.slice_mut(ptr, len)?;
|
||||
let buf = mem.slice_mut::<XLEN>(ptr, len)?;
|
||||
|
||||
let len = unsafe { libc::read(fd as i32, buf.as_mut_ptr().cast(), buf.len()) };
|
||||
let ret = if len < 0 {
|
||||
|
|
@ -101,11 +105,11 @@ fn ecall_handler(
|
|||
len as u32
|
||||
};
|
||||
|
||||
xreg[Reg::A0.0 as usize] = ret;
|
||||
xreg[Reg::A0.0 as usize] = ret.into();
|
||||
}
|
||||
// write
|
||||
64 => {
|
||||
let fd = arg0;
|
||||
let fd = arg0.into();
|
||||
let ptr = xreg[Reg::A1.0 as usize];
|
||||
let len = xreg[Reg::A2.0 as usize];
|
||||
|
||||
|
|
@ -118,13 +122,13 @@ fn ecall_handler(
|
|||
len as u32
|
||||
};
|
||||
|
||||
xreg[Reg::A0.0 as usize] = ret;
|
||||
xreg[Reg::A0.0 as usize] = ret.into();
|
||||
}
|
||||
// https://man7.org/linux/man-pages/man3/writev.3p.html
|
||||
66 => {
|
||||
let fd = arg0;
|
||||
let iovec = arg1;
|
||||
let iovcnt = arg2;
|
||||
let fd = arg0.into();
|
||||
let iovec = arg1.into();
|
||||
let iovcnt = arg2.into();
|
||||
|
||||
let mut written = 0;
|
||||
|
||||
|
|
@ -142,27 +146,27 @@ fn ecall_handler(
|
|||
};
|
||||
|
||||
if (ret as i32) < 0 {
|
||||
xreg[Reg::A0.0 as usize] = ret;
|
||||
xreg[Reg::A0.0 as usize] = ret.into();
|
||||
return Ok(());
|
||||
} else {
|
||||
written += ret;
|
||||
}
|
||||
}
|
||||
|
||||
xreg[Reg::A0.0 as usize] = written;
|
||||
xreg[Reg::A0.0 as usize] = written.into();
|
||||
}
|
||||
// exit | exit_group
|
||||
93 | 94 => {
|
||||
return Err(emu::Status::Exit {
|
||||
code: xreg[Reg::A0.0 as usize] as i32,
|
||||
code: xreg[Reg::A0.0 as usize].into() as i32,
|
||||
});
|
||||
}
|
||||
// <https://man7.org/linux/man-pages/man2/set_tid_address.2.html>
|
||||
96 => {
|
||||
let tidptr = arg0;
|
||||
syscall_state.set_child_tid = tidptr;
|
||||
syscall_state.set_child_tid = tidptr.into();
|
||||
|
||||
xreg[Reg::A0.0 as usize] = 1; // thread ID
|
||||
xreg[Reg::A0.0 as usize] = 1.into(); // thread ID
|
||||
}
|
||||
// ppoll - called for some stdin/stdout/stderr check.
|
||||
414 => {
|
||||
|
|
@ -170,10 +174,10 @@ fn ecall_handler(
|
|||
// and opens /dev/null for them if they are.
|
||||
// They're always valid here, so just get out.
|
||||
|
||||
xreg[Reg::A0.0 as usize] = 0;
|
||||
xreg[Reg::A0.0 as usize] = 0.into();
|
||||
}
|
||||
_ => {
|
||||
todo!("unkonwn syscall: {nr}");
|
||||
todo!("unkonwn syscall: {}", nr.into());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue