]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/usercalls/mod.rs
Rollup merge of #60385 - nnethercote:earlier-metadata, r=alexcrichton
[rust.git] / src / libstd / sys / sgx / abi / usercalls / mod.rs
1 use crate::cmp;
2 use crate::io::{Error as IoError, Result as IoResult, IoSlice, IoSliceMut};
3 use crate::time::Duration;
4
5 pub(crate) mod alloc;
6 #[macro_use]
7 pub(crate) mod raw;
8
9 use self::raw::*;
10
11 /// Usercall `read`. See the ABI documentation for more information.
12 ///
13 /// This will do a single `read` usercall and scatter the read data among
14 /// `bufs`. To read to a single buffer, just pass a slice of length one.
15 #[unstable(feature = "sgx_platform", issue = "56975")]
16 pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult<usize> {
17     unsafe {
18         let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len()));
19         let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len);
20         let ret_len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?;
21         let userbuf = &userbuf[..ret_len];
22         let mut index = 0;
23         for buf in bufs {
24             let end = cmp::min(index + buf.len(), userbuf.len());
25             if let Some(buflen) = end.checked_sub(index) {
26                 userbuf[index..end].copy_to_enclave(&mut buf[..buflen]);
27                 index += buf.len();
28             } else {
29                 break
30             }
31         }
32         Ok(userbuf.len())
33     }
34 }
35
36 /// Usercall `read_alloc`. See the ABI documentation for more information.
37 #[unstable(feature = "sgx_platform", issue = "56975")]
38 pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> {
39     unsafe {
40         let userbuf = ByteBuffer { data: crate::ptr::null_mut(), len: 0 };
41         let mut userbuf = alloc::User::new_from_enclave(&userbuf);
42         raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?;
43         Ok(userbuf.copy_user_buffer())
44     }
45 }
46
47 /// Usercall `write`. See the ABI documentation for more information.
48 ///
49 /// This will do a single `write` usercall and gather the written data from
50 /// `bufs`. To write from a single buffer, just pass a slice of length one.
51 #[unstable(feature = "sgx_platform", issue = "56975")]
52 pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> IoResult<usize> {
53     unsafe {
54         let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len()));
55         let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len);
56         let mut index = 0;
57         for buf in bufs {
58             let end = cmp::min(index + buf.len(), userbuf.len());
59             if let Some(buflen) = end.checked_sub(index) {
60                 userbuf[index..end].copy_from_enclave(&buf[..buflen]);
61                 index += buf.len();
62             } else {
63                 break
64             }
65         }
66         raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result()
67     }
68 }
69
70 /// Usercall `flush`. See the ABI documentation for more information.
71 #[unstable(feature = "sgx_platform", issue = "56975")]
72 pub fn flush(fd: Fd) -> IoResult<()> {
73     unsafe { raw::flush(fd).from_sgx_result() }
74 }
75
76 /// Usercall `close`. See the ABI documentation for more information.
77 #[unstable(feature = "sgx_platform", issue = "56975")]
78 pub fn close(fd: Fd) {
79     unsafe { raw::close(fd) }
80 }
81
82 fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
83     String::from_utf8(buf.copy_user_buffer())
84         .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
85 }
86
87 /// Usercall `bind_stream`. See the ABI documentation for more information.
88 #[unstable(feature = "sgx_platform", issue = "56975")]
89 pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
90     unsafe {
91         let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
92         let mut local = alloc::User::<ByteBuffer>::uninitialized();
93         let fd = raw::bind_stream(
94             addr_user.as_ptr(),
95             addr_user.len(),
96             local.as_raw_mut_ptr()
97         ).from_sgx_result()?;
98         let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
99         Ok((fd, local))
100     }
101 }
102
103 /// Usercall `accept_stream`. See the ABI documentation for more information.
104 #[unstable(feature = "sgx_platform", issue = "56975")]
105 pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
106     unsafe {
107         let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
108         let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
109                                                                // without forcing coercion?
110         let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
111         let fd = raw::accept_stream(
112             fd,
113             local.as_raw_mut_ptr(),
114             peer.as_raw_mut_ptr()
115         ).from_sgx_result()?;
116         let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
117         let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
118         Ok((fd, local, peer))
119     }
120 }
121
122 /// Usercall `connect_stream`. See the ABI documentation for more information.
123 #[unstable(feature = "sgx_platform", issue = "56975")]
124 pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
125     unsafe {
126         let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
127         let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
128         let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
129                                                                // without forcing coercion?
130         let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
131         let fd = raw::connect_stream(
132             addr_user.as_ptr(),
133             addr_user.len(),
134             local.as_raw_mut_ptr(),
135             peer.as_raw_mut_ptr()
136         ).from_sgx_result()?;
137         let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
138         let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
139         Ok((fd, local, peer))
140     }
141 }
142
143 /// Usercall `launch_thread`. See the ABI documentation for more information.
144 #[unstable(feature = "sgx_platform", issue = "56975")]
145 pub unsafe fn launch_thread() -> IoResult<()> {
146     raw::launch_thread().from_sgx_result()
147 }
148
149 /// Usercall `exit`. See the ABI documentation for more information.
150 #[unstable(feature = "sgx_platform", issue = "56975")]
151 pub fn exit(panic: bool) -> ! {
152     unsafe { raw::exit(panic) }
153 }
154
155 /// Usercall `wait`. See the ABI documentation for more information.
156 #[unstable(feature = "sgx_platform", issue = "56975")]
157 pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
158     unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
159 }
160
161 /// Usercall `send`. See the ABI documentation for more information.
162 #[unstable(feature = "sgx_platform", issue = "56975")]
163 pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
164     unsafe { raw::send(event_set, tcs).from_sgx_result() }
165 }
166
167 /// Usercall `insecure_time`. See the ABI documentation for more information.
168 #[unstable(feature = "sgx_platform", issue = "56975")]
169 pub fn insecure_time() -> Duration {
170     let t = unsafe { raw::insecure_time() };
171     Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
172 }
173
174 /// Usercall `alloc`. See the ABI documentation for more information.
175 #[unstable(feature = "sgx_platform", issue = "56975")]
176 pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> {
177     unsafe { raw::alloc(size, alignment).from_sgx_result() }
178 }
179
180 #[unstable(feature = "sgx_platform", issue = "56975")]
181 #[doc(inline)]
182 pub use self::raw::free;
183
184 fn check_os_error(err: Result) -> i32 {
185     // FIXME: not sure how to make sure all variants of Error are covered
186     if err == Error::NotFound as _ ||
187        err == Error::PermissionDenied as _ ||
188        err == Error::ConnectionRefused as _ ||
189        err == Error::ConnectionReset as _ ||
190        err == Error::ConnectionAborted as _ ||
191        err == Error::NotConnected as _ ||
192        err == Error::AddrInUse as _ ||
193        err == Error::AddrNotAvailable as _ ||
194        err == Error::BrokenPipe as _ ||
195        err == Error::AlreadyExists as _ ||
196        err == Error::WouldBlock as _ ||
197        err == Error::InvalidInput as _ ||
198        err == Error::InvalidData as _ ||
199        err == Error::TimedOut as _ ||
200        err == Error::WriteZero as _ ||
201        err == Error::Interrupted as _ ||
202        err == Error::Other as _ ||
203        err == Error::UnexpectedEof as _ ||
204        ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err)
205     {
206         err
207     } else {
208         rtabort!("Usercall: returned invalid error value {}", err)
209     }
210 }
211
212 trait FromSgxResult {
213     type Return;
214
215     fn from_sgx_result(self) -> IoResult<Self::Return>;
216 }
217
218 impl<T> FromSgxResult for (Result, T) {
219     type Return = T;
220
221     fn from_sgx_result(self) -> IoResult<Self::Return> {
222         if self.0 == RESULT_SUCCESS {
223             Ok(self.1)
224         } else {
225             Err(IoError::from_raw_os_error(check_os_error(self.0)))
226         }
227     }
228 }
229
230 impl FromSgxResult for Result {
231     type Return = ();
232
233     fn from_sgx_result(self) -> IoResult<Self::Return> {
234         if self == RESULT_SUCCESS {
235             Ok(())
236         } else {
237             Err(IoError::from_raw_os_error(check_os_error(self)))
238         }
239     }
240 }