Skip to content

Commit 35bde68

Browse files
ardbiesheuvelwilldeacon
authored andcommitted
arm64: random: implement arch_get_random_int/_long based on RNDR
When support for RNDR/RNDRRS was introduced, we elected to only implement arch_get_random_seed_int/_long(), and back them by RNDR instead of RNDRRS. This was needed to prevent potential performance and/or starvation issues resulting from the fact that the /dev/random driver used to invoke these routines on various hot paths. These issues have all been addressed now [0] [1], and so we can wire up this API more straight-forwardly: - map arch_get_random_int/_long() onto RNDR, which returns the output of a DRBG that is reseeded at an implemented defined rate; - map arch_get_random_seed_int/_long() onto the TRNG firmware service, which returns true, conditioned entropy, or onto RNDRRS if the TRNG service is unavailable, which returns the output of a DRBG that is reseeded every time it is used. [0] 390596c random: avoid arch_get_random_seed_long() when collecting IRQ randomness [1] 2ee25b6 random: avoid superfluous call to RDRAND in CRNG extraction Cc: Andre Przywara <andre.przywara@arm.com> Cc: Mark Brown <broonie@kernel.org> Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Acked-by: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20220113131239.1610455-1-ardb@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
1 parent dfd42fa commit 35bde68

1 file changed

Lines changed: 39 additions & 6 deletions

File tree

arch/arm64/include/asm/archrandom.h

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,47 @@ static inline bool __arm64_rndr(unsigned long *v)
4242
return ok;
4343
}
4444

45+
static inline bool __arm64_rndrrs(unsigned long *v)
46+
{
47+
bool ok;
48+
49+
/*
50+
* Reads of RNDRRS set PSTATE.NZCV to 0b0000 on success,
51+
* and set PSTATE.NZCV to 0b0100 otherwise.
52+
*/
53+
asm volatile(
54+
__mrs_s("%0", SYS_RNDRRS_EL0) "\n"
55+
" cset %w1, ne\n"
56+
: "=r" (*v), "=r" (ok)
57+
:
58+
: "cc");
59+
60+
return ok;
61+
}
62+
4563
static inline bool __must_check arch_get_random_long(unsigned long *v)
4664
{
65+
/*
66+
* Only support the generic interface after we have detected
67+
* the system wide capability, avoiding complexity with the
68+
* cpufeature code and with potential scheduling between CPUs
69+
* with and without the feature.
70+
*/
71+
if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
72+
return true;
4773
return false;
4874
}
4975

5076
static inline bool __must_check arch_get_random_int(unsigned int *v)
5177
{
78+
if (cpus_have_const_cap(ARM64_HAS_RNG)) {
79+
unsigned long val;
80+
81+
if (__arm64_rndr(&val)) {
82+
*v = val;
83+
return true;
84+
}
85+
}
5286
return false;
5387
}
5488

@@ -71,12 +105,11 @@ static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
71105
}
72106

73107
/*
74-
* Only support the generic interface after we have detected
75-
* the system wide capability, avoiding complexity with the
76-
* cpufeature code and with potential scheduling between CPUs
77-
* with and without the feature.
108+
* RNDRRS is not backed by an entropy source but by a DRBG that is
109+
* reseeded after each invocation. This is not a 100% fit but good
110+
* enough to implement this API if no other entropy source exists.
78111
*/
79-
if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
112+
if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndrrs(v))
80113
return true;
81114

82115
return false;
@@ -96,7 +129,7 @@ static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
96129
}
97130

98131
if (cpus_have_const_cap(ARM64_HAS_RNG)) {
99-
if (__arm64_rndr(&val)) {
132+
if (__arm64_rndrrs(&val)) {
100133
*v = val;
101134
return true;
102135
}

0 commit comments

Comments
 (0)