use core::{
mem::{MaybeUninit, size_of},
ptr::NonNull,
};
use crate::{
ByteRepr, Result,
os::{MadviseAdvice, ProtFlags},
};
use super::VmAddr;
pub trait RegionAccess: Send + Sync + 'static {
fn addr(&self) -> VmAddr;
fn len(&self) -> usize;
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
unsafe fn read_bytes(&self, offset: usize, dst: &mut [u8]) -> Result<()>;
#[inline]
unsafe fn read_value<T: ByteRepr>(&self, offset: usize) -> Result<T> {
unsafe { self.read_unaligned_value(offset) }
}
#[inline]
unsafe fn read_unaligned_value<T: ByteRepr>(&self, offset: usize) -> Result<T> {
let mut value = MaybeUninit::<T>::uninit();
let bytes = unsafe {
core::slice::from_raw_parts_mut(value.as_mut_ptr().cast::<u8>(), size_of::<T>())
};
unsafe { self.read_bytes(offset, bytes)? };
Ok(unsafe { value.assume_init() })
}
unsafe fn write_bytes(&self, offset: usize, src: &[u8]) -> Result<()>;
#[inline]
unsafe fn write_value<T: ByteRepr>(&self, offset: usize, value: T) -> Result<()> {
unsafe { self.write_unaligned_value(offset, value) }
}
#[inline]
unsafe fn write_unaligned_value<T: ByteRepr>(&self, offset: usize, value: T) -> Result<()> {
let bytes = unsafe {
core::slice::from_raw_parts((&value as *const T).cast::<u8>(), size_of::<T>())
};
unsafe { self.write_bytes(offset, bytes) }
}
unsafe fn zero_bytes(&self, offset: usize, len: usize) -> Result<()>;
unsafe fn borrow_bytes(&self, offset: usize, len: usize) -> Option<&'static [u8]>;
unsafe fn host_ptr(&self, offset: usize) -> Option<NonNull<u8>>;
unsafe fn madvise(&self, offset: usize, len: usize, behavior: MadviseAdvice) -> Result<()>;
unsafe fn mprotect(&self, offset: usize, len: usize, prot: ProtFlags) -> Result<()>;
}
pub trait ImageMemory: Send + Sync {
fn base(&self) -> VmAddr;
fn host_ptr(&self, addr: VmAddr) -> Option<NonNull<u8>>;
fn host_ptr_range(&self, addr: VmAddr, len: usize) -> Option<NonNull<u8>>;
fn read_bytes(&self, addr: VmAddr, dst: &mut [u8]) -> Result<()>;
fn write_bytes(&self, addr: VmAddr, src: &[u8]) -> Result<()>;
}
pub trait ImageMemoryExt: ImageMemory {
#[inline]
unsafe fn read_value<T: ByteRepr>(&self, addr: VmAddr) -> Result<T> {
let mut value = MaybeUninit::<T>::uninit();
let bytes = unsafe {
core::slice::from_raw_parts_mut(value.as_mut_ptr().cast::<u8>(), size_of::<T>())
};
self.read_bytes(addr, bytes)?;
Ok(unsafe { value.assume_init() })
}
#[inline]
unsafe fn write_value<T: ByteRepr>(&self, addr: VmAddr, value: T) -> Result<()> {
let bytes = unsafe {
core::slice::from_raw_parts((&value as *const T).cast::<u8>(), size_of::<T>())
};
self.write_bytes(addr, bytes)
}
#[inline]
unsafe fn update_value<T: ByteRepr + Copy>(
&self,
addr: VmAddr,
update: impl FnOnce(T) -> T,
) -> Result<()> {
if size_of::<T>() == 0 {
return Ok(());
}
let value = update(unsafe { self.read_value(addr)? });
unsafe { self.write_value(addr, value) }
}
}
impl<M: ImageMemory + ?Sized> ImageMemoryExt for M {}
impl<M> ImageMemory for &M
where
M: ImageMemory + ?Sized,
{
#[inline]
fn base(&self) -> VmAddr {
(**self).base()
}
#[inline]
fn host_ptr(&self, addr: VmAddr) -> Option<NonNull<u8>> {
(**self).host_ptr(addr)
}
#[inline]
fn host_ptr_range(&self, addr: VmAddr, len: usize) -> Option<NonNull<u8>> {
(**self).host_ptr_range(addr, len)
}
#[inline]
fn read_bytes(&self, addr: VmAddr, dst: &mut [u8]) -> Result<()> {
(**self).read_bytes(addr, dst)
}
#[inline]
fn write_bytes(&self, addr: VmAddr, src: &[u8]) -> Result<()> {
(**self).write_bytes(addr, src)
}
}