diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 87d1c77e8b1..0eae857e73a 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -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 */ diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index 24666bff987..994cc35b274 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -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 diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile index 192f911e155..47b323e61ee 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -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 index 00000000000..55989743eae --- /dev/null +++ b/drivers/rng/arm_rndr.c @@ -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 +#include +#include +#include +#include + +#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, +};