99//! Implementation for SGX using RDRAND instruction
1010use crate :: Error ;
1111use core:: mem;
12- use core:: arch:: x86_64:: _rdrand64_step;
12+ use core:: arch:: x86_64:: { __cpuid , _rdrand64_step} ;
1313use core:: num:: NonZeroU32 ;
14-
15- #[ cfg( not( target_feature = "rdrand" ) ) ]
16- compile_error ! ( "enable rdrand target feature!" ) ;
14+ use lazy_static:: lazy_static;
1715
1816// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
1917// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
@@ -31,11 +29,22 @@ fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
3129 }
3230 } ;
3331 }
34- error ! ( "RDRAND failed, CPU issue likely" ) ;
3532 Err ( Error :: UNKNOWN )
3633}
3734
35+ fn cpuid_check ( ) -> bool {
36+ const FEATURE_INFO_LEAF : u32 = 1 ;
37+ const RDRAND_FLAG : u32 = 1 << 30 ;
38+ // SAFETY: All platforms with CPUID support leaf 1
39+ unsafe { __cpuid ( FEATURE_INFO_LEAF ) . ecx & RDRAND_FLAG != 0 }
40+ }
41+
3842pub fn getrandom_inner ( dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
43+ lazy_static ! { static ref HAS_RDRAND : bool = cpuid_check( ) ; }
44+ if cfg ! ( not( target_feature = "rdrand" ) ) && !* HAS_RDRAND {
45+ return Err ( Error :: UNAVAILABLE ) ;
46+ }
47+
3948 // We use chunks_exact_mut instead of chunks_mut as it allows almost all
4049 // calls to memcpy to be elided by the compiler.
4150 let mut chunks = dest. chunks_exact_mut ( WORD_SIZE ) ;
0 commit comments