use crate::prelude::*;
use once_cell::sync::OnceCell;
use std::alloc::Layout;
use std::ops::Deref;
mod guest_align;
mod impls;
pub(crate) use guest_align::GuestAlign;
#[derive(Copy, Clone, Debug)]
pub struct GuestReadFail;
#[derive(Copy, Clone, Debug)]
pub struct GuestWriteFail;
pub trait GuestType: Sized {
fn guest_layout() -> Option<Layout>;
fn guest_size() -> Option<usize> {
Self::guest_layout().map(|layout| layout.size())
}
fn guest_align() -> usize {
Self::guest_layout()
.map(|layout| layout.align())
.unwrap_or(1)
}
fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail>;
fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail>;
fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail>;
fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail>;
}
pub struct GuestPtr<T: GuestType> {
pointer: target_ptr_t,
guest_type: OnceCell<Box<T>>,
}
impl<T: GuestType> From<target_ptr_t> for GuestPtr<T> {
fn from(pointer: target_ptr_t) -> Self {
GuestPtr {
pointer,
guest_type: OnceCell::new(),
}
}
}
impl<T: GuestType> Clone for GuestPtr<T> {
fn clone(&self) -> Self {
Self::from(self.pointer)
}
}
impl<T: GuestType> GuestPtr<T> {
pub fn read(&self) -> Result<&T, GuestReadFail> {
let cpu = unsafe { &mut *crate::sys::get_cpu() };
self.guest_type
.get_or_try_init(|| T::read_from_guest(cpu, self.pointer).map(Box::new))
.map(|x| &**x) }
pub fn update(&mut self) {
self.clear_cache();
self.read().unwrap();
}
pub fn clear_cache(&mut self) {
self.guest_type = OnceCell::new();
}
pub fn get_cached(&self) -> Option<&T> {
self.guest_type.get().map(Box::as_ref)
}
pub fn offset(&self, off: usize) -> Self {
let size =
T::guest_size().expect("Attempted to offset an unsized GuestType") as target_ptr_t;
GuestPtr {
pointer: self.pointer + (size * (off as target_ptr_t)),
guest_type: OnceCell::new(),
}
}
pub fn offset_bytes(&self, bytes: usize) -> Self {
GuestPtr {
pointer: self.pointer + (bytes as target_ptr_t),
guest_type: OnceCell::new(),
}
}
pub fn cast<U: GuestType>(&self) -> GuestPtr<U> {
GuestPtr {
pointer: self.pointer,
guest_type: OnceCell::new(),
}
}
pub fn write(&mut self, func: impl FnOnce(&mut T)) -> Result<(), GuestWriteFail> {
if self.guest_type.get().is_none() {
self.read().unwrap();
}
let mut inner = self.guest_type.get_mut();
let inner = inner.as_mut().unwrap();
func(inner);
let cpu = unsafe { &mut *crate::sys::get_cpu() };
inner.write_to_guest(cpu, self.pointer)
}
}
impl<T: GuestType> Deref for GuestPtr<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.read().unwrap();
self.get_cached()
.expect("Failed to read cached value from GuestPtr")
}
}