In InitHardwareRand, do trail test for RNDRRS by VerifyRNDRRS

Signed-off-by: Eval EXEC <execvy@gmail.com>
This commit is contained in:
Eval EXEC 2025-02-08 18:15:29 +08:00
parent 43e71f7498
commit 09b150bb8a
No known key found for this signature in database
GPG key ID: 0F0272C0D3AC91F7

View file

@ -192,11 +192,13 @@ uint64_t GetRdSeed() noexcept
#elif defined(__aarch64__) && defined(HWCAP2_RNG) #elif defined(__aarch64__) && defined(HWCAP2_RNG)
bool g_rndr_supported = false; bool g_rndr_supported = false;
bool g_rndrrs_supported = false;
void InitHardwareRand() void InitHardwareRand()
{ {
if (getauxval(AT_HWCAP2) & HWCAP2_RNG) { if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
g_rndr_supported = true; g_rndr_supported = true;
g_rndrrs_supported = VerifyRNDRRS();
} }
} }
@ -204,8 +206,10 @@ void ReportHardwareRand()
{ {
// This must be done in a separate function, as InitHardwareRand() may be indirectly called // This must be done in a separate function, as InitHardwareRand() may be indirectly called
// from global constructors, before logging is initialized. // from global constructors, before logging is initialized.
if (g_rndr_supported) { if (g_rndr_supported && g_rndrrs_supported) {
LogPrintf("Using RNDR and RNDRRS as additional entropy sources\n"); LogPrintf("Using RNDR and RNDRRS as additional entropy sources\n");
} else if (g_rndr_supported) {
LogPrintf("Using RNDR as an additional entropy source\n");
} }
} }
@ -227,24 +231,43 @@ uint64_t GetRNDR() noexcept
return r1; return r1;
} }
/** Read 64 bits of entropy using rndrrs. // Helper function to retrieve random value using RNDRRS
* bool GetRNDRRSInternal(uint64_t &r1) noexcept
{
uint8_t ok = 0;
__asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
: "=r"(r1), "=r"(ok)::"cc");
return ok != 0;
}
/** Read 64 bits of entropy using RNDRRS.
* Must only be called when RNDRRS is supported. * Must only be called when RNDRRS is supported.
*/ */
uint64_t GetRNDRRS() noexcept uint64_t GetRNDRRS() noexcept
{ {
uint8_t ok = 0;
uint64_t r1; uint64_t r1;
do { while (!GetRNDRRSInternal(r1)) {
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number
__asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
: "=r"(r1), "=r"(ok)::"cc");
if (ok) break;
__asm__ volatile("yield"); __asm__ volatile("yield");
} while (true); }
return r1; return r1;
} }
/** Verify if RNDRRS is supported and functional.
* Return true if it works within the retry limit.
*/
bool VerifyRNDRRS() noexcept
{
uint64_t test;
for (int retry = 0; retry < 10; ++retry) {
if (GetRNDRRSInternal(test)) {
return true;
}
__asm__ volatile("yield");
}
return false;
}
#else #else
/* Access to other hardware random number generators could be added here later, /* Access to other hardware random number generators could be added here later,
* assuming it is sufficiently fast (in the order of a few hundred CPU cycles). * assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
@ -295,7 +318,7 @@ void SeedHardwareSlow(CSHA512& hasher) noexcept {
return; return;
} }
#elif defined(__aarch64__) && defined(HWCAP2_RNG) #elif defined(__aarch64__) && defined(HWCAP2_RNG)
if (g_rndr_supported) { if (g_rndrrs_supported) {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
uint64_t out = GetRNDRRS(); uint64_t out = GetRNDRRS();
hasher.Write((const unsigned char*)&out, sizeof(out)); hasher.Write((const unsigned char*)&out, sizeof(out));