hyperlight_host/mem/
ptr.rs1use std::ops::Add;
18
19use tracing::{Span, instrument};
20
21use super::ptr_addr_space::{AddressSpace, GuestAddressSpace};
22use super::ptr_offset::Offset;
23use crate::Result;
24use crate::error::HyperlightError::{self, CheckedAddOverflow, RawPointerLessThanBaseAddress};
25
26#[derive(Debug, Clone, Eq, PartialEq)]
30pub struct RawPtr(u64);
31
32impl From<u64> for RawPtr {
33 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
34 fn from(val: u64) -> Self {
35 Self(val)
36 }
37}
38
39impl Add<Offset> for RawPtr {
40 type Output = RawPtr;
41 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
42 fn add(self, rhs: Offset) -> RawPtr {
43 let val = self.0 + u64::from(rhs);
44 RawPtr(val)
45 }
46}
47
48impl TryFrom<usize> for RawPtr {
49 type Error = HyperlightError;
50 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
51 fn try_from(val: usize) -> Result<Self> {
52 let val_u64 = u64::try_from(val)?;
53 Ok(Self::from(val_u64))
54 }
55}
56
57impl TryFrom<RawPtr> for usize {
58 type Error = HyperlightError;
59 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
60 fn try_from(val: RawPtr) -> Result<usize> {
61 Ok(usize::try_from(val.0)?)
62 }
63}
64
65impl From<RawPtr> for u64 {
66 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
67 fn from(val: RawPtr) -> u64 {
68 val.0
69 }
70}
71
72impl From<&RawPtr> for u64 {
73 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
74 fn from(val: &RawPtr) -> u64 {
75 val.0
76 }
77}
78
79pub(crate) type GuestPtr = Ptr<GuestAddressSpace>;
81
82impl TryFrom<RawPtr> for GuestPtr {
83 type Error = HyperlightError;
84 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
87 fn try_from(raw: RawPtr) -> Result<Self> {
88 GuestPtr::from_raw_ptr(GuestAddressSpace::new()?, raw)
89 }
90}
91
92impl TryFrom<Offset> for GuestPtr {
93 type Error = HyperlightError;
94 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
95 fn try_from(val: Offset) -> Result<Self> {
96 let addr_space = GuestAddressSpace::new()?;
97 Ok(Ptr::from_offset(addr_space, val))
98 }
99}
100
101impl TryFrom<i64> for GuestPtr {
102 type Error = HyperlightError;
103 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
104 fn try_from(val: i64) -> Result<Self> {
105 let offset = Offset::try_from(val)?;
106 GuestPtr::try_from(offset)
107 }
108}
109
110impl TryFrom<GuestPtr> for i64 {
111 type Error = HyperlightError;
112 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
113 fn try_from(val: GuestPtr) -> Result<Self> {
114 let offset = val.offset();
115 i64::try_from(offset)
116 }
117}
118
119#[derive(Debug, Copy, Clone)]
121pub(crate) struct Ptr<T: AddressSpace> {
122 addr_space: T,
123 offset: Offset,
124}
125
126impl<T: AddressSpace> std::cmp::PartialEq for Ptr<T> {
127 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
128 fn eq(&self, other: &Self) -> bool {
129 other.addr_space == self.addr_space && other.offset == self.offset
130 }
131}
132
133impl<T: AddressSpace> std::cmp::Eq for Ptr<T> {}
134#[instrument(skip_all, parent = Span::current(), level= "Trace")]
135fn cmp_helper<T: AddressSpace>(left: &Ptr<T>, right: &Ptr<T>) -> std::cmp::Ordering {
136 left.offset.cmp(&right.offset)
141}
142
143#[allow(clippy::non_canonical_partial_ord_impl)]
144impl<T: AddressSpace> std::cmp::PartialOrd for Ptr<T> {
145 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
146 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
147 Some(cmp_helper(self, other))
148 }
149}
150
151impl<T: AddressSpace> std::cmp::Ord for Ptr<T> {
152 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
153 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
154 cmp_helper(self, other)
155 }
156}
157
158impl<T: AddressSpace> Ptr<T> {
159 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
164 fn from_raw_ptr(addr_space: T, raw_ptr: RawPtr) -> Result<Ptr<T>> {
165 let offset = raw_ptr
166 .0
167 .checked_sub(addr_space.base())
168 .ok_or_else(|| RawPointerLessThanBaseAddress(raw_ptr, addr_space.base()))?;
169 Ok(Self {
170 addr_space,
171 offset: Offset::from(offset),
172 })
173 }
174
175 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
178 fn from_offset(addr_space: T, offset: Offset) -> Ptr<T> {
179 Self { addr_space, offset }
180 }
181
182 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
184 fn base(&self) -> u64 {
185 self.addr_space.base()
186 }
187
188 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
190 pub(super) fn offset(&self) -> Offset {
191 self.offset
192 }
193
194 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
199 pub(crate) fn absolute(&self) -> Result<u64> {
200 let offset_u64: u64 = self.offset.into();
201 self.base()
202 .checked_add(offset_u64)
203 .ok_or_else(|| CheckedAddOverflow(self.base(), offset_u64))
204 }
205}
206
207impl<T: AddressSpace> Add<Offset> for Ptr<T> {
208 type Output = Ptr<T>;
209 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
210 fn add(self, rhs: Offset) -> Self::Output {
211 Self {
212 addr_space: self.addr_space,
213 offset: self.offset + rhs,
214 }
215 }
216}
217
218impl<T: AddressSpace> TryFrom<Ptr<T>> for usize {
219 type Error = HyperlightError;
220 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
221 fn try_from(val: Ptr<T>) -> Result<usize> {
222 let abs = val.absolute()?;
223 Ok(usize::try_from(abs)?)
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::{GuestPtr, RawPtr};
230 use crate::mem::layout::SandboxMemoryLayout;
231 const OFFSET: u64 = 1;
232
233 #[test]
234 fn ptr_basic_ops() {
235 {
236 let raw_guest_ptr = RawPtr(OFFSET + SandboxMemoryLayout::BASE_ADDRESS as u64);
237 let guest_ptr = GuestPtr::try_from(raw_guest_ptr).unwrap();
238 assert_eq!(
239 OFFSET + SandboxMemoryLayout::BASE_ADDRESS as u64,
240 guest_ptr.absolute().unwrap()
241 );
242 }
243 }
244}