Revised trap API

This commit is contained in:
Erin 2023-07-11 17:04:48 +02:00 committed by ondra05
parent 6f4f156ca0
commit 3fc6bb9171
5 changed files with 46 additions and 84 deletions

View file

@ -1,8 +1,4 @@
use hbvm::vm::{ use hbvm::vm::mem::{HandlePageFault, Memory, MemoryAccessReason, PageSize};
mem::{Memory, MemoryAccessReason, PageSize},
trap::HandleTrap,
value::Value,
};
use { use {
hbvm::{validate::validate, vm::Vm}, hbvm::{validate::validate, vm::Vm},
@ -32,7 +28,7 @@ pub fn time() -> u32 {
} }
struct TestTrapHandler; struct TestTrapHandler;
impl HandleTrap for TestTrapHandler { impl HandlePageFault for TestTrapHandler {
fn page_fault( fn page_fault(
&mut self, &mut self,
_: MemoryAccessReason, _: MemoryAccessReason,
@ -43,17 +39,4 @@ impl HandleTrap for TestTrapHandler {
) -> bool { ) -> bool {
false 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,
{
}
} }

View file

@ -2,9 +2,13 @@
pub mod paging; pub mod paging;
mod pfhandler;
pub use pfhandler::HandlePageFault;
use { use {
self::paging::{PageTable, Permission, PtEntry}, self::paging::{PageTable, Permission, PtEntry},
super::{trap::HandleTrap, VmRunError}, super::VmRunError,
alloc::boxed::Box, alloc::boxed::Box,
core::mem::MaybeUninit, core::mem::MaybeUninit,
derive_more::Display, derive_more::Display,
@ -69,7 +73,7 @@ impl Memory {
addr: u64, addr: u64,
target: *mut u8, target: *mut u8,
count: usize, count: usize,
traph: &mut impl HandleTrap, traph: &mut impl HandlePageFault,
) -> Result<(), LoadError> { ) -> Result<(), LoadError> {
self.memory_access( self.memory_access(
MemoryAccessReason::Load, MemoryAccessReason::Load,
@ -97,7 +101,7 @@ impl Memory {
addr: u64, addr: u64,
source: *const u8, source: *const u8,
count: usize, count: usize,
traph: &mut impl HandleTrap, traph: &mut impl HandlePageFault,
) -> Result<(), StoreError> { ) -> Result<(), StoreError> {
self.memory_access( self.memory_access(
MemoryAccessReason::Store, MemoryAccessReason::Store,
@ -122,7 +126,7 @@ impl Memory {
src: u64, src: u64,
dst: u64, dst: u64,
count: usize, count: usize,
traph: &mut impl HandleTrap, traph: &mut impl HandlePageFault,
) -> Result<(), BlkCopyError> { ) -> Result<(), BlkCopyError> {
// Yea, i know it is possible to do this more efficiently, but I am too lazy. // Yea, i know it is possible to do this more efficiently, but I am too lazy.
@ -209,7 +213,7 @@ impl Memory {
len: usize, len: usize,
permission_check: fn(Permission) -> bool, permission_check: fn(Permission) -> bool,
action: fn(*mut u8, *mut u8, usize), action: fn(*mut u8, *mut u8, usize),
traph: &mut impl HandleTrap, traph: &mut impl HandlePageFault,
) -> Result<(), u64> { ) -> Result<(), u64> {
let mut pspl = AddrSplitter::new(src, len, self.root_pt); let mut pspl = AddrSplitter::new(src, len, self.root_pt);
loop { loop {

View file

@ -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;
}

View file

@ -11,10 +11,9 @@
// program size. If you are (rightfully) worried about the UB, for now just // program size. If you are (rightfully) worried about the UB, for now just
// append your program with 11 zeroes. // append your program with 11 zeroes.
use self::trap::HandleTrap; use self::mem::HandlePageFault;
pub mod mem; pub mod mem;
pub mod trap;
pub mod value; pub mod value;
use { use {
@ -79,7 +78,7 @@ macro_rules! cond_jump {
} }
/// HoleyBytes Virtual Machine /// HoleyBytes Virtual Machine
pub struct Vm<'a, T, const TIMER_QUOTIENT: usize> { pub struct Vm<'a, PfHandler, const TIMER_QUOTIENT: usize> {
/// Holds 256 registers /// Holds 256 registers
/// ///
/// Writing to register 0 is considered undefined behaviour /// Writing to register 0 is considered undefined behaviour
@ -90,7 +89,7 @@ pub struct Vm<'a, T, const TIMER_QUOTIENT: usize> {
pub memory: Memory, pub memory: Memory,
/// Trap handler /// Trap handler
pub traph: T, pub pfhandler: PfHandler,
// Program counter // Program counter
pc: usize, pc: usize,
@ -102,16 +101,18 @@ pub struct Vm<'a, T, const TIMER_QUOTIENT: usize> {
timer: 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 /// Create a new VM with program and trap handler
/// ///
/// # Safety /// # Safety
/// Program code has to be validated /// 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 { Self {
registers: [Value::from(0_u64); 256], registers: [Value::from(0_u64); 256],
memory: Default::default(), memory: Default::default(),
traph, pfhandler: traph,
pc: 0, pc: 0,
program, program,
timer: 0, 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 /// Create a new VM with program and trap handler only if it passes validation
pub fn new_validated(program: &'a [u8], traph: T) -> Result<Self, validate::Error> { pub fn new_validated(program: &'a [u8], traph: PfHandler) -> Result<Self, validate::Error> {
validate::validate(program)?; validate::validate(program)?;
Ok(unsafe { Self::new_unchecked(program, traph) }) 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.read_reg(base).as_u64() + off + n as u64,
self.registers.as_mut_ptr().add(usize::from(dst) + n).cast(), self.registers.as_mut_ptr().add(usize::from(dst) + n).cast(),
usize::from(count).saturating_sub(n), usize::from(count).saturating_sub(n),
&mut self.traph, &mut self.pfhandler,
)?; )?;
} }
ST => { 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.read_reg(base).as_u64() + off,
self.registers.as_ptr().add(usize::from(dst)).cast(), self.registers.as_ptr().add(usize::from(dst)).cast(),
count.into(), count.into(),
&mut self.traph, &mut self.pfhandler,
)?; )?;
} }
BMC => { 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(src).as_u64(),
self.read_reg(dst).as_u64(), self.read_reg(dst).as_u64(),
count as _, count as _,
&mut self.traph, &mut self.pfhandler,
)?; )?;
} }
BRC => { BRC => {
@ -275,8 +276,7 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> {
JGTU => cond_jump!(self, sint, Greater), JGTU => cond_jump!(self, sint, Greater),
ECALL => { ECALL => {
param!(self, ()); param!(self, ());
self.traph return Ok(VmRunOk::Ecall);
.ecall(&mut self.registers, &mut self.pc, &mut self.memory);
} }
ADDF => binary_op!(self, as_f64, ops::Add::add), ADDF => binary_op!(self, as_f64, ops::Add::add),
SUBF => binary_op!(self, as_f64, ops::Sub::sub), 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), ADDFI => binary_op_imm!(self, as_f64, ops::Add::add),
MULFI => binary_op_imm!(self, as_f64, ops::Mul::mul), MULFI => binary_op_imm!(self, as_f64, ops::Mul::mul),
op => { op => return Err(VmRunError::InvalidOpcode(op)),
if !self.traph.invalid_op(
&mut self.registers,
&mut self.pc,
&mut self.memory,
op,
) {
return Err(VmRunError::InvalidOpcodeEx(op));
}
}
} }
} }
@ -352,8 +343,8 @@ impl<'a, T: HandleTrap, const TIMER_QUOTIENT: usize> Vm<'a, T, TIMER_QUOTIENT> {
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
pub enum VmRunError { pub enum VmRunError {
/// Unhandled invalid opcode exceptions /// Tried to execute invalid instruction
InvalidOpcodeEx(u8), InvalidOpcode(u8),
/// Unhandled load access exception /// Unhandled load access exception
LoadAccessEx(u64), LoadAccessEx(u64),
@ -370,4 +361,7 @@ pub enum VmRunOk {
/// Program was interrupted by a timer /// Program was interrupted by a timer
Timer, Timer,
/// Environment call
Ecall,
} }

View file

@ -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;
}