11a50ec0bSRichard Henderson /* SPDX-License-Identifier: GPL-2.0 */ 21a50ec0bSRichard Henderson #ifndef _ASM_ARCHRANDOM_H 31a50ec0bSRichard Henderson #define _ASM_ARCHRANDOM_H 41a50ec0bSRichard Henderson 51a50ec0bSRichard Henderson #ifdef CONFIG_ARCH_RANDOM 61a50ec0bSRichard Henderson 7*ead5084cSMark Rutland #include <linux/bug.h> 8*ead5084cSMark Rutland #include <linux/kernel.h> 91a50ec0bSRichard Henderson #include <linux/random.h> 101a50ec0bSRichard Henderson #include <asm/cpufeature.h> 111a50ec0bSRichard Henderson 121a50ec0bSRichard Henderson static inline bool __arm64_rndr(unsigned long *v) 131a50ec0bSRichard Henderson { 141a50ec0bSRichard Henderson bool ok; 151a50ec0bSRichard Henderson 161a50ec0bSRichard Henderson /* 171a50ec0bSRichard Henderson * Reads of RNDR set PSTATE.NZCV to 0b0000 on success, 181a50ec0bSRichard Henderson * and set PSTATE.NZCV to 0b0100 otherwise. 191a50ec0bSRichard Henderson */ 201a50ec0bSRichard Henderson asm volatile( 211a50ec0bSRichard Henderson __mrs_s("%0", SYS_RNDR_EL0) "\n" 221a50ec0bSRichard Henderson " cset %w1, ne\n" 231a50ec0bSRichard Henderson : "=r" (*v), "=r" (ok) 241a50ec0bSRichard Henderson : 251a50ec0bSRichard Henderson : "cc"); 261a50ec0bSRichard Henderson 271a50ec0bSRichard Henderson return ok; 281a50ec0bSRichard Henderson } 291a50ec0bSRichard Henderson 301a50ec0bSRichard Henderson static inline bool __must_check arch_get_random_long(unsigned long *v) 311a50ec0bSRichard Henderson { 321a50ec0bSRichard Henderson return false; 331a50ec0bSRichard Henderson } 341a50ec0bSRichard Henderson 351a50ec0bSRichard Henderson static inline bool __must_check arch_get_random_int(unsigned int *v) 361a50ec0bSRichard Henderson { 371a50ec0bSRichard Henderson return false; 381a50ec0bSRichard Henderson } 391a50ec0bSRichard Henderson 401a50ec0bSRichard Henderson static inline bool __must_check arch_get_random_seed_long(unsigned long *v) 411a50ec0bSRichard Henderson { 421a50ec0bSRichard Henderson /* 431a50ec0bSRichard Henderson * Only support the generic interface after we have detected 441a50ec0bSRichard Henderson * the system wide capability, avoiding complexity with the 451a50ec0bSRichard Henderson * cpufeature code and with potential scheduling between CPUs 461a50ec0bSRichard Henderson * with and without the feature. 471a50ec0bSRichard Henderson */ 481a50ec0bSRichard Henderson if (!cpus_have_const_cap(ARM64_HAS_RNG)) 491a50ec0bSRichard Henderson return false; 501a50ec0bSRichard Henderson 511a50ec0bSRichard Henderson return __arm64_rndr(v); 521a50ec0bSRichard Henderson } 531a50ec0bSRichard Henderson 541a50ec0bSRichard Henderson 551a50ec0bSRichard Henderson static inline bool __must_check arch_get_random_seed_int(unsigned int *v) 561a50ec0bSRichard Henderson { 571a50ec0bSRichard Henderson unsigned long val; 581a50ec0bSRichard Henderson bool ok = arch_get_random_seed_long(&val); 591a50ec0bSRichard Henderson 601a50ec0bSRichard Henderson *v = val; 611a50ec0bSRichard Henderson return ok; 621a50ec0bSRichard Henderson } 631a50ec0bSRichard Henderson 642e8e1ea8SMark Brown static inline bool __init __early_cpu_has_rndr(void) 652e8e1ea8SMark Brown { 662e8e1ea8SMark Brown /* Open code as we run prior to the first call to cpufeature. */ 672e8e1ea8SMark Brown unsigned long ftr = read_sysreg_s(SYS_ID_AA64ISAR0_EL1); 682e8e1ea8SMark Brown return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf; 692e8e1ea8SMark Brown } 702e8e1ea8SMark Brown 71*ead5084cSMark Rutland static inline bool __init __must_check 72*ead5084cSMark Rutland arch_get_random_seed_long_early(unsigned long *v) 73*ead5084cSMark Rutland { 74*ead5084cSMark Rutland WARN_ON(system_state != SYSTEM_BOOTING); 75*ead5084cSMark Rutland 76*ead5084cSMark Rutland if (!__early_cpu_has_rndr()) 77*ead5084cSMark Rutland return false; 78*ead5084cSMark Rutland 79*ead5084cSMark Rutland return __arm64_rndr(v); 80*ead5084cSMark Rutland } 81*ead5084cSMark Rutland #define arch_get_random_seed_long_early arch_get_random_seed_long_early 82*ead5084cSMark Rutland 831a50ec0bSRichard Henderson #else 841a50ec0bSRichard Henderson 851a50ec0bSRichard Henderson static inline bool __arm64_rndr(unsigned long *v) { return false; } 862e8e1ea8SMark Brown static inline bool __init __early_cpu_has_rndr(void) { return false; } 871a50ec0bSRichard Henderson 881a50ec0bSRichard Henderson #endif /* CONFIG_ARCH_RANDOM */ 891a50ec0bSRichard Henderson #endif /* _ASM_ARCHRANDOM_H */ 90