aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sandbox/dts/test.dts4
-rw-r--r--board/emulation/qemu-arm/qemu-arm.c42
-rw-r--r--cmd/Kconfig14
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/bootefi.c135
-rw-r--r--cmd/efidebug.c78
-rw-r--r--cmd/rng.c56
-rw-r--r--common/bootm_os.c56
-rw-r--r--common/image-fit.c3
-rw-r--r--common/image.c1
-rw-r--r--configs/qemu_arm64_defconfig5
-rw-r--r--configs/qemu_arm_defconfig5
-rw-r--r--configs/sandbox64_defconfig2
-rw-r--r--configs/sandbox_defconfig2
-rw-r--r--configs/stm32mp15_basic_defconfig2
-rw-r--r--configs/stm32mp15_optee_defconfig2
-rw-r--r--configs/stm32mp15_trusted_defconfig2
-rw-r--r--doc/uImage.FIT/uefi.its67
-rw-r--r--doc/uefi/uefi.rst34
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/clk/clk_stm32mp1.c1
-rw-r--r--drivers/rng/Kconfig22
-rw-r--r--drivers/rng/Makefile8
-rw-r--r--drivers/rng/rng-uclass.c23
-rw-r--r--drivers/rng/sandbox_rng.c56
-rw-r--r--drivers/rng/stm32mp1_rng.c160
-rw-r--r--drivers/virtio/Kconfig6
-rw-r--r--drivers/virtio/Makefile1
-rw-r--r--drivers/virtio/virtio-uclass.c1
-rw-r--r--drivers/virtio/virtio_rng.c88
-rw-r--r--include/dm/uclass-id.h1
-rw-r--r--include/efi.h8
-rw-r--r--include/efi_loader.h16
-rw-r--r--include/efi_rng.h32
-rw-r--r--include/image.h1
-rw-r--r--include/part_efi.h2
-rw-r--r--include/pe.h18
-rw-r--r--include/rng.h33
-rw-r--r--include/virtio.h4
-rw-r--r--lib/efi_loader/.gitignore1
-rw-r--r--lib/efi_loader/Kconfig9
-rw-r--r--lib/efi_loader/Makefile1
-rw-r--r--lib/efi_loader/efi_boottime.c4
-rw-r--r--lib/efi_loader/efi_console.c16
-rw-r--r--lib/efi_loader/efi_file.c11
-rw-r--r--lib/efi_loader/efi_freestanding.c32
-rw-r--r--lib/efi_loader/efi_rng.c114
-rw-r--r--lib/efi_loader/efi_root_node.c4
-rw-r--r--lib/efi_selftest/.gitignore3
-rw-r--r--lib/efi_selftest/Makefile1
-rw-r--r--lib/efi_selftest/efi_selftest_rng.c117
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/rng.c26
-rw-r--r--test/py/conftest.py2
-rw-r--r--test/py/tests/test_efi_fit.py458
-rw-r--r--test/py/tests/test_efi_loader.py7
57 files changed, 1719 insertions, 83 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 57513a4..4ea8fea 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -630,6 +630,10 @@
reset-names = "other", "test";
};
+ rng {
+ compatible = "sandbox,sandbox-rng";
+ };
+
rproc_1: rproc@1 {
compatible = "sandbox,test-processor";
remoteproc-name = "remoteproc-test-dev1";
diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c
index e1f4709..4e18733 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 <efi_loader.h>
+#include <efi_rng.h>
+
+#include <dm/device-internal.h>
+
+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/cmd/Kconfig b/cmd/Kconfig
index 5f2562b..26c6551 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -259,6 +259,13 @@ config CMD_BOOTM
help
Boot an application image from the memory.
+config BOOTM_EFI
+ bool "Support booting UEFI FIT images"
+ depends on CMD_BOOTEFI && CMD_BOOTM && FIT
+ default y
+ help
+ Support booting UEFI FIT images via the bootm command.
+
config CMD_BOOTZ
bool "bootz"
help
@@ -1666,6 +1673,13 @@ config CMD_GETTIME
milliseconds. See also the 'bootstage' command which provides more
flexibility for boot timing.
+config CMD_RNG
+ bool "rng command"
+ depends on DM_RNG
+ select HEXDUMP
+ help
+ Print bytes from the hardware random number generator.
+
# TODO: rename to CMD_SLEEP
config CMD_MISC
bool "sleep"
diff --git a/cmd/Makefile b/cmd/Makefile
index 12e898d..8df39f3 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_CMD_READ) += read.o
obj-$(CONFIG_CMD_REGINFO) += reginfo.o
obj-$(CONFIG_CMD_REISER) += reiser.o
obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
+obj-$(CONFIG_CMD_RNG) += rng.o
obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o
obj-$(CONFIG_SANDBOX) += host.o
obj-$(CONFIG_CMD_SATA) += sata.o
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index f613cce..56bdff3 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -28,11 +28,13 @@ static struct efi_device_path *bootefi_device_path;
/**
* Set the load options of an image from an environment variable.
*
- * @handle: the image handle
- * @env_var: name of the environment variable
- * Return: status code
+ * @handle: the image handle
+ * @env_var: name of the environment variable
+ * @load_options: pointer to load options (output)
+ * Return: status code
*/
-static efi_status_t set_load_options(efi_handle_t handle, const char *env_var)
+static efi_status_t set_load_options(efi_handle_t handle, const char *env_var,
+ u16 **load_options)
{
struct efi_loaded_image *loaded_image_info;
size_t size;
@@ -40,6 +42,7 @@ static efi_status_t set_load_options(efi_handle_t handle, const char *env_var)
u16 *pos;
efi_status_t ret;
+ *load_options = NULL;
ret = EFI_CALL(systab.boottime->open_protocol(
handle,
&efi_guid_loaded_image,
@@ -64,6 +67,7 @@ static efi_status_t set_load_options(efi_handle_t handle, const char *env_var)
return EFI_OUT_OF_RESOURCES;
}
pos = loaded_image_info->load_options;
+ *load_options = pos;
utf8_utf16_strcpy(&pos, env);
loaded_image_info->load_options_size = size * 2;
@@ -196,58 +200,63 @@ 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.
+ * at the address indicated by environment variable fdt_addr or as fallback
+ * 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
+ * the hardware device tree as indicated by environment variable
+ * fdt_addr or as fallback the internal device tree as indicated by
+ * the environment variable fdtcontroladdr
* Return: status code
*/
-static efi_status_t efi_install_fdt(const char *fdt_opt)
+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_opt) {
+ if (fdt) {
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 == 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))
return EFI_SUCCESS;
- /* Use our own device tree as default */
- fdt_opt = env_get("fdtcontroladdr");
+ /* Check if there is a hardware device tree */
+ fdt_opt = env_get("fdt_addr");
+ /* Use our own device tree as fallback */
if (!fdt_opt) {
- printf("ERROR: need device tree\n");
- return EFI_NOT_FOUND;
+ fdt_opt = env_get("fdtcontroladdr");
+ if (!fdt_opt) {
+ printf("ERROR: need device tree\n");
+ return EFI_NOT_FOUND;
+ }
}
fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
if (!fdt_addr) {
- printf("ERROR: invalid $fdtcontroladdr\n");
+ 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;
@@ -293,9 +302,10 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle)
efi_status_t ret;
efi_uintn_t exit_data_size = 0;
u16 *exit_data = NULL;
+ u16 *load_options;
/* Transfer environment variable as load options */
- ret = set_load_options(handle, "bootargs");
+ ret = set_load_options(handle, "bootargs", &load_options);
if (ret != EFI_SUCCESS)
return ret;
@@ -309,12 +319,7 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle)
efi_restore_gd();
- /*
- * FIXME: Who is responsible for
- * free(loaded_image_info->load_options);
- * Once efi_exit() is implemented correctly,
- * handle itself doesn't exist here.
- */
+ free(load_options);
return ret;
}
@@ -355,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
@@ -377,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
{
@@ -394,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;
+}
- if (!device_path && !image_path) {
+/**
+ * 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 (!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.
@@ -420,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;
@@ -436,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
@@ -451,6 +469,7 @@ static efi_status_t bootefi_run_prepare(const char *load_options_path,
struct efi_loaded_image **loaded_image_infop)
{
efi_status_t ret;
+ u16 *load_options;
ret = efi_setup_loaded_image(device_path, image_path, image_objp,
loaded_image_infop);
@@ -458,7 +477,8 @@ static efi_status_t bootefi_run_prepare(const char *load_options_path,
return ret;
/* Transfer environment variable as load options */
- return set_load_options((efi_handle_t)*image_objp, load_options_path);
+ return set_load_options((efi_handle_t)*image_objp, load_options_path,
+ &load_options);
}
/**
@@ -556,6 +576,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;
+ void *fdt;
if (argc < 2)
return CMD_RET_USAGE;
@@ -568,7 +589,15 @@ 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) {
+ uintptr_t fdt_addr;
+
+ fdt_addr = simple_strtoul(argv[2], NULL, 16);
+ 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/cmd/efidebug.c b/cmd/efidebug.c
index 1fff439..576e95b3 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -251,27 +251,43 @@ static const struct {
"PXE Base Code",
EFI_PXE_BASE_CODE_PROTOCOL_GUID,
},
+ /* Configuration table GUIDs */
+ {
+ "ACPI table",
+ EFI_ACPI_TABLE_GUID,
+ },
+ {
+ "device tree",
+ EFI_FDT_GUID,
+ },
+ {
+ "SMBIOS table",
+ SMBIOS_TABLE_GUID,
+ },
};
/**
- * get_guid_text - get string of protocol guid
- * @guid: Protocol guid
- * Return: String
+ * get_guid_text - get string of GUID
+ *
+ * Return description of GUID.
*
- * Return string for display to represent the protocol.
+ * @guid: GUID
+ * Return: description of GUID or NULL
*/
-static const char *get_guid_text(const efi_guid_t *guid)
+static const char *get_guid_text(const void *guid)
{
int i;
- for (i = 0; i < ARRAY_SIZE(guid_list); i++)
+ for (i = 0; i < ARRAY_SIZE(guid_list); i++) {
+ /*
+ * As guidcmp uses memcmp() we can safely accept unaligned
+ * GUIDs.
+ */
if (!guidcmp(&guid_list[i].guid, guid))
- break;
+ return guid_list[i].text;
+ }
- if (i != ARRAY_SIZE(guid_list))
- return guid_list[i].text;
- else
- return NULL;
+ return NULL;
}
/**
@@ -478,6 +494,34 @@ static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
}
/**
+ * do_efi_show_tables() - show UEFI configuration tables
+ *
+ * @cmdtp: Command table
+ * @flag: Command flag
+ * @argc: Number of arguments
+ * @argv: Argument array
+ * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "tables" sub-command.
+ * Show UEFI configuration tables.
+ */
+static int do_efi_show_tables(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ efi_uintn_t i;
+ const char *guid_str;
+
+ for (i = 0; i < systab.nr_tables; ++i) {
+ guid_str = get_guid_text(&systab.tables[i].guid);
+ if (!guid_str)
+ guid_str = "";
+ printf("%pUl %s\n", &systab.tables[i].guid, guid_str);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+/**
* do_efi_boot_add() - set UEFI load option
*
* @cmdtp: Command table
@@ -1044,6 +1088,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = {
"", ""),
U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
"", ""),
+ U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables,
+ "", ""),
};
/**
@@ -1103,15 +1149,17 @@ static char efidebug_help_text[] =
" - set/show UEFI boot order\n"
"\n"
"efidebug devices\n"
- " - show uefi devices\n"
+ " - show UEFI devices\n"
"efidebug drivers\n"
- " - show uefi drivers\n"
+ " - show UEFI drivers\n"
"efidebug dh\n"
- " - show uefi handles\n"
+ " - show UEFI handles\n"
"efidebug images\n"
" - show loaded images\n"
"efidebug memmap\n"
- " - show uefi memory map\n";
+ " - show UEFI memory map\n"
+ "efidebug tables\n"
+ " - show UEFI configuration tables\n";
#endif
U_BOOT_CMD(
diff --git a/cmd/rng.c b/cmd/rng.c
new file mode 100644
index 0000000..36ca7a1
--- /dev/null
+++ b/cmd/rng.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * The 'rng' command prints bytes from the hardware random number generator.
+ *
+ * Copyright (c) 2019, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <hexdump.h>
+#include <rng.h>
+
+static int do_rng(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ size_t n = 0x40;
+ struct udevice *dev;
+ void *buf;
+ int ret = CMD_RET_SUCCESS;
+
+ if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) {
+ printf("No RNG device\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (argc >= 2)
+ n = simple_strtoul(argv[1], NULL, 16);
+
+ buf = malloc(n);
+ if (!buf) {
+ printf("Out of memory\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (dm_rng_read(dev, buf, n)) {
+ printf("Reading RNG failed\n");
+ ret = CMD_RET_FAILURE;
+ } else {
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, n);
+ }
+
+ free(buf);
+
+ return ret;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char rng_help_text[] =
+ "[n]\n"
+ " - print n random bytes\n";
+#endif
+
+U_BOOT_CMD(
+ rng, 2, 0, do_rng,
+ "print bytes from the hardware random number generator",
+ rng_help_text
+);
diff --git a/common/bootm_os.c b/common/bootm_os.c
index d89ddc3..1d58462 100644
--- a/common/bootm_os.c
+++ b/common/bootm_os.c
@@ -7,10 +7,12 @@
#include <common.h>
#include <bootm.h>
#include <cpu_func.h>
+#include <efi_loader.h>
#include <env.h>
#include <fdt_support.h>
#include <linux/libfdt.h>
#include <malloc.h>
+#include <mapmem.h>
#include <vxworks.h>
#include <tee/optee.h>
@@ -498,6 +500,57 @@ static int do_bootm_tee(int flag, int argc, char * const argv[],
}
#endif
+#ifdef CONFIG_BOOTM_EFI
+static int do_bootm_efi(int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ int ret;
+ efi_status_t efi_ret;
+ void *image_buf;
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+ /* Locate FDT, if provided */
+ ret = bootm_find_images(flag, argc, argv);
+ if (ret)
+ return ret;
+
+ /* Initialize EFI drivers */
+ efi_ret = efi_init_obj_list();
+ if (efi_ret != EFI_SUCCESS) {
+ printf("## Failed to initialize UEFI sub-system: r = %lu\n",
+ efi_ret & ~EFI_ERROR_MASK);
+ return 1;
+ }
+
+ /* Install device tree */
+ efi_ret = efi_install_fdt(images->ft_len
+ ? images->ft_addr : EFI_FDT_USE_INTERNAL);
+ if (efi_ret != EFI_SUCCESS) {
+ printf("## Failed to install device tree: r = %lu\n",
+ efi_ret & ~EFI_ERROR_MASK);
+ return 1;
+ }
+
+ /* Run EFI image */
+ printf("## Transferring control to EFI (at address %08lx) ...\n",
+ images->ep);
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ image_buf = map_sysmem(images->ep, images->os.image_len);
+
+ efi_ret = efi_run_image(image_buf, images->os.image_len);
+ if (efi_ret != EFI_SUCCESS) {
+ printf("## Failed to run EFI image: r = %lu\n",
+ efi_ret & ~EFI_ERROR_MASK);
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
static boot_os_fn *boot_os[] = {
[IH_OS_U_BOOT] = do_bootm_standalone,
#ifdef CONFIG_BOOTM_LINUX
@@ -534,6 +587,9 @@ static boot_os_fn *boot_os[] = {
#ifdef CONFIG_BOOTM_OPTEE
[IH_OS_TEE] = do_bootm_tee,
#endif
+#ifdef CONFIG_BOOTM_EFI
+ [IH_OS_EFI] = do_bootm_efi,
+#endif
};
/* Allow for arch specific config before we boot */
diff --git a/common/image-fit.c b/common/image-fit.c
index c52f945..231612f 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 eb626dc..75d5dd9 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/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig
index b7c3207..50d0aa5 100644
--- a/configs/qemu_arm64_defconfig
+++ b/configs/qemu_arm64_defconfig
@@ -6,6 +6,11 @@ CONFIG_NR_DRAM_BANKS=1
CONFIG_ENV_SECT_SIZE=0x40000
CONFIG_AHCI=y
CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_BEST_MATCH=y
+CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_USE_PREBOOT=y
CONFIG_PREBOOT="pci enum"
# CONFIG_DISPLAY_CPUINFO is not set
diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig
index 521c679..ff97d6b 100644
--- a/configs/qemu_arm_defconfig
+++ b/configs/qemu_arm_defconfig
@@ -7,6 +7,11 @@ CONFIG_NR_DRAM_BANKS=1
CONFIG_ENV_SECT_SIZE=0x40000
CONFIG_AHCI=y
CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_BEST_MATCH=y
+CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_USE_PREBOOT=y
CONFIG_PREBOOT="pci enum"
# CONFIG_DISPLAY_CPUINFO is not set
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index b06ffce..64d1d31 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -161,6 +161,8 @@ CONFIG_REGULATOR_RK8XX=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_SANDBOX=y
CONFIG_DM_PWM=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 858ad04..d8d8645 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -181,6 +181,8 @@ CONFIG_REGULATOR_RK8XX=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_SANDBOX=y
CONFIG_DM_PWM=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index 713a7e6..c85369c 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -143,3 +143,5 @@ CONFIG_VIDEO_STM32_DSI=y
CONFIG_VIDEO_STM32_MAX_XRES=1280
CONFIG_VIDEO_STM32_MAX_YRES=800
CONFIG_FDT_FIXUP_PARTITIONS=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_STM32MP1=y
diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig
index f9161fd..c192d8d 100644
--- a/configs/stm32mp15_optee_defconfig
+++ b/configs/stm32mp15_optee_defconfig
@@ -127,3 +127,5 @@ CONFIG_VIDEO_STM32_DSI=y
CONFIG_VIDEO_STM32_MAX_XRES=1280
CONFIG_VIDEO_STM32_MAX_YRES=800
CONFIG_FDT_FIXUP_PARTITIONS=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_STM32MP1=y
diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
index a5ea528..a846962 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -126,3 +126,5 @@ CONFIG_VIDEO_STM32_DSI=y
CONFIG_VIDEO_STM32_MAX_XRES=1280
CONFIG_VIDEO_STM32_MAX_YRES=800
CONFIG_FDT_FIXUP_PARTITIONS=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_STM32MP1=y
diff --git a/doc/uImage.FIT/uefi.its b/doc/uImage.FIT/uefi.its
new file mode 100644
index 0000000..378ca4e
--- /dev/null
+++ b/doc/uImage.FIT/uefi.its
@@ -0,0 +1,67 @@
+/*
+ * Example FIT image description file demonstrating the usage of the
+ * bootm command to launch UEFI binaries.
+ *
+ * Two boot configurations are available to enable booting GRUB2 on QEMU,
+ * the former uses a FDT blob contained in the FIT image, while the later
+ * relies on the FDT provided by the board emulator.
+ */
+
+/dts-v1/;
+
+/ {
+ description = "GRUB2 EFI and QEMU FDT blob";
+ #address-cells = <1>;
+
+ images {
+ efi-grub {
+ description = "GRUB EFI Firmware";
+ data = /incbin/("bootarm.efi");
+ type = "kernel_noload";
+ arch = "arm";
+ os = "efi";
+ compression = "none";
+ load = <0x0>;
+ entry = <0x0>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+
+ fdt-qemu {
+ description = "QEMU DTB";
+ data = /incbin/("qemu-arm.dtb");
+ type = "flat_dt";
+ arch = "arm";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ };
+
+ configurations {
+ default = "config-grub-fdt";
+
+ config-grub-fdt {
+ description = "GRUB EFI Boot w/ FDT";
+ kernel = "efi-grub";
+ fdt = "fdt-qemu";
+ signature-1 {
+ algo = "sha256,rsa2048";
+ key-name-hint = "dev";
+ sign-images = "kernel", "fdt";
+ };
+ };
+
+ config-grub-nofdt {
+ description = "GRUB EFI Boot w/o FDT";
+ kernel = "efi-grub";
+ signature-1 {
+ algo = "sha256,rsa2048";
+ key-name-hint = "dev";
+ sign-images = "kernel";
+ };
+ };
+ };
+};
diff --git a/doc/uefi/uefi.rst b/doc/uefi/uefi.rst
index db942df..a8fd886 100644
--- a/doc/uefi/uefi.rst
+++ b/doc/uefi/uefi.rst
@@ -63,6 +63,40 @@ The environment variable 'bootargs' is passed as load options in the UEFI system
table. The Linux kernel EFI stub uses the load options as command line
arguments.
+Launching a UEFI binary from a FIT image
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A signed FIT image can be used to securely boot a UEFI image via the
+bootm command. This feature is available if U-Boot is configured with::
+
+ CONFIG_BOOTM_EFI=y
+
+A sample configuration is provided as file doc/uImage.FIT/uefi.its.
+
+Below you find the output of an example session starting GRUB::
+
+ => load mmc 0:1 ${kernel_addr_r} image.fit
+ 4620426 bytes read in 83 ms (53.1 MiB/s)
+ => bootm ${kernel_addr_r}#config-grub-nofdt
+ ## Loading kernel from FIT Image at 40400000 ...
+ Using 'config-grub-nofdt' configuration
+ Verifying Hash Integrity ... sha256,rsa2048:dev+ OK
+ Trying 'efi-grub' kernel subimage
+ Description: GRUB EFI Firmware
+ Created: 2019-11-20 8:18:16 UTC
+ Type: Kernel Image (no loading done)
+ Compression: uncompressed
+ Data Start: 0x404000d0
+ Data Size: 450560 Bytes = 440 KiB
+ Hash algo: sha256
+ Hash value: 4dbee00021112df618f58b3f7cf5e1595533d543094064b9ce991e8b054a9eec
+ Verifying Hash Integrity ... sha256+ OK
+ XIP Kernel Image (no loading done)
+ ## Transferring control to EFI (at address 404000d0) ...
+ Welcome to GRUB!
+
+See doc/uImage.FIT/howto.txt for an introduction to FIT images.
+
Executing the boot manager
~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 9d99ce0..e34a227 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 44a08da..e7b5d22 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -117,4 +117,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/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index 3718970..da66bde 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -563,6 +563,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB5ENSETR, 6, RNG1_K, _UNKNOWN_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK_K, _ETH_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 8, ETHTX, _UNKNOWN_SEL),
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
new file mode 100644
index 0000000..35a3bd1
--- /dev/null
+++ b/drivers/rng/Kconfig
@@ -0,0 +1,22 @@
+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.
+
+config RNG_SANDBOX
+ bool "Sandbox random number generator"
+ depends on SANDBOX && DM_RNG
+ select CONFIG_LIB_RAND
+ help
+ Enable random number generator for sandbox. This is an
+ emulation of a rng device.
+
+config RNG_STM32MP1
+ bool "Enable random number generator for STM32MP1"
+ depends on ARCH_STM32MP && DM_RNG
+ default n
+ help
+ Enable STM32MP1 rng driver.
diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile
new file mode 100644
index 0000000..3517005
--- /dev/null
+++ b/drivers/rng/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2019, Linaro Limited
+#
+
+obj-$(CONFIG_DM_RNG) += rng-uclass.o
+obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o
+obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o
diff --git a/drivers/rng/rng-uclass.c b/drivers/rng/rng-uclass.c
new file mode 100644
index 0000000..b6af3b8
--- /dev/null
+++ b/drivers/rng/rng-uclass.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <rng.h>
+
+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/drivers/rng/sandbox_rng.c b/drivers/rng/sandbox_rng.c
new file mode 100644
index 0000000..cd0b0ac
--- /dev/null
+++ b/drivers/rng/sandbox_rng.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <rng.h>
+
+#include <linux/string.h>
+
+static int sandbox_rng_read(struct udevice *dev, void *data, size_t len)
+{
+ unsigned int i, seed, random;
+ unsigned char *buf = data;
+ size_t nrem, nloops;
+
+ if (!len)
+ return 0;
+
+ nloops = len / sizeof(random);
+ seed = get_timer(0) ^ rand();
+ srand(seed);
+
+ for (i = 0, nrem = len; i < nloops; i++) {
+ random = rand();
+ memcpy(buf, &random, sizeof(random));
+ buf += sizeof(random);
+ nrem -= sizeof(random);
+ }
+
+ if (nrem) {
+ random = rand();
+ memcpy(buf, &random, nrem);
+ }
+
+ return 0;
+}
+
+static const struct dm_rng_ops sandbox_rng_ops = {
+ .read = sandbox_rng_read,
+};
+
+static const struct udevice_id sandbox_rng_match[] = {
+ {
+ .compatible = "sandbox,sandbox-rng",
+ },
+ {},
+};
+
+U_BOOT_DRIVER(sandbox_rng) = {
+ .name = "sandbox-rng",
+ .id = UCLASS_RNG,
+ .of_match = sandbox_rng_match,
+ .ops = &sandbox_rng_ops,
+};
diff --git a/drivers/rng/stm32mp1_rng.c b/drivers/rng/stm32mp1_rng.c
new file mode 100644
index 0000000..dab3b99
--- /dev/null
+++ b/drivers/rng/stm32mp1_rng.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <reset.h>
+#include <rng.h>
+
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+
+#define RNG_CR 0x00
+#define RNG_CR_RNGEN BIT(2)
+#define RNG_CR_CED BIT(5)
+
+#define RNG_SR 0x04
+#define RNG_SR_SEIS BIT(6)
+#define RNG_SR_CEIS BIT(5)
+#define RNG_SR_SECS BIT(2)
+#define RNG_SR_DRDY BIT(0)
+
+#define RNG_DR 0x08
+
+struct stm32_rng_platdata {
+ fdt_addr_t base;
+ struct clk clk;
+ struct reset_ctl rst;
+};
+
+static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
+{
+ int retval = 0, i;
+ u32 sr, count, reg;
+ size_t increment;
+ struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
+
+ while (len > 0) {
+ retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
+ sr & RNG_SR_DRDY, 10000);
+ if (retval)
+ return retval;
+
+ if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
+ /* As per SoC TRM */
+ clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
+ for (i = 0; i < 12; i++)
+ readl(pdata->base + RNG_DR);
+ if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
+ printf("RNG Noise");
+ return -EIO;
+ }
+ /* start again */
+ continue;
+ }
+
+ /*
+ * Once the DRDY bit is set, the RNG_DR register can
+ * be read four consecutive times.
+ */
+ count = 4;
+ while (len && count) {
+ reg = readl(pdata->base + RNG_DR);
+ memcpy(data, &reg, min(len, sizeof(u32)));
+ increment = min(len, sizeof(u32));
+ data += increment;
+ len -= increment;
+ count--;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_rng_init(struct stm32_rng_platdata *pdata)
+{
+ int err;
+
+ err = clk_enable(&pdata->clk);
+ if (err)
+ return err;
+
+ /* Disable CED */
+ writel(RNG_CR_RNGEN | RNG_CR_CED, pdata->base + RNG_CR);
+
+ /* clear error indicators */
+ writel(0, pdata->base + RNG_SR);
+
+ return 0;
+}
+
+static int stm32_rng_cleanup(struct stm32_rng_platdata *pdata)
+{
+ writel(0, pdata->base + RNG_CR);
+
+ return clk_disable(&pdata->clk);
+}
+
+static int stm32_rng_probe(struct udevice *dev)
+{
+ struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
+
+ reset_assert(&pdata->rst);
+ udelay(20);
+ reset_deassert(&pdata->rst);
+
+ return stm32_rng_init(pdata);
+}
+
+static int stm32_rng_remove(struct udevice *dev)
+{
+ struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
+
+ return stm32_rng_cleanup(pdata);
+}
+
+static int stm32_rng_ofdata_to_platdata(struct udevice *dev)
+{
+ struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
+ int err;
+
+ pdata->base = dev_read_addr(dev);
+ if (!pdata->base)
+ return -ENOMEM;
+
+ err = clk_get_by_index(dev, 0, &pdata->clk);
+ if (err)
+ return err;
+
+ err = reset_get_by_index(dev, 0, &pdata->rst);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static const struct dm_rng_ops stm32_rng_ops = {
+ .read = stm32_rng_read,
+};
+
+static const struct udevice_id stm32_rng_match[] = {
+ {
+ .compatible = "st,stm32-rng",
+ },
+ {},
+};
+
+U_BOOT_DRIVER(stm32_rng) = {
+ .name = "stm32-rng",
+ .id = UCLASS_RNG,
+ .of_match = stm32_rng_match,
+ .ops = &stm32_rng_ops,
+ .probe = stm32_rng_probe,
+ .remove = stm32_rng_remove,
+ .platdata_auto_alloc_size = sizeof(struct stm32_rng_platdata),
+ .ofdata_to_platdata = stm32_rng_ofdata_to_platdata,
+};
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index a9d5fd0..2e3dd3b 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 4579044..dc88809 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 34397d7..436faa4 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 0000000..4edffa6
--- /dev/null
+++ b/drivers/virtio/virtio_rng.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <rng.h>
+#include <virtio_types.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+
+#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/dm/uclass-id.h b/include/dm/uclass-id.h
index c1bab17..67f5d67 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/efi.h b/include/efi.h
index 5f415a9..e12697a 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;
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 16a1b25..d4c59b5 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)
@@ -34,6 +39,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 NULL
+
/* Root node */
extern efi_handle_t efi_root;
@@ -125,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);
@@ -170,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;
@@ -338,6 +350,10 @@ 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 */
efi_status_t efi_init_variables(void);
/* Notify ExitBootServices() is called */
diff --git a/include/efi_rng.h b/include/efi_rng.h
new file mode 100644
index 0000000..35f5967
--- /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 <efi.h>
+#include <efi_api.h>
+
+/* 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/include/image.h b/include/image.h
index f4d2aaf..4a280b7 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,
};
diff --git a/include/part_efi.h b/include/part_efi.h
index eb5797a..1929e44 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
diff --git a/include/pe.h b/include/pe.h
index bff3b0a..086f2b8 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 */
diff --git a/include/rng.h b/include/rng.h
new file mode 100644
index 0000000..d2c0f9a
--- /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_ */
diff --git a/include/virtio.h b/include/virtio.h
index 654fdf1..561dcc3 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 */
diff --git a/lib/efi_loader/.gitignore b/lib/efi_loader/.gitignore
index 634a600..f2d7c14 100644
--- a/lib/efi_loader/.gitignore
+++ b/lib/efi_loader/.gitignore
@@ -1,2 +1,3 @@
*.efi
*.so
+*.S
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 21ef440..6727336 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -15,6 +15,7 @@ config EFI_LOADER
select HAVE_BLOCK_DEVICE
select REGEX
imply CFB_CONSOLE_ANSI
+ imply USB_KEYBOARD_FN_KEYS
help
Select this option if you want to run UEFI applications (like GNU
GRUB or iPXE) on top of U-Boot. If this option is enabled, U-Boot
@@ -120,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 7db4060..04dc864 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_boottime.c b/lib/efi_loader/efi_boottime.c
index 88a7604..3103a50 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;
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 218f7ca..8494044 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -360,12 +360,26 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
return EFI_EXIT(EFI_SUCCESS);
}
+/**
+ * efi_cout_clear_screen() - clear screen
+ *
+ * This function implements the ClearScreen service of the
+ * EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. See the Unified Extensible Firmware
+ * Interface (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_cout_clear_screen(
struct efi_simple_text_output_protocol *this)
{
EFI_ENTRY("%p", this);
- printf(ESC"[2J");
+ /*
+ * The Linux console wants both a clear and a home command. The video
+ * uclass does not support <ESC>[H without coordinates, yet.
+ */
+ printf(ESC "[2J" ESC "[1;1H");
efi_con_mode.cursor_column = 0;
efi_con_mode.cursor_row = 0;
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 6d3f680..140116d 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -656,9 +656,16 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
memset(info, 0, required_size);
info->size = required_size;
- info->read_only = true;
+ /*
+ * TODO: We cannot determine if the volume can be written to.
+ */
+ info->read_only = false;
info->volume_size = part.size * part.blksz;
- info->free_space = 0;
+ /*
+ * TODO: We currently have no function to determine the free
+ * space. The volume size is the best upper bound we have.
+ */
+ info->free_space = info->volume_size;
info->block_size = part.blksz;
/*
* TODO: The volume label is not available in U-Boot.
diff --git a/lib/efi_loader/efi_freestanding.c b/lib/efi_loader/efi_freestanding.c
index bd9da5b..dcf5d1c 100644
--- a/lib/efi_loader/efi_freestanding.c
+++ b/lib/efi_loader/efi_freestanding.c
@@ -88,3 +88,35 @@ void *memset(void *s, int c, size_t n)
*d++ = c;
return s;
}
+
+/**
+ * __cyg_profile_func_enter() - record function entry
+ *
+ * This is called on every function entry when compiling with
+ * -finstrument-functions.
+ *
+ * We do nothing here.
+ *
+ * @param func_ptr Pointer to function being entered
+ * @param caller Pointer to function which called this function
+ */
+void __attribute__((no_instrument_function))
+__cyg_profile_func_enter(void *func_ptr, void *caller)
+{
+}
+
+/**
+ * __cyg_profile_func_exit() - record function exit
+ *
+ * This is called on every function exit when compiling with
+ * -finstrument-functions.
+ *
+ * We do nothing here.
+ *
+ * @param func_ptr Pointer to function being entered
+ * @param caller Pointer to function which called this function
+ */
+void __attribute__((no_instrument_function))
+__cyg_profile_func_exit(void *func_ptr, void *caller)
+{
+}
diff --git a/lib/efi_loader/efi_rng.c b/lib/efi_loader/efi_rng.c
new file mode 100644
index 0000000..432c986
--- /dev/null
+++ b/lib/efi_loader/efi_rng.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <efi_rng.h>
+#include <rng.h>
+
+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;
+ 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,
+};
diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c
index f68b0fd..76d18fb 100644
--- a/lib/efi_loader/efi_root_node.c
+++ b/lib/efi_loader/efi_root_node.c
@@ -81,6 +81,10 @@ efi_status_t efi_root_node_register(void)
&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;
return ret;
diff --git a/lib/efi_selftest/.gitignore b/lib/efi_selftest/.gitignore
index 293a17b..5b25169 100644
--- a/lib/efi_selftest/.gitignore
+++ b/lib/efi_selftest/.gitignore
@@ -1,4 +1,3 @@
-efi_miniapp_file_image_exit.h
-efi_miniapp_file_image_return.h
+efi_miniapp_*.h
*.efi
*.so
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 487cb4c..3ad96e1 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -47,6 +47,7 @@ efi_selftest_unicode_collation.o
obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o
obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o
+obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_selftest_rng.o
obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
diff --git a/lib/efi_selftest/efi_selftest_rng.c b/lib/efi_selftest/efi_selftest_rng.c
new file mode 100644
index 0000000..fca9749
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_rng.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_rng
+ *
+ * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Test the random number generator service.
+ */
+
+#include <efi_selftest.h>
+#include <efi_rng.h>
+
+#define RNG_LEN 9
+
+static struct efi_boot_services *boottime;
+static efi_guid_t efi_rng_guid = EFI_RNG_PROTOCOL_GUID;
+
+/*
+ * Setup unit test.
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ boottime = systable->boottime;
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ * Retrieve available RNG algorithms.
+ * Retrieve two random values and compare them.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+ efi_uintn_t size;
+ struct efi_rng_protocol *rng;
+ efi_guid_t *algo_list;
+ u8 rnd1[RNG_LEN] __aligned(4), rnd2[RNG_LEN] __aligned(4);
+ int r;
+
+ /* Get random number generator protocol */
+ ret = boottime->locate_protocol(&efi_rng_guid, NULL, (void **)&rng);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error(
+ "Random number generator protocol not available\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = rng->get_info(rng, &size, NULL);
+ if (ret != EFI_BUFFER_TOO_SMALL) {
+ efi_st_error("Could not retrieve alorithm list size\n");
+ return EFI_ST_FAILURE;
+ }
+ if (size < sizeof(efi_guid_t)) {
+ efi_st_error("Empty alorithm list\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->allocate_pool(EFI_LOADER_DATA, size,
+ (void **)&algo_list);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Could not allocate pool memory\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = rng->get_info(rng, &size, algo_list);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Could not get info\n");
+ return EFI_ST_FAILURE;
+ }
+ if (size < sizeof(efi_guid_t)) {
+ efi_st_error("Empty alorithm list\n");
+ return EFI_ST_FAILURE;
+ }
+
+ memset(rnd1, 0, RNG_LEN);
+ memset(rnd2, 0, RNG_LEN);
+
+ ret = rng->get_rng(rng, NULL, RNG_LEN - 1, &rnd1[1]);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Could not get random value\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = rng->get_rng(rng, algo_list, RNG_LEN - 1, &rnd2[1]);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Could not get random value\n");
+ return EFI_ST_FAILURE;
+ }
+ r = memcmp(rnd1, rnd2, RNG_LEN);
+ if (!r) {
+ efi_st_error("Two equal consecutive random numbers\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->free_pool(algo_list);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Could not free pool memory\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(rng) = {
+ .name = "random number generator",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+};
diff --git a/test/dm/Makefile b/test/dm/Makefile
index a268783..201e2b0 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -68,4 +68,5 @@ obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
obj-$(CONFIG_DMA) += dma.o
obj-$(CONFIG_DM_MDIO) += mdio.o
obj-$(CONFIG_DM_MDIO_MUX) += mdio_mux.o
+obj-$(CONFIG_DM_RNG) += rng.o
endif
diff --git a/test/dm/rng.c b/test/dm/rng.c
new file mode 100644
index 0000000..ce20e2d
--- /dev/null
+++ b/test/dm/rng.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <rng.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Basic test of the rng uclass */
+static int dm_test_rng_read(struct unit_test_state *uts)
+{
+ unsigned long rand1 = 0, rand2 = 0;
+ struct udevice *dev;
+
+ ut_assertok(uclass_get_device(UCLASS_RNG, 0, &dev));
+ ut_assertnonnull(dev);
+ ut_assertok(dm_rng_read(dev, &rand1, sizeof(rand1)));
+ ut_assertok(dm_rng_read(dev, &rand2, sizeof(rand2)));
+ ut_assert(rand1 != rand2);
+
+ return 0;
+}
+DM_TEST(dm_test_rng_read, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 472dd05..34ac4fb 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -472,7 +472,7 @@ def setup_buildconfigspec(item):
option = options.args[0]
if not ubconfig.buildconfig.get('config_' + option.lower(), None):
pytest.skip('.config feature "%s" not enabled' % option.lower())
- for option in item.iter_markers('notbuildconfigspec'):
+ for options in item.iter_markers('notbuildconfigspec'):
option = options.args[0]
if ubconfig.buildconfig.get('config_' + option.lower(), None):
pytest.skip('.config feature "%s" enabled' % option.lower())
diff --git a/test/py/tests/test_efi_fit.py b/test/py/tests/test_efi_fit.py
new file mode 100644
index 0000000..6986b2d
--- /dev/null
+++ b/test/py/tests/test_efi_fit.py
@@ -0,0 +1,458 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019, Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+#
+# Work based on:
+# - test_net.py
+# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+# - test_fit.py
+# Copyright (c) 2013, Google Inc.
+#
+# Test launching UEFI binaries from FIT images.
+
+import os.path
+import pytest
+import u_boot_utils as util
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which network environment is available for testing. Without this, the parts
+that rely on network will be automatically skipped.
+
+For example:
+
+# Boolean indicating whether the Ethernet device is attached to USB, and hence
+# USB enumeration needs to be performed prior to network tests.
+# This variable may be omitted if its value is False.
+env__net_uses_usb = False
+
+# Boolean indicating whether the Ethernet device is attached to PCI, and hence
+# PCI enumeration needs to be performed prior to network tests.
+# This variable may be omitted if its value is False.
+env__net_uses_pci = True
+
+# True if a DHCP server is attached to the network, and should be tested.
+# If DHCP testing is not possible or desired, this variable may be omitted or
+# set to False.
+env__net_dhcp_server = True
+
+# A list of environment variables that should be set in order to configure a
+# static IP. If solely relying on DHCP, this variable may be omitted or set to
+# an empty list.
+env__net_static_env_vars = [
+ ('ipaddr', '10.0.0.100'),
+ ('netmask', '255.255.255.0'),
+ ('serverip', '10.0.0.1'),
+]
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if TFTP testing is not possible or desired.
+# Additionally, when the 'size' is not available, the file will be generated
+# automatically in the TFTP root directory, as specified by the 'dn' field.
+env__efi_fit_tftp_file = {
+ 'fn': 'test-efi-fit.img', # File path relative to TFTP root
+ 'size': 3831, # File size
+ 'crc32': '9fa3f79c', # Checksum using CRC-32 algorithm, optional
+ 'addr': 0x40400000, # Loading address, integer, optional
+ 'dn': 'tftp/root/dir', # TFTP root directory path, optional
+}
+"""
+
+# Define the parametrized ITS data to be used for FIT images generation.
+its_data = '''
+/dts-v1/;
+
+/ {
+ description = "EFI image with FDT blob";
+ #address-cells = <1>;
+
+ images {
+ efi {
+ description = "Test EFI";
+ data = /incbin/("%(efi-bin)s");
+ type = "%(kernel-type)s";
+ arch = "%(sys-arch)s";
+ os = "efi";
+ compression = "%(efi-comp)s";
+ load = <0x0>;
+ entry = <0x0>;
+ };
+ fdt {
+ description = "Test FDT";
+ data = /incbin/("%(fdt-bin)s");
+ type = "flat_dt";
+ arch = "%(sys-arch)s";
+ compression = "%(fdt-comp)s";
+ };
+ };
+
+ configurations {
+ default = "config-efi-fdt";
+ config-efi-fdt {
+ description = "EFI FIT w/ FDT";
+ kernel = "efi";
+ fdt = "fdt";
+ };
+ config-efi-nofdt {
+ description = "EFI FIT w/o FDT";
+ kernel = "efi";
+ };
+ };
+};
+'''
+
+# Define the parametrized FDT data to be used for DTB images generation.
+fdt_data = '''
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ model = "%(sys-arch)s %(fdt_type)s EFI FIT Boot Test";
+ compatible = "%(sys-arch)s";
+
+ reset@0 {
+ compatible = "%(sys-arch)s,reset";
+ reg = <0>;
+ };
+};
+'''
+
+@pytest.mark.buildconfigspec('bootm_efi')
+@pytest.mark.buildconfigspec('cmd_bootefi_hello_compile')
+@pytest.mark.buildconfigspec('fit')
+@pytest.mark.notbuildconfigspec('generate_acpi_table')
+@pytest.mark.requiredtool('dtc')
+def test_efi_fit_launch(u_boot_console):
+ """Test handling of UEFI binaries inside FIT images.
+
+ The tests are trying to launch U-Boot's helloworld.efi embedded into
+ FIT images, in uncompressed or gzip compressed format.
+
+ Additionally, a sample FDT blob is created and embedded into the above
+ mentioned FIT images, in uncompressed or gzip compressed format.
+
+ For more details, see launch_efi().
+
+ The following test cases are currently defined and enabled:
+ - Launch uncompressed FIT EFI & internal FDT
+ - Launch uncompressed FIT EFI & FIT FDT
+ - Launch compressed FIT EFI & internal FDT
+ - Launch compressed FIT EFI & FIT FDT
+ """
+
+ def net_pre_commands():
+ """Execute any commands required to enable network hardware.
+
+ These commands are provided by the boardenv_* file; see the comment
+ at the beginning of this file.
+ """
+
+ init_usb = cons.config.env.get('env__net_uses_usb', False)
+ if init_usb:
+ cons.run_command('usb start')
+
+ init_pci = cons.config.env.get('env__net_uses_pci', False)
+ if init_pci:
+ cons.run_command('pci enum')
+
+ def net_dhcp():
+ """Execute the dhcp command.
+
+ The boardenv_* file may be used to enable/disable DHCP; see the
+ comment at the beginning of this file.
+ """
+
+ has_dhcp = cons.config.buildconfig.get('config_cmd_dhcp', 'n') == 'y'
+ if not has_dhcp:
+ cons.log.warning('CONFIG_CMD_DHCP != y: Skipping DHCP network setup')
+ return False
+
+ test_dhcp = cons.config.env.get('env__net_dhcp_server', False)
+ if not test_dhcp:
+ cons.log.info('No DHCP server available')
+ return False
+
+ cons.run_command('setenv autoload no')
+ output = cons.run_command('dhcp')
+ assert 'DHCP client bound to address ' in output
+ return True
+
+ def net_setup_static():
+ """Set up a static IP configuration.
+
+ The configuration is provided by the boardenv_* file; see the comment at
+ the beginning of this file.
+ """
+
+ has_dhcp = cons.config.buildconfig.get('config_cmd_dhcp', 'n') == 'y'
+ if not has_dhcp:
+ cons.log.warning('CONFIG_NET != y: Skipping static network setup')
+ return False
+
+ env_vars = cons.config.env.get('env__net_static_env_vars', None)
+ if not env_vars:
+ cons.log.info('No static network configuration is defined')
+ return False
+
+ for (var, val) in env_vars:
+ cons.run_command('setenv %s %s' % (var, val))
+ return True
+
+ def make_fpath(fname):
+ """Compute the path of a given (temporary) file.
+
+ Args:
+ fname: The name of a file within U-Boot build dir.
+ Return:
+ The computed file path.
+ """
+
+ return os.path.join(cons.config.build_dir, fname)
+
+ def make_efi(fname, comp):
+ """Create an UEFI binary.
+
+ This simply copies lib/efi_loader/helloworld.efi into U-Boot
+ build dir and, optionally, compresses the file using gzip.
+
+ Args:
+ fname: The target file name within U-Boot build dir.
+ comp: Flag to enable gzip compression.
+ Return:
+ The path of the created file.
+ """
+
+ bin_path = make_fpath(fname)
+ util.run_and_log(cons,
+ ['cp', make_fpath('lib/efi_loader/helloworld.efi'), bin_path])
+ if comp:
+ util.run_and_log(cons, ['gzip', '-f', bin_path])
+ bin_path += '.gz'
+ return bin_path
+
+ def make_dtb(fdt_type, comp):
+ """Create a sample DTB file.
+
+ Creates a DTS file and compiles it to a DTB.
+
+ Args:
+ fdt_type: The type of the FDT, i.e. internal, user.
+ comp: Flag to enable gzip compression.
+ Return:
+ The path of the created file.
+ """
+
+ # Generate resources referenced by FDT.
+ fdt_params = {
+ 'sys-arch': sys_arch,
+ 'fdt_type': fdt_type,
+ }
+
+ # Generate a test FDT file.
+ dts = make_fpath('test-efi-fit-%s.dts' % fdt_type)
+ with open(dts, 'w') as fd:
+ fd.write(fdt_data % fdt_params)
+
+ # Build the test FDT.
+ dtb = make_fpath('test-efi-fit-%s.dtb' % fdt_type)
+ util.run_and_log(cons, ['dtc', '-I', 'dts', '-O', 'dtb', '-o', dtb, dts])
+ if comp:
+ util.run_and_log(cons, ['gzip', '-f', dtb])
+ dtb += '.gz'
+ return dtb
+
+ def make_fit(comp):
+ """Create a sample FIT image.
+
+ Runs 'mkimage' to create a FIT image within U-Boot build dir.
+ Args:
+ comp: Enable gzip compression for the EFI binary and FDT blob.
+ Return:
+ The path of the created file.
+ """
+
+ # Generate resources referenced by ITS.
+ its_params = {
+ 'sys-arch': sys_arch,
+ 'efi-bin': os.path.basename(make_efi('test-efi-fit-helloworld.efi', comp)),
+ 'kernel-type': 'kernel' if comp else 'kernel_noload',
+ 'efi-comp': 'gzip' if comp else 'none',
+ 'fdt-bin': os.path.basename(make_dtb('user', comp)),
+ 'fdt-comp': 'gzip' if comp else 'none',
+ }
+
+ # Generate a test ITS file.
+ its_path = make_fpath('test-efi-fit-helloworld.its')
+ with open(its_path, 'w') as fd:
+ fd.write(its_data % its_params)
+
+ # Build the test ITS.
+ fit_path = make_fpath('test-efi-fit-helloworld.fit')
+ util.run_and_log(
+ cons, [make_fpath('tools/mkimage'), '-f', its_path, fit_path])
+ return fit_path
+
+ def load_fit_from_host(f):
+ """Load the FIT image using the 'host load' command and return its address.
+
+ Args:
+ f: Dictionary describing the FIT image to load, see env__efi_fit_test_file
+ in the comment at the beginning of this file.
+ Return:
+ The address where the file has been loaded.
+ """
+
+ addr = f.get('addr', None)
+ if not addr:
+ addr = util.find_ram_base(cons)
+
+ output = cons.run_command(
+ 'host load hostfs - %x %s/%s' % (addr, f['dn'], f['fn']))
+ expected_text = ' bytes read'
+ sz = f.get('size', None)
+ if sz:
+ expected_text = '%d' % sz + expected_text
+ assert(expected_text in output)
+
+ return addr
+
+ def load_fit_from_tftp(f):
+ """Load the FIT image using the tftpboot command and return its address.
+
+ The file is downloaded from the TFTP server, its size and optionally its
+ CRC32 are validated.
+
+ Args:
+ f: Dictionary describing the FIT image to load, see env__efi_fit_tftp_file
+ in the comment at the beginning of this file.
+ Return:
+ The address where the file has been loaded.
+ """
+
+ addr = f.get('addr', None)
+ if not addr:
+ addr = util.find_ram_base(cons)
+
+ fn = f['fn']
+ output = cons.run_command('tftpboot %x %s' % (addr, fn))
+ expected_text = 'Bytes transferred = '
+ sz = f.get('size', None)
+ if sz:
+ expected_text += '%d' % sz
+ assert expected_text in output
+
+ expected_crc = f.get('crc32', None)
+ if not expected_crc:
+ return addr
+
+ if cons.config.buildconfig.get('config_cmd_crc32', 'n') != 'y':
+ return addr
+
+ output = cons.run_command('crc32 $fileaddr $filesize')
+ assert expected_crc in output
+
+ return addr
+
+ def launch_efi(enable_fdt, enable_comp):
+ """Launch U-Boot's helloworld.efi binary from a FIT image.
+
+ An external image file can be downloaded from TFTP, when related
+ details are provided by the boardenv_* file; see the comment at the
+ beginning of this file.
+
+ If the size of the TFTP file is not provided within env__efi_fit_tftp_file,
+ the test image is generated automatically and placed in the TFTP root
+ directory specified via the 'dn' field.
+
+ When running the tests on Sandbox, the image file is loaded directly
+ from the host filesystem.
+
+ Once the load address is available on U-Boot console, the 'bootm'
+ command is executed for either 'config-efi-fdt' or 'config-efi-nofdt'
+ FIT configuration, depending on the value of the 'enable_fdt' function
+ argument.
+
+ Eventually the 'Hello, world' message is expected in the U-Boot console.
+
+ Args:
+ enable_fdt: Flag to enable using the FDT blob inside FIT image.
+ enable_comp: Flag to enable GZIP compression on EFI and FDT
+ generated content.
+ """
+
+ with cons.log.section('FDT=%s;COMP=%s' % (enable_fdt, enable_comp)):
+ if is_sandbox:
+ fit = {
+ 'dn': cons.config.build_dir,
+ }
+ else:
+ # Init networking.
+ net_pre_commands()
+ net_set_up = net_dhcp()
+ net_set_up = net_setup_static() or net_set_up
+ if not net_set_up:
+ pytest.skip('Network not initialized')
+
+ fit = cons.config.env.get('env__efi_fit_tftp_file', None)
+ if not fit:
+ pytest.skip('No env__efi_fit_tftp_file binary specified in environment')
+
+ sz = fit.get('size', None)
+ if not sz:
+ if not fit.get('dn', None):
+ pytest.skip('Neither "size", nor "dn" info provided in env__efi_fit_tftp_file')
+
+ # Create test FIT image.
+ fit_path = make_fit(enable_comp)
+ fit['fn'] = os.path.basename(fit_path)
+ fit['size'] = os.path.getsize(fit_path)
+
+ # Copy image to TFTP root directory.
+ if fit['dn'] != cons.config.build_dir:
+ util.run_and_log(cons, ['mv', '-f', fit_path, '%s/' % fit['dn']])
+
+ # Load FIT image.
+ addr = load_fit_from_host(fit) if is_sandbox else load_fit_from_tftp(fit)
+
+ # Select boot configuration.
+ fit_config = 'config-efi-fdt' if enable_fdt else 'config-efi-nofdt'
+
+ # Try booting.
+ cons.run_command(
+ 'bootm %x#%s' % (addr, fit_config), wait_for_prompt=False)
+ if enable_fdt:
+ cons.wait_for('Booting using the fdt blob')
+ cons.wait_for('Hello, world')
+ cons.wait_for('## Application terminated, r = 0')
+ cons.restart_uboot();
+
+ cons = u_boot_console
+ # Array slice removes leading/trailing quotes.
+ sys_arch = cons.config.buildconfig.get('config_sys_arch', '"sandbox"')[1:-1]
+ is_sandbox = sys_arch == 'sandbox'
+
+ try:
+ if is_sandbox:
+ # Use our own device tree file, will be restored afterwards.
+ control_dtb = make_dtb('internal', False)
+ old_dtb = cons.config.dtb
+ cons.config.dtb = control_dtb
+
+ # Run tests
+ # - fdt OFF, gzip OFF
+ launch_efi(False, False)
+ # - fdt ON, gzip OFF
+ launch_efi(True, False)
+
+ if is_sandbox:
+ # - fdt OFF, gzip ON
+ launch_efi(False, True)
+ # - fdt ON, gzip ON
+ launch_efi(True, True)
+
+ finally:
+ if is_sandbox:
+ # Go back to the original U-Boot with the correct dtb.
+ cons.config.dtb = old_dtb
+ cons.restart_uboot()
diff --git a/test/py/tests/test_efi_loader.py b/test/py/tests/test_efi_loader.py
index d6b214f..adf9d77 100644
--- a/test/py/tests/test_efi_loader.py
+++ b/test/py/tests/test_efi_loader.py
@@ -43,9 +43,10 @@ env__net_static_env_vars = [
# Details regarding a file that may be read from a TFTP server. This variable
# may be omitted or set to None if TFTP testing is not possible or desired.
env__efi_loader_helloworld_file = {
- 'fn': 'lib/efi_loader/helloworld.efi',
- 'size': 5058624,
- 'crc32': 'c2244b26',
+ 'fn': 'lib/efi_loader/helloworld.efi', # file name
+ 'size': 5058624, # file length in bytes
+ 'crc32': 'c2244b26', # CRC32 check sum
+ 'addr': 0x40400000, # load address
}
"""