diff --git a/hbvm/src/main.rs b/hbvm/src/main.rs index 05c13d3..5aac639 100644 --- a/hbvm/src/main.rs +++ b/hbvm/src/main.rs @@ -1,4 +1,8 @@ -use hbvm::vm::trap::HandleTrap; +use hbvm::vm::{ + mem::{Memory, PageSize}, + trap::HandleTrap, + value::Value, +}; use { hbvm::{validate::validate, vm::Vm}, @@ -29,6 +33,20 @@ pub fn time() -> u32 { struct TestTrapHandler; impl HandleTrap for TestTrapHandler { - #[inline] - fn page_fault(&mut self) {} + fn page_fault(&mut self, _: &mut Memory, _: u64, _: PageSize, _: *mut u8) -> 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 05bb511..a09eae3 100644 --- a/hbvm/src/vm/mem/mod.rs +++ b/hbvm/src/vm/mem/mod.rs @@ -55,7 +55,7 @@ impl Memory { /// Load value from an address pub unsafe fn load( - &self, + &mut self, addr: u64, target: *mut u8, count: usize, @@ -96,7 +96,7 @@ impl Memory { /// Copy a block of memory 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 dsts = PageSplitter::new(dst, count, self.root_pt); @@ -123,7 +123,8 @@ impl Memory { (Some(src), Some(dst)) => (c_src, c_dst) = (src, dst), _ => return Err(()), } - } + } */ + Err(()) } #[inline] @@ -137,7 +138,7 @@ impl Memory { } fn memory_access( - &self, + &mut self, src: u64, mut dst: *mut u8, len: usize, @@ -145,16 +146,28 @@ impl Memory { action: fn(*mut u8, *mut u8, usize), traph: &mut impl HandleTrap, ) -> Result<(), ()> { - for PageSplitResult { ptr, size, perm } in PageSplitter::new(src, len, self.root_pt) { - if !permission_check(perm) { - return Err(()); + let mut pspl = PageSplitter::new(src, len, self.root_pt); + loop { + 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, } +struct PageSplitError { + addr: u64, + size: PageSize, +} + struct PageSplitter { addr: u64, size: usize, @@ -178,10 +196,15 @@ impl PageSplitter { 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 { - type Item = PageSplitResult; + type Item = Result; fn next(&mut self) -> Option { if self.size == 0 { @@ -199,18 +222,18 @@ impl Iterator for PageSplitter { let ptr = entry.ptr(); 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 _, perm => { break 'a ( ptr as *mut u8, perm, - match lvl { - 0 => PageSize::Size4K, - 1 => PageSize::Size2M, - 2 => PageSize::Size1G, - _ => return None, - }, + PageSize::from_lvl(lvl)?, 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); - self.addr += size as u64; - self.size = self.size.saturating_sub(size as _); - Some(PageSplitResult { + self.jump_page(size); + Some(Ok(PageSplitResult { ptr: unsafe { base.add(offset) }, size: avail, perm, - }) + })) } } @@ -237,3 +259,14 @@ pub enum PageSize { Size2M = 1024 * 1024 * 2, Size1G = 1024 * 1024 * 1024, } + +impl PageSize { + pub fn from_lvl(lvl: u8) -> Option { + match lvl { + 0 => Some(PageSize::Size4K), + 1 => Some(PageSize::Size2M), + 2 => Some(PageSize::Size1G), + _ => None, + } + } +} diff --git a/hbvm/src/vm/mod.rs b/hbvm/src/vm/mod.rs index 1ae52a1..14b0d60 100644 --- a/hbvm/src/vm/mod.rs +++ b/hbvm/src/vm/mod.rs @@ -13,10 +13,9 @@ use self::trap::HandleTrap; +pub mod mem; pub mod trap; - -mod mem; -mod value; +pub mod value; use { crate::validate, @@ -269,7 +268,8 @@ impl<'a, T: HandleTrap> Vm<'a, T> { JGTU => cond_jump!(self, sint, Greater), ECALL => { 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), 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), 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; + } + } } } } diff --git a/hbvm/src/vm/trap.rs b/hbvm/src/vm/trap.rs index 309180d..f7d6876 100644 --- a/hbvm/src/vm/trap.rs +++ b/hbvm/src/vm/trap.rs @@ -1,3 +1,21 @@ +use super::{ + mem::{Memory, PageSize}, + value::Value, + Vm, +}; + 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; }