forked from koniifer/ableos
funny thing
This commit is contained in:
parent
b8432d544c
commit
b84ff70014
|
@ -43,17 +43,19 @@ impl BlockCopier {
|
||||||
/// - Same as for [`Memory::load`] and [`Memory::store`]
|
/// - Same as for [`Memory::load`] and [`Memory::store`]
|
||||||
pub unsafe fn poll(&mut self, memory: &mut impl Memory) -> Poll<Result<(), BlkCopyError>> {
|
pub unsafe fn poll(&mut self, memory: &mut impl Memory) -> Poll<Result<(), BlkCopyError>> {
|
||||||
// Safety: Assuming uninit of array of MaybeUninit is sound
|
// Safety: Assuming uninit of array of MaybeUninit is sound
|
||||||
let mut buf = AlignedBuf(MaybeUninit::uninit().assume_init());
|
let mut buf = AlignedBuf(unsafe { MaybeUninit::uninit().assume_init() });
|
||||||
|
|
||||||
// We have at least one buffer size to copy
|
// We have at least one buffer size to copy
|
||||||
if self.n_buffers != 0 {
|
if self.n_buffers != 0 {
|
||||||
if let Err(e) = act(
|
if let Err(e) = unsafe {
|
||||||
|
act(
|
||||||
memory,
|
memory,
|
||||||
self.src,
|
self.src,
|
||||||
self.dst,
|
self.dst,
|
||||||
buf.0.as_mut_ptr().cast(),
|
buf.0.as_mut_ptr().cast(),
|
||||||
BUF_SIZE,
|
BUF_SIZE,
|
||||||
) {
|
)
|
||||||
|
} {
|
||||||
return Poll::Ready(Err(e));
|
return Poll::Ready(Err(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,13 +75,15 @@ impl BlockCopier {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.rem != 0 {
|
if self.rem != 0 {
|
||||||
if let Err(e) = act(
|
if let Err(e) = unsafe {
|
||||||
|
act(
|
||||||
memory,
|
memory,
|
||||||
self.src,
|
self.src,
|
||||||
self.dst,
|
self.dst,
|
||||||
buf.0.as_mut_ptr().cast(),
|
buf.0.as_mut_ptr().cast(),
|
||||||
self.rem,
|
self.rem,
|
||||||
) {
|
)
|
||||||
|
} {
|
||||||
return Poll::Ready(Err(e));
|
return Poll::Ready(Err(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +101,7 @@ unsafe fn act(
|
||||||
buf: *mut u8,
|
buf: *mut u8,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<(), BlkCopyError> {
|
) -> Result<(), BlkCopyError> {
|
||||||
|
unsafe {
|
||||||
// Load to buffer
|
// Load to buffer
|
||||||
memory
|
memory
|
||||||
.load(src, buf, count)
|
.load(src, buf, count)
|
||||||
|
@ -112,6 +117,7 @@ unsafe fn act(
|
||||||
access_reason: MemoryAccessReason::Store,
|
access_reason: MemoryAccessReason::Store,
|
||||||
addr,
|
addr,
|
||||||
})?;
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ unsafe fn set_rounding_mode(mode: RoundingMode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fpcr: u64;
|
let fpcr: u64;
|
||||||
asm!("mrs {}, fpcr", out(reg) fpcr);
|
unsafe { asm!("mrs {}, fpcr", out(reg) fpcr) };
|
||||||
|
|
||||||
let fpcr = fpcr & !(0b11 << 22)
|
let fpcr = fpcr & !(0b11 << 22)
|
||||||
| (match mode {
|
| (match mode {
|
||||||
|
@ -56,7 +56,7 @@ unsafe fn set_rounding_mode(mode: RoundingMode) {
|
||||||
RoundingMode::Down => 0b10,
|
RoundingMode::Down => 0b10,
|
||||||
}) << 22;
|
}) << 22;
|
||||||
|
|
||||||
asm!("msr fpcr, {}", in(reg) fpcr);
|
unsafe { asm!("msr fpcr, {}", in(reg) fpcr) };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -56,12 +56,14 @@ fnsdef! {
|
||||||
/// [`default_rounding_mode`], you have to rely on inline assembly
|
/// [`default_rounding_mode`], you have to rely on inline assembly
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn set_rounding_mode(mode: RoundingMode) {
|
unsafe fn set_rounding_mode(mode: RoundingMode) {
|
||||||
|
unsafe {
|
||||||
arin::_MM_SET_ROUNDING_MODE(match mode {
|
arin::_MM_SET_ROUNDING_MODE(match mode {
|
||||||
RoundingMode::NearestEven => return,
|
RoundingMode::NearestEven => return,
|
||||||
RoundingMode::Truncate => arin::_MM_ROUND_TOWARD_ZERO,
|
RoundingMode::Truncate => arin::_MM_ROUND_TOWARD_ZERO,
|
||||||
RoundingMode::Up => arin::_MM_ROUND_UP,
|
RoundingMode::Up => arin::_MM_ROUND_UP,
|
||||||
RoundingMode::Down => arin::_MM_ROUND_DOWN,
|
RoundingMode::Down => arin::_MM_ROUND_DOWN,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(feature = "nightly", feature(fn_align))]
|
#![cfg_attr(feature = "nightly", feature(fn_align))]
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
|
@ -48,14 +48,14 @@ impl ICache {
|
||||||
|
|
||||||
let pbase = self
|
let pbase = self
|
||||||
.data
|
.data
|
||||||
.or_else(|| self.fetch_page(self.base + self.size, root_pt))?;
|
.or_else(|| unsafe { self.fetch_page(self.base + self.size, root_pt) })?;
|
||||||
|
|
||||||
// Get address base
|
// Get address base
|
||||||
let base = addr.map(|x| x & self.mask);
|
let base = addr.map(|x| x & self.mask);
|
||||||
|
|
||||||
// Base not matching, fetch anew
|
// Base not matching, fetch anew
|
||||||
if base != self.base {
|
if base != self.base {
|
||||||
self.fetch_page(base, root_pt)?;
|
unsafe { self.fetch_page(base, root_pt) }?;
|
||||||
};
|
};
|
||||||
|
|
||||||
let offset = addr.get() & !self.mask;
|
let offset = addr.get() & !self.mask;
|
||||||
|
@ -68,25 +68,27 @@ impl ICache {
|
||||||
let first_copy = requ_size.saturating_sub(rem);
|
let first_copy = requ_size.saturating_sub(rem);
|
||||||
|
|
||||||
// Copy non-overflowing part
|
// Copy non-overflowing part
|
||||||
copy_nonoverlapping(pbase.as_ptr(), ret.as_mut_ptr().cast::<u8>(), first_copy);
|
unsafe { copy_nonoverlapping(pbase.as_ptr(), ret.as_mut_ptr().cast::<u8>(), first_copy) };
|
||||||
|
|
||||||
// Copy overflow
|
// Copy overflow
|
||||||
if rem != 0 {
|
if rem != 0 {
|
||||||
let pbase = self.fetch_page(self.base + self.size, root_pt)?;
|
let pbase = unsafe { self.fetch_page(self.base + self.size, root_pt) }?;
|
||||||
|
|
||||||
// Unlikely, unsupported scenario
|
// Unlikely, unsupported scenario
|
||||||
if rem > self.size as _ {
|
if rem > self.size as _ {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
copy_nonoverlapping(
|
copy_nonoverlapping(
|
||||||
pbase.as_ptr(),
|
pbase.as_ptr(),
|
||||||
ret.as_mut_ptr().cast::<u8>().add(first_copy),
|
ret.as_mut_ptr().cast::<u8>().add(first_copy),
|
||||||
rem,
|
rem,
|
||||||
);
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ret.assume_init())
|
Some(unsafe { ret.assume_init() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch a page
|
/// Fetch a page
|
||||||
|
|
|
@ -36,9 +36,11 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> {
|
||||||
|
|
||||||
// Walk pagetable levels
|
// Walk pagetable levels
|
||||||
for lvl in (lookup_depth + 1..5).rev() {
|
for lvl in (lookup_depth + 1..5).rev() {
|
||||||
let entry = (*current_pt)
|
let entry = unsafe {
|
||||||
|
(*current_pt)
|
||||||
.table
|
.table
|
||||||
.get_unchecked_mut(addr_extract_index(target, lvl));
|
.get_unchecked_mut(addr_extract_index(target, lvl))
|
||||||
|
};
|
||||||
|
|
||||||
let ptr = entry.ptr();
|
let ptr = entry.ptr();
|
||||||
match entry.permission() {
|
match entry.permission() {
|
||||||
|
@ -46,13 +48,13 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> {
|
||||||
// No worries! Let's create one (allocates).
|
// No worries! Let's create one (allocates).
|
||||||
Permission::Empty => {
|
Permission::Empty => {
|
||||||
// Increase children count
|
// Increase children count
|
||||||
(*current_pt).childen += 1;
|
unsafe { *current_pt }.childen += 1;
|
||||||
|
|
||||||
let table = Box::into_raw(Box::new(PtPointedData {
|
let table = Box::into_raw(Box::new(PtPointedData {
|
||||||
pt: PageTable::default(),
|
pt: PageTable::default(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
core::ptr::write(entry, PtEntry::new(table, Permission::Node));
|
unsafe { core::ptr::write(entry, PtEntry::new(table, Permission::Node)) };
|
||||||
current_pt = table as _;
|
current_pt = table as _;
|
||||||
}
|
}
|
||||||
// Continue walking
|
// Continue walking
|
||||||
|
@ -63,9 +65,11 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = (*current_pt)
|
let node = unsafe {
|
||||||
|
(*current_pt)
|
||||||
.table
|
.table
|
||||||
.get_unchecked_mut(addr_extract_index(target, lookup_depth));
|
.get_unchecked_mut(addr_extract_index(target, lookup_depth))
|
||||||
|
};
|
||||||
|
|
||||||
// Check if node is not mapped
|
// Check if node is not mapped
|
||||||
if node.permission() != Permission::Empty {
|
if node.permission() != Permission::Empty {
|
||||||
|
@ -73,8 +77,10 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write entry
|
// Write entry
|
||||||
|
unsafe {
|
||||||
(*current_pt).childen += 1;
|
(*current_pt).childen += 1;
|
||||||
core::ptr::write(node, PtEntry::new(host.cast(), perm));
|
core::ptr::write(node, PtEntry::new(host.cast(), perm));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl<'p, PfH: HandlePageFault, const OUT_PROG_EXEC: bool> Memory
|
||||||
target,
|
target,
|
||||||
count,
|
count,
|
||||||
perm_check::readable,
|
perm_check::readable,
|
||||||
|src, dst, count| core::ptr::copy_nonoverlapping(src, dst, count),
|
|src, dst, count| unsafe { core::ptr::copy_nonoverlapping(src, dst, count) },
|
||||||
)
|
)
|
||||||
.map_err(LoadError)
|
.map_err(LoadError)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ impl<'p, PfH: HandlePageFault, const OUT_PROG_EXEC: bool> Memory
|
||||||
source.cast_mut(),
|
source.cast_mut(),
|
||||||
count,
|
count,
|
||||||
perm_check::writable,
|
perm_check::writable,
|
||||||
|dst, src, count| core::ptr::copy_nonoverlapping(src, dst, count),
|
|dst, src, count| unsafe { core::ptr::copy_nonoverlapping(src, dst, count) },
|
||||||
)
|
)
|
||||||
.map_err(StoreError)
|
.map_err(StoreError)
|
||||||
}
|
}
|
||||||
|
@ -80,16 +80,14 @@ impl<'p, PfH: HandlePageFault, const OUT_PROG_EXEC: bool> Memory
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn prog_read<T>(&mut self, addr: Address) -> T {
|
unsafe fn prog_read<T>(&mut self, addr: Address) -> T {
|
||||||
if OUT_PROG_EXEC && addr.truncate_usize() > self.program.len() {
|
if OUT_PROG_EXEC && addr.truncate_usize() > self.program.len() {
|
||||||
return self
|
return unsafe { self.icache.fetch::<T>(addr, self.root_pt) }
|
||||||
.icache
|
|
||||||
.fetch::<T>(addr, self.root_pt)
|
|
||||||
.unwrap_or_else(|| unsafe { core::mem::zeroed() });
|
.unwrap_or_else(|| unsafe { core::mem::zeroed() });
|
||||||
}
|
}
|
||||||
|
|
||||||
let addr = addr.truncate_usize();
|
let addr = addr.truncate_usize();
|
||||||
self.program
|
self.program
|
||||||
.get(addr..addr + size_of::<T>())
|
.get(addr..addr + size_of::<T>())
|
||||||
.map(|x| x.as_ptr().cast::<T>().read())
|
.map(|x| unsafe { x.as_ptr().cast::<T>().read() })
|
||||||
.unwrap_or_else(|| unsafe { core::mem::zeroed() })
|
.unwrap_or_else(|| unsafe { core::mem::zeroed() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@ use {
|
||||||
|
|
||||||
macro_rules! handler {
|
macro_rules! handler {
|
||||||
($self:expr, |$ty:ident ($($ident:pat),* $(,)?)| $expr:expr) => {{
|
($self:expr, |$ty:ident ($($ident:pat),* $(,)?)| $expr:expr) => {{
|
||||||
let $ty($($ident),*) = $self.decode::<$ty>();
|
#[allow(unused_unsafe)]
|
||||||
|
let $ty($($ident),*) = unsafe { $self.decode::<$ty>() };
|
||||||
#[allow(clippy::no_effect)] let e = $expr;
|
#[allow(clippy::no_effect)] let e = $expr;
|
||||||
$self.bump_pc::<$ty>();
|
$self.bump_pc::<$ty>();
|
||||||
e
|
e
|
||||||
|
@ -383,7 +384,7 @@ where
|
||||||
/// Decode instruction operands
|
/// Decode instruction operands
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn decode<T: Copy>(&mut self) -> T {
|
unsafe fn decode<T: Copy>(&mut self) -> T {
|
||||||
self.memory.prog_read::<T>(self.pc + 1_u64)
|
unsafe { self.memory.prog_read::<T>(self.pc + 1_u64) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load
|
/// Load
|
||||||
|
@ -400,6 +401,7 @@ where
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
self.memory.load(
|
self.memory.load(
|
||||||
self.ldst_addr_uber(dst, base, offset, count, n)?,
|
self.ldst_addr_uber(dst, base, offset, count, n)?,
|
||||||
self.registers
|
self.registers
|
||||||
|
@ -407,7 +409,8 @@ where
|
||||||
.add(usize::from(dst) + usize::from(n))
|
.add(usize::from(dst) + usize::from(n))
|
||||||
.cast(),
|
.cast(),
|
||||||
usize::from(count).saturating_sub(n.into()),
|
usize::from(count).saturating_sub(n.into()),
|
||||||
)?;
|
)
|
||||||
|
}?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -421,11 +424,13 @@ where
|
||||||
offset: u64,
|
offset: u64,
|
||||||
count: u16,
|
count: u16,
|
||||||
) -> Result<(), VmRunError> {
|
) -> Result<(), VmRunError> {
|
||||||
|
unsafe {
|
||||||
self.memory.store(
|
self.memory.store(
|
||||||
self.ldst_addr_uber(dst, base, offset, count, 0)?,
|
self.ldst_addr_uber(dst, base, offset, count, 0)?,
|
||||||
self.registers.as_ptr().add(usize::from(dst)).cast(),
|
self.registers.as_ptr().add(usize::from(dst)).cast(),
|
||||||
count.into(),
|
count.into(),
|
||||||
)?;
|
)
|
||||||
|
}?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,7 +443,7 @@ where
|
||||||
/// Perform binary operating over two registers
|
/// Perform binary operating over two registers
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn binary_op<T: ValueVariant>(&mut self, op: impl Fn(T, T) -> T) {
|
unsafe fn binary_op<T: ValueVariant>(&mut self, op: impl Fn(T, T) -> T) {
|
||||||
let OpsRRR(tg, a0, a1) = self.decode();
|
let OpsRRR(tg, a0, a1) = unsafe { self.decode() };
|
||||||
self.write_reg(
|
self.write_reg(
|
||||||
tg,
|
tg,
|
||||||
op(self.read_reg(a0).cast::<T>(), self.read_reg(a1).cast::<T>()),
|
op(self.read_reg(a0).cast::<T>(), self.read_reg(a1).cast::<T>()),
|
||||||
|
@ -453,7 +458,7 @@ where
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
struct OpsRRImm<I>(OpsRR, I);
|
struct OpsRRImm<I>(OpsRR, I);
|
||||||
|
|
||||||
let OpsRRImm::<T>(OpsRR(tg, reg), imm) = self.decode();
|
let OpsRRImm::<T>(OpsRR(tg, reg), imm) = unsafe { self.decode() };
|
||||||
self.write_reg(tg, op(self.read_reg(reg).cast::<T>(), imm));
|
self.write_reg(tg, op(self.read_reg(reg).cast::<T>(), imm));
|
||||||
self.bump_pc::<OpsRRImm<T>>();
|
self.bump_pc::<OpsRRImm<T>>();
|
||||||
}
|
}
|
||||||
|
@ -461,7 +466,7 @@ where
|
||||||
/// Perform binary operation over register and shift immediate
|
/// Perform binary operation over register and shift immediate
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn binary_op_shift<T: ValueVariant>(&mut self, op: impl Fn(T, u32) -> T) {
|
unsafe fn binary_op_shift<T: ValueVariant>(&mut self, op: impl Fn(T, u32) -> T) {
|
||||||
let OpsRRR(tg, a0, a1) = self.decode();
|
let OpsRRR(tg, a0, a1) = unsafe { self.decode() };
|
||||||
self.write_reg(
|
self.write_reg(
|
||||||
tg,
|
tg,
|
||||||
op(
|
op(
|
||||||
|
@ -475,7 +480,7 @@ where
|
||||||
/// Perform binary operation over register and shift immediate
|
/// Perform binary operation over register and shift immediate
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn binary_op_ims<T: ValueVariant>(&mut self, op: impl Fn(T, u32) -> T) {
|
unsafe fn binary_op_ims<T: ValueVariant>(&mut self, op: impl Fn(T, u32) -> T) {
|
||||||
let OpsRRB(tg, reg, imm) = self.decode();
|
let OpsRRB(tg, reg, imm) = unsafe { self.decode() };
|
||||||
self.write_reg(tg, op(self.read_reg(reg).cast::<T>(), imm.into()));
|
self.write_reg(tg, op(self.read_reg(reg).cast::<T>(), imm.into()));
|
||||||
self.bump_pc::<OpsRRW>();
|
self.bump_pc::<OpsRRW>();
|
||||||
}
|
}
|
||||||
|
@ -534,7 +539,7 @@ where
|
||||||
/// Jump at `PC + #3` if ordering on `#0 <=> #1` is equal to expected
|
/// Jump at `PC + #3` if ordering on `#0 <=> #1` is equal to expected
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn cond_jmp<T: ValueVariant + Ord>(&mut self, expected: Ordering) {
|
unsafe fn cond_jmp<T: ValueVariant + Ord>(&mut self, expected: Ordering) {
|
||||||
let OpsRRP(a0, a1, ja) = self.decode();
|
let OpsRRP(a0, a1, ja) = unsafe { self.decode() };
|
||||||
if self
|
if self
|
||||||
.read_reg(a0)
|
.read_reg(a0)
|
||||||
.cast::<T>()
|
.cast::<T>()
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
//! Holey Bytes Experimental Runtime
|
//! Holey Bytes Experimental Runtime
|
||||||
|
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
mod mem;
|
mod mem;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
@ -32,7 +35,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
eprintln!("[I] Image loaded at {ptr:p}");
|
eprintln!("[I] Image loaded at {ptr:p}");
|
||||||
|
|
||||||
// Execute program
|
|
||||||
let mut vm = unsafe { Vm::<_, 0>::new(mem::HostMemory, Address::new(ptr as u64)) };
|
let mut vm = unsafe { Vm::<_, 0>::new(mem::HostMemory, Address::new(ptr as u64)) };
|
||||||
|
|
||||||
// Memory access fault handling
|
// Memory access fault handling
|
||||||
|
@ -60,6 +62,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute program
|
||||||
let stat = loop {
|
let stat = loop {
|
||||||
match vm.run() {
|
match vm.run() {
|
||||||
Ok(VmRunOk::Breakpoint) => eprintln!(
|
Ok(VmRunOk::Breakpoint) => eprintln!(
|
||||||
|
|
|
@ -26,6 +26,6 @@ impl Memory for HostMemory {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||||
core::ptr::read(addr.get() as *const T)
|
unsafe { core::ptr::read(addr.get() as *const T) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue