interrupt handling

This commit is contained in:
Erin 2023-06-23 09:44:26 +02:00 committed by ondra05
parent 965a6a2c19
commit 4fd96e1b0e
4 changed files with 111 additions and 33 deletions

View file

@ -1,4 +1,8 @@
use hbvm::vm::trap::HandleTrap; use hbvm::vm::{
mem::{Memory, PageSize},
trap::HandleTrap,
value::Value,
};
use { use {
hbvm::{validate::validate, vm::Vm}, hbvm::{validate::validate, vm::Vm},
@ -29,6 +33,20 @@ pub fn time() -> u32 {
struct TestTrapHandler; struct TestTrapHandler;
impl HandleTrap for TestTrapHandler { impl HandleTrap for TestTrapHandler {
#[inline] fn page_fault(&mut self, _: &mut Memory, _: u64, _: PageSize, _: *mut u8) -> bool {
fn page_fault(&mut self) {} 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

@ -55,7 +55,7 @@ impl Memory {
/// Load value from an address /// Load value from an address
pub unsafe fn load( pub unsafe fn load(
&self, &mut self,
addr: u64, addr: u64,
target: *mut u8, target: *mut u8,
count: usize, count: usize,
@ -96,7 +96,7 @@ impl Memory {
/// Copy a block of memory /// Copy a block of memory
pub unsafe fn block_copy(&mut self, src: u64, dst: u64, count: u64) -> Result<(), ()> { pub unsafe fn block_copy(&mut self, src: u64, dst: u64, count: u64) -> Result<(), ()> {
let count = usize::try_from(count).expect("?conradluget a better CPU"); /* let count = usize::try_from(count).expect("?conradluget a better CPU");
let mut srcs = PageSplitter::new(src, count, self.root_pt); let mut srcs = PageSplitter::new(src, count, self.root_pt);
let mut dsts = PageSplitter::new(dst, count, self.root_pt); let mut dsts = PageSplitter::new(dst, count, self.root_pt);
@ -123,7 +123,8 @@ impl Memory {
(Some(src), Some(dst)) => (c_src, c_dst) = (src, dst), (Some(src), Some(dst)) => (c_src, c_dst) = (src, dst),
_ => return Err(()), _ => return Err(()),
} }
} } */
Err(())
} }
#[inline] #[inline]
@ -137,7 +138,7 @@ impl Memory {
} }
fn memory_access( fn memory_access(
&self, &mut self,
src: u64, src: u64,
mut dst: *mut u8, mut dst: *mut u8,
len: usize, len: usize,
@ -145,16 +146,28 @@ impl Memory {
action: fn(*mut u8, *mut u8, usize), action: fn(*mut u8, *mut u8, usize),
traph: &mut impl HandleTrap, traph: &mut impl HandleTrap,
) -> Result<(), ()> { ) -> Result<(), ()> {
for PageSplitResult { ptr, size, perm } in PageSplitter::new(src, len, self.root_pt) { let mut pspl = PageSplitter::new(src, len, self.root_pt);
if !permission_check(perm) { loop {
return Err(()); match pspl.next() {
Some(Ok(PageSplitResult { ptr, size, perm })) => {
if !permission_check(perm) {
return Err(());
}
action(ptr, dst, size);
dst = unsafe { dst.add(size) };
}
Some(Err(PageSplitError { addr, size })) => {
if traph.page_fault(self, addr, size, dst) {
pspl.jump_page(size);
dst = unsafe { dst.add(size as _) };
} else {
return Err(());
}
}
None => return Ok(()),
} }
action(ptr, dst, size);
dst = unsafe { dst.add(size) };
} }
Ok(())
} }
} }
@ -164,6 +177,11 @@ struct PageSplitResult {
perm: Permission, perm: Permission,
} }
struct PageSplitError {
addr: u64,
size: PageSize,
}
struct PageSplitter { struct PageSplitter {
addr: u64, addr: u64,
size: usize, size: usize,
@ -178,10 +196,15 @@ impl PageSplitter {
pagetable, pagetable,
} }
} }
fn jump_page(&mut self, page_size: PageSize) {
self.addr += page_size as u64;
self.size = self.size.saturating_sub(page_size as _);
}
} }
impl Iterator for PageSplitter { impl Iterator for PageSplitter {
type Item = PageSplitResult; type Item = Result<PageSplitResult, PageSplitError>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.size == 0 { if self.size == 0 {
@ -199,18 +222,18 @@ impl Iterator for PageSplitter {
let ptr = entry.ptr(); let ptr = entry.ptr();
match entry.permission() { match entry.permission() {
Permission::Empty => return None, Permission::Empty => {
return Some(Err(PageSplitError {
addr: self.addr,
size: PageSize::from_lvl(lvl)?,
}))
}
Permission::Node => current_pt = ptr as _, Permission::Node => current_pt = ptr as _,
perm => { perm => {
break 'a ( break 'a (
ptr as *mut u8, ptr as *mut u8,
perm, perm,
match lvl { PageSize::from_lvl(lvl)?,
0 => PageSize::Size4K,
1 => PageSize::Size2M,
2 => PageSize::Size1G,
_ => return None,
},
self.addr as usize & ((1 << (lvl * 9 + 12)) - 1), self.addr as usize & ((1 << (lvl * 9 + 12)) - 1),
) )
} }
@ -221,13 +244,12 @@ impl Iterator for PageSplitter {
}; };
let avail = (size as usize - offset).clamp(0, self.size); let avail = (size as usize - offset).clamp(0, self.size);
self.addr += size as u64; self.jump_page(size);
self.size = self.size.saturating_sub(size as _); Some(Ok(PageSplitResult {
Some(PageSplitResult {
ptr: unsafe { base.add(offset) }, ptr: unsafe { base.add(offset) },
size: avail, size: avail,
perm, perm,
}) }))
} }
} }
@ -237,3 +259,14 @@ pub enum PageSize {
Size2M = 1024 * 1024 * 2, Size2M = 1024 * 1024 * 2,
Size1G = 1024 * 1024 * 1024, Size1G = 1024 * 1024 * 1024,
} }
impl PageSize {
pub fn from_lvl(lvl: u8) -> Option<Self> {
match lvl {
0 => Some(PageSize::Size4K),
1 => Some(PageSize::Size2M),
2 => Some(PageSize::Size1G),
_ => None,
}
}
}

View file

@ -13,10 +13,9 @@
use self::trap::HandleTrap; use self::trap::HandleTrap;
pub mod mem;
pub mod trap; pub mod trap;
pub mod value;
mod mem;
mod value;
use { use {
crate::validate, crate::validate,
@ -269,7 +268,8 @@ impl<'a, T: HandleTrap> Vm<'a, T> {
JGTU => cond_jump!(self, sint, Greater), JGTU => cond_jump!(self, sint, Greater),
ECALL => { ECALL => {
param!(self, ()); param!(self, ());
return HaltReason::Ecall; self.traph
.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),
MULF => binary_op!(self, as_f64, ops::Mul::mul), MULF => binary_op!(self, as_f64, ops::Mul::mul),
@ -282,7 +282,16 @@ impl<'a, T: HandleTrap> Vm<'a, T> {
} }
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),
_ => return HaltReason::InvalidOpcode, op => {
if !self.traph.invalid_op(
&mut self.registers,
&mut self.pc,
&mut self.memory,
op,
) {
return HaltReason::InvalidOpcode;
}
}
} }
} }
} }

View file

@ -1,3 +1,21 @@
use super::{
mem::{Memory, PageSize},
value::Value,
Vm,
};
pub trait HandleTrap { pub trait HandleTrap {
fn page_fault(&mut self) {} fn page_fault(&mut self, memory: &mut Memory, addr: u64, size: PageSize, dst: *mut u8) -> bool;
fn invalid_op(
&mut self,
regs: &mut [Value; 256],
pc: &mut usize,
memory: &mut Memory,
op: u8,
) -> bool
where
Self: Sized;
fn ecall(&mut self, regs: &mut [Value; 256], pc: &mut usize, memory: &mut Memory)
where
Self: Sized;
} }