1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_ARCHRANDOM_H
3 #define _ASM_ARCHRANDOM_H
5 #include <linux/arm-smccc.h>
7 #include <linux/kernel.h>
8 #include <linux/irqflags.h>
9 #include <asm/cpufeature.h>
11 #define ARM_SMCCC_TRNG_MIN_VERSION 0x10000UL
13 extern bool smccc_trng_available
;
15 static inline bool __init
smccc_probe_trng(void)
17 struct arm_smccc_res res
;
19 arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_VERSION
, &res
);
23 return res
.a0
>= ARM_SMCCC_TRNG_MIN_VERSION
;
26 static inline bool __arm64_rndr(unsigned long *v
)
31 * Reads of RNDR set PSTATE.NZCV to 0b0000 on success,
32 * and set PSTATE.NZCV to 0b0100 otherwise.
35 __mrs_s("%0", SYS_RNDR_EL0
) "\n"
37 : "=r" (*v
), "=r" (ok
)
44 static inline bool __arm64_rndrrs(unsigned long *v
)
49 * Reads of RNDRRS set PSTATE.NZCV to 0b0000 on success,
50 * and set PSTATE.NZCV to 0b0100 otherwise.
53 __mrs_s("%0", SYS_RNDRRS_EL0
) "\n"
55 : "=r" (*v
), "=r" (ok
)
62 static __always_inline
bool __cpu_has_rng(void)
64 if (unlikely(!system_capabilities_finalized() && !preemptible()))
65 return this_cpu_has_cap(ARM64_HAS_RNG
);
66 return alternative_has_cap_unlikely(ARM64_HAS_RNG
);
69 static inline size_t __must_check
arch_get_random_longs(unsigned long *v
, size_t max_longs
)
72 * Only support the generic interface after we have detected
73 * the system wide capability, avoiding complexity with the
74 * cpufeature code and with potential scheduling between CPUs
75 * with and without the feature.
77 if (max_longs
&& __cpu_has_rng() && __arm64_rndr(v
))
82 static inline size_t __must_check
arch_get_random_seed_longs(unsigned long *v
, size_t max_longs
)
88 * We prefer the SMCCC call, since its semantics (return actual
89 * hardware backed entropy) is closer to the idea behind this
90 * function here than what even the RNDRSS register provides
91 * (the output of a pseudo RNG freshly seeded by a TRNG).
93 if (smccc_trng_available
) {
94 struct arm_smccc_res res
;
96 max_longs
= min_t(size_t, 3, max_longs
);
97 arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64
, max_longs
* 64, &res
);
98 if ((int)res
.a0
>= 0) {
115 * RNDRRS is not backed by an entropy source but by a DRBG that is
116 * reseeded after each invocation. This is not a 100% fit but good
117 * enough to implement this API if no other entropy source exists.
119 if (__cpu_has_rng() && __arm64_rndrrs(v
))
125 static inline bool __init
__early_cpu_has_rndr(void)
127 /* Open code as we run prior to the first call to cpufeature. */
128 unsigned long ftr
= read_sysreg_s(SYS_ID_AA64ISAR0_EL1
);
129 return (ftr
>> ID_AA64ISAR0_EL1_RNDR_SHIFT
) & 0xf;
132 #endif /* _ASM_ARCHRANDOM_H */