Changed stuff aroud
This commit is contained in:
parent
82f23ec2e2
commit
bf50bcb203
|
@ -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
|
||||||
///
|
///
|
||||||
|
|
|
@ -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,
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue