interrupt handling
This commit is contained in:
parent
965a6a2c19
commit
4fd96e1b0e
|
@ -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,
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,7 +146,10 @@ 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);
|
||||||
|
loop {
|
||||||
|
match pspl.next() {
|
||||||
|
Some(Ok(PageSplitResult { ptr, size, perm })) => {
|
||||||
if !permission_check(perm) {
|
if !permission_check(perm) {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -153,8 +157,17 @@ impl Memory {
|
||||||
action(ptr, dst, size);
|
action(ptr, dst, size);
|
||||||
dst = unsafe { dst.add(size) };
|
dst = unsafe { dst.add(size) };
|
||||||
}
|
}
|
||||||
|
Some(Err(PageSplitError { addr, size })) => {
|
||||||
Ok(())
|
if traph.page_fault(self, addr, size, dst) {
|
||||||
|
pspl.jump_page(size);
|
||||||
|
dst = unsafe { dst.add(size as _) };
|
||||||
|
} else {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => return 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue