mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-03-17 23:37:01 +00:00
Pull request for efi-next
New: provide EFI ESRT table initrd via Load_File2_Protocol uses boot options create an S-CRTM event for measured boot Bug fixes: avoid double free of SPI device in dfu_free_entity() avoid memory leak in TCG2 protocol -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmBc/6QACgkQxIHbvCwF GsTZkBAAg2I6PuJV4n7Y5qsJOBCe49u3E0oIXZQBdJ459MEeY5kxXmm2D7jXA3ir RXJJIPK9BEOYSV3yLpSMj/jLMd+i777qcU63Sf4MKVMEAK7stv50QIcY6Jz2Lb9c /S0SDlqwtU9rq9mXHi/Vn6ky37S/gVD+N+8w18UHa3qyo3/b8TesPUcF10IhMaOM BOG4Wi5PwMre65OTBH6KvD7KPIuUwS0E1NCVEuAHMND2ueE9AAh+d4FvA43ejNZt Hw/gZh1siXzf2OnnF+zVpVuj5slZ7fVBhHNDjmNKAPI6dd2+5oDDWu/OavM3z3OS HX4MdLQWAQQiI3NI2ZIZ9xipC033cd3X2IzOX2LlSxq6+zm/ovAMXUHrPF4+erBz zatnKZczLPsBKgRbPZzv3LOgWDnroXkT12er/T8RTX0jPCLqloxpQp9261HHjYR+ zM1LYowjTOiEBMAQVuM9koQ2NhcQbcsr6uZmo22LcvUjWZIEVYhEI5mnXmQRBmR6 LeQbrSG68NbtaBNKPqsUy1GAC4WgCzLJ8fUOlaW8But/tnWzGxCPY3XgdtFMfkcj HIn28ihDMTtInUPhK7qIPuQRyAIA7LStYIOEBdBSlbKq+aiK1r98gjcshMM5LAtn RdZq2WSM6gvWH2qV/cEeGSzjd7SdqMGBkFds0GcluOpDBoX1+pk= =l6aM -----END PGP SIGNATURE----- Merge tag 'efi-next' of https://source.denx.de/u-boot/custodians/u-boot-efi into next Pull request for efi-next New: provide EFI ESRT table initrd via Load_File2_Protocol uses boot options create an S-CRTM event for measured boot Bug fixes: avoid double free of SPI device in dfu_free_entity() avoid memory leak in TCG2 protocol
This commit is contained in:
commit
4be994b0e1
36 changed files with 1783 additions and 455 deletions
|
@ -358,6 +358,9 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
|
|||
|
||||
free(load_options);
|
||||
|
||||
if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD))
|
||||
efi_initrd_deregister();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
281
cmd/efidebug.c
281
cmd/efidebug.c
|
@ -9,6 +9,7 @@
|
|||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <efi_dt_fixup.h>
|
||||
#include <efi_load_initrd.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_rng.h>
|
||||
#include <exports.h>
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include <part.h>
|
||||
#include <search.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define BS systab.boottime
|
||||
#define RT systab.runtime
|
||||
|
@ -72,7 +74,7 @@ static int do_efi_capsule_update(struct cmd_tbl *cmdtp, int flag,
|
|||
capsule->capsule_image_size);
|
||||
}
|
||||
|
||||
ret = EFI_CALL(RT->update_capsule(&capsule, 1, (u64)NULL));
|
||||
ret = EFI_CALL(RT->update_capsule(&capsule, 1, 0));
|
||||
if (ret) {
|
||||
printf("Cannot handle a capsule at %p", capsule);
|
||||
return CMD_RET_FAILURE;
|
||||
|
@ -129,6 +131,82 @@ static int do_efi_capsule_show(struct cmd_tbl *cmdtp, int flag,
|
|||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_ESRT
|
||||
|
||||
#define EFI_ESRT_FW_TYPE_NUM 4
|
||||
char *efi_fw_type_str[EFI_ESRT_FW_TYPE_NUM] = {"unknown", "system FW", "device FW",
|
||||
"UEFI driver"};
|
||||
|
||||
#define EFI_ESRT_UPDATE_STATUS_NUM 9
|
||||
char *efi_update_status_str[EFI_ESRT_UPDATE_STATUS_NUM] = {"success", "unsuccessful",
|
||||
"insufficient resources", "incorrect version", "invalid format",
|
||||
"auth error", "power event (AC)", "power event (batt)",
|
||||
"unsatisfied dependencies"};
|
||||
|
||||
#define EFI_FW_TYPE_STR_GET(idx) (\
|
||||
EFI_ESRT_FW_TYPE_NUM > (idx) ? efi_fw_type_str[(idx)] : "error"\
|
||||
)
|
||||
|
||||
#define EFI_FW_STATUS_STR_GET(idx) (\
|
||||
EFI_ESRT_UPDATE_STATUS_NUM > (idx) ? efi_update_status_str[(idx)] : "error"\
|
||||
)
|
||||
|
||||
/**
|
||||
* do_efi_capsule_esrt() - manage UEFI capsules
|
||||
*
|
||||
* @cmdtp: Command table
|
||||
* @flag: Command flag
|
||||
* @argc: Number of arguments
|
||||
* @argv: Argument array
|
||||
* Return: CMD_RET_SUCCESS on success,
|
||||
* CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
|
||||
*
|
||||
* Implement efidebug "capsule esrt" sub-command.
|
||||
* The prints the current ESRT table.
|
||||
*
|
||||
* efidebug capsule esrt
|
||||
*/
|
||||
static int do_efi_capsule_esrt(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
struct efi_system_resource_table *esrt = NULL;
|
||||
|
||||
if (argc != 1)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
for (int idx = 0; idx < systab.nr_tables; idx++)
|
||||
if (!guidcmp(&efi_esrt_guid, &systab.tables[idx].guid))
|
||||
esrt = (struct efi_system_resource_table *)systab.tables[idx].table;
|
||||
|
||||
if (!esrt) {
|
||||
log_info("ESRT: table not present\n");
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("========================================\n");
|
||||
printf("ESRT: fw_resource_count=%d\n", esrt->fw_resource_count);
|
||||
printf("ESRT: fw_resource_count_max=%d\n", esrt->fw_resource_count_max);
|
||||
printf("ESRT: fw_resource_version=%lld\n", esrt->fw_resource_version);
|
||||
|
||||
for (int idx = 0; idx < esrt->fw_resource_count; idx++) {
|
||||
printf("[entry %d]==============================\n", idx);
|
||||
printf("ESRT: fw_class=%pUL\n", &esrt->entries[idx].fw_class);
|
||||
printf("ESRT: fw_type=%s\n", EFI_FW_TYPE_STR_GET(esrt->entries[idx].fw_type));
|
||||
printf("ESRT: fw_version=%d\n", esrt->entries[idx].fw_version);
|
||||
printf("ESRT: lowest_supported_fw_version=%d\n",
|
||||
esrt->entries[idx].lowest_supported_fw_version);
|
||||
printf("ESRT: capsule_flags=%d\n",
|
||||
esrt->entries[idx].capsule_flags);
|
||||
printf("ESRT: last_attempt_version=%d\n",
|
||||
esrt->entries[idx].last_attempt_version);
|
||||
printf("ESRT: last_attempt_status=%s\n",
|
||||
EFI_FW_STATUS_STR_GET(esrt->entries[idx].last_attempt_status));
|
||||
}
|
||||
printf("========================================\n");
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
#endif /* CONFIG_EFI_ESRT */
|
||||
/**
|
||||
* do_efi_capsule_res() - show a capsule update result
|
||||
*
|
||||
|
@ -221,6 +299,10 @@ static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
|
|||
"", ""),
|
||||
U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show,
|
||||
"", ""),
|
||||
#ifdef CONFIG_EFI_ESRT
|
||||
U_BOOT_CMD_MKENT(esrt, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_esrt,
|
||||
"", ""),
|
||||
#endif
|
||||
U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update,
|
||||
"", ""),
|
||||
U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
|
||||
|
@ -516,6 +598,10 @@ static const struct {
|
|||
"ACPI table",
|
||||
EFI_ACPI_TABLE_GUID,
|
||||
},
|
||||
{
|
||||
"EFI System Resource Table",
|
||||
EFI_SYSTEM_RESOURCE_TABLE_GUID,
|
||||
},
|
||||
{
|
||||
"device tree",
|
||||
EFI_FDT_GUID,
|
||||
|
@ -798,6 +884,54 @@ static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
|
|||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* create_initrd_dp() - Create a special device for our Boot### option
|
||||
*
|
||||
* @dev: Device
|
||||
* @part: Disk partition
|
||||
* @file: Filename
|
||||
* Return: Pointer to the device path or ERR_PTR
|
||||
*
|
||||
*/
|
||||
static
|
||||
struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
|
||||
const char *file)
|
||||
|
||||
{
|
||||
struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL;
|
||||
struct efi_device_path *initrd_dp = NULL;
|
||||
efi_status_t ret;
|
||||
const struct efi_initrd_dp id_dp = {
|
||||
.vendor = {
|
||||
{
|
||||
DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||||
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
|
||||
sizeof(id_dp.vendor),
|
||||
},
|
||||
EFI_INITRD_MEDIA_GUID,
|
||||
},
|
||||
.end = {
|
||||
DEVICE_PATH_TYPE_END,
|
||||
DEVICE_PATH_SUB_TYPE_END,
|
||||
sizeof(id_dp.end),
|
||||
}
|
||||
};
|
||||
|
||||
ret = efi_dp_from_name(dev, part, file, &tmp_dp, &tmp_fp);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("Cannot create device path for \"%s %s\"\n", part, file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp,
|
||||
tmp_fp);
|
||||
|
||||
out:
|
||||
efi_free_pool(tmp_dp);
|
||||
efi_free_pool(tmp_fp);
|
||||
return initrd_dp;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_efi_boot_add() - set UEFI load option
|
||||
*
|
||||
|
@ -810,7 +944,9 @@ static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
|
|||
*
|
||||
* Implement efidebug "boot add" sub-command. Create or change UEFI load option.
|
||||
*
|
||||
* efidebug boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
|
||||
* efidebug boot add -b <id> <label> <interface> <devnum>[:<part>] <file>
|
||||
* -i <file> <interface2> <devnum2>[:<part>] <initrd>
|
||||
* -s '<options>'
|
||||
*/
|
||||
static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
|
@ -823,55 +959,105 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
|
|||
size_t label_len, label_len16;
|
||||
u16 *label;
|
||||
struct efi_device_path *device_path = NULL, *file_path = NULL;
|
||||
struct efi_device_path *final_fp = NULL;
|
||||
struct efi_device_path *initrd_dp = NULL;
|
||||
struct efi_load_option lo;
|
||||
void *data = NULL;
|
||||
efi_uintn_t size;
|
||||
efi_uintn_t fp_size = 0;
|
||||
efi_status_t ret;
|
||||
int r = CMD_RET_SUCCESS;
|
||||
|
||||
if (argc < 6 || argc > 7)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
id = (int)simple_strtoul(argv[1], &endp, 16);
|
||||
if (*endp != '\0' || id > 0xffff)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
sprintf(var_name, "Boot%04X", id);
|
||||
p = var_name16;
|
||||
utf8_utf16_strncpy(&p, var_name, 9);
|
||||
|
||||
guid = efi_global_variable_guid;
|
||||
|
||||
/* attributes */
|
||||
lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
|
||||
lo.optional_data = NULL;
|
||||
lo.label = NULL;
|
||||
|
||||
/* label */
|
||||
label_len = strlen(argv[2]);
|
||||
label_len16 = utf8_utf16_strnlen(argv[2], label_len);
|
||||
label = malloc((label_len16 + 1) * sizeof(u16));
|
||||
if (!label)
|
||||
return CMD_RET_FAILURE;
|
||||
lo.label = label; /* label will be changed below */
|
||||
utf8_utf16_strncpy(&label, argv[2], label_len);
|
||||
argc--;
|
||||
argv++; /* 'add' */
|
||||
for (; argc > 0; argc--, argv++) {
|
||||
if (!strcmp(argv[0], "-b")) {
|
||||
if (argc < 5 || lo.label) {
|
||||
r = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
id = (int)simple_strtoul(argv[1], &endp, 16);
|
||||
if (*endp != '\0' || id > 0xffff)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* file path */
|
||||
ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
|
||||
&file_path);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("Cannot create device path for \"%s %s\"\n",
|
||||
argv[3], argv[4]);
|
||||
sprintf(var_name, "Boot%04X", id);
|
||||
p = var_name16;
|
||||
utf8_utf16_strncpy(&p, var_name, 9);
|
||||
|
||||
/* label */
|
||||
label_len = strlen(argv[2]);
|
||||
label_len16 = utf8_utf16_strnlen(argv[2], label_len);
|
||||
label = malloc((label_len16 + 1) * sizeof(u16));
|
||||
if (!label)
|
||||
return CMD_RET_FAILURE;
|
||||
lo.label = label; /* label will be changed below */
|
||||
utf8_utf16_strncpy(&label, argv[2], label_len);
|
||||
|
||||
/* file path */
|
||||
ret = efi_dp_from_name(argv[3], argv[4], argv[5],
|
||||
&device_path, &file_path);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("Cannot create device path for \"%s %s\"\n",
|
||||
argv[3], argv[4]);
|
||||
r = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
fp_size += efi_dp_size(file_path) +
|
||||
sizeof(struct efi_device_path);
|
||||
argc -= 5;
|
||||
argv += 5;
|
||||
} else if (!strcmp(argv[0], "-i")) {
|
||||
if (argc < 3 || initrd_dp) {
|
||||
r = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3]);
|
||||
if (!initrd_dp) {
|
||||
printf("Cannot add an initrd\n");
|
||||
r = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
argc -= 3;
|
||||
argv += 3;
|
||||
fp_size += efi_dp_size(initrd_dp) +
|
||||
sizeof(struct efi_device_path);
|
||||
} else if (!strcmp(argv[0], "-s")) {
|
||||
if (argc < 1 || lo.optional_data) {
|
||||
r = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
lo.optional_data = (const u8 *)argv[1];
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
} else {
|
||||
r = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_path) {
|
||||
printf("Missing binary\n");
|
||||
r = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
final_fp = efi_dp_concat(file_path, initrd_dp);
|
||||
if (!final_fp) {
|
||||
printf("Cannot create final device path\n");
|
||||
r = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
lo.file_path = file_path;
|
||||
lo.file_path_length = efi_dp_size(file_path)
|
||||
+ sizeof(struct efi_device_path); /* for END */
|
||||
|
||||
/* optional data */
|
||||
if (argc == 6)
|
||||
lo.optional_data = NULL;
|
||||
else
|
||||
lo.optional_data = (const u8 *)argv[6];
|
||||
lo.file_path = final_fp;
|
||||
lo.file_path_length = fp_size;
|
||||
|
||||
size = efi_serialize_load_option(&lo, (u8 **)&data);
|
||||
if (!size) {
|
||||
|
@ -888,8 +1074,11 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
|
|||
printf("Cannot set %ls\n", var_name16);
|
||||
r = CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
out:
|
||||
free(data);
|
||||
efi_free_pool(final_fp);
|
||||
efi_free_pool(initrd_dp);
|
||||
efi_free_pool(device_path);
|
||||
efi_free_pool(file_path);
|
||||
free(lo.label);
|
||||
|
@ -955,11 +1144,14 @@ static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag,
|
|||
*/
|
||||
static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size)
|
||||
{
|
||||
struct efi_device_path *initrd_path = NULL;
|
||||
struct efi_load_option lo;
|
||||
char *label, *p;
|
||||
size_t label_len16, label_len;
|
||||
u16 *dp_str;
|
||||
efi_status_t ret;
|
||||
efi_uintn_t initrd_dp_size;
|
||||
const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
|
||||
|
||||
ret = efi_deserialize_load_option(&lo, data, size);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
|
@ -990,6 +1182,14 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size)
|
|||
printf(" file_path: %ls\n", dp_str);
|
||||
efi_free_pool(dp_str);
|
||||
|
||||
initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, lf2_initrd_guid);
|
||||
if (initrd_path) {
|
||||
dp_str = efi_dp_str(initrd_path);
|
||||
printf(" initrd_path: %ls\n", dp_str);
|
||||
efi_free_pool(dp_str);
|
||||
efi_free_pool(initrd_path);
|
||||
}
|
||||
|
||||
printf(" data:\n");
|
||||
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
lo.optional_data, *size, true);
|
||||
|
@ -1559,7 +1759,10 @@ static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
|
|||
static char efidebug_help_text[] =
|
||||
" - UEFI Shell-like interface to configure UEFI environment\n"
|
||||
"\n"
|
||||
"efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n"
|
||||
"efidebug boot add "
|
||||
"-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
|
||||
"-i <interface> <devnum>[:<part>] <initrd file path> "
|
||||
"-s '<optional data>'\n"
|
||||
" - set UEFI BootXXXX variable\n"
|
||||
" <load options> will be passed to UEFI application\n"
|
||||
"efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
|
||||
|
@ -1580,6 +1783,10 @@ static char efidebug_help_text[] =
|
|||
" - show capsule information\n"
|
||||
"efidebug capsule result [<capsule result var>]\n"
|
||||
" - show a capsule update result\n"
|
||||
#ifdef CONFIG_EFI_ESRT
|
||||
"efidebug capsule esrt\n"
|
||||
" - print the ESRT\n"
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
"efidebug devices\n"
|
||||
|
@ -1603,7 +1810,7 @@ static char efidebug_help_text[] =
|
|||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
efidebug, 10, 0, do_efidebug,
|
||||
efidebug, CONFIG_SYS_MAXARGS, 0, do_efidebug,
|
||||
"Configure UEFI environment",
|
||||
efidebug_help_text
|
||||
);
|
||||
|
|
10
cmd/load.c
10
cmd/load.c
|
@ -11,12 +11,14 @@
|
|||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <cpu_func.h>
|
||||
#include <efi_loader.h>
|
||||
#include <env.h>
|
||||
#include <exports.h>
|
||||
#include <flash.h>
|
||||
#include <image.h>
|
||||
#include <s_record.h>
|
||||
#include <mapmem.h>
|
||||
#include <net.h>
|
||||
#include <exports.h>
|
||||
#include <s_record.h>
|
||||
#include <serial.h>
|
||||
#include <xyzModem.h>
|
||||
#include <asm/cache.h>
|
||||
|
@ -996,6 +998,10 @@ static ulong load_serial_ymodem(ulong offset, int mode)
|
|||
}
|
||||
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_CMD_BOOTEFI))
|
||||
efi_set_bootdev("Uart", "", "",
|
||||
map_sysmem(offset, 0), size);
|
||||
|
||||
} else {
|
||||
printf("%s\n", xyzModem_error(err));
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ to be pointing to the EFI System Partition which contains the capsule
|
|||
file. The BootNext, BootXXXX and OsIndications variables can be set
|
||||
using the following commands::
|
||||
|
||||
=> efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
|
||||
=> efidebug boot add -b 0 Boot0000 virtio 0:1 <capsule_file_name>
|
||||
=> efidebug boot next 0
|
||||
=> setenv -e -nv -bs -rt -v OsIndications =0x04
|
||||
=> saveenv
|
||||
|
@ -198,7 +198,7 @@ command line::
|
|||
3. Set the following environment and UEFI boot variables
|
||||
|
||||
=> setenv -e -nv -bs -rt -v OsIndications =0x04
|
||||
=> efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
|
||||
=> efidebug boot add -b 0 Boot0000 virtio 0:1 <capsule_file_name>
|
||||
=> efidebug boot next 0
|
||||
=> saveenv
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ Now in U-Boot install the keys on your board::
|
|||
|
||||
Set up boot parameters on your board::
|
||||
|
||||
efidebug boot add 1 HELLO mmc 0:1 /helloworld.efi.signed ""
|
||||
efidebug boot add -b 1 HELLO mmc 0:1 /helloworld.efi.signed ""
|
||||
|
||||
Now your board can run the signed image via the boot manager (see below).
|
||||
You can also try this sequence by running Pytest, test_efi_secboot,
|
||||
|
|
|
@ -87,7 +87,23 @@ static unsigned int dfu_polltimeout_sf(struct dfu_entity *dfu)
|
|||
|
||||
static void dfu_free_entity_sf(struct dfu_entity *dfu)
|
||||
{
|
||||
spi_flash_free(dfu->data.sf.dev);
|
||||
/*
|
||||
* In the DM case it is not necessary to free the SPI device.
|
||||
* For the non-DM case we must ensure that the the SPI device is only
|
||||
* freed once.
|
||||
*/
|
||||
if (!CONFIG_IS_ENABLED(DM_SPI_FLASH)) {
|
||||
struct spi_flash *dev = dfu->data.sf.dev;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
dfu->data.sf.dev = NULL;
|
||||
list_for_each_entry(dfu, &dfu_list, list) {
|
||||
if (dfu->data.sf.dev == dev)
|
||||
dfu->data.sf.dev = NULL;
|
||||
}
|
||||
spi_flash_free(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static struct spi_flash *parse_dev(char *devstr)
|
||||
|
|
|
@ -523,6 +523,7 @@ struct efi_device_path_acpi_path {
|
|||
# define DEVICE_PATH_SUB_TYPE_MSG_SCSI 0x02
|
||||
# define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05
|
||||
# define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b
|
||||
# define DEVICE_PATH_SUB_TYPE_MSG_UART 0x0e
|
||||
# define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f
|
||||
# define DEVICE_PATH_SUB_TYPE_MSG_SATA 0x12
|
||||
# define DEVICE_PATH_SUB_TYPE_MSG_NVME 0x17
|
||||
|
@ -542,6 +543,15 @@ struct efi_device_path_scsi {
|
|||
u16 logical_unit_number;
|
||||
} __packed;
|
||||
|
||||
struct efi_device_path_uart {
|
||||
struct efi_device_path dp;
|
||||
u32 reserved;
|
||||
u64 baud_rate;
|
||||
u8 data_bits;
|
||||
u8 parity;
|
||||
u8 stop_bits;
|
||||
} __packed;
|
||||
|
||||
struct efi_device_path_usb {
|
||||
struct efi_device_path dp;
|
||||
u8 parent_port_number;
|
||||
|
@ -1722,6 +1732,23 @@ struct efi_load_file_protocol {
|
|||
void *buffer);
|
||||
};
|
||||
|
||||
struct efi_system_resource_entry {
|
||||
efi_guid_t fw_class;
|
||||
u32 fw_type;
|
||||
u32 fw_version;
|
||||
u32 lowest_supported_fw_version;
|
||||
u32 capsule_flags;
|
||||
u32 last_attempt_version;
|
||||
u32 last_attempt_status;
|
||||
} __packed;
|
||||
|
||||
struct efi_system_resource_table {
|
||||
u32 fw_resource_count;
|
||||
u32 fw_resource_count_max;
|
||||
u64 fw_resource_version;
|
||||
struct efi_system_resource_entry entries[];
|
||||
} __packed;
|
||||
|
||||
/* Boot manager load options */
|
||||
#define LOAD_OPTION_ACTIVE 0x00000001
|
||||
#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
|
||||
|
@ -1740,6 +1767,10 @@ struct efi_load_file_protocol {
|
|||
#define ESRT_FW_TYPE_DEVICEFIRMWARE 0x00000002
|
||||
#define ESRT_FW_TYPE_UEFIDRIVER 0x00000003
|
||||
|
||||
#define EFI_SYSTEM_RESOURCE_TABLE_GUID\
|
||||
EFI_GUID(0xb122a263, 0x3661, 0x4f68,\
|
||||
0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80)
|
||||
|
||||
/* Last Attempt Status Values */
|
||||
#define LAST_ATTEMPT_STATUS_SUCCESS 0x00000000
|
||||
#define LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL 0x00000001
|
||||
|
|
|
@ -214,6 +214,8 @@ extern const efi_guid_t efi_guid_rng_protocol;
|
|||
extern const efi_guid_t efi_guid_capsule_report;
|
||||
/* GUID of firmware management protocol */
|
||||
extern const efi_guid_t efi_guid_firmware_management_protocol;
|
||||
/* GUID for the ESRT */
|
||||
extern const efi_guid_t efi_esrt_guid;
|
||||
|
||||
extern unsigned int __efi_runtime_start, __efi_runtime_stop;
|
||||
extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
|
||||
|
@ -437,6 +439,7 @@ efi_status_t efi_net_register(void);
|
|||
/* Called by bootefi to make the watchdog available */
|
||||
efi_status_t efi_watchdog_register(void);
|
||||
efi_status_t efi_initrd_register(void);
|
||||
void efi_initrd_deregister(void);
|
||||
/* Called by bootefi to make SMBIOS tables available */
|
||||
/**
|
||||
* efi_acpi_register() - write out ACPI tables
|
||||
|
@ -558,6 +561,15 @@ struct efi_simple_file_system_protocol *efi_simple_file_system(
|
|||
/* open file from device-path: */
|
||||
struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
|
||||
|
||||
/* Registers a callback function for a notification event. */
|
||||
efi_status_t EFIAPI efi_register_protocol_notify(const efi_guid_t *protocol,
|
||||
struct efi_event *event,
|
||||
void **registration);
|
||||
efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size);
|
||||
|
||||
/* get a device path from a Boot#### option */
|
||||
struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid);
|
||||
|
||||
/**
|
||||
* efi_size_in_pages() - convert size in bytes to size in pages
|
||||
*
|
||||
|
@ -723,6 +735,8 @@ efi_status_t EFIAPI efi_query_variable_info(
|
|||
u64 *remaining_variable_storage_size,
|
||||
u64 *maximum_variable_size);
|
||||
|
||||
void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size);
|
||||
|
||||
/*
|
||||
* See section 3.1.3 in the v2.7 UEFI spec for more details on
|
||||
* the layout of EFI_LOAD_OPTION. In short it is:
|
||||
|
@ -744,6 +758,10 @@ struct efi_load_option {
|
|||
const u8 *optional_data;
|
||||
};
|
||||
|
||||
struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
|
||||
efi_uintn_t *size, efi_guid_t guid);
|
||||
struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
|
||||
const struct efi_device_path *dp2);
|
||||
efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
|
||||
efi_uintn_t *size);
|
||||
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
|
||||
|
@ -890,4 +908,22 @@ static inline efi_status_t efi_launch_capsules(void)
|
|||
|
||||
#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
|
||||
|
||||
/**
|
||||
* Install the ESRT system table.
|
||||
*
|
||||
* @return status code
|
||||
*/
|
||||
efi_status_t efi_esrt_register(void);
|
||||
|
||||
/**
|
||||
* efi_esrt_populate() - Populates the ESRT entries from the FMP instances
|
||||
* present in the system.
|
||||
* If an ESRT already exists, the old ESRT is replaced in the system table.
|
||||
* The memory of the old ESRT is deallocated.
|
||||
*
|
||||
* Return:
|
||||
* - EFI_SUCCESS if the ESRT is correctly created
|
||||
* - error code otherwise.
|
||||
*/
|
||||
efi_status_t efi_esrt_populate(void);
|
||||
#endif /* _EFI_LOADER_H */
|
||||
|
|
|
@ -66,11 +66,10 @@ enum efi_test_phase {
|
|||
*/
|
||||
EFI_SETUP_BEFORE_BOOTTIME_EXIT,
|
||||
/**
|
||||
* @EFI_SETUP_AFTER_BOOTTIME_EXIT: - setup after ExitBootServices
|
||||
*
|
||||
* Setup, execute, and teardown are executed after ExitBootServices().
|
||||
* @EFI_SETTING_VIRTUAL_ADDRESS_MAP - calls SetVirtualAddressMap()
|
||||
* Execute calls SetVirtualAddressMap().
|
||||
*/
|
||||
EFI_SETUP_AFTER_BOOTTIME_EXIT,
|
||||
EFI_SETTING_VIRTUAL_ADDRESS_MAP,
|
||||
};
|
||||
|
||||
extern struct efi_simple_text_output_protocol *con_out;
|
||||
|
|
|
@ -281,7 +281,7 @@ config EFI_HAVE_RUNTIME_RESET
|
|||
|
||||
config EFI_GRUB_ARM32_WORKAROUND
|
||||
bool "Workaround for GRUB on 32bit ARM"
|
||||
default n if ARCH_QEMU
|
||||
default n if ARCH_BCM283X || ARCH_SUNXI || ARCH_QEMU
|
||||
default y
|
||||
depends on ARM && !ARM64
|
||||
help
|
||||
|
@ -315,18 +315,13 @@ config EFI_TCG2_PROTOCOL_EVENTLOG_SIZE
|
|||
|
||||
config EFI_LOAD_FILE2_INITRD
|
||||
bool "EFI_FILE_LOAD2_PROTOCOL for Linux initial ramdisk"
|
||||
default n
|
||||
default y
|
||||
help
|
||||
Expose a EFI_FILE_LOAD2_PROTOCOL that the Linux UEFI stub can
|
||||
use to load the initial ramdisk. Once this is enabled using
|
||||
initrd=<ramdisk> will stop working.
|
||||
|
||||
config EFI_INITRD_FILESPEC
|
||||
string "initramfs path"
|
||||
default "host 0:1 initrd"
|
||||
depends on EFI_LOAD_FILE2_INITRD
|
||||
help
|
||||
Full path of the initramfs file, e.g. mmc 0:2 initramfs.cpio.gz.
|
||||
Linux v5.7 and later can make use of this option. If the boot option
|
||||
selected by the UEFI boot manager specifies an existing file to be used
|
||||
as initial RAM disk, a Linux specific Load File2 protocol will be
|
||||
installed and Linux 5.7+ will ignore any initrd=<ramdisk> command line
|
||||
argument.
|
||||
|
||||
config EFI_SECURE_BOOT
|
||||
bool "Enable EFI secure boot support"
|
||||
|
@ -347,4 +342,11 @@ config EFI_SECURE_BOOT
|
|||
it is signed with a trusted key. To do that, you need to install,
|
||||
at least, PK, KEK and db.
|
||||
|
||||
config EFI_ESRT
|
||||
bool "Enable the UEFI ESRT generation"
|
||||
depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
|
||||
default y
|
||||
help
|
||||
Enabling this option creates the ESRT UEFI system table.
|
||||
|
||||
endif
|
||||
|
|
|
@ -23,6 +23,7 @@ endif
|
|||
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
|
||||
obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
|
||||
obj-y += efi_boottime.o
|
||||
obj-y += efi_helper.o
|
||||
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
|
||||
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
|
||||
obj-y += efi_console.o
|
||||
|
@ -52,6 +53,7 @@ obj-y += efi_variable.o
|
|||
obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o
|
||||
endif
|
||||
obj-y += efi_watchdog.o
|
||||
obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
|
||||
obj-$(CONFIG_LCD) += efi_gop.o
|
||||
obj-$(CONFIG_DM_VIDEO) += efi_gop.o
|
||||
obj-$(CONFIG_PARTITIONS) += efi_disk.o
|
||||
|
|
|
@ -118,11 +118,13 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
|
|||
ret = efi_set_variable_int(L"BootCurrent",
|
||||
&efi_global_variable_guid,
|
||||
attributes, sizeof(n), &n, false);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
if (EFI_CALL(efi_unload_image(*handle))
|
||||
!= EFI_SUCCESS)
|
||||
log_err("Unloading image failed\n");
|
||||
goto error;
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto unload;
|
||||
/* try to register load file2 for initrd's */
|
||||
if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
|
||||
ret = efi_initrd_register();
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto unload;
|
||||
}
|
||||
|
||||
log_info("Booting: %ls\n", lo.label);
|
||||
|
@ -146,6 +148,13 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
|
|||
error:
|
||||
free(load_option);
|
||||
|
||||
return ret;
|
||||
|
||||
unload:
|
||||
if (EFI_CALL(efi_unload_image(*handle)) != EFI_SUCCESS)
|
||||
log_err("Unloading image failed\n");
|
||||
free(load_option);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1406,10 +1406,9 @@ out:
|
|||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_register_protocol_notify(
|
||||
const efi_guid_t *protocol,
|
||||
struct efi_event *event,
|
||||
void **registration)
|
||||
efi_status_t EFIAPI efi_register_protocol_notify(const efi_guid_t *protocol,
|
||||
struct efi_event *event,
|
||||
void **registration)
|
||||
{
|
||||
struct efi_register_notify_event *item;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
@ -1877,7 +1876,6 @@ static
|
|||
efi_status_t efi_load_image_from_file(struct efi_device_path *file_path,
|
||||
void **buffer, efi_uintn_t *size)
|
||||
{
|
||||
struct efi_file_info *info = NULL;
|
||||
struct efi_file_handle *f;
|
||||
efi_status_t ret;
|
||||
u64 addr;
|
||||
|
@ -1888,18 +1886,7 @@ efi_status_t efi_load_image_from_file(struct efi_device_path *file_path,
|
|||
if (!f)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
/* Get file size */
|
||||
bs = 0;
|
||||
EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid,
|
||||
&bs, info));
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
ret = EFI_DEVICE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
info = malloc(bs);
|
||||
EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs,
|
||||
info));
|
||||
ret = efi_file_size(f, &bs);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto error;
|
||||
|
||||
|
@ -1909,7 +1896,6 @@ efi_status_t efi_load_image_from_file(struct efi_device_path *file_path,
|
|||
* allocate a buffer as EFI_BOOT_SERVICES_DATA. The caller has to
|
||||
* update the reservation according to the image type.
|
||||
*/
|
||||
bs = info->file_size;
|
||||
ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
||||
EFI_BOOT_SERVICES_DATA,
|
||||
efi_size_in_pages(bs), &addr);
|
||||
|
@ -1926,7 +1912,6 @@ efi_status_t efi_load_image_from_file(struct efi_device_path *file_path,
|
|||
*size = bs;
|
||||
error:
|
||||
EFI_CALL(f->close(f));
|
||||
free(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -449,7 +449,7 @@ efi_status_t EFIAPI efi_update_capsule(
|
|||
unsigned int i;
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_ENTRY("%p, %lu, %llu\n", capsule_header_array, capsule_count,
|
||||
EFI_ENTRY("%p, %zu, %llu\n", capsule_header_array, capsule_count,
|
||||
scatter_gather_list);
|
||||
|
||||
if (!capsule_count) {
|
||||
|
@ -482,6 +482,14 @@ efi_status_t EFIAPI efi_update_capsule(
|
|||
goto out;
|
||||
}
|
||||
out:
|
||||
|
||||
if (IS_ENABLED(CONFIG_EFI_ESRT)) {
|
||||
/* Rebuild the ESRT to reflect any updated FW images. */
|
||||
ret = efi_esrt_populate();
|
||||
if (ret != EFI_SUCCESS)
|
||||
log_warning("EFI Capsule: failed to update ESRT\n");
|
||||
}
|
||||
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
|
@ -509,7 +517,7 @@ efi_status_t EFIAPI efi_query_capsule_caps(
|
|||
unsigned int i;
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_ENTRY("%p, %lu, %p, %p\n", capsule_header_array, capsule_count,
|
||||
EFI_ENTRY("%p, %zu, %p, %p\n", capsule_header_array, capsule_count,
|
||||
maximum_capsule_size, reset_type);
|
||||
|
||||
if (!maximum_capsule_size) {
|
||||
|
|
|
@ -254,7 +254,7 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
|
|||
}
|
||||
|
||||
/**
|
||||
* query_console_serial() - query console size
|
||||
* query_console_serial() - query serial console size
|
||||
*
|
||||
* When using a serial console or the net console we can only devise the
|
||||
* terminal size by querying the terminal using ECMA-48 control sequences.
|
||||
|
@ -299,6 +299,37 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* query_vidconsole() - query video console size
|
||||
*
|
||||
*
|
||||
* @rows: pointer to return number of rows
|
||||
* @cols: pointer to return number of columns
|
||||
* Returns: 0 on success
|
||||
*/
|
||||
static int __maybe_unused query_vidconsole(int *rows, int *cols)
|
||||
{
|
||||
const char *stdout_name = env_get("stdout");
|
||||
struct stdio_dev *stdout_dev;
|
||||
struct udevice *dev;
|
||||
struct vidconsole_priv *priv;
|
||||
|
||||
if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
|
||||
return -ENODEV;
|
||||
stdout_dev = stdio_get_by_name("vidconsole");
|
||||
if (!stdout_dev)
|
||||
return -ENODEV;
|
||||
dev = stdout_dev->priv;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
priv = dev_get_uclass_priv(dev);
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
*rows = priv->rows;
|
||||
*cols = priv->cols;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* query_console_size() - update the mode table.
|
||||
*
|
||||
|
@ -308,21 +339,15 @@ out:
|
|||
*/
|
||||
static void query_console_size(void)
|
||||
{
|
||||
const char *stdout_name = env_get("stdout");
|
||||
int rows = 25, cols = 80;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (stdout_name && !strncmp(stdout_name, "vidconsole", 10) &&
|
||||
IS_ENABLED(CONFIG_DM_VIDEO)) {
|
||||
struct stdio_dev *stdout_dev =
|
||||
stdio_get_by_name("vidconsole");
|
||||
struct udevice *dev = stdout_dev->priv;
|
||||
struct vidconsole_priv *priv =
|
||||
dev_get_uclass_priv(dev);
|
||||
rows = priv->rows;
|
||||
cols = priv->cols;
|
||||
} else if (query_console_serial(&rows, &cols)) {
|
||||
if IS_ENABLED(CONFIG_DM_VIDEO)
|
||||
ret = query_vidconsole(&rows, &cols);
|
||||
if (ret)
|
||||
ret = query_console_serial(&rows, &cols);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test if we can have Mode 1 */
|
||||
if (cols >= 80 && rows >= 50) {
|
||||
|
|
|
@ -282,11 +282,31 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
|
|||
return ndp;
|
||||
}
|
||||
|
||||
struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
|
||||
const struct efi_device_path *dp2)
|
||||
/**
|
||||
* efi_dp_append_or_concatenate() - Append or concatenate two device paths.
|
||||
* Concatenated device path will be separated
|
||||
* by a sub-type 0xff end node
|
||||
*
|
||||
* @dp1: First device path
|
||||
* @dp2: Second device path
|
||||
* @concat: If true the two device paths will be concatenated and separated
|
||||
* by an end of entrire device path sub-type 0xff end node.
|
||||
* If true the second device path will be appended to the first and
|
||||
* terminated by an end node
|
||||
*
|
||||
* Return:
|
||||
* concatenated device path or NULL. Caller must free the returned value
|
||||
*/
|
||||
static struct
|
||||
efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1,
|
||||
const struct efi_device_path *dp2,
|
||||
bool concat)
|
||||
{
|
||||
struct efi_device_path *ret;
|
||||
size_t end_size = sizeof(END);
|
||||
|
||||
if (concat)
|
||||
end_size = 2 * sizeof(END);
|
||||
if (!dp1 && !dp2) {
|
||||
/* return an end node */
|
||||
ret = efi_dp_dup(&END);
|
||||
|
@ -298,18 +318,58 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
|
|||
/* both dp1 and dp2 are non-null */
|
||||
unsigned sz1 = efi_dp_size(dp1);
|
||||
unsigned sz2 = efi_dp_size(dp2);
|
||||
void *p = dp_alloc(sz1 + sz2 + sizeof(END));
|
||||
void *p = dp_alloc(sz1 + sz2 + end_size);
|
||||
if (!p)
|
||||
return NULL;
|
||||
memcpy(p, dp1, sz1);
|
||||
/* the end node of the second device path has to be retained */
|
||||
memcpy(p + sz1, dp2, sz2 + sizeof(END));
|
||||
ret = p;
|
||||
memcpy(p, dp1, sz1);
|
||||
p += sz1;
|
||||
|
||||
if (concat) {
|
||||
memcpy(p, &END, sizeof(END));
|
||||
p += sizeof(END);
|
||||
}
|
||||
|
||||
/* the end node of the second device path has to be retained */
|
||||
memcpy(p, dp2, sz2);
|
||||
p += sz2;
|
||||
memcpy(p, &END, sizeof(END));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_dp_append() - Append a device to an existing device path.
|
||||
*
|
||||
* @dp1: First device path
|
||||
* @dp2: Second device path
|
||||
*
|
||||
* Return:
|
||||
* concatenated device path or NULL. Caller must free the returned value
|
||||
*/
|
||||
struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
|
||||
const struct efi_device_path *dp2)
|
||||
{
|
||||
return efi_dp_append_or_concatenate(dp1, dp2, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_dp_concat() - Concatenate 2 device paths. The final device path will
|
||||
* contain two device paths separated by and end node (0xff).
|
||||
*
|
||||
* @dp1: First device path
|
||||
* @dp2: Second device path
|
||||
*
|
||||
* Return:
|
||||
* concatenated device path or NULL. Caller must free the returned value
|
||||
*/
|
||||
struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
|
||||
const struct efi_device_path *dp2)
|
||||
{
|
||||
return efi_dp_append_or_concatenate(dp1, dp2, true);
|
||||
}
|
||||
|
||||
struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
|
||||
const struct efi_device_path *node)
|
||||
{
|
||||
|
@ -960,6 +1020,28 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
|
|||
return start;
|
||||
}
|
||||
|
||||
struct efi_device_path *efi_dp_from_uart(void)
|
||||
{
|
||||
void *buf, *pos;
|
||||
struct efi_device_path_uart *uart;
|
||||
size_t dpsize = sizeof(ROOT) + sizeof(*uart) + sizeof(END);
|
||||
|
||||
buf = dp_alloc(dpsize);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
pos = buf;
|
||||
memcpy(pos, &ROOT, sizeof(ROOT));
|
||||
pos += sizeof(ROOT);
|
||||
uart = pos;
|
||||
uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
|
||||
uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;
|
||||
uart->dp.length = sizeof(*uart);
|
||||
pos += sizeof(*uart);
|
||||
memcpy(pos, &END, sizeof(END));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
struct efi_device_path *efi_dp_from_eth(void)
|
||||
{
|
||||
|
@ -1086,7 +1168,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
|
|||
struct efi_device_path **device,
|
||||
struct efi_device_path **file)
|
||||
{
|
||||
int is_net;
|
||||
struct blk_desc *desc = NULL;
|
||||
struct disk_partition fs_partition;
|
||||
int part = 0;
|
||||
|
@ -1096,8 +1177,15 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
|
|||
if (path && !file)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
is_net = !strcmp(dev, "Net");
|
||||
if (!is_net) {
|
||||
if (!strcmp(dev, "Net")) {
|
||||
#ifdef CONFIG_NET
|
||||
if (device)
|
||||
*device = efi_dp_from_eth();
|
||||
#endif
|
||||
} else if (!strcmp(dev, "Uart")) {
|
||||
if (device)
|
||||
*device = efi_dp_from_uart();
|
||||
} else {
|
||||
part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
|
||||
1);
|
||||
if (part < 0 || !desc)
|
||||
|
@ -1105,11 +1193,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
|
|||
|
||||
if (device)
|
||||
*device = efi_dp_from_part(desc, part);
|
||||
} else {
|
||||
#ifdef CONFIG_NET
|
||||
if (device)
|
||||
*device = efi_dp_from_eth();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!path)
|
||||
|
@ -1120,7 +1203,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
|
|||
s = filename;
|
||||
while ((s = strchr(s, '/')))
|
||||
*s++ = '\\';
|
||||
*file = efi_dp_from_file(is_net ? NULL : desc, part, filename);
|
||||
*file = efi_dp_from_file(desc, part, filename);
|
||||
|
||||
if (!*file)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
@ -1160,3 +1243,43 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp,
|
|||
dp = (const struct efi_device_path *)((const u8 *)dp + len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_dp_from_lo() - Get the instance of a VenMedia node in a
|
||||
* multi-instance device path that matches
|
||||
* a specific GUID. This kind of device paths
|
||||
* is found in Boot#### options describing an
|
||||
* initrd location
|
||||
*
|
||||
* @lo: EFI_LOAD_OPTION containing a valid device path
|
||||
* @size: size of the discovered device path
|
||||
* @guid: guid to search for
|
||||
*
|
||||
* Return:
|
||||
* device path including the VenMedia node or NULL.
|
||||
* Caller must free the returned value.
|
||||
*/
|
||||
struct
|
||||
efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
|
||||
efi_uintn_t *size, efi_guid_t guid)
|
||||
{
|
||||
struct efi_device_path *fp = lo->file_path;
|
||||
struct efi_device_path_vendor *vendor;
|
||||
int lo_len = lo->file_path_length;
|
||||
|
||||
for (; lo_len >= sizeof(struct efi_device_path);
|
||||
lo_len -= fp->length, fp = (void *)fp + fp->length) {
|
||||
if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
|
||||
break;
|
||||
if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
|
||||
fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH)
|
||||
continue;
|
||||
|
||||
vendor = (struct efi_device_path_vendor *)fp;
|
||||
if (!guidcmp(&vendor->guid, &guid))
|
||||
return efi_dp_dup(fp);
|
||||
}
|
||||
log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,19 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
|
|||
ide->logical_unit_number);
|
||||
break;
|
||||
}
|
||||
case DEVICE_PATH_SUB_TYPE_MSG_UART: {
|
||||
struct efi_device_path_uart *uart =
|
||||
(struct efi_device_path_uart *)dp;
|
||||
s += sprintf(s, "Uart(%lld,%d,%d,", uart->baud_rate,
|
||||
uart->data_bits, uart->parity);
|
||||
switch (uart->stop_bits) {
|
||||
case 2:
|
||||
s += sprintf(s, "1.5)");
|
||||
default:
|
||||
s += sprintf(s, "%d)", uart->stop_bits);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DEVICE_PATH_SUB_TYPE_MSG_USB: {
|
||||
struct efi_device_path_usb *udp =
|
||||
(struct efi_device_path_usb *)dp;
|
||||
|
|
|
@ -61,7 +61,7 @@ void efi_carve_out_dt_rsv(void *fdt)
|
|||
for (i = 0; i < nr_rsv; i++) {
|
||||
if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
|
||||
continue;
|
||||
efi_reserve_memory(addr, size, false);
|
||||
efi_reserve_memory(addr, size, true);
|
||||
}
|
||||
|
||||
/* process reserved-memory */
|
||||
|
|
510
lib/efi_loader/efi_esrt.c
Normal file
510
lib/efi_loader/efi_esrt.c
Normal file
|
@ -0,0 +1,510 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* EFI application ESRT tables support
|
||||
*
|
||||
* Copyright (C) 2021 Arm Ltd.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <log.h>
|
||||
#include <efi_api.h>
|
||||
#include <malloc.h>
|
||||
|
||||
const efi_guid_t efi_esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID;
|
||||
|
||||
static struct efi_system_resource_table *esrt;
|
||||
|
||||
#define EFI_ESRT_VERSION 1
|
||||
|
||||
/**
|
||||
* efi_esrt_image_info_to_entry() - copy the information present in a fw image
|
||||
* descriptor to a ESRT entry.
|
||||
* The function ensures the ESRT entry matches the image_type_id in @img_info.
|
||||
* In case of a mismatch we leave the entry unchanged.
|
||||
*
|
||||
* @img_info: the source image info descriptor
|
||||
* @entry: pointer to the ESRT entry to be filled
|
||||
* @desc_version: the version of the elements in img_info
|
||||
* @image_type: the image type value to be set in the ESRT entry
|
||||
* @flags: the capsule flags value to be set in the ESRT entry
|
||||
*
|
||||
* Return:
|
||||
* - EFI_SUCCESS if the entry is correctly updated
|
||||
* - EFI_INVALID_PARAMETER if entry does not match image_type_id in @img_info.
|
||||
*/
|
||||
static efi_status_t
|
||||
efi_esrt_image_info_to_entry(struct efi_firmware_image_descriptor *img_info,
|
||||
struct efi_system_resource_entry *entry,
|
||||
u32 desc_version, u32 image_type, u32 flags)
|
||||
{
|
||||
if (guidcmp(&entry->fw_class, &img_info->image_type_id)) {
|
||||
EFI_PRINT("ESRT entry %pUL mismatches img_type_id %pUL\n",
|
||||
&entry->fw_class, &img_info->image_type_id);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
entry->fw_version = img_info->version;
|
||||
|
||||
entry->fw_type = image_type;
|
||||
entry->capsule_flags = flags;
|
||||
|
||||
/*
|
||||
* The field lowest_supported_image_version is only present
|
||||
* on image info structure of version 2 or greater.
|
||||
* See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
|
||||
*/
|
||||
if (desc_version >= 2)
|
||||
entry->lowest_supported_fw_version =
|
||||
img_info->lowest_supported_image_version;
|
||||
else
|
||||
entry->lowest_supported_fw_version = 0;
|
||||
|
||||
/*
|
||||
* The fields last_attempt_version and last_attempt_status
|
||||
* are only present on image info structure of version 3 or
|
||||
* greater.
|
||||
* See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
|
||||
*/
|
||||
if (desc_version >= 3) {
|
||||
entry->last_attempt_version =
|
||||
img_info->last_attempt_version;
|
||||
|
||||
entry->last_attempt_status =
|
||||
img_info->last_attempt_status;
|
||||
} else {
|
||||
entry->last_attempt_version = 0;
|
||||
entry->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_esrt_entries_to_size() - Obtain the bytes used by an ESRT
|
||||
* datastructure with @num_entries.
|
||||
*
|
||||
* @num_entries: the number of entries in the ESRT.
|
||||
*
|
||||
* Return: the number of bytes an ESRT with @num_entries occupies in memory.
|
||||
*/
|
||||
static
|
||||
inline u32 efi_esrt_entries_to_size(u32 num_entries)
|
||||
{
|
||||
u32 esrt_size = sizeof(struct efi_system_resource_table) +
|
||||
num_entries * sizeof(struct efi_system_resource_entry);
|
||||
|
||||
return esrt_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_esrt_allocate_install() - Allocates @num_entries for the ESRT and
|
||||
* performs basic ESRT initialization.
|
||||
*
|
||||
* @num_entries: the number of entries that the ESRT will hold.
|
||||
*
|
||||
* Return:
|
||||
* - pointer to the ESRT if successful.
|
||||
* - NULL otherwise.
|
||||
*/
|
||||
static
|
||||
efi_status_t efi_esrt_allocate_install(u32 num_entries)
|
||||
{
|
||||
efi_status_t ret;
|
||||
struct efi_system_resource_table *new_esrt;
|
||||
u32 size = efi_esrt_entries_to_size(num_entries);
|
||||
efi_guid_t esrt_guid = efi_esrt_guid;
|
||||
|
||||
/* Reserve num_pages for ESRT */
|
||||
ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size,
|
||||
(void **)&new_esrt);
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT cannot allocate memory for %d entries (%d bytes)\n",
|
||||
num_entries, efi_esrt_entries_to_size(num_entries));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_esrt->fw_resource_count_max = num_entries;
|
||||
new_esrt->fw_resource_count = 0;
|
||||
new_esrt->fw_resource_version = EFI_ESRT_VERSION;
|
||||
|
||||
/* Install the ESRT in the system configuration table. */
|
||||
ret = efi_install_configuration_table(&esrt_guid, (void *)new_esrt);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to install the ESRT in the system table\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If there was a previous ESRT, deallocate its memory now. */
|
||||
if (esrt)
|
||||
ret = EFI_CALL(efi_free_pool(esrt));
|
||||
|
||||
esrt = new_esrt;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* esrt_find_entry() - Obtain the ESRT entry for the image with GUID
|
||||
* @img_fw_class.
|
||||
*
|
||||
* If the img_fw_class is not yet present in the ESRT, this function
|
||||
* reserves the tail element of the current ESRT as the entry for that fw_class.
|
||||
* The number of elements in the ESRT is updated in that case.
|
||||
*
|
||||
* @img_fw_class: the GUID of the FW image which ESRT entry we want to obtain.
|
||||
*
|
||||
* Return:
|
||||
* - A pointer to the ESRT entry for the image with GUID img_fw_class,
|
||||
* - NULL if:
|
||||
* - there is no more space in the ESRT,
|
||||
* - ESRT is not initialized,
|
||||
*/
|
||||
static
|
||||
struct efi_system_resource_entry *esrt_find_entry(efi_guid_t *img_fw_class)
|
||||
{
|
||||
u32 filled_entries;
|
||||
u32 max_entries;
|
||||
struct efi_system_resource_entry *entry;
|
||||
|
||||
if (!esrt) {
|
||||
EFI_PRINT("ESRT access before initialized\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
filled_entries = esrt->fw_resource_count;
|
||||
entry = esrt->entries;
|
||||
|
||||
/* Check if the image with img_fw_class is already in the ESRT. */
|
||||
for (u32 idx = 0; idx < filled_entries; idx++) {
|
||||
if (!guidcmp(&entry[idx].fw_class, img_fw_class)) {
|
||||
EFI_PRINT("ESRT found entry for image %pUl at index %d\n",
|
||||
img_fw_class, idx);
|
||||
return &entry[idx];
|
||||
}
|
||||
}
|
||||
|
||||
max_entries = esrt->fw_resource_count_max;
|
||||
/*
|
||||
* Since the image with img_fw_class is not present in the ESRT, check
|
||||
* if ESRT is full before appending the new entry to it.
|
||||
*/
|
||||
if (filled_entries == max_entries) {
|
||||
EFI_PRINT("ESRT full, this should not happen\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a new entry for a fw image, increment the element
|
||||
* number in the table and set the fw_class field.
|
||||
*/
|
||||
esrt->fw_resource_count++;
|
||||
entry[filled_entries].fw_class = *img_fw_class;
|
||||
EFI_PRINT("ESRT allocated new entry for image %pUl at index %d\n",
|
||||
img_fw_class, filled_entries);
|
||||
|
||||
return &entry[filled_entries];
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_esrt_add_from_fmp() - Populates a sequence of ESRT entries from the FW
|
||||
* images in the FMP.
|
||||
*
|
||||
* @fmp: the FMP instance from which FW images are added to the ESRT
|
||||
*
|
||||
* Return:
|
||||
* - EFI_SUCCESS if all the FW images in the FMP are added to the ESRT
|
||||
* - Error status otherwise
|
||||
*/
|
||||
static
|
||||
efi_status_t efi_esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp)
|
||||
{
|
||||
struct efi_system_resource_entry *entry = NULL;
|
||||
size_t info_size = 0;
|
||||
struct efi_firmware_image_descriptor *img_info = NULL;
|
||||
u32 desc_version;
|
||||
u8 desc_count;
|
||||
size_t desc_size;
|
||||
u32 package_version;
|
||||
u16 *package_version_name;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
/*
|
||||
* TODO: set the field image_type depending on the FW image type
|
||||
* defined in a platform basis.
|
||||
*/
|
||||
u32 image_type = ESRT_FW_TYPE_UNKNOWN;
|
||||
|
||||
/* TODO: set the capsule flags as a function of the FW image type. */
|
||||
u32 flags = 0;
|
||||
|
||||
ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
|
||||
&desc_version, &desc_count,
|
||||
&desc_size, NULL, NULL));
|
||||
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
/*
|
||||
* An input of info_size=0 should always lead
|
||||
* fmp->get_image_info to return BUFFER_TO_SMALL.
|
||||
*/
|
||||
EFI_PRINT("Erroneous FMP implementation\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
ret = EFI_CALL(efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
|
||||
(void **)&img_info));
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to allocate memory for image info.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
|
||||
&desc_version, &desc_count,
|
||||
&desc_size, &package_version,
|
||||
&package_version_name));
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to obtain the FMP image info\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all the FW images in the FMP.
|
||||
*/
|
||||
for (u32 desc_idx = 0; desc_idx < desc_count; desc_idx++) {
|
||||
struct efi_firmware_image_descriptor *cur_img_info =
|
||||
(struct efi_firmware_image_descriptor *)
|
||||
((uintptr_t)img_info + desc_idx * desc_size);
|
||||
|
||||
/*
|
||||
* Obtain the ESRT entry for the FW image with fw_class
|
||||
* equal to cur_img_info->image_type_id.
|
||||
*/
|
||||
entry = esrt_find_entry(&cur_img_info->image_type_id);
|
||||
|
||||
if (entry) {
|
||||
ret = efi_esrt_image_info_to_entry(cur_img_info, entry,
|
||||
desc_version,
|
||||
image_type, flags);
|
||||
if (ret != EFI_SUCCESS)
|
||||
EFI_PRINT("ESRT entry mismatches image_type\n");
|
||||
|
||||
} else {
|
||||
EFI_PRINT("ESRT failed to add entry for %pUl\n",
|
||||
&cur_img_info->image_type_id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
EFI_CALL(efi_free_pool(img_info));
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_esrt_populate() - Populates the ESRT entries from the FMP instances
|
||||
* present in the system.
|
||||
* If an ESRT already exists, the old ESRT is replaced in the system table.
|
||||
* The memory of the old ESRT is deallocated.
|
||||
*
|
||||
* Return:
|
||||
* - EFI_SUCCESS if the ESRT is correctly created
|
||||
* - error code otherwise.
|
||||
*/
|
||||
efi_status_t efi_esrt_populate(void)
|
||||
{
|
||||
efi_handle_t *base_handle = NULL;
|
||||
efi_handle_t *it_handle;
|
||||
size_t no_handles = 0;
|
||||
struct efi_firmware_management_protocol *fmp;
|
||||
efi_status_t ret;
|
||||
u32 num_entries = 0;
|
||||
struct efi_handler *handler;
|
||||
|
||||
/*
|
||||
* Obtain the number of registered FMP handles.
|
||||
*/
|
||||
ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
|
||||
&efi_guid_firmware_management_protocol,
|
||||
NULL, &no_handles,
|
||||
(efi_handle_t **)&base_handle));
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT There are no FMP instances\n");
|
||||
|
||||
ret = efi_esrt_allocate_install(0);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to create table with 0 entries\n");
|
||||
return ret;
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_PRINT("ESRT populate esrt from (%ld) available FMP handles\n",
|
||||
no_handles);
|
||||
|
||||
/*
|
||||
* Iterate over all FMPs to determine an upper bound on the number of
|
||||
* ESRT entries.
|
||||
*/
|
||||
it_handle = base_handle;
|
||||
for (u32 idx = 0; idx < no_handles; idx++, it_handle++) {
|
||||
struct efi_firmware_image_descriptor *img_info = NULL;
|
||||
size_t info_size = 0;
|
||||
u32 desc_version = 0;
|
||||
u8 desc_count = 0;
|
||||
size_t desc_size = 0;
|
||||
u32 package_version;
|
||||
u16 *package_version_name;
|
||||
|
||||
ret = efi_search_protocol(*it_handle,
|
||||
&efi_guid_firmware_management_protocol,
|
||||
&handler);
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT Unable to find FMP handle (%d)\n",
|
||||
idx);
|
||||
goto out;
|
||||
}
|
||||
fmp = handler->protocol_interface;
|
||||
|
||||
ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, NULL,
|
||||
&desc_version, &desc_count,
|
||||
&desc_size, &package_version,
|
||||
&package_version_name));
|
||||
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
/*
|
||||
* An input of info_size=0 should always lead
|
||||
* fmp->get_image_info to return BUFFER_TO_SMALL.
|
||||
*/
|
||||
EFI_PRINT("ESRT erroneous FMP implementation\n");
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = EFI_CALL(efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
|
||||
(void **)&img_info));
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to allocate memory for image info\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls to a FMP get_image_info method do not return the
|
||||
* desc_count value if the return status differs from EFI_SUCCESS.
|
||||
* We need to repeat the call to get_image_info with a properly
|
||||
* sized buffer in order to obtain the real number of images
|
||||
* handled by the FMP.
|
||||
*/
|
||||
ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
|
||||
&desc_version, &desc_count,
|
||||
&desc_size, &package_version,
|
||||
&package_version_name));
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to obtain image info from FMP\n");
|
||||
EFI_CALL(efi_free_pool(img_info));
|
||||
goto out;
|
||||
}
|
||||
|
||||
num_entries += desc_count;
|
||||
|
||||
EFI_CALL(efi_free_pool(img_info));
|
||||
}
|
||||
|
||||
EFI_PRINT("ESRT create table with %d entries\n", num_entries);
|
||||
/*
|
||||
* Allocate an ESRT with the sufficient number of entries to accommodate
|
||||
* all the FMPs in the system.
|
||||
*/
|
||||
ret = efi_esrt_allocate_install(num_entries);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to initialize table\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate the ESRT entries with all existing FMP.
|
||||
*/
|
||||
it_handle = base_handle;
|
||||
for (u32 idx = 0; idx < no_handles; idx++, it_handle++) {
|
||||
ret = EFI_CALL(efi_search_protocol(*it_handle,
|
||||
&efi_guid_firmware_management_protocol,
|
||||
&handler));
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT unable to find FMP handle (%d)\n",
|
||||
idx);
|
||||
break;
|
||||
}
|
||||
fmp = handler->protocol_interface;
|
||||
|
||||
ret = efi_esrt_add_from_fmp(fmp);
|
||||
if (ret != EFI_SUCCESS)
|
||||
EFI_PRINT("ESRT failed to add FMP to the table\n");
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
EFI_CALL(efi_free_pool(base_handle));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_esrt_new_fmp_notify() - Callback for the EVT_NOTIFY_SIGNAL event raised
|
||||
* when a new FMP protocol instance is registered in the system.
|
||||
*/
|
||||
static void EFIAPI efi_esrt_new_fmp_notify(struct efi_event *event,
|
||||
void *context)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_ENTRY();
|
||||
|
||||
ret = efi_esrt_populate();
|
||||
if (ret != EFI_SUCCESS)
|
||||
EFI_PRINT("ESRT failed to populate ESRT entry\n");
|
||||
|
||||
EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_esrt_register() - Install the ESRT system table.
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_esrt_register(void)
|
||||
{
|
||||
struct efi_event *ev = NULL;
|
||||
void *registration;
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_PRINT("ESRT creation start\n");
|
||||
|
||||
ret = efi_esrt_populate();
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to initiate the table\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = EFI_CALL(efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
||||
efi_esrt_new_fmp_notify, NULL, NULL, &ev));
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to create event\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = EFI_CALL(efi_register_protocol_notify(&efi_guid_firmware_management_protocol,
|
||||
ev, ®istration));
|
||||
if (ret != EFI_SUCCESS) {
|
||||
EFI_PRINT("ESRT failed to register FMP callback\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
EFI_PRINT("ESRT table created\n");
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -409,6 +409,45 @@ static efi_status_t efi_get_file_size(struct file_handle *fh,
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_file_size() - Get the size of a file using an EFI file handle
|
||||
*
|
||||
* @fh: EFI file handle
|
||||
* @size: buffer to fill in the discovered size
|
||||
*
|
||||
* Return: size of the file
|
||||
*/
|
||||
efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size)
|
||||
{
|
||||
struct efi_file_info *info = NULL;
|
||||
efi_uintn_t bs = 0;
|
||||
efi_status_t ret;
|
||||
|
||||
*size = 0;
|
||||
ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs,
|
||||
info));
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
ret = EFI_DEVICE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = malloc(bs);
|
||||
if (!info) {
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs,
|
||||
info));
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
*size = info->file_size;
|
||||
|
||||
out:
|
||||
free(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
|
||||
void *buffer)
|
||||
{
|
||||
|
|
|
@ -299,7 +299,7 @@ efi_status_t EFIAPI efi_firmware_fit_set_image(
|
|||
efi_status_t (*progress)(efi_uintn_t completion),
|
||||
u16 **abort_reason)
|
||||
{
|
||||
EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
|
||||
EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
|
||||
image_size, vendor_code, progress, abort_reason);
|
||||
|
||||
if (!image || image_index != 1)
|
||||
|
@ -414,7 +414,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
|
|||
efi_status_t status;
|
||||
efi_uintn_t capsule_payload_size;
|
||||
|
||||
EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
|
||||
EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
|
||||
image_size, vendor_code, progress, abort_reason);
|
||||
|
||||
if (!image)
|
||||
|
|
98
lib/efi_loader/efi_helper.c
Normal file
98
lib/efi_loader/efi_helper.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2020, Linaro Limited
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_EFI
|
||||
#include <common.h>
|
||||
#include <env.h>
|
||||
#include <malloc.h>
|
||||
#include <dm.h>
|
||||
#include <fs.h>
|
||||
#include <efi_load_initrd.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_variable.h>
|
||||
|
||||
/**
|
||||
* efi_create_current_boot_var() - Return Boot#### name were #### is replaced by
|
||||
* the value of BootCurrent
|
||||
*
|
||||
* @var_name: variable name
|
||||
* @var_name_size: size of var_name
|
||||
*
|
||||
* Return: Status code
|
||||
*/
|
||||
static efi_status_t efi_create_current_boot_var(u16 var_name[],
|
||||
size_t var_name_size)
|
||||
{
|
||||
efi_uintn_t boot_current_size;
|
||||
efi_status_t ret;
|
||||
u16 boot_current;
|
||||
u16 *pos;
|
||||
|
||||
boot_current_size = sizeof(boot_current);
|
||||
ret = efi_get_variable_int(L"BootCurrent",
|
||||
&efi_global_variable_guid, NULL,
|
||||
&boot_current_size, &boot_current, NULL);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
pos = efi_create_indexed_name(var_name, var_name_size, "Boot",
|
||||
boot_current);
|
||||
if (!pos) {
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_get_dp_from_boot() - Retrieve and return a device path from an EFI
|
||||
* Boot### variable.
|
||||
* A boot option may contain an array of device paths.
|
||||
* We use a VenMedia() with a specific GUID to identify
|
||||
* the usage of the array members. This function is
|
||||
* used to extract a specific device path
|
||||
*
|
||||
* @guid: vendor GUID of the VenMedia() device path node identifying the
|
||||
* device path
|
||||
*
|
||||
* Return: device path or NULL. Caller must free the returned value
|
||||
*/
|
||||
struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid)
|
||||
{
|
||||
struct efi_device_path *file_path = NULL;
|
||||
struct efi_device_path *tmp = NULL;
|
||||
struct efi_load_option lo;
|
||||
void *var_value = NULL;
|
||||
efi_uintn_t size;
|
||||
efi_status_t ret;
|
||||
u16 var_name[16];
|
||||
|
||||
ret = efi_create_current_boot_var(var_name, sizeof(var_name));
|
||||
if (ret != EFI_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
var_value = efi_get_var(var_name, &efi_global_variable_guid, &size);
|
||||
if (!var_value)
|
||||
return NULL;
|
||||
|
||||
ret = efi_deserialize_load_option(&lo, var_value, &size);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
tmp = efi_dp_from_lo(&lo, &size, guid);
|
||||
if (!tmp)
|
||||
goto out;
|
||||
|
||||
/* efi_dp_dup will just return NULL if efi_dp_next is NULL */
|
||||
file_path = efi_dp_dup(efi_dp_next(tmp));
|
||||
|
||||
out:
|
||||
efi_free_pool(tmp);
|
||||
free(var_value);
|
||||
|
||||
return file_path;
|
||||
}
|
|
@ -3,9 +3,11 @@
|
|||
* Copyright (c) 2020, Linaro Limited
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_EFI
|
||||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_load_initrd.h>
|
||||
#include <efi_variable.h>
|
||||
#include <fs.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
|
@ -23,57 +25,56 @@ static const struct efi_load_file_protocol efi_lf2_protocol = {
|
|||
* Device path defined by Linux to identify the handle providing the
|
||||
* EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
|
||||
*/
|
||||
static const struct efi_initrd_dp dp = {
|
||||
static const struct efi_initrd_dp dp_lf2_handle = {
|
||||
.vendor = {
|
||||
{
|
||||
DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||||
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
|
||||
sizeof(dp.vendor),
|
||||
sizeof(dp_lf2_handle.vendor),
|
||||
},
|
||||
EFI_INITRD_MEDIA_GUID,
|
||||
},
|
||||
.end = {
|
||||
DEVICE_PATH_TYPE_END,
|
||||
DEVICE_PATH_SUB_TYPE_END,
|
||||
sizeof(dp.end),
|
||||
sizeof(dp_lf2_handle.end),
|
||||
}
|
||||
};
|
||||
|
||||
static efi_handle_t efi_initrd_handle;
|
||||
|
||||
/**
|
||||
* get_file_size() - retrieve the size of initramfs, set efi status on error
|
||||
* get_initrd_fp() - Get initrd device path from a FilePathList device path
|
||||
*
|
||||
* @dev: device to read from, e.g. "mmc"
|
||||
* @part: device partition, e.g. "0:1"
|
||||
* @file: name of file
|
||||
* @status: EFI exit code in case of failure
|
||||
* @initrd_fp: the final initrd filepath
|
||||
*
|
||||
* Return: size of file
|
||||
* Return: status code. Caller must free initrd_fp
|
||||
*/
|
||||
static loff_t get_file_size(const char *dev, const char *part, const char *file,
|
||||
efi_status_t *status)
|
||||
static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp)
|
||||
{
|
||||
loff_t sz = 0;
|
||||
int ret;
|
||||
const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
|
||||
struct efi_device_path *dp = NULL;
|
||||
|
||||
ret = fs_set_blk_dev(dev, part, FS_TYPE_ANY);
|
||||
if (ret) {
|
||||
*status = EFI_NO_MEDIA;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* if bootmgr is setup with and initrd, the device path will be
|
||||
* in the FilePathList[] of our load options in Boot####.
|
||||
* The first device path of the multi instance device path will
|
||||
* start with a VenMedia and the initrds will follow.
|
||||
*
|
||||
* If the device path is not found return EFI_INVALID_PARAMETER.
|
||||
* We can then use this specific return value and not install the
|
||||
* protocol, while allowing the boot to continue
|
||||
*/
|
||||
dp = efi_get_dp_from_boot(lf2_initrd_guid);
|
||||
if (!dp)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
ret = fs_size(file, &sz);
|
||||
if (ret) {
|
||||
sz = 0;
|
||||
*status = EFI_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return sz;
|
||||
*initrd_fp = dp;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_load_file2initrd() - load initial RAM disk
|
||||
* efi_load_file2_initrd() - load initial RAM disk
|
||||
*
|
||||
* This function implements the LoadFile service of the EFI_LOAD_FILE2_PROTOCOL
|
||||
* in order to load an initial RAM disk requested by the Linux kernel stub.
|
||||
|
@ -93,102 +94,125 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
|
|||
struct efi_device_path *file_path, bool boot_policy,
|
||||
efi_uintn_t *buffer_size, void *buffer)
|
||||
{
|
||||
char *filespec;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
loff_t file_sz = 0, read_sz = 0;
|
||||
char *dev, *part, *file;
|
||||
char *pos;
|
||||
int ret;
|
||||
struct efi_device_path *initrd_fp = NULL;
|
||||
efi_status_t ret = EFI_NOT_FOUND;
|
||||
struct efi_file_handle *f = NULL;
|
||||
efi_uintn_t bs;
|
||||
|
||||
EFI_ENTRY("%p, %p, %d, %p, %p", this, file_path, boot_policy,
|
||||
buffer_size, buffer);
|
||||
|
||||
filespec = strdup(CONFIG_EFI_INITRD_FILESPEC);
|
||||
if (!filespec)
|
||||
goto out;
|
||||
pos = filespec;
|
||||
|
||||
if (!this || this != &efi_lf2_protocol ||
|
||||
!buffer_size) {
|
||||
status = EFI_INVALID_PARAMETER;
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (file_path->type != dp.end.type ||
|
||||
file_path->sub_type != dp.end.sub_type) {
|
||||
status = EFI_INVALID_PARAMETER;
|
||||
if (file_path->type != dp_lf2_handle.end.type ||
|
||||
file_path->sub_type != dp_lf2_handle.end.sub_type) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (boot_policy) {
|
||||
status = EFI_UNSUPPORTED;
|
||||
ret = EFI_UNSUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* expect a string with three space separated parts:
|
||||
*
|
||||
* * a block device type, e.g. "mmc"
|
||||
* * a device and partition identifier, e.g. "0:1"
|
||||
* * a file path on the block device, e.g. "/boot/initrd.cpio.gz"
|
||||
*/
|
||||
dev = strsep(&pos, " ");
|
||||
if (!dev)
|
||||
goto out;
|
||||
part = strsep(&pos, " ");
|
||||
if (!part)
|
||||
goto out;
|
||||
file = strsep(&pos, " ");
|
||||
if (!file)
|
||||
ret = get_initrd_fp(&initrd_fp);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
file_sz = get_file_size(dev, part, file, &status);
|
||||
if (!file_sz)
|
||||
/* Open file */
|
||||
f = efi_file_from_path(initrd_fp);
|
||||
if (!f) {
|
||||
log_err("Can't find initrd specified in Boot####\n");
|
||||
ret = EFI_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get file size */
|
||||
ret = efi_file_size(f, &bs);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
if (!buffer || *buffer_size < file_sz) {
|
||||
status = EFI_BUFFER_TOO_SMALL;
|
||||
*buffer_size = file_sz;
|
||||
if (!buffer || *buffer_size < bs) {
|
||||
ret = EFI_BUFFER_TOO_SMALL;
|
||||
*buffer_size = bs;
|
||||
} else {
|
||||
ret = fs_set_blk_dev(dev, part, FS_TYPE_ANY);
|
||||
if (ret) {
|
||||
status = EFI_NO_MEDIA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fs_read(file, map_to_sysmem(buffer), 0, *buffer_size,
|
||||
&read_sz);
|
||||
if (ret || read_sz != file_sz)
|
||||
goto out;
|
||||
*buffer_size = read_sz;
|
||||
|
||||
status = EFI_SUCCESS;
|
||||
ret = EFI_CALL(f->read(f, &bs, (void *)(uintptr_t)buffer));
|
||||
*buffer_size = bs;
|
||||
}
|
||||
|
||||
out:
|
||||
free(filespec);
|
||||
return EFI_EXIT(status);
|
||||
efi_free_pool(initrd_fp);
|
||||
if (f)
|
||||
EFI_CALL(f->close(f));
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_initrd() - Determine if the file defined as an initrd in Boot####
|
||||
* load_options device path is present
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t check_initrd(void)
|
||||
{
|
||||
struct efi_device_path *initrd_fp = NULL;
|
||||
struct efi_file_handle *f;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = get_initrd_fp(&initrd_fp);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If the file is not found, but the file path is set, return an error
|
||||
* and trigger the bootmgr fallback
|
||||
*/
|
||||
f = efi_file_from_path(initrd_fp);
|
||||
if (!f) {
|
||||
log_err("Can't find initrd specified in Boot####\n");
|
||||
ret = EFI_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
EFI_CALL(f->close(f));
|
||||
|
||||
out:
|
||||
efi_free_pool(initrd_fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_initrd_register() - create handle for loading initial RAM disk
|
||||
*
|
||||
* This function creates a new handle and installs a Linux specific vendor
|
||||
* device path and an EFI_LOAD_FILE_2_PROTOCOL. Linux uses the device path
|
||||
* device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path
|
||||
* to identify the handle and then calls the LoadFile service of the
|
||||
* EFI_LOAD_FILE_2_PROTOCOL to read the initial RAM disk.
|
||||
* EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk.
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_initrd_register(void)
|
||||
{
|
||||
efi_handle_t efi_initrd_handle = NULL;
|
||||
efi_status_t ret;
|
||||
|
||||
/*
|
||||
* Allow the user to continue if Boot#### file path is not set for
|
||||
* an initrd
|
||||
*/
|
||||
ret = check_initrd();
|
||||
if (ret == EFI_INVALID_PARAMETER)
|
||||
return EFI_SUCCESS;
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = EFI_CALL(efi_install_multiple_protocol_interfaces
|
||||
(&efi_initrd_handle,
|
||||
/* initramfs */
|
||||
&efi_guid_device_path, &dp,
|
||||
&efi_guid_device_path, &dp_lf2_handle,
|
||||
/* LOAD_FILE2 */
|
||||
&efi_guid_load_file2_protocol,
|
||||
(void *)&efi_lf2_protocol,
|
||||
|
@ -196,3 +220,17 @@ efi_status_t efi_initrd_register(void)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_initrd_deregister() - delete the handle for loading initial RAM disk
|
||||
*
|
||||
* This will delete the handle containing the Linux specific vendor device
|
||||
* path and EFI_LOAD_FILE2_PROTOCOL for loading an initrd
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
void efi_initrd_deregister(void)
|
||||
{
|
||||
efi_delete_handle(efi_initrd_handle);
|
||||
efi_initrd_handle = NULL;
|
||||
}
|
||||
|
|
|
@ -227,6 +227,12 @@ efi_status_t efi_init_obj_list(void)
|
|||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
if (IS_ENABLED(CONFIG_EFI_ESRT)) {
|
||||
ret = efi_esrt_register();
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
|
||||
ret = efi_tcg2_register();
|
||||
if (ret != EFI_SUCCESS)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <efi_loader.h>
|
||||
#include <efi_tcg2.h>
|
||||
#include <log.h>
|
||||
#include <version.h>
|
||||
#include <tpm-v2.h>
|
||||
#include <u-boot/sha1.h>
|
||||
#include <u-boot/sha256.h>
|
||||
|
@ -957,6 +958,23 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tcg2_uninit - remove the final event table and free efi memory on failures
|
||||
*/
|
||||
void tcg2_uninit(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
ret = efi_install_configuration_table(&efi_guid_final_events, NULL);
|
||||
if (ret != EFI_SUCCESS)
|
||||
log_err("Failed to delete final events config table\n");
|
||||
|
||||
efi_free_pool(event_log.buffer);
|
||||
event_log.buffer = NULL;
|
||||
efi_free_pool(event_log.final_buffer);
|
||||
event_log.final_buffer = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* create_final_event() - Create the final event and install the config
|
||||
* defined by the TCG EFI spec
|
||||
|
@ -983,10 +1001,6 @@ static efi_status_t create_final_event(void)
|
|||
event_log.final_pos = sizeof(*final_event);
|
||||
ret = efi_install_configuration_table(&efi_guid_final_events,
|
||||
final_event);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1041,6 +1055,40 @@ static efi_status_t efi_init_event_log(void)
|
|||
event_log.last_event_size = event_log.pos;
|
||||
|
||||
ret = create_final_event();
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
out:
|
||||
tcg2_uninit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_append_scrtm_version - Append an S-CRTM EV_S_CRTM_VERSION event on the
|
||||
* eventlog and extend the PCRs
|
||||
*
|
||||
* @dev: TPM device
|
||||
*
|
||||
* @Return: status code
|
||||
*/
|
||||
static efi_status_t efi_append_scrtm_version(struct udevice *dev)
|
||||
{
|
||||
struct tpml_digest_values digest_list;
|
||||
u8 ver[] = U_BOOT_VERSION_STRING;
|
||||
const int pcr_index = 0;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = tcg2_create_digest(ver, sizeof(ver), &digest_list);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = tcg2_pcr_extend(dev, pcr_index, &digest_list);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = tcg2_agile_log_append(pcr_index, EV_S_CRTM_VERSION, &digest_list,
|
||||
sizeof(ver), ver);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -1055,23 +1103,34 @@ out:
|
|||
*/
|
||||
efi_status_t efi_tcg2_register(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
struct udevice *dev;
|
||||
|
||||
ret = platform_get_tpm2_device(&dev);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
log_warning("Unable to find TPMv2 device\n");
|
||||
return EFI_SUCCESS;
|
||||
ret = EFI_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = efi_init_event_log();
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
goto fail;
|
||||
|
||||
ret = efi_append_scrtm_version(dev);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = efi_add_protocol(efi_root, &efi_guid_tcg2_protocol,
|
||||
(void *)&efi_tcg2_protocol);
|
||||
if (ret != EFI_SUCCESS)
|
||||
if (ret != EFI_SUCCESS) {
|
||||
log_err("Cannot install EFI_TCG2_PROTOCOL\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
fail:
|
||||
tcg2_uninit();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_variable.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum efi_secure_mode {
|
||||
EFI_MODE_SETUP,
|
||||
|
@ -343,3 +344,35 @@ enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
|
|||
}
|
||||
return EFI_AUTH_VAR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_get_var() - read value of an EFI variable
|
||||
*
|
||||
* @name: variable name
|
||||
* @start: vendor GUID
|
||||
* @size: size of allocated buffer
|
||||
*
|
||||
* Return: buffer with variable data or NULL
|
||||
*/
|
||||
void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
|
||||
{
|
||||
efi_status_t ret;
|
||||
void *buf = NULL;
|
||||
|
||||
*size = 0;
|
||||
ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
|
||||
if (ret == EFI_BUFFER_TOO_SMALL) {
|
||||
buf = malloc(*size);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
|
||||
}
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
free(buf);
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ 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
|
||||
obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_selftest_load_initrd.o
|
||||
obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_selftest_tcg2.o
|
||||
|
||||
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
|
||||
|
@ -72,6 +71,8 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy)
|
|||
obj-y += efi_selftest_block_device.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o
|
||||
|
||||
targets += \
|
||||
efi_miniapp_file_image_exception.h \
|
||||
efi_miniapp_file_image_exit.h \
|
||||
|
|
|
@ -160,7 +160,7 @@ static bool need_reset(const u16 *testname)
|
|||
if (testname && efi_st_strcmp_16_8(testname, test->name))
|
||||
continue;
|
||||
if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT ||
|
||||
test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT)
|
||||
test->phase == EFI_SETTING_VIRTUAL_ADDRESS_MAP)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -327,15 +327,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
|
|||
/* Execute mixed tests */
|
||||
efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
|
||||
EFI_ST_SETUP, &failures);
|
||||
efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP,
|
||||
EFI_ST_SETUP, &failures);
|
||||
|
||||
efi_st_exit_boot_services();
|
||||
|
||||
efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
|
||||
EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures);
|
||||
|
||||
/* Execute runtime tests */
|
||||
efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT,
|
||||
EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
|
||||
/* Execute test setting the virtual address map */
|
||||
efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP,
|
||||
EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
|
||||
&failures);
|
||||
|
||||
/* Give feedback */
|
||||
|
|
291
lib/efi_selftest/efi_selftest_esrt.c
Normal file
291
lib/efi_selftest/efi_selftest_esrt.c
Normal file
|
@ -0,0 +1,291 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Test ESRT tables support
|
||||
*
|
||||
* Copyright (C) 2021 Arm Ltd.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_selftest.h>
|
||||
|
||||
// This value must not exceed 255.
|
||||
// An FMP cannot contain more than 255 FW images.
|
||||
#define TEST_ESRT_NUM_ENTRIES 255
|
||||
|
||||
static
|
||||
struct efi_firmware_image_descriptor static_img_info[TEST_ESRT_NUM_ENTRIES];
|
||||
|
||||
static const struct efi_system_table *local_systable;
|
||||
|
||||
static efi_handle_t fmp_handle;
|
||||
|
||||
static const efi_guid_t efi_fmp_guid =
|
||||
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
|
||||
|
||||
static void efi_test_esrt_init_info(void)
|
||||
{
|
||||
for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) {
|
||||
static_img_info[idx].image_index = idx;
|
||||
|
||||
// Note: the 16 byte value present in
|
||||
// static_img_info[idx].image_type_id is not strictly a GUID.
|
||||
// The value is used for the sake of code testing.
|
||||
static_img_info[idx].image_type_id.b[0] = idx;
|
||||
|
||||
static_img_info[idx].image_id = 0;
|
||||
static_img_info[idx].image_id_name = NULL;
|
||||
static_img_info[idx].version = 0;
|
||||
static_img_info[idx].version_name = NULL;
|
||||
static_img_info[idx].size = 0;
|
||||
static_img_info[idx].lowest_supported_image_version = 1;
|
||||
static_img_info[idx].last_attempt_version = 2;
|
||||
static_img_info[idx].last_attempt_status = 3;
|
||||
static_img_info[idx].hardware_instance = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this,
|
||||
efi_uintn_t *image_info_size,
|
||||
struct efi_firmware_image_descriptor *image_info,
|
||||
u32 *descriptor_version,
|
||||
u8 *descriptor_count,
|
||||
efi_uintn_t *descriptor_size,
|
||||
u32 *package_version,
|
||||
u16 **package_version_name)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
if (!image_info_size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
if (descriptor_version)
|
||||
*descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
|
||||
if (descriptor_count)
|
||||
*descriptor_count = TEST_ESRT_NUM_ENTRIES;
|
||||
if (descriptor_size)
|
||||
*descriptor_size = sizeof(*image_info);
|
||||
if (package_version)
|
||||
*package_version = 0xffffffff;
|
||||
if (package_version_name)
|
||||
*package_version_name = NULL;
|
||||
|
||||
if (*image_info_size < sizeof(*image_info)) {
|
||||
*image_info_size = *descriptor_size * *descriptor_count;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
|
||||
image_info[idx] = static_img_info[idx];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct efi_firmware_management_protocol efi_test_fmp = {
|
||||
.get_image_info = efi_test_fmp_get_image_info,
|
||||
.get_image = NULL,
|
||||
.set_image = NULL,
|
||||
.check_image = NULL,
|
||||
.get_package_info = NULL,
|
||||
.set_package_info = NULL,
|
||||
};
|
||||
|
||||
static void *lib_test_get_esrt(void)
|
||||
{
|
||||
for (int idx = 0; idx < local_systable->nr_tables; idx++)
|
||||
if (!guidcmp(&efi_esrt_guid, &local_systable->tables[idx].guid))
|
||||
return local_systable->tables[idx].table;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* lib_test_check_uuid_entry: Find an ESRT entry for which the fw_calss field matches
|
||||
* the image_type_id in the @img_info.
|
||||
* Ensure that all of the field in the ESRT entry have the same value as the corresponding
|
||||
* fields in the @img_info.
|
||||
*
|
||||
* @esrt: pointer to the ESRT
|
||||
* @img_info: an image_info_descriptor output by the FMP get_image_info
|
||||
*
|
||||
* @return: true if matching ESRT entry is found and if all the ESRT entry fields match the
|
||||
* corresponding @img_info fields.
|
||||
*/
|
||||
static bool lib_test_check_uuid_entry(struct efi_system_resource_table *esrt,
|
||||
struct efi_firmware_image_descriptor
|
||||
*img_info)
|
||||
{
|
||||
const u32 filled_entries = esrt->fw_resource_count;
|
||||
struct efi_system_resource_entry *entry = esrt->entries;
|
||||
|
||||
for (u32 idx = 0; idx < filled_entries; idx++) {
|
||||
if (!guidcmp(&entry[idx].fw_class, &img_info->image_type_id)) {
|
||||
if (entry[idx].fw_version != img_info->version) {
|
||||
efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
|
||||
&img_info->image_type_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry[idx].lowest_supported_fw_version !=
|
||||
img_info->lowest_supported_image_version) {
|
||||
efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
|
||||
&img_info->image_type_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry[idx].last_attempt_version !=
|
||||
img_info->last_attempt_version) {
|
||||
efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
|
||||
&img_info->image_type_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry[idx].last_attempt_status !=
|
||||
img_info->last_attempt_status) {
|
||||
efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
|
||||
&img_info->image_type_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The entry with fw_class = img_uuid matches with the
|
||||
* remainder fmp input.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* There exists no entry with fw_class equal to img_uuid in the ESRT. */
|
||||
efi_st_error("ESRT no entry with fw_class= %pUl\n", &img_info->image_type_id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup unit test.
|
||||
*
|
||||
* Initialize the test FMP datastructure.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
local_systable = systable;
|
||||
|
||||
efi_test_esrt_init_info();
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tear down unit test.
|
||||
*
|
||||
* Uninstall the test FMP.
|
||||
*
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int teardown(void)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
struct efi_boot_services *bt;
|
||||
|
||||
bt = local_systable->boottime;
|
||||
|
||||
if (!bt) {
|
||||
efi_st_error("Cannot find boottime services structure\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = bt->uninstall_multiple_protocol_interfaces
|
||||
(fmp_handle, &efi_fmp_guid,
|
||||
&efi_test_fmp, NULL);
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("Failed to uninstall FMP\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the test
|
||||
*
|
||||
* The test consists of the following steps:
|
||||
*
|
||||
* 1) Obtain the ESRT
|
||||
* 2) Record the number of ESRT entries prior to test start
|
||||
* 3) Install the test FMP
|
||||
* 4) Re-obtain the ESRT (the ESRT pointer may have changed with the FMP install)
|
||||
* 5) verify that the ESRT entries have increased by the number of entries in the
|
||||
* test FMP.
|
||||
* 6) Traverse all the elements used as the test FMP input and verify that each
|
||||
* has a corresponding ESRT entry and that the fields are correctly set.
|
||||
*
|
||||
* The failure of any of the above steps results in a test failure.
|
||||
*
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
struct efi_system_resource_table *esrt;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
u32 base_entry_count;
|
||||
u32 entry_delta;
|
||||
struct efi_boot_services *bt;
|
||||
|
||||
bt = local_systable->boottime;
|
||||
|
||||
if (!bt) {
|
||||
efi_st_error("Cannot find boottime services structure\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
esrt = lib_test_get_esrt();
|
||||
if (!esrt) {
|
||||
efi_st_error("ESRT table not present\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
base_entry_count = esrt->fw_resource_count;
|
||||
|
||||
ret = bt->install_multiple_protocol_interfaces(&fmp_handle,
|
||||
&efi_fmp_guid,
|
||||
&efi_test_fmp,
|
||||
NULL);
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("Failed to install FMP\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
esrt = lib_test_get_esrt();
|
||||
if (!esrt) {
|
||||
efi_st_error("ESRT table not present\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
entry_delta = esrt->fw_resource_count - base_entry_count;
|
||||
if (entry_delta != TEST_ESRT_NUM_ENTRIES) {
|
||||
efi_st_error("ESRT mismatch in new entry count (%d), expected (%d).\n",
|
||||
entry_delta, TEST_ESRT_NUM_ENTRIES);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
|
||||
if (!lib_test_check_uuid_entry(esrt, &static_img_info[idx])) {
|
||||
efi_st_error("ESRT entry mismatch\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(esrt) = {
|
||||
.name = "esrt",
|
||||
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
.teardown = teardown,
|
||||
};
|
|
@ -1,221 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* efi_selftest_load_initrd
|
||||
*
|
||||
* Copyright (c) 2020 Ilias Apalodimas <ilias.apalodimas@linaro.org>
|
||||
*
|
||||
* This test checks the FileLoad2 protocol.
|
||||
* A known file is read from the file system and verified.
|
||||
*
|
||||
* An example usage - given a file image with a file system in partition 1
|
||||
* holding file initrd - is:
|
||||
*
|
||||
* * Configure the sandbox with
|
||||
*
|
||||
* CONFIG_EFI_SELFTEST=y
|
||||
* CONFIG_EFI_LOAD_FILE2_INITRD=y
|
||||
* CONFIG_EFI_INITRD_FILESPEC="host 0:1 initrd"
|
||||
*
|
||||
* * Run ./u-boot and execute
|
||||
*
|
||||
* host bind 0 image
|
||||
* setenv efi_selftest load initrd
|
||||
* bootefi selftest
|
||||
*
|
||||
* This would provide a test output like:
|
||||
*
|
||||
* Testing EFI API implementation
|
||||
*
|
||||
* Selected test: 'load initrd'
|
||||
*
|
||||
* Setting up 'load initrd'
|
||||
* Setting up 'load initrd' succeeded
|
||||
*
|
||||
* Executing 'load initrd'
|
||||
* Loaded 12378613 bytes
|
||||
* CRC32 2997478465
|
||||
*
|
||||
* Now the size and CRC32 can be compared to the provided file.
|
||||
*/
|
||||
|
||||
#include <efi_selftest.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_load_initrd.h>
|
||||
|
||||
static struct efi_boot_services *boottime;
|
||||
|
||||
static struct efi_initrd_dp dp = {
|
||||
.vendor = {
|
||||
{
|
||||
DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||||
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
|
||||
sizeof(dp.vendor),
|
||||
},
|
||||
EFI_INITRD_MEDIA_GUID,
|
||||
},
|
||||
.end = {
|
||||
DEVICE_PATH_TYPE_END,
|
||||
DEVICE_PATH_SUB_TYPE_END,
|
||||
sizeof(dp.end),
|
||||
}
|
||||
};
|
||||
|
||||
static struct efi_initrd_dp dp_invalid = {
|
||||
.vendor = {
|
||||
{
|
||||
DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||||
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
|
||||
sizeof(dp.vendor),
|
||||
},
|
||||
EFI_INITRD_MEDIA_GUID,
|
||||
},
|
||||
.end = {
|
||||
0x8f, /* invalid */
|
||||
0xfe, /* invalid */
|
||||
sizeof(dp.end),
|
||||
}
|
||||
};
|
||||
|
||||
static int setup(const efi_handle_t handle,
|
||||
const struct efi_system_table *systable)
|
||||
{
|
||||
boottime = systable->boottime;
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int execute(void)
|
||||
{
|
||||
struct efi_load_file_protocol *lf2;
|
||||
struct efi_device_path *dp2, *dp2_invalid;
|
||||
efi_status_t status;
|
||||
efi_handle_t handle;
|
||||
char buffer[64];
|
||||
efi_uintn_t buffer_size;
|
||||
void *buf;
|
||||
u32 crc32;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
dp2 = (struct efi_device_path *)&dp;
|
||||
status = boottime->locate_device_path(&efi_guid_load_file2_protocol,
|
||||
&dp2, &handle);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_st_error("Unable to locate device path\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
status = boottime->handle_protocol(handle,
|
||||
&efi_guid_load_file2_protocol,
|
||||
(void **)&lf2);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_st_error("Unable to locate protocol\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/* Case 1:
|
||||
* buffer_size can't be NULL
|
||||
* protocol can't be NULL
|
||||
*/
|
||||
status = lf2->load_file(lf2, dp2, false, NULL, &buffer);
|
||||
if (status != EFI_INVALID_PARAMETER) {
|
||||
efi_st_error("Buffer size can't be NULL\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
buffer_size = sizeof(buffer);
|
||||
status = lf2->load_file(NULL, dp2, false, &buffer_size, &buffer);
|
||||
if (status != EFI_INVALID_PARAMETER) {
|
||||
efi_st_error("Protocol can't be NULL\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 2: Match end node type/sub-type on device path
|
||||
*/
|
||||
dp2_invalid = (struct efi_device_path *)&dp_invalid;
|
||||
buffer_size = sizeof(buffer);
|
||||
status = lf2->load_file(lf2, dp2_invalid, false, &buffer_size, &buffer);
|
||||
if (status != EFI_INVALID_PARAMETER) {
|
||||
efi_st_error("Invalid device path type must return EFI_INVALID_PARAMETER\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
status = lf2->load_file(lf2, dp2_invalid, false, &buffer_size, &buffer);
|
||||
if (status != EFI_INVALID_PARAMETER) {
|
||||
efi_st_error("Invalid device path sub-type must return EFI_INVALID_PARAMETER\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 3:
|
||||
* BootPolicy 'true' must return EFI_UNSUPPORTED
|
||||
*/
|
||||
buffer_size = sizeof(buffer);
|
||||
status = lf2->load_file(lf2, dp2, true, &buffer_size, &buffer);
|
||||
if (status != EFI_UNSUPPORTED) {
|
||||
efi_st_error("BootPolicy true must return EFI_UNSUPPORTED\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case: Pass buffer size as zero, firmware must return
|
||||
* EFI_BUFFER_TOO_SMALL and an appropriate size
|
||||
*/
|
||||
buffer_size = 0;
|
||||
status = lf2->load_file(lf2, dp2, false, &buffer_size, NULL);
|
||||
if (status != EFI_BUFFER_TOO_SMALL || !buffer_size) {
|
||||
efi_st_printf("buffer_size: %u\n", (unsigned int)buffer_size);
|
||||
efi_st_printf("status: %x\n", (unsigned int)status);
|
||||
efi_st_error("Buffer size not updated\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case: Pass buffer size as smaller than the file_size,
|
||||
* firmware must return * EFI_BUFFER_TOO_SMALL and an appropriate size
|
||||
*/
|
||||
buffer_size = 1;
|
||||
status = lf2->load_file(lf2, dp2, false, &buffer_size, &buffer);
|
||||
if (status != EFI_BUFFER_TOO_SMALL || buffer_size <= 1) {
|
||||
efi_st_error("Buffer size not updated\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
status = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size,
|
||||
&buf);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_st_error("Cannot allocate buffer\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/* Case: Pass correct buffer, load the file and verify checksum*/
|
||||
status = lf2->load_file(lf2, dp2, false, &buffer_size, buf);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_st_error("Loading initrd failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
efi_st_printf("Loaded %u bytes\n", (unsigned int)buffer_size);
|
||||
status = boottime->calculate_crc32(buf, buffer_size, &crc32);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_st_error("Could not determine CRC32\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
efi_st_printf("CRC32 %.8x\n", (unsigned int)crc32);
|
||||
|
||||
status = boottime->free_pool(buf);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_st_error("Cannot free buffer\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(load_initrd) = {
|
||||
.name = "load initrd",
|
||||
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
.on_request = true,
|
||||
};
|
|
@ -201,7 +201,7 @@ static int execute(void)
|
|||
|
||||
EFI_UNIT_TEST(virtaddrmap) = {
|
||||
.name = "virtual address map",
|
||||
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
|
||||
.phase = EFI_SETTING_VIRTUAL_ADDRESS_MAP,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
};
|
||||
|
|
|
@ -272,7 +272,7 @@ static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
|
|||
error(L"Out of memory\r\n");
|
||||
return ret;
|
||||
}
|
||||
*initrd = (void *)buffer;
|
||||
*initrd = (void *)(uintptr_t)buffer;
|
||||
ret = load_file2_prot->load_file(load_file2_prot, dp, false,
|
||||
initrd_size, *initrd);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestEfiCapsuleFirmwareFit(object):
|
|||
with u_boot_console.log.section('Test Case 1-a, before reboot'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'efidebug boot add 1 TEST host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot order 1',
|
||||
'env set -e OsIndications',
|
||||
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
|
||||
|
@ -114,7 +114,7 @@ class TestEfiCapsuleFirmwareFit(object):
|
|||
with u_boot_console.log.section('Test Case 2-a, before reboot'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'efidebug boot add 1 TEST host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot order 1',
|
||||
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
|
||||
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
|
||||
|
@ -188,7 +188,7 @@ class TestEfiCapsuleFirmwareFit(object):
|
|||
with u_boot_console.log.section('Test Case 3-a, before reboot'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'efidebug boot add 1 TEST host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot order 1',
|
||||
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
|
||||
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
|
||||
|
@ -229,6 +229,14 @@ class TestEfiCapsuleFirmwareFit(object):
|
|||
output = u_boot_console.run_command(
|
||||
'env print -e -all Capsule0000')
|
||||
|
||||
output = u_boot_console.run_command_list(['efidebug capsule esrt'])
|
||||
|
||||
# ensure that EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID is in the ESRT.
|
||||
assert 'AE13FF2D-9AD4-4E25-9AC8-6D80B3B22147' in ''.join(output)
|
||||
|
||||
# ensure that EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID is in the ESRT.
|
||||
assert 'E2BB9C06-70E9-4B14-97A3-5A7913176E3F' in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
|
||||
|
|
|
@ -28,7 +28,7 @@ class TestEfiSignedImage(object):
|
|||
# Test Case 1a, run signed image if no PK
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'efidebug boot add 1 HELLO1 host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot next 1',
|
||||
'bootefi bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
@ -36,7 +36,7 @@ class TestEfiSignedImage(object):
|
|||
with u_boot_console.log.section('Test Case 1b'):
|
||||
# Test Case 1b, run unsigned image if no PK
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 2 HELLO2 host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot next 2',
|
||||
'bootefi bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
@ -58,13 +58,13 @@ class TestEfiSignedImage(object):
|
|||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO1 host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert('\'HELLO1\' failed' in ''.join(output))
|
||||
assert('efi_start_image() returned: 26' in ''.join(output))
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 2 HELLO2 host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot next 2',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO2\' failed' in ''.join(output)
|
||||
|
@ -104,7 +104,7 @@ class TestEfiSignedImage(object):
|
|||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
|
@ -142,7 +142,7 @@ class TestEfiSignedImage(object):
|
|||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
|
@ -169,7 +169,7 @@ class TestEfiSignedImage(object):
|
|||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
@ -227,7 +227,7 @@ class TestEfiSignedImage(object):
|
|||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed ""',
|
||||
'efidebug boot next 1',
|
||||
'bootefi bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestEfiSignedImageIntca(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO_a host 0:1 /helloworld.efi.signed_a ""',
|
||||
'efidebug boot add -b 1 HELLO_a host 0:1 /helloworld.efi.signed_a ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO_a\' failed' in ''.join(output)
|
||||
|
@ -48,7 +48,7 @@ class TestEfiSignedImageIntca(object):
|
|||
with u_boot_console.log.section('Test Case 1b'):
|
||||
# Test Case 1b, signed and authenticated by root CA
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 2 HELLO_ab host 0:1 /helloworld.efi.signed_ab ""',
|
||||
'efidebug boot add -b 2 HELLO_ab host 0:1 /helloworld.efi.signed_ab ""',
|
||||
'efidebug boot next 2',
|
||||
'bootefi bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
@ -70,7 +70,7 @@ class TestEfiSignedImageIntca(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""',
|
||||
'efidebug boot add -b 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO_abc\' failed' in ''.join(output)
|
||||
|
@ -116,7 +116,7 @@ class TestEfiSignedImageIntca(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""',
|
||||
'efidebug boot add -b 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
|
|
@ -35,7 +35,7 @@ class TestEfiUnsignedImage(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot next 1',
|
||||
'bootefi bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
|
@ -64,7 +64,7 @@ class TestEfiUnsignedImage(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot next 1',
|
||||
'bootefi bootmgr'])
|
||||
assert 'Hello, world!' in ''.join(output)
|
||||
|
@ -88,7 +88,7 @@ class TestEfiUnsignedImage(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot next 1',
|
||||
'bootefi bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
|
@ -106,7 +106,7 @@ class TestEfiUnsignedImage(object):
|
|||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi ""',
|
||||
'efidebug boot next 1',
|
||||
'bootefi bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
|
|
Loading…
Add table
Reference in a new issue