From 75fe571a4194ac26de7deffb2aa6db494596f58f Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 26 Nov 2019 09:51:05 +0900 Subject: include: pe.h: add signature-related definitions The index (IMAGE_DIRECTORY_ENTRY_SECURITY) in a table points to a region containing authentication information (image's signature) in PE format. WIN_CERTIFICATE structure defines an embedded signature format. Those definitions will be used in my UEFI secure boot patch. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- include/pe.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include') diff --git a/include/pe.h b/include/pe.h index bff3b0aa7a6..086f2b860e9 100644 --- a/include/pe.h +++ b/include/pe.h @@ -155,6 +155,8 @@ typedef struct _IMAGE_SECTION_HEADER { uint32_t Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; +/* Indices for Optional Header Data Directories */ +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 typedef struct _IMAGE_BASE_RELOCATION @@ -252,4 +254,20 @@ typedef struct _IMAGE_RELOCATION #define IMAGE_REL_AMD64_PAIR 0x000F #define IMAGE_REL_AMD64_SSPAN32 0x0010 +/* certificate appended to PE image */ +typedef struct _WIN_CERTIFICATE { + uint32_t dwLength; + uint16_t wRevision; + uint16_t wCertificateType; + uint8_t bCertificate[]; +} WIN_CERTIFICATE, *LPWIN_CERTIFICATE; + +/* Definitions for the contents of the certs data block */ +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 +#define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0 +#define WIN_CERT_TYPE_EFI_GUID 0x0EF1 + +#define WIN_CERT_REVISION_1_0 0x0100 +#define WIN_CERT_REVISION_2_0 0x0200 + #endif /* _PE_H */ -- cgit v1.3.1 From 7a597259d26f84a63350b6a1af5b29445e9d451b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Nov 2019 06:46:09 +0100 Subject: efi_loader: pass address to efi_install_fdt() As part of moving the parsing of command line arguments to do_bootefi() call efi_install_fdt() with the address of the device tree instead of a string. If the address is EFI_FDT_USE_INTERNAL (= 0), the internal device tree is used. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 32 ++++++++++++++++++-------------- include/efi_loader.h | 3 +++ 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index f613cce7e26..2b190a3edda 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -196,40 +196,39 @@ static void *get_config_table(const efi_guid_t *guid) #endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */ /** - * efi_install_fdt() - install fdt passed by a command argument + * efi_install_fdt() - install device tree * - * If fdt_opt is available, the device tree located at that memory address will + * If fdt_addr is available, the device tree located at that memory address will * will be installed as configuration table, otherwise the device tree located * at the address indicated by environment variable fdtcontroladdr will be used. * - * On architectures (x86) using ACPI tables device trees shall not be installed - * as configuration table. + * On architectures using ACPI tables device trees shall not be installed as + * configuration table. * - * @fdt_opt: pointer to argument + * @fdt_addr: address of device tree or EFI_FDT_USE_INTERNAL to use the + * internal device tree as indicated by environment variable + * fdtcontroladdr * Return: status code */ -static efi_status_t efi_install_fdt(const char *fdt_opt) +static efi_status_t efi_install_fdt(uintptr_t fdt_addr) { /* * The EBBR spec requires that we have either an FDT or an ACPI table * but not both. */ #if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) - if (fdt_opt) { + if (fdt_addr) { printf("ERROR: can't have ACPI table and device tree.\n"); return EFI_LOAD_ERROR; } #else - unsigned long fdt_addr; void *fdt; bootm_headers_t img = { 0 }; efi_status_t ret; - if (fdt_opt) { - fdt_addr = simple_strtoul(fdt_opt, NULL, 16); - if (!fdt_addr) - return EFI_INVALID_PARAMETER; - } else { + if (fdt_addr == EFI_FDT_USE_INTERNAL) { + const char *fdt_opt; + /* Look for device tree that is already installed */ if (get_config_table(&efi_guid_fdt)) return EFI_SUCCESS; @@ -556,6 +555,7 @@ static int do_efi_selftest(void) static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { efi_status_t ret; + uintptr_t fdt_addr; if (argc < 2) return CMD_RET_USAGE; @@ -568,7 +568,11 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_FAILURE; } - ret = efi_install_fdt(argc > 2 ? argv[2] : NULL); + if (argc > 2) + fdt_addr = simple_strtoul(argv[2], NULL, 16); + else + fdt_addr = EFI_FDT_USE_INTERNAL; + ret = efi_install_fdt(fdt_addr); if (ret == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; else if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index 16a1b258b17..3a220893298 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -34,6 +34,9 @@ static inline int guidcmp(const void *g1, const void *g2) EFI_GUID(0xbbe4e671, 0x5773, 0x4ea1, \ 0x9a, 0xab, 0x3a, 0x7d, 0xbf, 0x40, 0xc4, 0x82) +/* Use internal device tree when starting UEFI application */ +#define EFI_FDT_USE_INTERNAL 0UL + /* Root node */ extern efi_handle_t efi_root; -- cgit v1.3.1 From f9ceb6ac1443b824e94a9df9ec1dfb2bc742e451 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Dec 2019 20:51:06 +0100 Subject: efi_loader: carve out efi_run_image() Provide public function efi_run_imager() which can be used to run an UEFI image from memory. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 51 ++++++++++++++++++++++++++++++++------------------- include/efi_loader.h | 2 ++ 2 files changed, 34 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index a3e2a051263..15b4ff95159 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -360,11 +360,8 @@ static int do_efibootmgr(void) static int do_bootefi_image(const char *image_opt) { void *image_buf; - struct efi_device_path *device_path, *image_path; - struct efi_device_path *file_path = NULL; unsigned long addr, size; const char *size_str; - efi_handle_t mem_handle = NULL, handle; efi_status_t ret; #ifdef CONFIG_CMD_BOOTEFI_HELLO @@ -382,8 +379,10 @@ static int do_bootefi_image(const char *image_opt) image_buf = map_sysmem(addr, size); memcpy(image_buf, __efi_helloworld_begin, size); - device_path = NULL; - image_path = NULL; + efi_free_pool(bootefi_device_path); + efi_free_pool(bootefi_image_path); + bootefi_device_path = NULL; + bootefi_image_path = NULL; } else #endif { @@ -399,19 +398,37 @@ static int do_bootefi_image(const char *image_opt) return CMD_RET_USAGE; image_buf = map_sysmem(addr, size); - - device_path = bootefi_device_path; - image_path = bootefi_image_path; } + ret = efi_run_image(image_buf, size); + + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +/** + * efi_run_image() - run loaded UEFI image + * + * @source_buffer: memory address of the UEFI image + * @source_size: size of the UEFI image + * Return: status code + */ +efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size) +{ + efi_handle_t mem_handle = NULL, handle; + struct efi_device_path *file_path = NULL; + efi_status_t ret; - if (!device_path && !image_path) { + if (!bootefi_device_path || !bootefi_image_path) { /* * Special case for efi payload not loaded from disk, * such as 'bootefi hello' or for example payload * loaded directly into memory via JTAG, etc: */ file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, - (uintptr_t)image_buf, size); + (uintptr_t)source_buffer, + source_size); /* * Make sure that device for device_path exist * in load_image(). Otherwise, shell and grub will fail. @@ -425,12 +442,12 @@ static int do_bootefi_image(const char *image_opt) if (ret != EFI_SUCCESS) goto out; } else { - assert(device_path && image_path); - file_path = efi_dp_append(device_path, image_path); + file_path = efi_dp_append(bootefi_device_path, + bootefi_image_path); } - ret = EFI_CALL(efi_load_image(false, efi_root, - file_path, image_buf, size, &handle)); + ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer, + source_size, &handle)); if (ret != EFI_SUCCESS) goto out; @@ -441,11 +458,7 @@ out: efi_delete_handle(mem_handle); if (file_path) efi_free_pool(file_path); - - if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; + return ret; } #ifdef CONFIG_CMD_BOOTEFI_SELFTEST diff --git a/include/efi_loader.h b/include/efi_loader.h index 3a220893298..1e1fe52bc0f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -341,6 +341,8 @@ extern struct list_head efi_register_notify_events; /* Initialize efi execution environment */ efi_status_t efi_init_obj_list(void); +/* Run loaded UEFI image */ +efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size); /* Initialize variable services */ efi_status_t efi_init_variables(void); /* Notify ExitBootServices() is called */ -- cgit v1.3.1 From f64f223256f32e86d97ec32eea7dc36d5e9c5fd9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 8 Dec 2019 01:07:01 +0100 Subject: efi_loader: export efi_install_fdt() Use a pointer to addressable memory instead of a "physical" address in the virtual address space of the sandbox to efi_install_fdt(). Export the efi_install_fdt() function. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 24 ++++++++++++++---------- include/efi_loader.h | 4 +++- 2 files changed, 17 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 15b4ff95159..78c8b8dbd16 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -212,24 +212,24 @@ static void *get_config_table(const efi_guid_t *guid) * the environment variable fdtcontroladdr * Return: status code */ -static efi_status_t efi_install_fdt(uintptr_t fdt_addr) +efi_status_t efi_install_fdt(void *fdt) { /* * The EBBR spec requires that we have either an FDT or an ACPI table * but not both. */ #if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) - if (fdt_addr) { + if (fdt) { printf("ERROR: can't have ACPI table and device tree.\n"); return EFI_LOAD_ERROR; } #else - void *fdt; bootm_headers_t img = { 0 }; efi_status_t ret; - if (fdt_addr == EFI_FDT_USE_INTERNAL) { + if (fdt == EFI_FDT_USE_INTERNAL) { const char *fdt_opt; + uintptr_t fdt_addr; /* Look for device tree that is already installed */ if (get_config_table(&efi_guid_fdt)) @@ -249,10 +249,10 @@ static efi_status_t efi_install_fdt(uintptr_t fdt_addr) printf("ERROR: invalid $fdt_addr or $fdtcontroladdr\n"); return EFI_LOAD_ERROR; } + fdt = map_sysmem(fdt_addr, 0); } /* Install device tree */ - fdt = map_sysmem(fdt_addr, 0); if (fdt_check_header(fdt)) { printf("ERROR: invalid device tree\n"); return EFI_LOAD_ERROR; @@ -574,7 +574,7 @@ static int do_efi_selftest(void) static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { efi_status_t ret; - uintptr_t fdt_addr; + void *fdt; if (argc < 2) return CMD_RET_USAGE; @@ -587,11 +587,15 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_FAILURE; } - if (argc > 2) + if (argc > 2) { + uintptr_t fdt_addr; + fdt_addr = simple_strtoul(argv[2], NULL, 16); - else - fdt_addr = EFI_FDT_USE_INTERNAL; - ret = efi_install_fdt(fdt_addr); + fdt = map_sysmem(fdt_addr, 0); + } else { + fdt = EFI_FDT_USE_INTERNAL; + } + ret = efi_install_fdt(fdt); if (ret == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; else if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index 1e1fe52bc0f..4d401f69d75 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -35,7 +35,7 @@ static inline int guidcmp(const void *g1, const void *g2) 0x9a, 0xab, 0x3a, 0x7d, 0xbf, 0x40, 0xc4, 0x82) /* Use internal device tree when starting UEFI application */ -#define EFI_FDT_USE_INTERNAL 0UL +#define EFI_FDT_USE_INTERNAL NULL /* Root node */ extern efi_handle_t efi_root; @@ -341,6 +341,8 @@ extern struct list_head efi_register_notify_events; /* Initialize efi execution environment */ efi_status_t efi_init_obj_list(void); +/* Install device tree */ +efi_status_t efi_install_fdt(void *fdt); /* Run loaded UEFI image */ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size); /* Initialize variable services */ -- cgit v1.3.1 From 9b8d264b5af801a56e06aceab34dc74cb66121b1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 24 Dec 2019 08:11:01 +0100 Subject: part: efi: comment for GPT_HEADER_SIGNATURE_UBOOT Add a comment indicating that the value of GPT_HEADER_SIGNATURE_UBOOT equals the ASCII string 'EFI PART'. Signed-off-by: Heinrich Schuchardt --- include/part_efi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/part_efi.h b/include/part_efi.h index eb5797af745..1929e4400f1 100644 --- a/include/part_efi.h +++ b/include/part_efi.h @@ -24,7 +24,7 @@ #define EFI_PMBR_OSTYPE_EFI 0xEF #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE -#define GPT_HEADER_SIGNATURE_UBOOT 0x5452415020494645ULL +#define GPT_HEADER_SIGNATURE_UBOOT 0x5452415020494645ULL // 'EFI PART' #define GPT_HEADER_CHROMEOS_IGNORE 0x454d45524f4e4749ULL // 'IGNOREME' #define GPT_HEADER_REVISION_V1 0x00010000 -- cgit v1.3.1 From 61e42d9465ef36857693cc3db615438241a06bf6 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Sun, 29 Dec 2019 00:01:04 +0530 Subject: efi_loader: Add guidcpy function Add guidcpy function to copy the source guid to the destination guid. Use this function instead of memcpy for copying to the destination guid. Signed-off-by: Sughosh Ganu Use void * instead of efi_guid_t * for arguments to allow copying unaligned GUIDs. The GUIDs of configuration tables are __packed. Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 5 +++++ lib/efi_loader/efi_boottime.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 4d401f69d75..e1c9b1fd6a9 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -17,6 +17,11 @@ static inline int guidcmp(const void *g1, const void *g2) return memcmp(g1, g2, sizeof(efi_guid_t)); } +static inline void *guidcpy(void *dst, const void *src) +{ + return memcpy(dst, src, sizeof(efi_guid_t)); +} + /* No need for efi loader support in SPL */ #if CONFIG_IS_ENABLED(EFI_LOADER) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 88a7604bbf3..3103a50158a 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1401,7 +1401,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify( } item->event = event; - memcpy(&item->protocol, protocol, sizeof(efi_guid_t)); + guidcpy(&item->protocol, protocol); INIT_LIST_HEAD(&item->handles); list_add_tail(&item->link, &efi_register_notify_events); @@ -1632,7 +1632,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, return EFI_OUT_OF_RESOURCES; /* Add a new entry */ - memcpy(&systab.tables[i].guid, guid, sizeof(*guid)); + guidcpy(&systab.tables[i].guid, guid); systab.tables[i].table = table; systab.nr_tables = i + 1; -- cgit v1.3.1 From 7b31efc54c3fba33d1305a0f9b730472bb0f63eb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 3 Jan 2020 22:47:19 +0100 Subject: efi_loader: define all known warning status codes Of all warning status codes up to now only EFI_WARN_DELETE_FAILURE is defined. The patch adds the missing definitions for later usage. Signed-off-by: Heinrich Schuchardt --- include/efi.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/efi.h b/include/efi.h index 5f415a99cc9..e12697a5d5b 100644 --- a/include/efi.h +++ b/include/efi.h @@ -91,7 +91,13 @@ typedef struct { #define EFI_IP_ADDRESS_CONFLICT (EFI_ERROR_MASK | 34) #define EFI_HTTP_ERROR (EFI_ERROR_MASK | 35) -#define EFI_WARN_DELETE_FAILURE 2 +#define EFI_WARN_UNKNOWN_GLYPH 1 +#define EFI_WARN_DELETE_FAILURE 2 +#define EFI_WARN_WRITE_FAILURE 3 +#define EFI_WARN_BUFFER_TOO_SMALL 4 +#define EFI_WARN_STALE_DATA 5 +#define EFI_WARN_FILE_SYSTEM 6 +#define EFI_WARN_RESET_REQUIRED 7 typedef unsigned long efi_status_t; typedef u64 efi_physical_addr_t; -- cgit v1.3.1 From a031b03f6448fafba46d08f7a88fa33690d50858 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 24 Dec 2019 18:05:38 +0200 Subject: image: Add IH_OS_EFI for EFI chain-load boot Add a new OS type to be used for chain-loading an EFI compatible firmware or boot loader like GRUB2, possibly in a verified boot scenario. Bellow is sample ITS file that generates a FIT image supporting secure boot. Please note the presence of 'os = "efi";' line, which identifies the currently introduced OS type: / { #address-cells = <1>; images { efi-grub { description = "GRUB EFI"; data = /incbin/("bootarm.efi"); type = "kernel_noload"; arch = "arm"; os = "efi"; compression = "none"; load = <0x0>; entry = <0x0>; hash-1 { algo = "sha256"; }; }; }; configurations { default = "config-grub"; config-grub { kernel = "efi-grub"; signature-1 { algo = "sha256,rsa2048"; sign-images = "kernel"; }; }; }; }; Signed-off-by: Cristian Ciocaltea Reviewed-by: Heinrich Schuchardt --- common/image-fit.c | 3 ++- common/image.c | 1 + include/image.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/common/image-fit.c b/common/image-fit.c index c52f9451208..231612ff5f0 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -1926,7 +1926,8 @@ int fit_image_load(bootm_headers_t *images, ulong addr, image_type == IH_TYPE_FPGA || fit_image_check_os(fit, noffset, IH_OS_LINUX) || fit_image_check_os(fit, noffset, IH_OS_U_BOOT) || - fit_image_check_os(fit, noffset, IH_OS_OPENRTOS); + fit_image_check_os(fit, noffset, IH_OS_OPENRTOS) || + fit_image_check_os(fit, noffset, IH_OS_EFI); /* * If either of the checks fail, we should report an error, but diff --git a/common/image.c b/common/image.c index eb626dcac92..75d5dd944ff 100644 --- a/common/image.c +++ b/common/image.c @@ -137,6 +137,7 @@ static const table_entry_t uimage_os[] = { { IH_OS_OPENRTOS, "openrtos", "OpenRTOS", }, #endif { IH_OS_OPENSBI, "opensbi", "RISC-V OpenSBI", }, + { IH_OS_EFI, "efi", "EFI Firmware" }, { -1, "", "", }, }; diff --git a/include/image.h b/include/image.h index f4d2aaf53e8..4a280b78e74 100644 --- a/include/image.h +++ b/include/image.h @@ -157,6 +157,7 @@ enum { IH_OS_ARM_TRUSTED_FIRMWARE, /* ARM Trusted Firmware */ IH_OS_TEE, /* Trusted Execution Environment */ IH_OS_OPENSBI, /* RISC-V OpenSBI */ + IH_OS_EFI, /* EFI Firmware (e.g. GRUB2) */ IH_OS_COUNT, }; -- cgit v1.3.1 From a2487684003b0bc380955e1a38cdd71da3ca4366 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Sat, 28 Dec 2019 23:58:27 +0530 Subject: dm: rng: Add random number generator(rng) uclass Add a uclass for reading a random number seed from a random number generator device. Signed-off-by: Sughosh Ganu Reviewed-by: Patrice Chotard Reviewed-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/rng/Kconfig | 7 +++++++ drivers/rng/Makefile | 6 ++++++ drivers/rng/rng-uclass.c | 23 +++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/rng.h | 33 +++++++++++++++++++++++++++++++++ 7 files changed, 73 insertions(+) create mode 100644 drivers/rng/Kconfig create mode 100644 drivers/rng/Makefile create mode 100644 drivers/rng/rng-uclass.c create mode 100644 include/rng.h (limited to 'include') diff --git a/drivers/Kconfig b/drivers/Kconfig index 9d99ce02261..e34a22708c3 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -90,6 +90,8 @@ source "drivers/remoteproc/Kconfig" source "drivers/reset/Kconfig" +source "drivers/rng/Kconfig" + source "drivers/rtc/Kconfig" source "drivers/scsi/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index cb8c215e767..8eec4e8176c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -116,4 +116,5 @@ obj-$(CONFIG_W1_EEPROM) += w1-eeprom/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/ +obj-$(CONFIG_DM_RNG) += rng/ endif diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig new file mode 100644 index 00000000000..dd44cc0242a --- /dev/null +++ b/drivers/rng/Kconfig @@ -0,0 +1,7 @@ +config DM_RNG + bool "Driver support for Random Number Generator devices" + depends on DM + help + Enable driver model for random number generator(rng) devices. + This interface is used to initialise the rng device and to + read the random seed from the device. diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile new file mode 100644 index 00000000000..311705b6e67 --- /dev/null +++ b/drivers/rng/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2019, Linaro Limited +# + +obj-$(CONFIG_DM_RNG) += rng-uclass.o diff --git a/drivers/rng/rng-uclass.c b/drivers/rng/rng-uclass.c new file mode 100644 index 00000000000..b6af3b8606a --- /dev/null +++ b/drivers/rng/rng-uclass.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include + +int dm_rng_read(struct udevice *dev, void *buffer, size_t size) +{ + const struct dm_rng_ops *ops = device_get_ops(dev); + + if (!ops->read) + return -ENOSYS; + + return ops->read(dev, buffer, size); +} + +UCLASS_DRIVER(rng) = { + .name = "rng", + .id = UCLASS_RNG, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index c1bab17ad11..67f5d673cb8 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -88,6 +88,7 @@ enum uclass_id { UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */ UCLASS_RESET, /* Reset controller device */ + UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ diff --git a/include/rng.h b/include/rng.h new file mode 100644 index 00000000000..d2c0f9af62c --- /dev/null +++ b/include/rng.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019, Linaro Limited + */ + +#if !defined _RNG_H_ +#define _RNG_H_ + +struct udevice; + +/** + * dm_rng_read() - read a random number seed from the rng device + * @buffer: input buffer to put the read random seed into + * @size: number of bytes of random seed read + * + * Return: 0 if OK, -ve on error + */ +int dm_rng_read(struct udevice *dev, void *buffer, size_t size); + +/* struct dm_rng_ops - Operations for the hwrng uclass */ +struct dm_rng_ops { + /** + * @read() - read a random number seed + * + * @data: input buffer to read the random seed + * @max: total number of bytes to read + * + * Return: 0 if OK, -ve on error + */ + int (*read)(struct udevice *dev, void *data, size_t max); +}; + +#endif /* _RNG_H_ */ -- cgit v1.3.1 From 03018ea8fd09b3dffb63830e5c0e445de42f572a Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Sun, 29 Dec 2019 15:30:14 +0530 Subject: virtio: rng: Add a random number generator(rng) driver Add a driver for the virtio-rng device on the qemu platform. The device uses pci as a transport medium. The driver can be enabled with the following configs CONFIG_VIRTIO CONFIG_DM_RNG CONFIG_VIRTIO_PCI CONFIG_VIRTIO_RNG Signed-off-by: Sughosh Ganu --- drivers/virtio/Kconfig | 6 +++ drivers/virtio/Makefile | 1 + drivers/virtio/virtio-uclass.c | 1 + drivers/virtio/virtio_rng.c | 88 ++++++++++++++++++++++++++++++++++++++++++ include/virtio.h | 4 +- 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 drivers/virtio/virtio_rng.c (limited to 'include') diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index a9d5fd07b77..2e3dd3bad07 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -59,4 +59,10 @@ config VIRTIO_BLK This is the virtual block driver for virtio. It can be used with QEMU based targets. +config VIRTIO_RNG + bool "virtio rng driver" + depends on VIRTIO + help + This is the virtual random number generator driver. It can be used + with Qemu based targets. endmenu diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 4579044ae39..dc8880937a8 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_VIRTIO_PCI) += virtio_pci_legacy.o virtio_pci_modern.o obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o obj-$(CONFIG_VIRTIO_NET) += virtio_net.o obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o +obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index 34397d7dbb1..436faa46eec 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -24,6 +24,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = { [VIRTIO_ID_NET] = VIRTIO_NET_DRV_NAME, [VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME, + [VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME, }; int virtio_get_config(struct udevice *vdev, unsigned int offset, diff --git a/drivers/virtio/virtio_rng.c b/drivers/virtio/virtio_rng.c new file mode 100644 index 00000000000..4edffa6f31a --- /dev/null +++ b/drivers/virtio/virtio_rng.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 16UL + +struct virtio_rng_priv { + struct virtqueue *rng_vq; +}; + +static int virtio_rng_read(struct udevice *dev, void *data, size_t len) +{ + int ret; + unsigned int rsize; + unsigned char buf[BUFFER_SIZE] __aligned(4); + unsigned char *ptr = data; + struct virtio_sg sg; + struct virtio_sg *sgs[1]; + struct virtio_rng_priv *priv = dev_get_priv(dev); + + while (len) { + sg.addr = buf; + sg.length = min(len, sizeof(buf)); + sgs[0] = &sg; + + ret = virtqueue_add(priv->rng_vq, sgs, 0, 1); + if (ret) + return ret; + + virtqueue_kick(priv->rng_vq); + + while (!virtqueue_get_buf(priv->rng_vq, &rsize)) + ; + + memcpy(ptr, buf, rsize); + len -= rsize; + ptr += rsize; + } + + return 0; +} + +static int virtio_rng_bind(struct udevice *dev) +{ + struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent); + + /* Indicate what driver features we support */ + virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0); + + return 0; +} + +static int virtio_rng_probe(struct udevice *dev) +{ + struct virtio_rng_priv *priv = dev_get_priv(dev); + int ret; + + ret = virtio_find_vqs(dev, 1, &priv->rng_vq); + if (ret < 0) { + debug("%s: virtio_find_vqs failed\n", __func__); + return ret; + } + + return 0; +} + +static const struct dm_rng_ops virtio_rng_ops = { + .read = virtio_rng_read, +}; + +U_BOOT_DRIVER(virtio_rng) = { + .name = VIRTIO_RNG_DRV_NAME, + .id = UCLASS_RNG, + .bind = virtio_rng_bind, + .probe = virtio_rng_probe, + .remove = virtio_reset, + .ops = &virtio_rng_ops, + .priv_auto_alloc_size = sizeof(struct virtio_rng_priv), + .flags = DM_FLAG_ACTIVE_DMA, +}; diff --git a/include/virtio.h b/include/virtio.h index 654fdf154b6..561dcc34baf 100644 --- a/include/virtio.h +++ b/include/virtio.h @@ -22,10 +22,12 @@ #define VIRTIO_ID_NET 1 /* virtio net */ #define VIRTIO_ID_BLOCK 2 /* virtio block */ -#define VIRTIO_ID_MAX_NUM 3 +#define VIRTIO_ID_RNG 4 /* virtio rng */ +#define VIRTIO_ID_MAX_NUM 5 #define VIRTIO_NET_DRV_NAME "virtio-net" #define VIRTIO_BLK_DRV_NAME "virtio-blk" +#define VIRTIO_RNG_DRV_NAME "virtio-rng" /* Status byte for guest to report progress, and synchronize features */ -- cgit v1.3.1 From f552fa496c9e738afa069dd33578558fe4eb41ee Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Sun, 29 Dec 2019 00:01:05 +0530 Subject: efi: qemu: arm64: Add efi_rng_protocol implementation for the platform Add support for the EFI_RNG_PROTOCOL routines for the qemu arm64 platform. EFI_RNG_PROTOCOL is an uefi boottime service which is invoked by the efi stub in the kernel for getting random seed for kaslr. The routines are platform specific, and use the virtio-rng device on the platform to get random data. The feature can be enabled through the following config CONFIG_EFI_RNG_PROTOCOL Signed-off-by: Sughosh Ganu Changed SPDX header to use /* instead of //. Reviewed-by: Heinrich Schuchardt --- board/emulation/qemu-arm/qemu-arm.c | 42 ++++++++++++++ include/efi_rng.h | 32 +++++++++++ lib/efi_loader/Kconfig | 8 +++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_rng.c | 112 ++++++++++++++++++++++++++++++++++++ 5 files changed, 195 insertions(+) create mode 100644 include/efi_rng.h create mode 100644 lib/efi_loader/efi_rng.c (limited to 'include') diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c index e1f4709c4cf..4e187330014 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 00000000000..35f59678c7a --- /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 e2cb7293039..6727336169c 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 7db40602861..04dc8648512 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 00000000000..47aaa6adca8 --- /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, +}; -- cgit v1.3.1 From 33c37d9784168ac75be91e890329712d9a849539 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Sun, 29 Dec 2019 00:01:06 +0530 Subject: efi_rng_protocol: Install the efi_rng_protocol on the root node Install the EFI_RNG_PROTOCOL implementation for it's subsequent use by the kernel for features like kaslr. Signed-off-by: Sughosh Ganu Reviewed-by: Heinrich Schuchardt --- include/efi_loader.h | 4 ++++ lib/efi_loader/efi_rng.c | 2 ++ lib/efi_loader/efi_root_node.c | 4 ++++ 3 files changed, 10 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index e1c9b1fd6a9..d4c59b54c48 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -133,6 +133,7 @@ extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; extern const struct efi_hii_config_access_protocol efi_hii_config_access; extern const struct efi_hii_database_protocol efi_hii_database; extern const struct efi_hii_string_protocol efi_hii_string; +extern const struct efi_rng_protocol efi_rng_protocol; uint16_t *efi_dp_str(struct efi_device_path *dp); @@ -178,6 +179,9 @@ extern const efi_guid_t efi_guid_hii_config_access_protocol; extern const efi_guid_t efi_guid_hii_database_protocol; extern const efi_guid_t efi_guid_hii_string_protocol; +/* GUID of RNG protocol */ +extern const efi_guid_t efi_guid_rng_protocol; + extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; diff --git a/lib/efi_loader/efi_rng.c b/lib/efi_loader/efi_rng.c index 47aaa6adca8..432c9862046 100644 --- a/lib/efi_loader/efi_rng.c +++ b/lib/efi_loader/efi_rng.c @@ -11,6 +11,8 @@ DECLARE_GLOBAL_DATA_PTR; +const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID; + __weak efi_status_t platform_get_rng_device(struct udevice **dev) { int ret; diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index f68b0fdc610..76d18fb1a4a 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -80,6 +80,10 @@ efi_status_t efi_root_node_register(void) /* HII configuration routing protocol */ &efi_guid_hii_config_routing_protocol, (void *)&efi_hii_config_routing, +#endif +#if CONFIG_IS_ENABLED(EFI_RNG_PROTOCOL) + &efi_guid_rng_protocol, + (void *)&efi_rng_protocol, #endif NULL)); efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE; -- cgit v1.3.1