holey-bytes/hbvm/src/vm/mem/mod.rs

130 lines
3.6 KiB
Rust
Raw Normal View History

2023-06-11 06:26:16 -05:00
// HACK: This is temporary implementation so we can have memory instructions working
mod paging;
use self::paging::{PageTable, Permission, PtEntry};
use alloc::boxed::Box;
use core::mem::MaybeUninit;
use {crate::vm::value::Value, ma_size::MemAccessSize};
#[derive(Clone, Debug)]
pub struct Memory {
root_pt: *mut PageTable,
}
impl Default for Memory {
fn default() -> Self {
Self {
root_pt: Box::into_raw(Box::default()),
}
}
}
impl Drop for Memory {
fn drop(&mut self) {
let _ = unsafe { Box::from_raw(self.root_pt) };
}
}
impl Memory {
// HACK: Just for allocation testing, will be removed when proper memory interfaces
// implemented.
pub fn insert_test_page(&mut self) {
unsafe {
let mut entry = PtEntry::new(
{
let layout = alloc::alloc::Layout::from_size_align_unchecked(4096, 4096);
let ptr = alloc::alloc::alloc(layout);
if ptr.is_null() {
alloc::alloc::handle_alloc_error(layout);
}
core::ptr::write_bytes(ptr, 69, 10);
ptr.cast()
},
Permission::Write,
);
for _ in 0..4 {
let mut pt = Box::<PageTable>::default();
pt[0] = entry;
entry = PtEntry::new(Box::into_raw(pt) as _, Permission::Node);
}
self.root_pt_mut()[0] = entry;
}
}
/// Load value from an address
pub fn load<S: MemAccessSize>(&self, addr: u64) -> Option<Value> {
let mut current_pt = self.root_pt;
for lvl in (0..5).rev() {
unsafe {
let entry = (*current_pt).get_unchecked(
usize::try_from((addr >> (lvl * 9 + 12)) & ((1 << 9) - 1))
.expect("?conradluget a better CPU"),
);
let ptr = entry.ptr();
match entry.permission() {
Permission::Empty => return None,
Permission::Node => current_pt = ptr as _,
Permission::Readonly | Permission::Write | Permission::Exec => {
let mut value = MaybeUninit::<Value>::zeroed();
core::ptr::copy_nonoverlapping::<u8>(
entry.ptr() as _,
value.as_mut_ptr().cast(),
1,
);
return Some(value.assume_init());
}
}
}
}
None
}
/// Store value to an address
pub fn store<S: MemAccessSize>(&mut self, addr: u64, value: Value) -> Result<(), ()> {
Err(())
}
#[inline]
pub fn root_pt(&self) -> &PageTable {
unsafe { &*self.root_pt }
}
#[inline]
pub fn root_pt_mut(&mut self) -> &mut PageTable {
unsafe { &mut *self.root_pt }
}
}
macro_rules! size_markers {
($($name:ident = $size:expr),* $(,)?) => {
pub mod ma_size {
/// # Safety
/// Implementor has to assure that [`MemAccessSize::BYTES`] won't be larger than
/// size of [`Value`]
pub unsafe trait MemAccessSize {
const BYTES: usize;
}
$(
pub struct $name;
unsafe impl MemAccessSize for $name {
const BYTES: usize = $size;
}
)*
}
};
}
size_markers! {
Byte = 1,
Doublet = 2,
Quadlet = 4,
Octlet = 8,
}