Disable RDRAND on AMD chips before Zen.

There are reports that RDRAND on these chips can fail. Thus this change
disables the use RDRAND. Outside of FIPS mode, RDRAND is only used for
protection against forks and VM clones anyway.

(Note: I don't have any AMD chips to test on, so this is done blindly
from AMD's docs.)

Change-Id: Id61b2f6ba74c5ecf66804f7268a26e480a5bf815
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/36144
Commit-Queue: Adam Langley <alangley@gmail.com>
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/cpu-intel.c b/crypto/cpu-intel.c
index 98d8d4e..1621ef6 100644
--- a/crypto/cpu-intel.c
+++ b/crypto/cpu-intel.c
@@ -148,6 +148,9 @@
   int is_intel = ebx == 0x756e6547 /* Genu */ &&
                  edx == 0x49656e69 /* ineI */ &&
                  ecx == 0x6c65746e /* ntel */;
+  int is_amd = ebx == 0x68747541 /* Auth */ &&
+               edx == 0x69746e65 /* enti */ &&
+               ecx == 0x444d4163 /* cAMD */;
 
   uint32_t extended_features[2] = {0};
   if (num_ids >= 7) {
@@ -158,6 +161,24 @@
 
   OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1);
 
+  if (is_amd) {
+    // See https://www.amd.com/system/files/TechDocs/25481.pdf, page 10.
+    const uint32_t base_family = (eax >> 8) & 15;
+
+    uint32_t family = base_family;
+    if (base_family == 0xf) {
+      const uint32_t ext_family = (eax >> 20) & 255;
+      family += ext_family;
+    }
+
+    if (family < 0x17) {
+      // Disable RDRAND on AMD families before 0x17 (Zen) due to reported
+      // failures after suspend.
+      // https://bugzilla.redhat.com/show_bug.cgi?id=1150286
+      ecx &= ~(1u << 30);
+    }
+  }
+
   // Force the hyper-threading bit so that the more conservative path is always
   // chosen.
   edx |= 1u << 28;