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::{
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,
{
}
}

View file

@ -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 {

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
// 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<Self, validate::Error> {
pub fn new_validated(program: &'a [u8], traph: PfHandler) -> Result<Self, validate::Error> {
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,
}

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