xref: /drstd/src/std/sys/sgx/abi/usercalls/raw.rs (revision 9670759b785600bf6315e4173e46a602f16add7a)
1 #![allow(unused)]
2 
3 pub use fortanix_sgx_abi::*;
4 
5 use crate::std::num::NonZeroU64;
6 use crate::std::ptr::NonNull;
7 
8 #[repr(C)]
9 struct UsercallReturn(u64, u64);
10 
11 extern "C" {
usercall(nr: NonZeroU64, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64) -> UsercallReturn12     fn usercall(nr: NonZeroU64, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64) -> UsercallReturn;
13 }
14 
15 /// Performs the raw usercall operation as defined in the ABI calling convention.
16 ///
17 /// # Safety
18 ///
19 /// The caller must ensure to pass parameters appropriate for the usercall `nr`
20 /// and to observe all requirements specified in the ABI.
21 ///
22 /// # Panics
23 ///
24 /// Panics if `nr` is `0`.
25 #[inline]
do_usercall( nr: NonZeroU64, p1: u64, p2: u64, p3: u64, p4: u64, abort: bool, ) -> (u64, u64)26 pub unsafe fn do_usercall(
27     nr: NonZeroU64,
28     p1: u64,
29     p2: u64,
30     p3: u64,
31     p4: u64,
32     abort: bool,
33 ) -> (u64, u64) {
34     let UsercallReturn(a, b) = unsafe { usercall(nr, p1, p2, abort as _, p3, p4) };
35     (a, b)
36 }
37 
38 /// A value passed or returned in a CPU register.
39 pub type Register = u64;
40 
41 /// Translate a type from/to Register to be used as an argument.
42 pub trait RegisterArgument {
43     /// Translate a Register to Self.
from_register(_: Register) -> Self44     fn from_register(_: Register) -> Self;
45     /// Translate self to a Register.
into_register(self) -> Register46     fn into_register(self) -> Register;
47 }
48 
49 /// Translate a pair of Registers to the raw usercall return value.
50 pub trait ReturnValue {
51     /// Translate a pair of Registers to the raw usercall return value.
from_registers(call: &'static str, regs: (Register, Register)) -> Self52     fn from_registers(call: &'static str, regs: (Register, Register)) -> Self;
53 }
54 
55 macro_rules! define_usercalls {
56     ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => {
57         /// Usercall numbers as per the ABI.
58         #[repr(u64)]
59                 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
60         #[allow(missing_docs, non_camel_case_types)]
61         #[non_exhaustive]
62         pub enum Usercalls {
63             #[doc(hidden)]
64             __enclave_usercalls_invalid = 0,
65             $($f,)*
66         }
67 
68         $(enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) $(-> $r)*);)*
69     };
70 }
71 
72 macro_rules! define_ra {
73     (< $i:ident > $t:ty) => {
74         impl<$i> RegisterArgument for $t {
75             fn from_register(a: Register) -> Self {
76                 a as _
77             }
78             fn into_register(self) -> Register {
79                 self as _
80             }
81         }
82     };
83     ($i:ty as $t:ty) => {
84         impl RegisterArgument for $t {
85             fn from_register(a: Register) -> Self {
86                 a as $i as _
87             }
88             fn into_register(self) -> Register {
89                 self as $i as _
90             }
91         }
92     };
93     ($t:ty) => {
94         impl RegisterArgument for $t {
95             fn from_register(a: Register) -> Self {
96                 a as _
97             }
98             fn into_register(self) -> Register {
99                 self as _
100             }
101         }
102     };
103 }
104 
105 define_ra!(Register);
106 define_ra!(i64);
107 define_ra!(u32);
108 define_ra!(u32 as i32);
109 define_ra!(u16);
110 define_ra!(u16 as i16);
111 define_ra!(u8);
112 define_ra!(u8 as i8);
113 define_ra!(usize);
114 define_ra!(usize as isize);
115 define_ra!(<T> *const T);
116 define_ra!(<T> *mut T);
117 
118 impl RegisterArgument for bool {
from_register(a: Register) -> bool119     fn from_register(a: Register) -> bool {
120         if a != 0 {
121             true
122         } else {
123             false
124         }
125     }
into_register(self) -> Register126     fn into_register(self) -> Register {
127         self as _
128     }
129 }
130 
131 impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
from_register(a: Register) -> Option<NonNull<T>>132     fn from_register(a: Register) -> Option<NonNull<T>> {
133         NonNull::new(a as _)
134     }
into_register(self) -> Register135     fn into_register(self) -> Register {
136         self.map_or(0 as _, NonNull::as_ptr) as _
137     }
138 }
139 
140 impl ReturnValue for ! {
from_registers(call: &'static str, _regs: (Register, Register)) -> Self141     fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
142         rtabort!("Usercall {call}: did not expect to be re-entered");
143     }
144 }
145 
146 impl ReturnValue for () {
from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self147     fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
148         rtassert!(usercall_retval.0 == 0);
149         rtassert!(usercall_retval.1 == 0);
150         ()
151     }
152 }
153 
154 impl<T: RegisterArgument> ReturnValue for T {
from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self155     fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
156         rtassert!(usercall_retval.1 == 0);
157         T::from_register(usercall_retval.0)
158     }
159 }
160 
161 impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
from_registers(_call: &'static str, regs: (Register, Register)) -> Self162     fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self {
163         (T::from_register(regs.0), U::from_register(regs.1))
164     }
165 }
166 
167 macro_rules! return_type_is_abort {
168     (!) => {
169         true
170     };
171     ($r:ty) => {
172         false
173     };
174 }
175 
176 // In this macro: using `$r:tt` because `$r:ty` doesn't match ! in `return_type_is_abort`
177 macro_rules! enclave_usercalls_internal_define_usercalls {
178     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
179                      $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:tt) => (
180         /// This is the raw function definition, see the ABI documentation for
181         /// more information.
182                 #[inline(always)]
183         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
184             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
185                     rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
186                     RegisterArgument::into_register($n1),
187                     RegisterArgument::into_register($n2),
188                     RegisterArgument::into_register($n3),
189                     RegisterArgument::into_register($n4),
190                     return_type_is_abort!($r)
191             ) })
192         }
193     );
194     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => (
195         /// This is the raw function definition, see the ABI documentation for
196         /// more information.
197                 #[inline(always)]
198         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
199             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
200                     rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
201                     RegisterArgument::into_register($n1),
202                     RegisterArgument::into_register($n2),
203                     RegisterArgument::into_register($n3),
204                     0,
205                     return_type_is_abort!($r)
206             ) })
207         }
208     );
209     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => (
210         /// This is the raw function definition, see the ABI documentation for
211         /// more information.
212                 #[inline(always)]
213         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
214             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
215                     rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
216                     RegisterArgument::into_register($n1),
217                     RegisterArgument::into_register($n2),
218                     0,0,
219                     return_type_is_abort!($r)
220             ) })
221         }
222     );
223     (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => (
224         /// This is the raw function definition, see the ABI documentation for
225         /// more information.
226                 #[inline(always)]
227         pub unsafe fn $f($n1: $t1) -> $r {
228             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
229                     rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
230                     RegisterArgument::into_register($n1),
231                     0,0,0,
232                     return_type_is_abort!($r)
233             ) })
234         }
235     );
236     (def fn $f:ident() -> $r:tt) => (
237         /// This is the raw function definition, see the ABI documentation for
238         /// more information.
239                 #[inline(always)]
240         pub unsafe fn $f() -> $r {
241             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
242                     rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
243                     0,0,0,0,
244                     return_type_is_abort!($r)
245             ) })
246         }
247     );
248     (def fn $f:ident($($n:ident: $t:ty),*)) => (
249         enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) -> ());
250     );
251 }
252 
253 invoke_with_usercalls!(define_usercalls);
254