Block memory copy
This commit is contained in:
parent
6356b7dd24
commit
498e729c90
|
@ -1,7 +1,9 @@
|
||||||
mod paging;
|
mod paging;
|
||||||
|
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use self::paging::{PageTable, Permission, PtEntry};
|
use self::paging::{PageTable, Permission, PtEntry};
|
||||||
use super::trap::HandleTrap;
|
use super::{trap::HandleTrap, VmRunError};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use derive_more::Display;
|
use derive_more::Display;
|
||||||
|
|
||||||
|
@ -105,37 +107,80 @@ 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<(), ()> {
|
///
|
||||||
/* let count = usize::try_from(count).expect("?conradluget a better CPU");
|
/// # Safety
|
||||||
|
/// - Same as for [`Self::load`] and [`Self::store`]
|
||||||
|
/// - Your faith in the gods of UB
|
||||||
|
/// - Addr-san claims it's fine but who knows is she isn't lying :ferrisSus:
|
||||||
|
pub unsafe fn block_copy(
|
||||||
|
&mut self,
|
||||||
|
src: u64,
|
||||||
|
dst: u64,
|
||||||
|
count: usize,
|
||||||
|
traph: &mut impl HandleTrap,
|
||||||
|
) -> Result<(), BlkCopyError> {
|
||||||
|
// Yea, i know it is possible to do this more efficiently, but I am too lazy.
|
||||||
|
|
||||||
let mut srcs = PageSplitter::new(src, count, self.root_pt);
|
const STACK_BUFFER_SIZE: usize = 512;
|
||||||
let mut dsts = PageSplitter::new(dst, count, self.root_pt);
|
|
||||||
let mut c_src = srcs.next().ok_or(())?;
|
|
||||||
let mut c_dst = dsts.next().ok_or(())?;
|
|
||||||
|
|
||||||
loop {
|
// Decide if to use stack-allocated buffer or to heap allocate
|
||||||
let min_size = c_src.size.min(c_dst.size);
|
// Deallocation is again decided on size at the end of the function
|
||||||
|
let mut buf = MaybeUninit::<[u8; STACK_BUFFER_SIZE]>::uninit();
|
||||||
|
let buf = if count <= STACK_BUFFER_SIZE {
|
||||||
|
buf.as_mut_ptr().cast()
|
||||||
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
core::ptr::copy(c_src.ptr, c_dst.ptr, min_size);
|
let layout = core::alloc::Layout::from_size_align_unchecked(count, 1);
|
||||||
}
|
let ptr = alloc::alloc::alloc(layout);
|
||||||
|
if ptr.is_null() {
|
||||||
|
alloc::alloc::handle_alloc_error(layout);
|
||||||
|
}
|
||||||
|
|
||||||
match (
|
ptr
|
||||||
match c_src.size.saturating_sub(min_size) {
|
|
||||||
0 => srcs.next(),
|
|
||||||
size => Some(PageSplitResult { size, ..c_src }),
|
|
||||||
},
|
|
||||||
match c_dst.size.saturating_sub(min_size) {
|
|
||||||
0 => dsts.next(),
|
|
||||||
size => Some(PageSplitResult { size, ..c_dst }),
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
(None, None) => return Ok(()),
|
|
||||||
(Some(src), Some(dst)) => (c_src, c_dst) = (src, dst),
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
}
|
||||||
} */
|
};
|
||||||
// TODO
|
|
||||||
Err(())
|
// Perform memory block transfer
|
||||||
|
let status = (|| {
|
||||||
|
// Load to buffer
|
||||||
|
self.memory_access(
|
||||||
|
src,
|
||||||
|
buf,
|
||||||
|
count,
|
||||||
|
|perm| {
|
||||||
|
matches!(
|
||||||
|
perm,
|
||||||
|
Permission::Readonly | Permission::Write | Permission::Exec
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|src, dst, count| core::ptr::copy(src, dst, count),
|
||||||
|
traph,
|
||||||
|
)
|
||||||
|
.map_err(|_| BlkCopyError::Load)?;
|
||||||
|
|
||||||
|
// Store from buffer
|
||||||
|
self.memory_access(
|
||||||
|
dst,
|
||||||
|
buf,
|
||||||
|
count,
|
||||||
|
|perm| perm == Permission::Write,
|
||||||
|
|dst, src, count| core::ptr::copy(src, dst, count),
|
||||||
|
traph,
|
||||||
|
)
|
||||||
|
.map_err(|_| BlkCopyError::Store)?;
|
||||||
|
|
||||||
|
Ok::<_, BlkCopyError>(())
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Deallocate if used heap-allocated array
|
||||||
|
if count > STACK_BUFFER_SIZE {
|
||||||
|
alloc::alloc::dealloc(
|
||||||
|
buf,
|
||||||
|
core::alloc::Layout::from_size_align_unchecked(count, 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split address to pages, check their permissions and feed pointers with offset
|
/// Split address to pages, check their permissions and feed pointers with offset
|
||||||
|
@ -302,7 +347,7 @@ pub enum PageSize {
|
||||||
|
|
||||||
/// 2 MiB page (on level 1)
|
/// 2 MiB page (on level 1)
|
||||||
Size2M = 1024 * 1024 * 2,
|
Size2M = 1024 * 1024 * 2,
|
||||||
|
|
||||||
/// 1 GiB page (on level 2)
|
/// 1 GiB page (on level 2)
|
||||||
Size1G = 1024 * 1024 * 1024,
|
Size1G = 1024 * 1024 * 1024,
|
||||||
}
|
}
|
||||||
|
@ -326,3 +371,31 @@ pub struct LoadError;
|
||||||
/// Unhandled store access trap
|
/// Unhandled store access trap
|
||||||
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
|
||||||
pub struct StoreError;
|
pub struct StoreError;
|
||||||
|
|
||||||
|
/// Unhandled block transfer trap
|
||||||
|
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
|
||||||
|
pub enum BlkCopyError {
|
||||||
|
Load,
|
||||||
|
Store,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LoadError> for VmRunError {
|
||||||
|
fn from(_: LoadError) -> Self {
|
||||||
|
Self::LoadAccessEx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StoreError> for VmRunError {
|
||||||
|
fn from(_: StoreError) -> Self {
|
||||||
|
Self::StoreAccessEx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BlkCopyError> for VmRunError {
|
||||||
|
fn from(value: BlkCopyError) -> Self {
|
||||||
|
match value {
|
||||||
|
BlkCopyError::Load => Self::LoadAccessEx,
|
||||||
|
BlkCopyError::Store => Self::StoreAccessEx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ use {
|
||||||
value::Value,
|
value::Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Extract a parameter from program
|
/// Extract a parameter from program
|
||||||
macro_rules! param {
|
macro_rules! param {
|
||||||
($self:expr, $ty:ty) => {{
|
($self:expr, $ty:ty) => {{
|
||||||
|
@ -227,47 +226,30 @@ impl<'a, T: HandleTrap> Vm<'a, T> {
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if self
|
self.memory.load(
|
||||||
.memory
|
self.read_reg(base).as_u64() + off + n as u64,
|
||||||
.load(
|
self.registers.as_mut_ptr().add(usize::from(dst) + n).cast(),
|
||||||
self.read_reg(base).as_u64() + off + n as u64,
|
usize::from(count).saturating_sub(n),
|
||||||
self.registers.as_mut_ptr().add(usize::from(dst) + n).cast(),
|
&mut self.traph,
|
||||||
usize::from(count).saturating_sub(n),
|
)?;
|
||||||
&mut self.traph,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return Err(VmRunError::LoadAccessEx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ST => {
|
ST => {
|
||||||
let ParamBBDH(dst, base, off, count) = param!(self, ParamBBDH);
|
let ParamBBDH(dst, base, off, count) = param!(self, ParamBBDH);
|
||||||
if self
|
self.memory.store(
|
||||||
.memory
|
self.read_reg(base).as_u64() + off,
|
||||||
.store(
|
self.registers.as_ptr().add(usize::from(dst)).cast(),
|
||||||
self.read_reg(base).as_u64() + off,
|
count.into(),
|
||||||
self.registers.as_ptr().add(usize::from(dst)).cast(),
|
&mut self.traph,
|
||||||
count.into(),
|
)?;
|
||||||
&mut self.traph,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return Err(VmRunError::LoadAccessEx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
BMC => {
|
BMC => {
|
||||||
let ParamBBD(src, dst, count) = param!(self, ParamBBD);
|
let ParamBBD(src, dst, count) = param!(self, ParamBBD);
|
||||||
if self
|
self.memory.block_copy(
|
||||||
.memory
|
self.read_reg(src).as_u64(),
|
||||||
.block_copy(
|
self.read_reg(dst).as_u64(),
|
||||||
self.read_reg(src).as_u64(),
|
count as _,
|
||||||
self.read_reg(dst).as_u64(),
|
&mut self.traph,
|
||||||
count,
|
)?;
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
return Err(VmRunError::LoadAccessEx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
BRC => {
|
BRC => {
|
||||||
let ParamBBB(src, dst, count) = param!(self, ParamBBB);
|
let ParamBBB(src, dst, count) = param!(self, ParamBBB);
|
||||||
|
|
Loading…
Reference in a new issue