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