mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
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:
commit
7086de4948
57 changed files with 1719 additions and 83 deletions
|
@ -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";
|
||||
|
|
|
@ -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 */
|
||||
|
|
14
cmd/Kconfig
14
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"
|
||||
|
|
|
@ -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
|
||||
|
|
135
cmd/bootefi.c
135
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 (!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)
|
||||
|
|
|
@ -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
56
cmd/rng.c
Normal 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
|
||||
);
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, "", "", },
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
67
doc/uImage.FIT/uefi.its
Normal 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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -90,6 +90,8 @@ source "drivers/remoteproc/Kconfig"
|
|||
|
||||
source "drivers/reset/Kconfig"
|
||||
|
||||
source "drivers/rng/Kconfig"
|
||||
|
||||
source "drivers/rtc/Kconfig"
|
||||
|
||||
source "drivers/scsi/Kconfig"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
22
drivers/rng/Kconfig
Normal 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
8
drivers/rng/Makefile
Normal 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
23
drivers/rng/rng-uclass.c
Normal 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
56
drivers/rng/sandbox_rng.c
Normal 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
160
drivers/rng/stm32mp1_rng.c
Normal 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, ®, 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,
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
88
drivers/virtio/virtio_rng.c
Normal file
88
drivers/virtio/virtio_rng.c
Normal 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,
|
||||
};
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
32
include/efi_rng.h
Normal 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_ */
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
18
include/pe.h
18
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 */
|
||||
|
|
33
include/rng.h
Normal file
33
include/rng.h
Normal 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_ */
|
|
@ -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 */
|
||||
|
||||
|
|
1
lib/efi_loader/.gitignore
vendored
1
lib/efi_loader/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
*.efi
|
||||
*.so
|
||||
*.S
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
114
lib/efi_loader/efi_rng.c
Normal 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,
|
||||
};
|
|
@ -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;
|
||||
|
|
3
lib/efi_selftest/.gitignore
vendored
3
lib/efi_selftest/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
efi_miniapp_file_image_exit.h
|
||||
efi_miniapp_file_image_return.h
|
||||
efi_miniapp_*.h
|
||||
*.efi
|
||||
*.so
|
||||
|
|
|
@ -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),)
|
||||
|
|
117
lib/efi_selftest/efi_selftest_rng.c
Normal file
117
lib/efi_selftest/efi_selftest_rng.c
Normal 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,
|
||||
};
|
|
@ -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
26
test/dm/rng.c
Normal 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);
|
|
@ -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())
|
||||
|
|
458
test/py/tests/test_efi_fit.py
Normal file
458
test/py/tests/test_efi_fit.py
Normal 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()
|
|
@ -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
|
||||
}
|
||||
"""
|
||||
|
||||
|
|
Loading…
Reference in a new issue