@@ -1667,6 +1667,10 @@ config STACKPROTECTOR_PER_TASK
Enable this option to switch to a different method that uses a
different canary value for each task.
+config ARCH_RANDOM
+ def_bool y
+ depends on HAVE_ARM_SMCCC_DISCOVERY
+
endmenu
menu "Boot options"
@@ -2,9 +2,73 @@
#ifndef _ASM_ARCHRANDOM_H
#define _ASM_ARCHRANDOM_H
+#ifdef CONFIG_ARCH_RANDOM
+
+#include <linux/arm-smccc.h>
+#include <linux/kernel.h>
+
+#define ARM_SMCCC_TRNG_MIN_VERSION 0x10000UL
+
+extern bool smccc_trng_available;
+
+static inline bool __init smccc_probe_trng(void)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_VERSION, &res);
+ if ((s32)res.a0 < 0)
+ return false;
+ if (res.a0 >= ARM_SMCCC_TRNG_MIN_VERSION) {
+ /* double check that the 32-bit flavor is available */
+ arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_FEATURES,
+ ARM_SMCCC_TRNG_RND32,
+ &res);
+ if ((s32)res.a0 >= 0)
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool __must_check arch_get_random_long(unsigned long *v)
+{
+ return false;
+}
+
+static inline bool __must_check arch_get_random_int(unsigned int *v)
+{
+ return false;
+}
+
+static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
+{
+ struct arm_smccc_res res;
+
+ if (smccc_trng_available) {
+ arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND32, 8 * sizeof(*v), &res);
+
+ if (res.a0 != 0)
+ return false;
+
+ *v = res.a3;
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
+{
+ return arch_get_random_seed_long((unsigned long *)v);
+}
+
+
+#else /* !CONFIG_ARCH_RANDOM */
+
static inline bool __init smccc_probe_trng(void)
{
return false;
}
+#endif /* CONFIG_ARCH_RANDOM */
#endif /* _ASM_ARCHRANDOM_H */