Pull request for UEFI sub-system for efi-2020-04-rc1

This pull request provides:
 
 * support for FIT images for UEFI binaries
 * drivers for hardware random number generators
 * an implementation of the EFI_RNG_PROTOCOL
 * a sub-command for efidebug to display configuration tables
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl4UvR4ACgkQxIHbvCwF
 GsRJZhAAmlsRBUS3fvFV5GtB8bkWcSU4/s3TVYJui0fOhY02ZDIKkrubZzDx/Lgv
 9OaVwjQ3JSmq5XkDmXqzNDzYkxitQ5Qf/cFiBF5HpA3USkOttb3GIfgj0qD6DGzM
 cKyhgJm7bZoMN/mkIzkWsry1ASwYpB3ipyoJAfRfryw9ok4j9RfJ7pPieeycGWGJ
 0sZsJI0v7e6xt5Qsytk5sZNvlCFhyhl2OMYliAlRKBryh31Ahr2e6KEwsJh7VyCP
 4K12eBTqIJq1qHk7Lr0g1CnMCdeOT8J7qvX1+kvt3HupxTMkYRv2AR5CQWRKck5E
 RsmcKmiTHz/76w6Gk7kLan7y0UCSHnfHQ3aSEkkx4O/v4OC85VteyLAEriS7J9Hx
 xSNyoj01U2wG3SLrUjkAZv6JgyC8uCezRzOHOqN25Q2mRROVq781mcMfRXwdq6cD
 L4rrTsIDPzNF19wDa7P5tK6JMF8BDifLNuMTQj5LdJYMHJTJZBWG/vTNFPEldaIP
 D9RPoCibTolpiuCYneeXJURHGm5yme7KoxAPiMU+fAWO1F6SO25zxYA7MAiY4OYw
 zk7Ipaat0luIu1gC2ICYxrLnsMBq9glABrdq99i0DpUg9n9N/7SpcJSj2DMrFGmY
 u4yenWM1KTgjLoVHRhpTbCzF15GlYN4SHXV5iYO+Pof5WQYnv8w=
 =SjPV
 -----END PGP SIGNATURE-----

Merge tag 'efi-2020-04-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2020-04-rc1

This pull request provides:

* support for FIT images for UEFI binaries
* drivers for hardware random number generators
* an implementation of the EFI_RNG_PROTOCOL
* a sub-command for efidebug to display configuration tables
This commit is contained in:
Tom Rini 2020-01-08 18:57:11 -05:00
commit 7086de4948
57 changed files with 1719 additions and 83 deletions

View file

@ -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";

View file

@ -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 */

View file

@ -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"

View file

@ -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

View file

@ -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 (!device_path && !image_path) {
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 (!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)

View file

@ -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 string for display to represent the protocol.
* Return description of GUID.
*
* @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;
}
/**
@ -477,6 +493,34 @@ static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_SUCCESS;
}
/**
* 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
*
@ -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(

56
cmd/rng.c Normal file
View file

@ -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
);

View file

@ -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 */

View file

@ -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

View file

@ -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, "", "", },
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

67
doc/uImage.FIT/uefi.its Normal file
View file

@ -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";
};
};
};
};

View file

@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -90,6 +90,8 @@ source "drivers/remoteproc/Kconfig"
source "drivers/reset/Kconfig"
source "drivers/rng/Kconfig"
source "drivers/rtc/Kconfig"
source "drivers/scsi/Kconfig"

View file

@ -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

View file

@ -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),

22
drivers/rng/Kconfig Normal file
View file

@ -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.

8
drivers/rng/Makefile Normal file
View file

@ -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

23
drivers/rng/rng-uclass.c Normal file
View file

@ -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,
};

56
drivers/rng/sandbox_rng.c Normal file
View file

@ -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,
};

160
drivers/rng/stm32mp1_rng.c Normal file
View file

@ -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,
};

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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,
};

View file

@ -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 */

View file

@ -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;

View file

@ -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 */

32
include/efi_rng.h Normal file
View file

@ -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_ */

View file

@ -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,
};

View file

@ -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

View file

@ -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 */

33
include/rng.h Normal file
View file

@ -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_ */

View file

@ -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 */

View file

@ -1,2 +1,3 @@
*.efi
*.so
*.S

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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.

View file

@ -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)
{
}

114
lib/efi_loader/efi_rng.c Normal file
View file

@ -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,
};

View file

@ -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;

View file

@ -1,4 +1,3 @@
efi_miniapp_file_image_exit.h
efi_miniapp_file_image_return.h
efi_miniapp_*.h
*.efi
*.so

View file

@ -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),)

View file

@ -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,
};

View file

@ -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

26
test/dm/rng.c Normal file
View file

@ -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);

View file

@ -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())

View file

@ -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()

View file

@ -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
}
"""