@@ -192,20 +192,24 @@ uint64_t GetRdSeed() noexcept
192
192
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
193
193
194
194
bool g_rndr_supported = false ;
195
+ bool g_rndrrs_supported = false ;
195
196
196
197
void InitHardwareRand ()
197
198
{
198
199
if (getauxval (AT_HWCAP2) & HWCAP2_RNG) {
199
200
g_rndr_supported = true ;
201
+ g_rndrrs_supported = VerifyRNDRRS ();
200
202
}
201
203
}
202
204
203
205
void ReportHardwareRand ()
204
206
{
205
207
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
206
208
// from global constructors, before logging is initialized.
207
- if (g_rndr_supported) {
209
+ if (g_rndr_supported && g_rndrrs_supported ) {
208
210
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 " );
209
213
}
210
214
}
211
215
@@ -227,24 +231,43 @@ uint64_t GetRNDR() noexcept
227
231
return r1;
228
232
}
229
233
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.
232
245
* Must only be called when RNDRRS is supported.
233
246
*/
234
247
uint64_t GetRNDRRS () noexcept
235
248
{
236
- uint8_t ok = 0 ;
237
249
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)) {
243
251
__asm__ volatile (" yield" );
244
- } while ( true );
252
+ }
245
253
return r1;
246
254
}
247
255
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
+
248
271
#else
249
272
/* Access to other hardware random number generators could be added here later,
250
273
* assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
@@ -295,7 +318,7 @@ void SeedHardwareSlow(CSHA512& hasher) noexcept {
295
318
return ;
296
319
}
297
320
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
298
- if (g_rndr_supported ) {
321
+ if (g_rndrrs_supported ) {
299
322
for (int i = 0 ; i < 4 ; ++i) {
300
323
uint64_t out = GetRNDRRS ();
301
324
hasher.Write ((const unsigned char *)&out, sizeof (out));
0 commit comments