@@ -23,13 +23,6 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
2323 for _ in 0 ..RETRY_LIMIT {
2424 let mut el = mem:: uninitialized ( ) ;
2525 if _rdrand64_step ( & mut el) == 1 {
26- // AMD CPUs from families 14h to 16h (pre Ryzen) will sometimes give
27- // bogus random data. Discard these values and warn the user.
28- // See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
29- if cfg ! ( not( target_env = "sgx" ) ) && ( el == 0 || el == !0 ) {
30- error ! ( "RDRAND returned suspicious value {}, CPU RNG is broken" , el) ;
31- return Err ( Error :: UNKNOWN )
32- }
3326 return Ok ( el. to_ne_bytes ( ) ) ;
3427 }
3528 }
@@ -43,25 +36,53 @@ compile_error!(
4336 "SGX targets require 'rdrand' target feature. Enable by using -C target-feature=+rdrnd."
4437) ;
4538
46- #[ cfg( target_feature = "rdrand " ) ]
39+ #[ cfg( target_env = "sgx " ) ]
4740fn is_rdrand_supported ( ) -> bool {
4841 true
4942}
5043
5144// TODO use is_x86_feature_detected!("rdrand") when that works in core. See:
5245// https://github.com/rust-lang-nursery/stdsimd/issues/464
53- #[ cfg( not( target_feature = "rdrand " ) ) ]
46+ #[ cfg( not( target_env = "sgx " ) ) ]
5447fn is_rdrand_supported ( ) -> bool {
55- use core:: arch:: x86_64:: __cpuid;
5648 use lazy_static:: lazy_static;
57- // SAFETY: All x86_64 CPUs support CPUID leaf 1
58- const FLAG : u32 = 1 << 30 ;
5949 lazy_static ! {
60- static ref HAS_RDRAND : bool = unsafe { __cpuid ( 1 ) . ecx & FLAG != 0 } ;
50+ static ref HAS_RDRAND : bool = has_rdrand ( ) ;
6151 }
6252 * HAS_RDRAND
6353}
6454
55+ #[ cfg( not( target_env = "sgx" ) ) ]
56+ pub fn has_rdrand ( ) -> bool {
57+ use core:: arch:: x86_64:: __cpuid;
58+ // SAFETY: All x86_64 CPUs support CPUID leaf 0 and 1
59+ let leaf_0 = unsafe { __cpuid ( 0 ) } ;
60+ let vendor_id: [ u8 ; 12 ] = unsafe { mem:: transmute ( [ leaf_0. ebx , leaf_0. edx , leaf_0. ecx ] ) } ;
61+ let is_amd = & vendor_id == b"AuthenticAMD" ;
62+
63+ if cfg ! ( target_feature = "rdrand" ) && !is_amd {
64+ return true ;
65+ }
66+ let leaf_1 = unsafe { __cpuid ( 1 ) } ;
67+
68+ // Early AMD CPUs have a broken RDRAND. They return nonrandom data when
69+ // resuming from sleep. We will ignore RDRAND support on such platfroms.
70+ // See: https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
71+ if is_amd {
72+ let mut family_id = ( leaf_1. eax & 0x00000f00 ) >> 8 ;
73+ if family_id == 0xF {
74+ let extended_id = ( leaf_1. eax & 0x0ff00000 ) >> 20 ;
75+ family_id += extended_id;
76+ }
77+ // This issue is only present before Zen (family 17h).
78+ if family_id < 0x17 {
79+ return false ;
80+ }
81+ }
82+ const RDRAND_FLAG : u32 = 1 << 30 ;
83+ leaf_1. ecx & RDRAND_FLAG != 0
84+ }
85+
6586pub fn getrandom_inner ( dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
6687 if !is_rdrand_supported ( ) {
6788 return Err ( Error :: UNAVAILABLE ) ;
0 commit comments