@@ -192,20 +192,24 @@ uint64_t GetRdSeed() noexcept
192192#elif defined(__aarch64__) && defined(HWCAP2_RNG)
193193
194194bool g_rndr_supported = false ;
195+ bool g_rndrrs_supported = false ;
195196
196197void InitHardwareRand ()
197198{
198199 if (getauxval (AT_HWCAP2) & HWCAP2_RNG) {
199200 g_rndr_supported = true ;
201+ g_rndrrs_supported = VerifyRNDRRS ();
200202 }
201203}
202204
203205void ReportHardwareRand ()
204206{
205207 // This must be done in a separate function, as InitHardwareRand() may be indirectly called
206208 // from global constructors, before logging is initialized.
207- if (g_rndr_supported) {
209+ if (g_rndr_supported && g_rndrrs_supported ) {
208210 LogPrintf (" Using RNDR and RNDRRS as additional entropy sources\n " );
211+ } else if (g_rndr_supported) {
212+ LogPrintf (" Using RNDR as an additional entropy source\n " );
209213 }
210214}
211215
@@ -227,24 +231,43 @@ uint64_t GetRNDR() noexcept
227231 return r1;
228232}
229233
230- /* * Read 64 bits of entropy using rndrrs.
231- *
234+ // Helper function to retrieve random value using RNDRRS
235+ bool GetRNDRRSInternal (uint64_t &r1) noexcept
236+ {
237+ uint8_t ok = 0 ;
238+ __asm__ volatile (" mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
239+ : " =r" (r1), " =r" (ok)::" cc" );
240+ return ok != 0 ;
241+ }
242+
243+
244+ /* * Read 64 bits of entropy using RNDRRS.
232245 * Must only be called when RNDRRS is supported.
233246 */
234247uint64_t GetRNDRRS () noexcept
235248{
236- uint8_t ok = 0 ;
237249 uint64_t r1;
238- do {
239- // https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number
240- __asm__ volatile (" mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
241- : " =r" (r1), " =r" (ok)::" cc" );
242- if (ok) break ;
250+ while (!GetRNDRRSInternal (r1)) {
243251 __asm__ volatile (" yield" );
244- } while ( true );
252+ }
245253 return r1;
246254}
247255
256+ /* * Verify if RNDRRS is supported and functional.
257+ * Return true if it works within the retry limit.
258+ */
259+ bool VerifyRNDRRS () noexcept
260+ {
261+ uint64_t test;
262+ for (int retry = 0 ; retry < 10 ; ++retry) {
263+ if (GetRNDRRSInternal (test)) {
264+ return true ;
265+ }
266+ __asm__ volatile (" yield" );
267+ }
268+ return false ;
269+ }
270+
248271#else
249272/* Access to other hardware random number generators could be added here later,
250273 * assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
@@ -295,7 +318,7 @@ void SeedHardwareSlow(CSHA512& hasher) noexcept {
295318 return ;
296319 }
297320#elif defined(__aarch64__) && defined(HWCAP2_RNG)
298- if (g_rndr_supported ) {
321+ if (g_rndrrs_supported ) {
299322 for (int i = 0 ; i < 4 ; ++i) {
300323 uint64_t out = GetRNDRRS ();
301324 hasher.Write ((const unsigned char *)&out, sizeof (out));
0 commit comments