Some stuff
This commit is contained in:
parent
af1de4b9ec
commit
04da28ce44
|
@ -1,2 +1,3 @@
|
|||
[workspace]
|
||||
members = ["hbasm", "hbbytecode", "hbvm"]
|
||||
resolver = "2"
|
||||
members = ["hbasm", "hbbytecode", "hbvm"]
|
||||
|
|
|
@ -21,6 +21,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
pf_handler: TestTrapHandler,
|
||||
program: &prog,
|
||||
root_pt: Box::into_raw(Default::default()),
|
||||
icache: Default::default(),
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
|
107
hbvm/src/mem/softpaging/icache.rs
Normal file
107
hbvm/src/mem/softpaging/icache.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
//! Program instruction cache
|
||||
|
||||
use {
|
||||
super::{lookup::AddrPageLookuper, paging::PageTable, HandlePageFault, PageSize},
|
||||
core::{
|
||||
mem::{size_of, MaybeUninit},
|
||||
ptr::{copy_nonoverlapping, NonNull},
|
||||
},
|
||||
};
|
||||
|
||||
/// Instruction cache
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ICache {
|
||||
/// Current page address base
|
||||
base: u64,
|
||||
/// Curent page pointer
|
||||
data: Option<NonNull<u8>>,
|
||||
/// Current page size
|
||||
size: PageSize,
|
||||
/// Address mask
|
||||
mask: u64,
|
||||
}
|
||||
|
||||
impl Default for ICache {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base: Default::default(),
|
||||
data: Default::default(),
|
||||
size: PageSize::Size4K,
|
||||
mask: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ICache {
|
||||
/// Fetch instruction from cache
|
||||
///
|
||||
/// # Safety
|
||||
/// `T` should be valid to read from instruction memory
|
||||
pub(super) unsafe fn fetch<T>(
|
||||
&mut self,
|
||||
addr: u64,
|
||||
root_pt: *const PageTable,
|
||||
) -> Option<T> {
|
||||
let mut ret = MaybeUninit::<T>::uninit();
|
||||
|
||||
let pbase = self
|
||||
.data
|
||||
.or_else(|| self.fetch_page(self.base.checked_add(self.size as _)?, root_pt))?;
|
||||
|
||||
// Get address base
|
||||
let base = addr & self.mask;
|
||||
|
||||
// Base not matching, fetch anew
|
||||
if base != self.base {
|
||||
self.fetch_page(base, root_pt)?;
|
||||
};
|
||||
|
||||
let offset = addr & !self.mask;
|
||||
let requ_size = size_of::<T>();
|
||||
|
||||
// Page overflow
|
||||
let rem = (offset as usize)
|
||||
.saturating_add(requ_size)
|
||||
.saturating_sub(self.size as _);
|
||||
let first_copy = requ_size.saturating_sub(rem);
|
||||
|
||||
// Copy non-overflowing part
|
||||
copy_nonoverlapping(pbase.as_ptr(), ret.as_mut_ptr().cast::<u8>(), first_copy);
|
||||
|
||||
// Copy overflow
|
||||
if rem != 0 {
|
||||
let pbase = self.fetch_page(self.base.checked_add(self.size as _)?, root_pt)?;
|
||||
|
||||
// Unlikely, unsupported scenario
|
||||
if rem > self.size as _ {
|
||||
return None;
|
||||
}
|
||||
|
||||
copy_nonoverlapping(
|
||||
pbase.as_ptr(),
|
||||
ret.as_mut_ptr().cast::<u8>().add(first_copy),
|
||||
rem,
|
||||
);
|
||||
}
|
||||
|
||||
Some(ret.assume_init())
|
||||
}
|
||||
|
||||
/// Fetch a page
|
||||
unsafe fn fetch_page(&mut self, addr: u64, pt: *const PageTable) -> Option<NonNull<u8>> {
|
||||
let res = AddrPageLookuper::new(addr, 0, pt).next()?.ok()?;
|
||||
if !super::perm_check::executable(res.perm) {
|
||||
return None;
|
||||
}
|
||||
|
||||
(self.size, self.mask) = match res.size {
|
||||
4096 => (PageSize::Size4K, !((1 << 8) - 1)),
|
||||
2097152 => (PageSize::Size2M, !((1 << (8 * 2)) - 1)),
|
||||
1073741824 => (PageSize::Size1G, !((1 << (8 * 3)) - 1)),
|
||||
_ => return None,
|
||||
};
|
||||
self.data = Some(NonNull::new(res.ptr)?);
|
||||
self.base = addr & self.mask;
|
||||
self.data
|
||||
}
|
||||
}
|
|
@ -111,7 +111,7 @@ impl Iterator for AddrPageLookuper {
|
|||
};
|
||||
|
||||
// Get available byte count in the selected page with offset
|
||||
let avail = (size as usize - offset).clamp(0, self.size);
|
||||
let avail = (size as usize).saturating_sub(offset).clamp(0, self.size);
|
||||
self.bump(size);
|
||||
|
||||
Some(Ok(AddrPageLookupOk {
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
use core::mem::size_of;
|
||||
|
||||
use self::icache::ICache;
|
||||
|
||||
pub mod icache;
|
||||
pub mod lookup;
|
||||
pub mod paging;
|
||||
|
||||
|
@ -23,6 +26,8 @@ pub struct SoftPagedMem<'p, PfH> {
|
|||
pub pf_handler: PfH,
|
||||
/// Program memory segment
|
||||
pub program: &'p [u8],
|
||||
/// Program instruction cache
|
||||
pub icache: ICache,
|
||||
}
|
||||
|
||||
impl<'p, PfH: HandlePageFault> Memory for SoftPagedMem<'p, PfH> {
|
||||
|
@ -65,6 +70,10 @@ impl<'p, PfH: HandlePageFault> Memory for SoftPagedMem<'p, PfH> {
|
|||
|
||||
#[inline(always)]
|
||||
unsafe fn prog_read<T>(&mut self, addr: u64) -> Option<T> {
|
||||
if addr as usize > self.program.len() {
|
||||
return self.icache.fetch::<T>(addr, self.root_pt);
|
||||
}
|
||||
|
||||
let addr = addr as usize;
|
||||
self.program
|
||||
.get(addr..addr + size_of::<T>())
|
||||
|
@ -73,6 +82,13 @@ impl<'p, PfH: HandlePageFault> Memory for SoftPagedMem<'p, PfH> {
|
|||
|
||||
#[inline(always)]
|
||||
unsafe fn prog_read_unchecked<T>(&mut self, addr: u64) -> T {
|
||||
if addr as usize > self.program.len() {
|
||||
return self
|
||||
.icache
|
||||
.fetch::<T>(addr as _, self.root_pt)
|
||||
.unwrap_or_else(|| core::mem::zeroed());
|
||||
}
|
||||
|
||||
self.program.as_ptr().add(addr as _).cast::<T>().read()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue