Changed stuff aroud

This commit is contained in:
Erin 2023-08-08 03:03:15 +02:00 committed by ondra05
parent 1e92797775
commit 62d241e78c
8 changed files with 99 additions and 75 deletions

View file

@ -17,6 +17,7 @@ macro_rules! constmod {
}; };
} }
#[allow(rustdoc::invalid_rust_codeblocks)]
/// Invoke macro with bytecode definition /// Invoke macro with bytecode definition
/// # Input syntax /// # Input syntax
/// ```no_run /// ```no_run
@ -31,7 +32,7 @@ macro_rules! constmod {
/// - Per-instructions there will be generated opcode-specific functions calling the generic ones /// - Per-instructions there will be generated opcode-specific functions calling the generic ones
/// - Operand types /// - Operand types
/// - R: Register (u8) /// - R: Register (u8)
/// - I: Immediate (implements [`crate::Imm`] trait) /// - I: Immediate
/// - L: Memory load / store size (u16) /// - L: Memory load / store size (u16)
/// - Other types are identity-mapped /// - Other types are identity-mapped
/// ///

View file

@ -1,16 +1,18 @@
//! Block memory copier state machine
use { use {
super::MemoryAccessReason, super::{Memory, MemoryAccessReason, VmRunError},
crate::{mem::Memory, VmRunError},
core::{mem::MaybeUninit, task::Poll}, core::{mem::MaybeUninit, task::Poll},
}; };
// Buffer size (defaults to 4 KiB, a smallest page size on most platforms) /// Buffer size (defaults to 4 KiB, a smallest page size on most platforms)
const BUF_SIZE: usize = 4096; const BUF_SIZE: usize = 4096;
// This should be equal to `BUF_SIZE` /// Buffer of possibly uninitialised bytes, aligned to [`BUF_SIZE`]
#[repr(align(4096))] #[repr(align(4096))]
struct AlignedBuf([MaybeUninit<u8>; BUF_SIZE]); struct AlignedBuf([MaybeUninit<u8>; BUF_SIZE]);
/// State for block memory copy
pub struct BlockCopier { pub struct BlockCopier {
/// Source address /// Source address
src: u64, src: u64,
@ -23,6 +25,7 @@ pub struct BlockCopier {
} }
impl BlockCopier { impl BlockCopier {
/// Construct a new one
#[inline] #[inline]
pub fn new(src: u64, dst: u64, count: usize) -> Self { pub fn new(src: u64, dst: u64, count: usize) -> Self {
Self { Self {
@ -93,6 +96,7 @@ impl BlockCopier {
} }
} }
/// Load to buffer and store from buffer
#[inline] #[inline]
unsafe fn act( unsafe fn act(
memory: &mut impl Memory, memory: &mut impl Memory,

View file

@ -2,8 +2,8 @@
//! //!
//! # Alloc feature //! # Alloc feature
//! - Enabled by default //! - Enabled by default
//! - Provides [`mem::Memory`] mapping / unmapping, as well as //! - Provides mapping / unmapping, as well as [`Default`] and [`Drop`]
//! [`Default`] and [`Drop`] implementation //! implementations for soft-paged memory implementation
// # General safety notice: // # General safety notice:
// - Validation has to assure there is 256 registers (r0 - r255) // - Validation has to assure there is 256 registers (r0 - r255)
@ -12,26 +12,30 @@
#![no_std] #![no_std]
#![cfg_attr(feature = "nightly", feature(fn_align))] #![cfg_attr(feature = "nightly", feature(fn_align))]
#![warn(missing_docs, clippy::missing_docs_in_private_items)]
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
pub mod mem; pub mod softpaging;
pub mod value; pub mod value;
mod bmc;
use { use {
bmc::BlockCopier,
core::{cmp::Ordering, mem::size_of, ops}, core::{cmp::Ordering, mem::size_of, ops},
derive_more::Display,
hbbytecode::{ hbbytecode::{
valider, OpParam, ParamBB, ParamBBB, ParamBBBB, ParamBBD, ParamBBDH, ParamBBW, ParamBD, valider, OpParam, ParamBB, ParamBBB, ParamBBBB, ParamBBD, ParamBBDH, ParamBBW, ParamBD,
}, },
mem::bmc::BlockCopier,
value::{Value, ValueVariant}, value::{Value, ValueVariant},
}; };
/// HoleyBytes Virtual Machine /// HoleyBytes Virtual Machine
pub struct Vm<'a, Memory, const TIMER_QUOTIENT: usize> { pub struct Vm<'a, Mem, const TIMER_QUOTIENT: usize> {
/// Holds 256 registers /// Holds 256 registers
/// ///
/// Writing to register 0 is considered undefined behaviour /// Writing to register 0 is considered undefined behaviour
@ -39,7 +43,7 @@ pub struct Vm<'a, Memory, const TIMER_QUOTIENT: usize> {
pub registers: [Value; 256], pub registers: [Value; 256],
/// Memory implementation /// Memory implementation
pub memory: Memory, pub memory: Mem,
/// Program counter /// Program counter
pub pc: usize, pub pc: usize,
@ -60,15 +64,15 @@ pub struct Vm<'a, Memory, const TIMER_QUOTIENT: usize> {
copier: Option<BlockCopier>, copier: Option<BlockCopier>,
} }
impl<'a, Memory, const TIMER_QUOTIENT: usize> Vm<'a, Memory, TIMER_QUOTIENT> impl<'a, Mem, const TIMER_QUOTIENT: usize> Vm<'a, Mem, TIMER_QUOTIENT>
where where
Memory: mem::Memory, Mem: Memory,
{ {
/// Create a new VM with program and trap handler /// Create a new VM with program and trap handler
/// ///
/// # Safety /// # Safety
/// Program code has to be validated /// Program code has to be validated
pub unsafe fn new_unchecked(program: &'a [u8], memory: Memory) -> Self { pub unsafe fn new_unchecked(program: &'a [u8], memory: Mem) -> Self {
Self { Self {
registers: [Value::from(0_u64); 256], registers: [Value::from(0_u64); 256],
memory, memory,
@ -82,7 +86,7 @@ where
} }
/// Create a new VM with program and trap handler only if it passes validation /// Create a new VM with program and trap handler only if it passes validation
pub fn new_validated(program: &'a [u8], memory: Memory) -> Result<Self, valider::Error> { pub fn new_validated(program: &'a [u8], memory: Mem) -> Result<Self, valider::Error> {
valider::validate(program)?; valider::validate(program)?;
Ok(unsafe { Self::new_unchecked(program, memory) }) Ok(unsafe { Self::new_unchecked(program, memory) })
} }
@ -502,3 +506,54 @@ pub enum VmRunOk {
/// Environment call /// Environment call
Ecall, Ecall,
} }
/// Load-store memory access
pub trait Memory {
/// Load data from memory on address
///
/// # Safety
/// - Shall not overrun the buffer
unsafe fn load(&mut self, addr: u64, target: *mut u8, count: usize) -> Result<(), LoadError>;
/// Store data to memory on address
///
/// # Safety
/// - Shall not overrun the buffer
unsafe fn store(
&mut self,
addr: u64,
source: *const u8,
count: usize,
) -> Result<(), StoreError>;
}
/// Unhandled load access trap
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
#[display(fmt = "Load access error at address {_0:#x}")]
pub struct LoadError(pub u64);
/// Unhandled store access trap
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
#[display(fmt = "Store access error at address {_0:#x}")]
pub struct StoreError(pub u64);
/// Reason to access memory
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
pub enum MemoryAccessReason {
/// Memory was accessed for load (read)
Load,
/// Memory was accessed for store (write)
Store,
}
impl From<LoadError> for VmRunError {
fn from(value: LoadError) -> Self {
Self::LoadAccessEx(value.0)
}
}
impl From<StoreError> for VmRunError {
fn from(value: StoreError) -> Self {
Self::StoreAccessEx(value.0)
}
}

View file

@ -1,8 +1,9 @@
use hbvm::mem::softpaged::{HandlePageFault, PageSize, SoftPagedMem};
use { use {
hbbytecode::valider::validate, hbbytecode::valider::validate,
hbvm::{mem::MemoryAccessReason, Vm}, hbvm::{
softpaging::{HandlePageFault, PageSize, SoftPagedMem},
MemoryAccessReason, Vm,
},
std::io::{stdin, Read}, std::io::{stdin, Read},
}; };
@ -31,7 +32,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.map( .map(
data, data,
0, 0,
hbvm::mem::softpaged::paging::Permission::Write, hbvm::softpaging::paging::Permission::Write,
PageSize::Size4K, PageSize::Size4K,
) )
.unwrap(); .unwrap();

View file

@ -1,54 +0,0 @@
//! Program memory implementation
pub mod bmc;
pub mod softpaged;
use {super::VmRunError, derive_more::Display};
pub trait Memory {
/// Load data from memory on address
///
/// # Safety
/// - Shall not overrun the buffer
unsafe fn load(&mut self, addr: u64, target: *mut u8, count: usize) -> Result<(), LoadError>;
/// Store data to memory on address
///
/// # Safety
/// - Shall not overrun the buffer
unsafe fn store(
&mut self,
addr: u64,
source: *const u8,
count: usize,
) -> Result<(), StoreError>;
}
/// Unhandled load access trap
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
#[display(fmt = "Load access error at address {_0:#x}")]
pub struct LoadError(pub u64);
/// Unhandled store access trap
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
#[display(fmt = "Store access error at address {_0:#x}")]
pub struct StoreError(pub u64);
/// Reason to access memory
#[derive(Clone, Copy, Display, Debug, PartialEq, Eq)]
pub enum MemoryAccessReason {
Load,
Store,
}
impl From<LoadError> for VmRunError {
fn from(value: LoadError) -> Self {
Self::LoadAccessEx(value.0)
}
}
impl From<StoreError> for VmRunError {
fn from(value: StoreError) -> Self {
Self::StoreAccessEx(value.0)
}
}

View file

@ -59,7 +59,9 @@ impl Debug for PtEntry {
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(align(4096))] #[repr(align(4096))]
pub struct PageTable { pub struct PageTable {
/// How much entries are in use
pub childen: u8, pub childen: u8,
/// Entries
pub table: [PtEntry; 256], pub table: [PtEntry; 256],
} }

View file

@ -13,7 +13,10 @@ macro_rules! value_def {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(packed)] #[repr(packed)]
pub union Value { pub union Value {
$(pub $ty: $ty),* $(
#[doc = concat!(stringify!($ty), " type")]
pub $ty: $ty
),*
} }
@ -37,10 +40,22 @@ macro_rules! value_def {
} }
impl Value { impl Value {
/// Byte reinterpret value to target variant
#[inline] #[inline]
pub fn cast<Variant: ValueVariant>(self) -> Variant { pub fn cast<V: ValueVariant>(self) -> V {
/// Evil.
///
/// Transmute cannot be performed with generic type
/// as size is unknown, so union is used.
///
/// # Safety
/// If [`ValueVariant`] implemented correctly, it's fine :)
///
/// :ferrisClueless:
union Transmute<Variant: ValueVariant> { union Transmute<Variant: ValueVariant> {
/// Self
src: Value, src: Value,
/// Target variant
variant: Variant, variant: Variant,
} }