diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c index e1f4709c4c..4e18733001 100644 --- a/board/emulation/qemu-arm/qemu-arm.c +++ b/board/emulation/qemu-arm/qemu-arm.c @@ -91,3 +91,45 @@ void *board_fdt_blob_setup(void) /* QEMU loads a generated DTB for us at the start of RAM. */ return (void *)CONFIG_SYS_SDRAM_BASE; } + +#if defined(CONFIG_EFI_RNG_PROTOCOL) +#include +#include + +#include + +efi_status_t platform_get_rng_device(struct udevice **dev) +{ + int ret; + efi_status_t status = EFI_DEVICE_ERROR; + struct udevice *bus, *devp; + + for (uclass_first_device(UCLASS_VIRTIO, &bus); bus; + uclass_next_device(&bus)) { + for (device_find_first_child(bus, &devp); devp; + device_find_next_child(&devp)) { + if (device_get_uclass_id(devp) == UCLASS_RNG) { + *dev = devp; + status = EFI_SUCCESS; + break; + } + } + } + + if (status != EFI_SUCCESS) { + debug("No rng device found\n"); + return EFI_DEVICE_ERROR; + } + + if (*dev) { + ret = device_probe(*dev); + if (ret) + return EFI_DEVICE_ERROR; + } else { + debug("Couldn't get child device\n"); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} +#endif /* CONFIG_EFI_RNG_PROTOCOL */ diff --git a/include/efi_rng.h b/include/efi_rng.h new file mode 100644 index 0000000000..35f59678c7 --- /dev/null +++ b/include/efi_rng.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019, Linaro Limited + */ + +#if !defined _EFI_RNG_H_ +#define _EFI_RNG_H_ + +#include +#include + +/* EFI random number generation protocol related GUID definitions */ +#define EFI_RNG_PROTOCOL_GUID \ + EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, \ + 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) + +#define EFI_RNG_ALGORITHM_RAW \ + EFI_GUID(0xe43176d7, 0xb6e8, 0x4827, 0xb7, 0x84, \ + 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61) + +struct efi_rng_protocol { + efi_status_t (EFIAPI *get_info)(struct efi_rng_protocol *protocol, + efi_uintn_t *rng_algorithm_list_size, + efi_guid_t *rng_algorithm_list); + efi_status_t (EFIAPI *get_rng)(struct efi_rng_protocol *protocol, + efi_guid_t *rng_algorithm, + efi_uintn_t rng_value_length, uint8_t *rng_value); +}; + +efi_status_t platform_get_rng_device(struct udevice **dev); + +#endif /* _EFI_RNG_H_ */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index e2cb729303..6727336169 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -121,4 +121,12 @@ config EFI_GRUB_ARM32_WORKAROUND GRUB prior to version 2.04 requires U-Boot to disable caches. This workaround currently is also needed on systems with caches that cannot be managed via CP15. + +config EFI_RNG_PROTOCOL + bool "EFI_RNG_PROTOCOL support" + depends on DM_RNG + help + "Support for EFI_RNG_PROTOCOL implementation. Uses the rng + device on the platform" + endif diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 7db4060286..04dc864851 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o +obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o diff --git a/lib/efi_loader/efi_rng.c b/lib/efi_loader/efi_rng.c new file mode 100644 index 0000000000..47aaa6adca --- /dev/null +++ b/lib/efi_loader/efi_rng.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +__weak efi_status_t platform_get_rng_device(struct udevice **dev) +{ + int ret; + struct udevice *devp; + + ret = uclass_get_device(UCLASS_RNG, 0, &devp); + if (ret) { + debug("Unable to get rng device\n"); + return EFI_DEVICE_ERROR; + } + + *dev = devp; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI rng_getinfo(struct efi_rng_protocol *this, + efi_uintn_t *rng_algorithm_list_size, + efi_guid_t *rng_algorithm_list) +{ + efi_status_t ret = EFI_SUCCESS; + efi_guid_t rng_algo_guid = EFI_RNG_ALGORITHM_RAW; + + EFI_ENTRY("%p, %p, %p", this, rng_algorithm_list_size, + rng_algorithm_list); + + if (!this || !rng_algorithm_list_size) { + ret = EFI_INVALID_PARAMETER; + goto back; + } + + if (!rng_algorithm_list || + *rng_algorithm_list_size < sizeof(*rng_algorithm_list)) { + *rng_algorithm_list_size = sizeof(*rng_algorithm_list); + ret = EFI_BUFFER_TOO_SMALL; + goto back; + } + + /* + * For now, use EFI_RNG_ALGORITHM_RAW as the default + * algorithm. If a new algorithm gets added in the + * future through a Kconfig, rng_algo_guid will be set + * based on that Kconfig option + */ + *rng_algorithm_list_size = sizeof(*rng_algorithm_list); + guidcpy(rng_algorithm_list, &rng_algo_guid); + +back: + return EFI_EXIT(ret); +} + +static efi_status_t EFIAPI getrng(struct efi_rng_protocol *this, + efi_guid_t *rng_algorithm, + efi_uintn_t rng_value_length, + uint8_t *rng_value) +{ + int ret; + efi_status_t status = EFI_SUCCESS; + struct udevice *dev; + const efi_guid_t rng_raw_guid = EFI_RNG_ALGORITHM_RAW; + + EFI_ENTRY("%p, %p, %zu, %p", this, rng_algorithm, rng_value_length, + rng_value); + + if (!this || !rng_value || !rng_value_length) { + status = EFI_INVALID_PARAMETER; + goto back; + } + + if (rng_algorithm) { + EFI_PRINT("RNG algorithm %pUl\n", rng_algorithm); + if (guidcmp(rng_algorithm, &rng_raw_guid)) { + status = EFI_UNSUPPORTED; + goto back; + } + } + + ret = platform_get_rng_device(&dev); + if (ret != EFI_SUCCESS) { + EFI_PRINT("Rng device not found\n"); + status = EFI_UNSUPPORTED; + goto back; + } + + ret = dm_rng_read(dev, rng_value, rng_value_length); + if (ret < 0) { + EFI_PRINT("Rng device read failed\n"); + status = EFI_DEVICE_ERROR; + goto back; + } + +back: + return EFI_EXIT(status); +} + +const struct efi_rng_protocol efi_rng_protocol = { + .get_info = rng_getinfo, + .get_rng = getrng, +};