[PATCH] driver: rng: Add DM_RNG interface for ARMv8.5 RNDR registers

Simon Glass sjg at chromium.org
Thu Aug 31 04:49:18 CEST 2023


Hi Andre,

On Wed, 30 Aug 2023 at 05:32, Andre Przywara <andre.przywara at arm.com> wrote:
>
> 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 at arm.com>
> ---
> Hi Simon,
>
> not sure if this is the expected way to model a driver which autodetects
> its device at runtime. It somewhat works, but always lists the bound
> device, even if the registers are not supported. If I do the check in bind
> instead, it fails booting when this returns -ENODEV, since it expects
> the fixed device to always bind successfully, I guess?
> Is there any other way of modeling this? And before you say your
> favourite two letters: this is not a DT job, since it can be safely
> auto-detected in an architectural way.
>
> Thanks,
> Andre
>
>  arch/arm/include/asm/system.h |  1 +
>  drivers/rng/Kconfig           |  6 +++
>  drivers/rng/Makefile          |  1 +
>  drivers/rng/arm_rndr.c        | 82 +++++++++++++++++++++++++++++++++++
>  4 files changed, 90 insertions(+)
>  create mode 100644 drivers/rng/arm_rndr.c

Reviewed-by: Simon Glass <sjg at chromium.org>

nit below

>
> 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 5deb5db5b71..72788d479cc 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 78f61051acf..572fa7a0c66 100644
> --- a/drivers/rng/Makefile
> +++ b/drivers/rng/Makefile
> @@ -13,4 +13,5 @@ obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_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 <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;

Can you put this in a bind() function instead, if not too expensive?

> +
> +       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,
> +};
> --
> 2.25.1
>

Regards,
Simon


More information about the U-Boot mailing list