]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
driver: rng: Add DM_RNG interface for ARMv8.5 RNDR registers
authorAndre Przywara <andre.przywara@arm.com>
Wed, 30 Aug 2023 11:32:30 +0000 (12:32 +0100)
committerTom Rini <trini@konsulko.com>
Wed, 11 Oct 2023 17:22:32 +0000 (13:22 -0400)
The ARMv8.5 architecture extension defines architectural RNDR/RNDRRS
system registers, that provide 64 bits worth of randomness on every
read. Since it's an extension, and implementing it is optional, there is
a field in the ID_AA64ISAR0_EL1 ID register to query the availability
of those registers.

Add a UCLASS_RNG driver that returns entropy via repeated reads from
those system registers, if the extension is implemented.
The driver always binds, but checks the availability in the probe()
routine.

This helps systems which suffer from low boot entropy, since U-Boot can
provide entropy via the generic UEFI entropy gathering protocol to the OS,
at an early stage.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
arch/arm/include/asm/system.h
drivers/rng/Kconfig
drivers/rng/Makefile
drivers/rng/arm_rndr.c [new file with mode: 0644]

index 87d1c77e8b1e6a846861fbc8a0e99ec54da85697..0eae857e73a0adcc9eaa2279214685bfcdb897c7 100644 (file)
@@ -84,6 +84,7 @@
 #define HCR_EL2_HCD_DIS                (1 << 29) /* Hypervisor Call disabled         */
 #define HCR_EL2_AMO_EL2                (1 <<  5) /* Route SErrors to EL2             */
 
+#define ID_AA64ISAR0_EL1_RNDR  (0xFUL << 60) /* RNDR random registers */
 /*
  * ID_AA64ISAR1_EL1 bits definitions
  */
index 24666bff987e81ba37f3cc1f12748dc2dc117378..994cc35b274483942e0a2f0f025046cb68b0416a 100644 (file)
@@ -76,6 +76,12 @@ config RNG_SMCCC_TRNG
          Enable random number generator for platforms that support Arm
          SMCCC TRNG interface.
 
+config RNG_ARM_RNDR
+       bool "Generic ARMv8.5 RNDR register"
+       depends on DM_RNG && ARM64
+       help
+         Use the ARMv8.5 RNDR register to provide random numbers.
+
 config TPM_RNG
        bool "Enable random number generator on TPM device"
        depends on TPM
index 192f911e15521930c793a002347663bf59bc3971..47b323e61ee344dc658447d643cece9d517870a6 100644 (file)
@@ -13,4 +13,5 @@ obj-$(CONFIG_RNG_STM32) += stm32_rng.o
 obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o
 obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o
 obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o
+obj-$(CONFIG_RNG_ARM_RNDR) += arm_rndr.o
 obj-$(CONFIG_TPM_RNG) += tpm_rng.o
diff --git a/drivers/rng/arm_rndr.c b/drivers/rng/arm_rndr.c
new file mode 100644 (file)
index 0000000..5598974
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Arm Ltd.
+ *
+ * Use the (optional) ARMv8.5 RNDR register to provide random numbers to
+ * U-Boot's UCLASS_RNG users.
+ * Detection is done at runtime using the CPU ID registers.
+ */
+
+#define LOG_CATEGORY UCLASS_RNG
+
+#include <common.h>
+#include <dm.h>
+#include <linux/kernel.h>
+#include <rng.h>
+#include <asm/system.h>
+
+#define DRIVER_NAME    "arm-rndr"
+
+static bool cpu_has_rndr(void)
+{
+       uint64_t reg;
+
+       __asm__ volatile("mrs %0, ID_AA64ISAR0_EL1\n" : "=r" (reg));
+       return !!(reg & ID_AA64ISAR0_EL1_RNDR);
+}
+
+/*
+ * The system register name is RNDR, but this isn't widely known among older
+ * toolchains, and also triggers errors because of it being an architecture
+ * extension. Since we check the availability of the register before, it's
+ * fine to use here, though.
+ */
+#define RNDR   "S3_3_C2_C4_0"
+
+static uint64_t read_rndr(void)
+{
+       uint64_t reg;
+
+       __asm__ volatile("mrs %0, " RNDR "\n" : "=r" (reg));
+
+       return reg;
+}
+
+static int arm_rndr_read(struct udevice *dev, void *data, size_t len)
+{
+       uint64_t random;
+
+       while (len) {
+               int tocopy = min(sizeof(uint64_t), len);
+
+               random = read_rndr();
+               memcpy(data, &random, tocopy);
+               len -= tocopy;
+               data += tocopy;
+       }
+
+       return 0;
+}
+
+static const struct dm_rng_ops arm_rndr_ops = {
+       .read = arm_rndr_read,
+};
+
+static int arm_rndr_probe(struct udevice *dev)
+{
+       if (!cpu_has_rndr())
+               return -ENODEV;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(arm_rndr) = {
+       .name = DRIVER_NAME,
+       .id = UCLASS_RNG,
+       .ops = &arm_rndr_ops,
+       .probe = arm_rndr_probe,
+};
+
+U_BOOT_DRVINFO(cpu_arm_rndr) = {
+       .name = DRIVER_NAME,
+};