Skip to main content

std/sys/pal/sgx/abi/usercalls/
raw.rs

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