diff --git a/hbvm/src/main.rs b/hbvm/src/main.rs index 5f9b27f..79ced04 100644 --- a/hbvm/src/main.rs +++ b/hbvm/src/main.rs @@ -1,8 +1,4 @@ -use hbvm::vm::{ - mem::{Memory, MemoryAccessReason, PageSize}, - trap::HandleTrap, - value::Value, -}; +use hbvm::vm::mem::{HandlePageFault, Memory, MemoryAccessReason, PageSize}; use { hbvm::{validate::validate, vm::Vm}, @@ -32,7 +28,7 @@ pub fn time() -> u32 { } struct TestTrapHandler; -impl HandleTrap for TestTrapHandler { +impl HandlePageFault for TestTrapHandler { fn page_fault( &mut self, _: MemoryAccessReason, @@ -43,17 +39,4 @@ impl HandleTrap for TestTrapHandler { ) -> bool { false } - - fn invalid_op(&mut self, _: &mut [Value; 256], _: &mut usize, _: &mut Memory, _: u8) -> bool - where - Self: Sized, - { - false - } - - fn ecall(&mut self, _: &mut [Value; 256], _: &mut usize, _: &mut Memory) - where - Self: Sized, - { - } } diff --git a/hbvm/src/vm/mem/mod.rs b/hbvm/src/vm/mem/mod.rs index 65f5800..901c41c 100644 --- a/hbvm/src/vm/mem/mod.rs +++ b/hbvm/src/vm/mem/mod.rs @@ -2,9 +2,13 @@ pub mod paging; +mod pfhandler; + +pub use pfhandler::HandlePageFault; + use { self::paging::{PageTable, Permission, PtEntry}, - super::{trap::HandleTrap, VmRunError}, + super::VmRunError, alloc::boxed::Box, core::mem::MaybeUninit, derive_more::Display, @@ -69,7 +73,7 @@ impl Memory { addr: u64, target: *mut u8, count: usize, - traph: &mut impl HandleTrap, + traph: &mut impl HandlePageFault, ) -> Result<(), LoadError> { self.memory_access( MemoryAccessReason::Load, @@ -97,7 +101,7 @@ impl Memory { addr: u64, source: *const u8, count: usize, - traph: &mut impl HandleTrap, + traph: &mut impl HandlePageFault, ) -> Result<(), StoreError> { self.memory_access( MemoryAccessReason::Store, @@ -122,7 +126,7 @@ impl Memory { src: u64, dst: u64, count: usize, - traph: &mut impl HandleTrap, + traph: &mut impl HandlePageFault, ) -> Result<(), BlkCopyError> { // Yea, i know it is possible to do this more efficiently, but I am too lazy. @@ -209,7 +213,7 @@ impl Memory { len: usize, permission_check: fn(Permission) -> bool, action: fn(*mut u8, *mut u8, usize), - traph: &mut impl HandleTrap, + traph: &mut impl HandlePageFault, ) -> Result<(), u64> { let mut pspl = AddrSplitter::new(src, len, self.root_pt); loop { diff --git a/hbvm/src/vm/mem/pfhandler.rs b/hbvm/src/vm/mem/pfhandler.rs new file mode 100644 index 0000000..580e44e --- /dev/null +++ b/hbvm/src/vm/mem/pfhandler.rs @@ -0,0 +1,16 @@ +//! Program trap handling interfaces + +use super::{Memory, MemoryAccessReason, PageSize}; + +/// Handle VM traps +pub trait HandlePageFault { + /// Handle page fault + fn page_fault( + &mut self, + reason: MemoryAccessReason, + memory: &mut Memory, + vaddr: u64, + size: PageSize, + dataptr: *mut u8, + ) -> bool; +} diff --git a/hbvm/src/vm/mod.rs b/hbvm/src/vm/mod.rs index 182b574..7c3a50f 100644 --- a/hbvm/src/vm/mod.rs +++ b/hbvm/src/vm/mod.rs @@ -11,10 +11,9 @@ // program size. If you are (rightfully) worried about the UB, for now just // append your program with 11 zeroes. -use self::trap::HandleTrap; +use self::mem::HandlePageFault; pub mod mem; -pub mod trap; pub mod value; use { @@ -79,7 +78,7 @@ macro_rules! cond_jump { } /// HoleyBytes Virtual Machine -pub struct Vm<'a, T, const TIMER_QUOTIENT: usize> { +pub struct Vm<'a, PfHandler, const TIMER_QUOTIENT: usize> { /// Holds 256 registers /// /// Writing to register 0 is considered undefined behaviour @@ -90,7 +89,7 @@ pub struct Vm<'a, T, const TIMER_QUOTIENT: usize> { pub memory: Memory, /// Trap handler - pub traph: T, + pub pfhandler: PfHandler, // Program counter pc: usize, @@ -102,16 +101,18 @@ pub struct Vm<'a, T, const TIMER_QUOTIENT: usize> { timer: usize, } -impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { +impl<'a, PfHandler: HandlePageFault, const TIMER_QUOTIENT: usize> + Vm<'a, PfHandler, TIMER_QUOTIENT> +{ /// Create a new VM with program and trap handler /// /// # Safety /// Program code has to be validated - pub unsafe fn new_unchecked(program: &'a [u8], traph: T) -> Self { + pub unsafe fn new_unchecked(program: &'a [u8], traph: PfHandler) -> Self { Self { registers: [Value::from(0_u64); 256], memory: Default::default(), - traph, + pfhandler: traph, pc: 0, program, timer: 0, @@ -119,7 +120,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { } /// Create a new VM with program and trap handler only if it passes validation - pub fn new_validated(program: &'a [u8], traph: T) -> Result { + pub fn new_validated(program: &'a [u8], traph: PfHandler) -> Result { validate::validate(program)?; Ok(unsafe { Self::new_unchecked(program, traph) }) } @@ -229,7 +230,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { self.read_reg(base).as_u64() + off + n as u64, self.registers.as_mut_ptr().add(usize::from(dst) + n).cast(), usize::from(count).saturating_sub(n), - &mut self.traph, + &mut self.pfhandler, )?; } ST => { @@ -238,7 +239,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { self.read_reg(base).as_u64() + off, self.registers.as_ptr().add(usize::from(dst)).cast(), count.into(), - &mut self.traph, + &mut self.pfhandler, )?; } BMC => { @@ -247,7 +248,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { self.read_reg(src).as_u64(), self.read_reg(dst).as_u64(), count as _, - &mut self.traph, + &mut self.pfhandler, )?; } BRC => { @@ -275,8 +276,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { JGTU => cond_jump!(self, sint, Greater), ECALL => { param!(self, ()); - self.traph - .ecall(&mut self.registers, &mut self.pc, &mut self.memory); + return Ok(VmRunOk::Ecall); } ADDF => binary_op!(self, as_f64, ops::Add::add), SUBF => binary_op!(self, as_f64, ops::Sub::sub), @@ -310,16 +310,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { } ADDFI => binary_op_imm!(self, as_f64, ops::Add::add), MULFI => binary_op_imm!(self, as_f64, ops::Mul::mul), - op => { - if !self.traph.invalid_op( - &mut self.registers, - &mut self.pc, - &mut self.memory, - op, - ) { - return Err(VmRunError::InvalidOpcodeEx(op)); - } - } + op => return Err(VmRunError::InvalidOpcode(op)), } } @@ -352,8 +343,8 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u8)] pub enum VmRunError { - /// Unhandled invalid opcode exceptions - InvalidOpcodeEx(u8), + /// Tried to execute invalid instruction + InvalidOpcode(u8), /// Unhandled load access exception LoadAccessEx(u64), @@ -370,4 +361,7 @@ pub enum VmRunOk { /// Program was interrupted by a timer Timer, + + /// Environment call + Ecall, } diff --git a/hbvm/src/vm/trap.rs b/hbvm/src/vm/trap.rs deleted file mode 100644 index 94d93e9..0000000 --- a/hbvm/src/vm/trap.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Program trap handling interfaces - -use super::{ - mem::{Memory, MemoryAccessReason, PageSize}, - value::Value, -}; - -/// Handle VM traps -pub trait HandleTrap { - /// Handle page fault - fn page_fault( - &mut self, - reason: MemoryAccessReason, - memory: &mut Memory, - vaddr: u64, - size: PageSize, - dataptr: *mut u8, - ) -> bool; - - /// Handle invalid opcode exception - fn invalid_op( - &mut self, - regs: &mut [Value; 256], - pc: &mut usize, - memory: &mut Memory, - op: u8, - ) -> bool - where - Self: Sized; - - /// Handle environment calls - fn ecall(&mut self, regs: &mut [Value; 256], pc: &mut usize, memory: &mut Memory) - where - Self: Sized; -}