:: commit 74ddd08758e15a98e7f68c321f03ceba0da39e7d

Mintsuki <mintsuki@protonmail.com> — 2026-04-01 21:30

parents: a28a8ec0a2

lib/rand: Mix hardware entropy on non-x86 via RNDR and EFI RNG protocol

diff --git a/common/lib/rand.c b/common/lib/rand.c
index f31419d5..8a443277 100644
--- a/common/lib/rand.c
+++ b/common/lib/rand.c
@@ -21,23 +21,63 @@ static bool rand_initialised = false;
 static uint32_t *status;
 static int ctr;
 
-static void init_rand(void) {
-    uint32_t seed = ((uint32_t)0xc597060c * (uint32_t)rdtsc())
-                  * ((uint32_t)0xce86d624)
-                  ^ ((uint32_t)0xee0da130 * (uint32_t)rdtsc());
-
-    // TODO(qookie): aarch64 also has an optional HW random number generator
+static uint32_t hw_entropy(void) {
 #if defined (__x86_64__) || defined(__i386__)
     uint32_t eax, ebx, ecx, edx;
 
-    // Check for rdseed
     if (cpuid(0x07, 0, &eax, &ebx, &ecx, &edx) && (ebx & (1 << 18))) {
-        seed *= (seed ^ rdseed(uint32_t));
+        return rdseed(uint32_t);
     } else if (cpuid(0x01, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 30))) {
-        seed *= (seed ^ rdrand(uint32_t));
+        return rdrand(uint32_t);
+    }
+#elif defined (__aarch64__)
+    // ARMv8.5-RNG: check ID_AA64ISAR0_EL1 RNDR field (bits [63:60])
+    uint64_t isar0;
+    asm volatile ("mrs %0, id_aa64isar0_el1" : "=r" (isar0));
+    if ((isar0 >> 60) & 0xf) {
+        uint64_t rndr;
+        // RNDR register: s3_3_c2_c4_0
+        bool ok;
+        asm volatile (
+            "mrs %0, s3_3_c2_c4_0\n\t"
+            "cset %w1, ne"
+            : "=r" (rndr), "=r" (ok)
+            :
+            : "cc"
+        );
+        if (ok) {
+            return (uint32_t)rndr;
+        }
+    }
+#endif
+
+#if defined (UEFI)
+    // Try EFI RNG protocol as a fallback for all UEFI platforms
+    {
+        EFI_GUID rng_guid = EFI_RNG_PROTOCOL_GUID;
+        EFI_RNG_PROTOCOL *rng = NULL;
+        if (gBS->LocateProtocol(&rng_guid, NULL, (void **)&rng) == EFI_SUCCESS && rng != NULL) {
+            uint32_t val;
+            if (rng->GetRNG(rng, NULL, sizeof(val), (UINT8 *)&val) == EFI_SUCCESS) {
+                return val;
+            }
+        }
     }
 #endif
 
+    return 0;
+}
+
+static void init_rand(void) {
+    uint32_t seed = ((uint32_t)0xc597060c * (uint32_t)rdtsc())
+                  * ((uint32_t)0xce86d624)
+                  ^ ((uint32_t)0xee0da130 * (uint32_t)rdtsc());
+
+    uint32_t hw = hw_entropy();
+    if (hw != 0) {
+        seed *= (seed ^ hw);
+    }
+
     status = ext_mem_alloc_counted(n, sizeof(uint32_t));
 
     srand(seed);
tab: 248 wrap: offon