1use crate::prelude::*;
2use once_cell::sync::OnceCell;
3
4use std::alloc::Layout;
5use std::ops::Deref;
6
7mod guest_align;
8mod impls;
9
10pub(crate) use guest_align::GuestAlign;
11
12#[derive(Copy, Clone, Debug)]
13pub struct GuestReadFail;
14
15#[derive(Copy, Clone, Debug)]
16pub struct GuestWriteFail;
17
18pub trait GuestType: Sized {
21 fn guest_layout() -> Option<Layout>;
22
23 fn guest_size() -> Option<usize> {
25 Self::guest_layout().map(|layout| layout.size())
26 }
27
28 fn guest_align() -> usize {
30 Self::guest_layout()
31 .map(|layout| layout.align())
32 .unwrap_or(1)
33 }
34
35 fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail>;
36 fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail>;
37
38 fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail>;
39 fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail>;
40}
41
42pub struct GuestPtr<T: GuestType> {
43 pointer: target_ptr_t,
44 guest_type: OnceCell<Box<T>>,
45}
46
47impl<T: GuestType> From<target_ptr_t> for GuestPtr<T> {
48 fn from(pointer: target_ptr_t) -> Self {
49 GuestPtr {
50 pointer,
51 guest_type: OnceCell::new(),
52 }
53 }
54}
55
56impl<T: GuestType> Clone for GuestPtr<T> {
57 fn clone(&self) -> Self {
58 Self::from(self.pointer)
59 }
60}
61
62impl<T: GuestType> GuestPtr<T> {
63 pub fn read(&self) -> Result<&T, GuestReadFail> {
72 let cpu = unsafe { &mut *crate::sys::get_cpu() };
73
74 self.guest_type
75 .get_or_try_init(|| T::read_from_guest(cpu, self.pointer).map(Box::new))
76 .map(|x| &**x) }
78
79 pub fn update(&mut self) {
81 self.clear_cache();
82 self.read().unwrap();
83 }
84
85 pub fn clear_cache(&mut self) {
87 self.guest_type = OnceCell::new();
88 }
89
90 pub fn get_cached(&self) -> Option<&T> {
92 self.guest_type.get().map(Box::as_ref)
93 }
94
95 pub fn offset(&self, off: usize) -> Self {
100 let size =
101 T::guest_size().expect("Attempted to offset an unsized GuestType") as target_ptr_t;
102 GuestPtr {
103 pointer: self.pointer + (size * (off as target_ptr_t)),
104 guest_type: OnceCell::new(),
105 }
106 }
107
108 pub fn offset_bytes(&self, bytes: usize) -> Self {
110 GuestPtr {
111 pointer: self.pointer + (bytes as target_ptr_t),
112 guest_type: OnceCell::new(),
113 }
114 }
115
116 pub fn cast<U: GuestType>(&self) -> GuestPtr<U> {
118 GuestPtr {
119 pointer: self.pointer,
120 guest_type: OnceCell::new(),
121 }
122 }
123
124 pub fn write(&mut self, func: impl FnOnce(&mut T)) -> Result<(), GuestWriteFail> {
127 if self.guest_type.get().is_none() {
128 self.read().unwrap();
129 }
130
131 let mut inner = self.guest_type.get_mut();
132 let inner = inner.as_mut().unwrap();
133
134 func(inner);
135
136 let cpu = unsafe { &mut *crate::sys::get_cpu() };
137 inner.write_to_guest(cpu, self.pointer)
138 }
139}
140
141impl<T: GuestType> Deref for GuestPtr<T> {
142 type Target = T;
143
144 fn deref(&self) -> &Self::Target {
145 self.read().unwrap();
146 self.get_cached()
147 .expect("Failed to read cached value from GuestPtr")
148 }
149}