Some stuff

This commit is contained in:
Erin 2023-08-17 03:33:47 +02:00 committed by ondra05
parent af1de4b9ec
commit 04da28ce44
5 changed files with 127 additions and 2 deletions

View file

@ -1,2 +1,3 @@
[workspace]
resolver = "2"
members = ["hbasm", "hbbytecode", "hbvm"]

View file

@ -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,
);

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

View file

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

View file

@ -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()
}
}