1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_ARCHRANDOM_H
3 #define _ASM_ARCHRANDOM_H
4 
5 #ifdef CONFIG_ARCH_RANDOM
6 
7 #include <linux/bug.h>
8 #include <linux/kernel.h>
9 #include <linux/random.h>
10 #include <asm/cpufeature.h>
11 
12 static inline bool __arm64_rndr(unsigned long *v)
13 {
14 	bool ok;
15 
16 	/*
17 	 * Reads of RNDR set PSTATE.NZCV to 0b0000 on success,
18 	 * and set PSTATE.NZCV to 0b0100 otherwise.
19 	 */
20 	asm volatile(
21 		__mrs_s("%0", SYS_RNDR_EL0) "\n"
22 	"	cset %w1, ne\n"
23 	: "=r" (*v), "=r" (ok)
24 	:
25 	: "cc");
26 
27 	return ok;
28 }
29 
30 static inline bool __must_check arch_get_random_long(unsigned long *v)
31 {
32 	return false;
33 }
34 
35 static inline bool __must_check arch_get_random_int(unsigned int *v)
36 {
37 	return false;
38 }
39 
40 static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
41 {
42 	/*
43 	 * Only support the generic interface after we have detected
44 	 * the system wide capability, avoiding complexity with the
45 	 * cpufeature code and with potential scheduling between CPUs
46 	 * with and without the feature.
47 	 */
48 	if (!cpus_have_const_cap(ARM64_HAS_RNG))
49 		return false;
50 
51 	return __arm64_rndr(v);
52 }
53 
54 
55 static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
56 {
57 	unsigned long val;
58 	bool ok = arch_get_random_seed_long(&val);
59 
60 	*v = val;
61 	return ok;
62 }
63 
64 static inline bool __init __early_cpu_has_rndr(void)
65 {
66 	/* Open code as we run prior to the first call to cpufeature. */
67 	unsigned long ftr = read_sysreg_s(SYS_ID_AA64ISAR0_EL1);
68 	return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf;
69 }
70 
71 static inline bool __init __must_check
72 arch_get_random_seed_long_early(unsigned long *v)
73 {
74 	WARN_ON(system_state != SYSTEM_BOOTING);
75 
76 	if (!__early_cpu_has_rndr())
77 		return false;
78 
79 	return __arm64_rndr(v);
80 }
81 #define arch_get_random_seed_long_early arch_get_random_seed_long_early
82 
83 #else
84 
85 static inline bool __arm64_rndr(unsigned long *v) { return false; }
86 static inline bool __init __early_cpu_has_rndr(void) { return false; }
87 
88 #endif /* CONFIG_ARCH_RANDOM */
89 #endif /* _ASM_ARCHRANDOM_H */
90