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