On 2022-07-19 15:02, Jason A. Donenfeld wrote:
The archrandom interface was originally designed for x86, which
supplies
RDRAND/RDSEED for receiving random words into registers, resulting in
one function to generate an int and another to generate a long.
However,
other architectures don't follow this.
On arm64, the SMCCC TRNG interface can return between 1 and 3 longs. On
s390, the CPACF TRNG interface can return arbitrary amounts, with 32
longs having the same cost as one. On UML, the os_getrandom() interface
can return arbitrary amounts.
So change the api signature to take a "max_longs" parameter designating
the maximum number of longs requested, and then return the number of
longs generated.
Since callers need to check this return value and loop anyway, each
arch
implementation does not bother implementing its own loop to try again
to
fill the maximum number of longs. Additionally, all existing callers
pass in a constant max_longs parameter. Taken together, these two
things
mean that the codegen doesn't really change much for one-word-at-a-time
platforms, while performance is greatly improved on platforms such as
s390.
Cc: Will Deacon
Cc: Alexander Gordeev
Cc: Thomas Gleixner
Cc: H. Peter Anvin
Cc: Catalin Marinas
Cc: Borislav Petkov
Cc: Heiko Carstens
Cc: Johannes Berg
Cc: Mark Rutland
Cc: Harald Freudenberger
Acked-by: Michael Ellerman
Signed-off-by: Jason A. Donenfeld
---
arch/arm64/include/asm/archrandom.h | 102 --
arch/arm64/kernel/kaslr.c | 2 +-
arch/powerpc/include/asm/archrandom.h | 30 ++--
arch/powerpc/kvm/book3s_hv.c | 2 +-
arch/s390/include/asm/archrandom.h| 29 ++--
arch/um/include/asm/archrandom.h | 21 ++
arch/x86/include/asm/archrandom.h | 41 +--
arch/x86/kernel/espfix_64.c | 2 +-
drivers/char/random.c | 45
include/asm-generic/archrandom.h | 18 +
include/linux/random.h| 12 +--
11 files changed, 116 insertions(+), 188 deletions(-)
diff --git a/arch/arm64/include/asm/archrandom.h
b/arch/arm64/include/asm/archrandom.h
index c3b9fa56af67..109e2a4454be 100644
--- a/arch/arm64/include/asm/archrandom.h
+++ b/arch/arm64/include/asm/archrandom.h
@@ -58,7 +58,7 @@ static inline bool __arm64_rndrrs(unsigned long *v)
return ok;
}
-static inline bool __must_check arch_get_random_long(unsigned long *v)
+static inline size_t __must_check arch_get_random_longs(unsigned long
*v, size_t max_longs)
{
/*
* Only support the generic interface after we have detected
@@ -66,27 +66,15 @@ static inline bool __must_check
arch_get_random_long(unsigned long *v)
* cpufeature code and with potential scheduling between CPUs
* with and without the feature.
*/
- if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
- return true;
- return false;
+ if (max_longs && cpus_have_const_cap(ARM64_HAS_RNG) &&
__arm64_rndr(v))
+ return 1;
+ return 0;
}
-static inline bool __must_check arch_get_random_int(unsigned int *v)
+static inline size_t __must_check arch_get_random_seed_longs(unsigned
long *v, size_t max_longs)
{
- if (cpus_have_const_cap(ARM64_HAS_RNG)) {
- unsigned long val;
-
- if (__arm64_rndr(&val)) {
- *v = val;
- return true;
- }
- }
- return false;
-}
-
-static inline bool __must_check arch_get_random_seed_long(unsigned
long *v)
-{
- struct arm_smccc_res res;
+ if (!max_longs)
+ return 0;
/*
* We prefer the SMCCC call, since its semantics (return actual
@@ -95,10 +83,23 @@ static inline bool __must_check
arch_get_random_seed_long(unsigned long *v)
* (the output of a pseudo RNG freshly seeded by a TRNG).
*/
if (smccc_trng_available) {
- arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, 64, &res);
+ struct arm_smccc_res res;
+
+ max_longs = min_t(size_t, 3, max_longs);
+ arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, max_longs * 64,
&res);
if ((int)res.a0 >= 0) {
- *v = res.a3;
- return true;
+ switch (max_longs) {
+ case 3:
+ *v++ = res.a1;
+ fallthrough;
+ case 2:
+ *v++ = res.a2;
+ fallthrough;
+ case 1:
+ *v++ = res.a3;
+ break;
+ }
+ return max_longs;
}
}
@@ -108,32 +109,9 @@ static inline bool __must_check
arch_get_random_seed_long(unsigned l