std/sys/pal/sgx/abi/usercalls/
mod.rs1use crate::arch::x86_64::_rdrand64_step;
2use crate::cmp;
3use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
4use crate::time::{Duration, Instant};
5
6pub(crate) mod alloc;
7#[macro_use]
8pub(crate) mod raw;
9#[cfg(test)]
10mod tests;
11
12use self::raw::*;
13
14#[unstable(feature = "sgx_platform", issue = "56975")]
19pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
20 unsafe {
21 let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len()));
22 let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len);
23 let ret_len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?;
24 let userbuf = &userbuf[..ret_len];
25 let mut index = 0;
26 for buf in bufs {
27 let end = cmp::min(index + buf.len(), userbuf.len());
28 if let Some(buflen) = end.checked_sub(index) {
29 userbuf[index..end].copy_to_enclave(&mut buf[..buflen]);
30 index += buf.len();
31 } else {
32 break;
33 }
34 }
35 Ok(userbuf.len())
36 }
37}
38
39#[unstable(feature = "sgx_platform", issue = "56975")]
42pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
43 unsafe {
44 let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity());
45 let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?;
46 userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]);
47 buf.advance(len);
48 Ok(())
49 }
50}
51
52#[unstable(feature = "sgx_platform", issue = "56975")]
54pub fn read_alloc(fd: Fd) -> io::Result<Vec<u8>> {
55 unsafe {
56 let userbuf = ByteBuffer { data: crate::ptr::null_mut(), len: 0 };
57 let mut userbuf = alloc::User::new_from_enclave(&userbuf);
58 raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?;
59 Ok(userbuf.copy_user_buffer())
60 }
61}
62
63#[unstable(feature = "sgx_platform", issue = "56975")]
68pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
69 unsafe {
70 let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len()));
71 let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len);
72 let mut index = 0;
73 for buf in bufs {
74 let end = cmp::min(index + buf.len(), userbuf.len());
75 if let Some(buflen) = end.checked_sub(index) {
76 userbuf[index..end].copy_from_enclave(&buf[..buflen]);
77 index += buf.len();
78 } else {
79 break;
80 }
81 }
82 raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result()
83 }
84}
85
86#[unstable(feature = "sgx_platform", issue = "56975")]
88pub fn flush(fd: Fd) -> io::Result<()> {
89 unsafe { raw::flush(fd).from_sgx_result() }
90}
91
92#[unstable(feature = "sgx_platform", issue = "56975")]
94pub fn close(fd: Fd) {
95 unsafe { raw::close(fd) }
96}
97
98fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
99 String::from_utf8(buf.copy_user_buffer())
100 .unwrap_or_else(|_| rtabort!("Usercall {usercall}: expected {arg} to be valid UTF-8"))
101}
102
103#[unstable(feature = "sgx_platform", issue = "56975")]
105pub fn bind_stream(addr: &str) -> io::Result<(Fd, String)> {
106 unsafe {
107 let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
108 let mut local = alloc::User::<ByteBuffer>::uninitialized();
109 let fd = raw::bind_stream(addr_user.as_ptr(), addr_user.len(), local.as_raw_mut_ptr())
110 .from_sgx_result()?;
111 let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
112 Ok((fd, local))
113 }
114}
115
116#[unstable(feature = "sgx_platform", issue = "56975")]
118pub fn accept_stream(fd: Fd) -> io::Result<(Fd, String, String)> {
119 unsafe {
120 let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
121 let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
124 let fd = raw::accept_stream(fd, local.as_raw_mut_ptr(), peer.as_raw_mut_ptr())
125 .from_sgx_result()?;
126 let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
127 let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
128 Ok((fd, local, peer))
129 }
130}
131
132#[unstable(feature = "sgx_platform", issue = "56975")]
134pub fn connect_stream(addr: &str) -> io::Result<(Fd, String, String)> {
135 unsafe {
136 let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
137 let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
138 let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
141 let fd = raw::connect_stream(
142 addr_user.as_ptr(),
143 addr_user.len(),
144 local.as_raw_mut_ptr(),
145 peer.as_raw_mut_ptr(),
146 )
147 .from_sgx_result()?;
148 let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
149 let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
150 Ok((fd, local, peer))
151 }
152}
153
154#[unstable(feature = "sgx_platform", issue = "56975")]
156pub unsafe fn launch_thread() -> io::Result<()> {
157 unsafe { raw::launch_thread().from_sgx_result() }
159}
160
161#[unstable(feature = "sgx_platform", issue = "56975")]
163pub fn exit(panic: bool) -> ! {
164 unsafe { raw::exit(panic) }
165}
166
167#[unstable(feature = "sgx_platform", issue = "56975")]
169pub fn wait(event_mask: u64, mut timeout: u64) -> io::Result<u64> {
170 fn try_rdrand() -> Option<u64> {
171 let mut val: u64 = 0;
172 if unsafe { _rdrand64_step(&mut val) } == 1 { Some(val) } else { None }
174 }
175
176 if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
177 if let Ok(timeout_signed) = i64::try_from(timeout) {
189 let tenth = timeout_signed / 10;
190 let deviation =
191 try_rdrand().and_then(|rnd| (rnd as i64).checked_rem(tenth)).unwrap_or(0);
192 timeout = timeout_signed.saturating_add(deviation) as _;
193 }
194 }
195 unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
196}
197
198#[unstable(feature = "sgx_platform", issue = "56975")]
208pub fn wait_timeout<F>(event_mask: u64, duration: Duration, should_wake_up: F)
209where
210 F: Fn() -> bool,
211{
212 fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
216 let timeout = duration.map_or(raw::WAIT_NO, |duration| {
217 cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
218 });
219 match wait(event_mask, timeout) {
220 Ok(eventset) => {
221 if event_mask == 0 {
222 rtabort!("expected wait() to return Err, found Ok.");
223 }
224 rtassert!(eventset != 0 && eventset & !event_mask == 0);
225 true
226 }
227 Err(e) => {
228 rtassert!(
229 e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock
230 );
231 false
232 }
233 }
234 }
235
236 match wait_checked(event_mask, Some(duration)) {
237 false => return, true if should_wake_up() => return, true => {} }
241
242 loop {
245 match wait_checked(event_mask, None) {
246 false => break, true if should_wake_up() => return, true => {} }
250 }
251
252 let start = Instant::now();
258 let mut remaining = duration;
259 loop {
260 match wait_checked(event_mask, Some(remaining)) {
261 false => return, true if should_wake_up() => return, true => {} }
265 remaining = match duration.checked_sub(start.elapsed()) {
266 Some(remaining) => remaining,
267 None => break,
268 }
269 }
270}
271
272#[unstable(feature = "sgx_platform", issue = "56975")]
274pub fn send(event_set: u64, tcs: Option<Tcs>) -> io::Result<()> {
275 unsafe { raw::send(event_set, tcs).from_sgx_result() }
276}
277
278#[unstable(feature = "sgx_platform", issue = "56975")]
280pub fn insecure_time() -> Duration {
281 let t = unsafe { raw::insecure_time().0 };
282 Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
283}
284
285#[unstable(feature = "sgx_platform", issue = "56975")]
287pub fn alloc(size: usize, alignment: usize) -> io::Result<*mut u8> {
288 unsafe { raw::alloc(size, alignment).from_sgx_result() }
289}
290
291#[unstable(feature = "sgx_platform", issue = "56975")]
292#[doc(inline)]
293pub use self::raw::free;
294
295fn check_os_error(err: Result) -> i32 {
296 if err == Error::NotFound as _
298 || err == Error::PermissionDenied as _
299 || err == Error::ConnectionRefused as _
300 || err == Error::ConnectionReset as _
301 || err == Error::ConnectionAborted as _
302 || err == Error::NotConnected as _
303 || err == Error::AddrInUse as _
304 || err == Error::AddrNotAvailable as _
305 || err == Error::BrokenPipe as _
306 || err == Error::AlreadyExists as _
307 || err == Error::WouldBlock as _
308 || err == Error::InvalidInput as _
309 || err == Error::InvalidData as _
310 || err == Error::TimedOut as _
311 || err == Error::WriteZero as _
312 || err == Error::Interrupted as _
313 || err == Error::Other as _
314 || err == Error::UnexpectedEof as _
315 || ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err)
316 {
317 err
318 } else {
319 rtabort!("Usercall: returned invalid error value {err}")
320 }
321}
322
323#[unstable(feature = "sgx_platform", issue = "56975")]
325pub trait FromSgxResult {
326 type Return;
328
329 fn from_sgx_result(self) -> io::Result<Self::Return>;
331}
332
333#[unstable(feature = "sgx_platform", issue = "56975")]
334impl<T> FromSgxResult for (Result, T) {
335 type Return = T;
336
337 fn from_sgx_result(self) -> io::Result<Self::Return> {
338 if self.0 == RESULT_SUCCESS {
339 Ok(self.1)
340 } else {
341 Err(io::Error::from_raw_os_error(check_os_error(self.0)))
342 }
343 }
344}
345
346#[unstable(feature = "sgx_platform", issue = "56975")]
347impl FromSgxResult for Result {
348 type Return = ();
349
350 fn from_sgx_result(self) -> io::Result<Self::Return> {
351 if self == RESULT_SUCCESS {
352 Ok(())
353 } else {
354 Err(io::Error::from_raw_os_error(check_os_error(self)))
355 }
356 }
357}