1
1
use crate :: cmp;
2
2
use crate :: io:: { Error as IoError , ErrorKind , IoSlice , IoSliceMut , Result as IoResult } ;
3
3
use crate :: random:: { DefaultRandomSource , Random } ;
4
+ use crate :: sync:: OnceLock ;
4
5
use crate :: time:: { Duration , Instant } ;
6
+ use crate :: ops:: Add ;
7
+ use insecure_time:: { Freq , Tsc , TscBuilder , LearningFreqTscBuilder , NativeTime , NoRdtscTscBuilder } ;
5
8
6
9
pub ( crate ) mod alloc;
7
10
#[ macro_use]
@@ -10,6 +13,7 @@ pub(crate) mod raw;
10
13
mod tests;
11
14
12
15
use self :: raw:: * ;
16
+ use self :: alloc:: UserRef ;
13
17
14
18
/// Usercall `read`. See the ABI documentation for more information.
15
19
///
@@ -249,11 +253,79 @@ pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
249
253
unsafe { raw:: send ( event_set, tcs) . from_sgx_result ( ) }
250
254
}
251
255
256
+ #[ derive( Copy , Clone , PartialOrd , PartialEq ) ]
257
+ struct SgxTime ( u64 ) ;
258
+
259
+ impl SgxTime {
260
+ const NANOS_PER_SEC : u32 = 1_000_000_000 ;
261
+
262
+ pub fn as_duration ( & self ) -> Duration {
263
+ Duration :: new ( self . 0 / Self :: NANOS_PER_SEC as u64 , ( self . 0 % Self :: NANOS_PER_SEC as u64 ) as _ )
264
+ }
265
+ }
266
+
267
+ impl Add < Duration > for SgxTime {
268
+ type Output = SgxTime ;
269
+
270
+ fn add ( self , other : Duration ) -> Self :: Output {
271
+ let t = self . 0 + other. as_secs ( ) * Self :: NANOS_PER_SEC as u64 + other. subsec_nanos ( ) as u64 ;
272
+ SgxTime ( t)
273
+ }
274
+ }
275
+
276
+ impl NativeTime for SgxTime {
277
+ fn minimum ( ) -> SgxTime {
278
+ SgxTime ( 0 )
279
+ }
280
+
281
+ fn abs_diff ( & self , other : & Self ) -> Duration {
282
+ Duration :: from_nanos ( self . 0 . abs_diff ( other. 0 ) )
283
+ }
284
+
285
+ fn now ( ) -> Self {
286
+ let ( t, _info) = unsafe { raw:: insecure_time ( ) } ;
287
+ SgxTime ( t)
288
+ }
289
+ }
290
+
252
291
/// Usercall `insecure_time`. See the ABI documentation for more information.
253
292
#[ unstable( feature = "sgx_platform" , issue = "56975" ) ]
254
293
pub fn insecure_time ( ) -> Duration {
255
- let t = unsafe { raw:: insecure_time ( ) } ;
256
- Duration :: new ( t / 1_000_000_000 , ( t % 1_000_000_000 ) as _ )
294
+ static TSC : OnceLock < Tsc < SgxTime > > = OnceLock :: new ( ) ;
295
+
296
+ let tsc = TSC . get_or_init ( || {
297
+ let ( _t, info) = unsafe { raw:: insecure_time ( ) } ;
298
+ let freq = if !info. is_null ( ) {
299
+ let info = unsafe { UserRef :: < InsecureTimeInfo > :: from_ptr ( info) . to_enclave ( ) } ;
300
+ if info. frequency != 0 {
301
+ Some ( Freq :: from_u64 ( info. frequency ) )
302
+ } else {
303
+ // Enclave runner passed in info, but the host didn't report frequency. In
304
+ // the current implementation of the runner, that can't happen, but we may need
305
+ // something like that in the future when we pass in additional info. Just being
306
+ // very defensive here.
307
+ None
308
+ }
309
+ } else {
310
+ // Old enclave runner that doesn't pass in information
311
+ None
312
+ } ;
313
+
314
+ if let Some ( freq) = freq {
315
+ LearningFreqTscBuilder :: new ( )
316
+ . set_initial_frequency ( freq)
317
+ . set_frequency_learning_period ( Duration :: from_secs ( 1 ) )
318
+ . set_max_acceptable_drift ( Duration :: from_millis ( 1 ) )
319
+ . set_max_sync_interval ( Duration :: from_secs ( 60 ) )
320
+ . set_monotonic_time ( )
321
+ . build ( )
322
+ } else {
323
+ NoRdtscTscBuilder :: new ( )
324
+ . set_monotonic_time ( )
325
+ . build ( )
326
+ }
327
+ } ) ;
328
+ tsc. now ( ) . as_duration ( )
257
329
}
258
330
259
331
/// Usercall `alloc`. See the ABI documentation for more information.
0 commit comments