diff options
author | Tom Rini <trini@konsulko.com> | 2019-05-03 07:10:17 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-05-03 07:10:17 -0400 |
commit | 6e25cfe9a475e8177bad7d9f97cffead6aab6b0d (patch) | |
tree | 2a74f7339892266a8d1d9afd812e9dad38ba0593 | |
parent | 3570ea1f98229dc8c166dfc2693510db9167f7f8 (diff) | |
parent | 4ccf678f37731d8ec09eae8dca5f4cbe84132a52 (diff) |
Merge tag 'efi-2019-07-rc2' of git://git.denx.de/u-boot-efi
Pull request for UEFI sub-system for v2019.07-rc2
This pull request provides error fixes for the handling of GPT partitions
and for the UEFI subsystem.
-rw-r--r-- | cmd/bootefi.c | 15 | ||||
-rw-r--r-- | cmd/efidebug.c | 106 | ||||
-rw-r--r-- | cmd/gpt.c | 12 | ||||
-rw-r--r-- | cmd/nvedit_efi.c | 5 | ||||
-rw-r--r-- | disk/part_efi.c | 6 | ||||
-rw-r--r-- | include/efi_loader.h | 7 | ||||
-rw-r--r-- | include/efi_selftest.h | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 15 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 57 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_setup.c | 11 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_miniapp_exit.c | 17 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_startimage_exit.c | 15 | ||||
-rw-r--r-- | lib/uuid.c | 2 |
14 files changed, 204 insertions, 68 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index efaa548be4..f1d7d8bc66 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -297,18 +297,21 @@ static efi_status_t efi_install_fdt(const char *fdt_opt) static efi_status_t do_bootefi_exec(efi_handle_t handle) { efi_status_t ret; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; /* Transfer environment variable as load options */ ret = set_load_options(handle, "bootargs"); if (ret != EFI_SUCCESS) return ret; - /* we don't support much: */ - env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported", - "{ro,boot}(blob)0000000000000000"); - /* Call our payload! */ - ret = EFI_CALL(efi_start_image(handle, NULL, NULL)); + ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data)); + printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); + if (ret && exit_data) { + printf("## %ls\n", exit_data); + efi_free_pool(exit_data); + } efi_restore_gd(); @@ -361,7 +364,6 @@ static int do_efibootmgr(const char *fdt_opt) } ret = do_bootefi_exec(handle); - printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; @@ -476,7 +478,6 @@ static int do_bootefi_image(const char *image_opt, const char *fdt_opt) goto out; ret = do_bootefi_exec(handle); - printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); out: if (mem_handle) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index a40c4f4be2..c4ac9dd634 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -11,6 +11,7 @@ #include <efi_loader.h> #include <environment.h> #include <exports.h> +#include <hexdump.h> #include <malloc.h> #include <search.h> #include <linux/ctype.h> @@ -545,7 +546,10 @@ static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, + sizeof(struct efi_device_path); /* for END */ /* optional data */ - lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]); + if (argc < 6) + lo.optional_data = NULL; + else + lo.optional_data = (const u8 *)argv[6]; size = efi_serialize_load_option(&lo, (u8 **)&data); if (!size) { @@ -615,12 +619,13 @@ static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag, /** * show_efi_boot_opt_data() - dump UEFI load option * - * @id: Load option number - * @data: Value of UEFI load option variable + * @id: load option number + * @data: value of UEFI load option variable + * @size: size of the boot option * * Decode the value of UEFI load option variable and print information. */ -static void show_efi_boot_opt_data(int id, void *data) +static void show_efi_boot_opt_data(int id, void *data, size_t size) { struct efi_load_option lo; char *label, *p; @@ -638,7 +643,7 @@ static void show_efi_boot_opt_data(int id, void *data) utf16_utf8_strncpy(&p, lo.label, label_len16); printf("Boot%04X:\n", id); - printf("\tattributes: %c%c%c (0x%08x)\n", + printf(" attributes: %c%c%c (0x%08x)\n", /* ACTIVE */ lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-', /* FORCE RECONNECT */ @@ -646,14 +651,16 @@ static void show_efi_boot_opt_data(int id, void *data) /* HIDDEN */ lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-', lo.attributes); - printf("\tlabel: %s\n", label); + printf(" label: %s\n", label); dp_str = efi_dp_str(lo.file_path); - printf("\tfile_path: %ls\n", dp_str); + printf(" file_path: %ls\n", dp_str); efi_free_pool(dp_str); - printf("\tdata: %s\n", lo.optional_data); - + printf(" data:\n"); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, + lo.optional_data, size + (u8 *)data - + (u8 *)lo.optional_data, true); free(label); } @@ -686,13 +693,24 @@ static void show_efi_boot_opt(int id) data)); } if (ret == EFI_SUCCESS) - show_efi_boot_opt_data(id, data); + show_efi_boot_opt_data(id, data, size); else if (ret == EFI_NOT_FOUND) printf("Boot%04X: not found\n", id); free(data); } +static int u16_tohex(u16 c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + /* not hexadecimal */ + return -1; +} + /** * show_efi_boot_dump() - dump all UEFI load options * @@ -709,38 +727,58 @@ static void show_efi_boot_opt(int id) static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - char regex[256]; - char * const regexlist[] = {regex}; - char *variables = NULL, *boot, *value; - int len; - int id; + u16 *var_name16, *p; + efi_uintn_t buf_size, size; + efi_guid_t guid; + int id, i, digit; + efi_status_t ret; if (argc > 1) return CMD_RET_USAGE; - snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+"); - - /* TODO: use GetNextVariableName? */ - len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, - &variables, 0, 1, regexlist); - - if (!len) - return CMD_RET_SUCCESS; - - if (len < 0) + buf_size = 128; + var_name16 = malloc(buf_size); + if (!var_name16) return CMD_RET_FAILURE; - boot = variables; - while (*boot) { - value = strstr(boot, "Boot") + 4; - id = (int)simple_strtoul(value, NULL, 16); - show_efi_boot_opt(id); - boot = strchr(boot, '\n'); - if (!*boot) + var_name16[0] = 0; + for (;;) { + size = buf_size; + ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16, + &guid)); + if (ret == EFI_NOT_FOUND) break; - boot++; + if (ret == EFI_BUFFER_TOO_SMALL) { + buf_size = size; + p = realloc(var_name16, buf_size); + if (!p) { + free(var_name16); + return CMD_RET_FAILURE; + } + var_name16 = p; + ret = EFI_CALL(efi_get_next_variable_name(&size, + var_name16, + &guid)); + } + if (ret != EFI_SUCCESS) { + free(var_name16); + return CMD_RET_FAILURE; + } + + if (memcmp(var_name16, L"Boot", 8)) + continue; + + for (id = 0, i = 0; i < 4; i++) { + digit = u16_tohex(var_name16[4 + i]); + if (digit < 0) + break; + id = (id << 4) + digit; + } + if (i == 4 && !var_name16[8]) + show_efi_boot_opt(id); } - free(variables); + + free(var_name16); return CMD_RET_SUCCESS; } @@ -876,21 +876,21 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " Example usage:\n" " gpt write mmc 0 $partitions\n" " gpt verify mmc 0 $partitions\n" - " read <interface> <dev>\n" - " - read GPT into a data structure for manipulation\n" - " guid <interface> <dev>\n" + " gpt guid <interface> <dev>\n" " - print disk GUID\n" - " guid <interface> <dev> <varname>\n" + " gpt guid <interface> <dev> <varname>\n" " - set environment variable to disk GUID\n" " Example usage:\n" " gpt guid mmc 0\n" " gpt guid mmc 0 varname\n" #ifdef CONFIG_CMD_GPT_RENAME "gpt partition renaming commands:\n" - "gpt swap <interface> <dev> <name1> <name2>\n" + " gpt read <interface> <dev>\n" + " - read GPT into a data structure for manipulation\n" + " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n" - "gpt rename <interface> <dev> <part> <name>\n" + " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index e65b38dbf3..2805e8182b 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -291,8 +291,11 @@ static int append_value(char **bufp, size_t *sizep, char *data) if (!tmp_buf) return -1; - if (hex2bin((u8 *)tmp_buf, data, len) < 0) + if (hex2bin((u8 *)tmp_buf, data, len) < 0) { + printf("Error: illegal hexadecimal string\n"); + free(tmp_buf); return -1; + } value = tmp_buf; } else { /* string */ diff --git a/disk/part_efi.c b/disk/part_efi.c index 239455b816..c0fa753339 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -209,6 +209,8 @@ int get_disk_guid(struct blk_desc * dev_desc, char *guid) guid_bin = gpt_head->disk_guid.b; uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID); + /* Remember to free pte */ + free(gpt_pte); return 0; } @@ -696,6 +698,10 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head, __func__); return -1; } + + /* Free pte before allocating again */ + free(*gpt_pte); + if (is_gpt_valid(dev_desc, (dev_desc->lba - 1), gpt_head, gpt_pte) != 1) { printf("%s: *** ERROR: Invalid Backup GPT ***\n", diff --git a/include/efi_loader.h b/include/efi_loader.h index 39ed8a6fa5..7af3f16ef8 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -207,12 +207,17 @@ struct efi_object { * struct efi_loaded_image_obj - handle of a loaded image * * @header: EFI object header + * @exit_status: exit status passed to Exit() + * @exit_data_size: exit data size passed to Exit() + * @exit_data: exit data passed to Exit() * @exit_jmp: long jump buffer for returning form started image * @entry: entry address of the relocated image */ struct efi_loaded_image_obj { struct efi_object header; efi_status_t exit_status; + efi_uintn_t *exit_data_size; + u16 **exit_data; struct jmp_buf_data exit_jmp; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); @@ -560,7 +565,7 @@ struct efi_load_option { u16 file_path_length; u16 *label; struct efi_device_path *file_path; - u8 *optional_data; + const u8 *optional_data; }; void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data); diff --git a/include/efi_selftest.h b/include/efi_selftest.h index 49d3d6d0b4..dd42e49023 100644 --- a/include/efi_selftest.h +++ b/include/efi_selftest.h @@ -16,7 +16,7 @@ #define EFI_ST_SUCCESS 0 #define EFI_ST_FAILURE 1 - +#define EFI_ST_SUCCESS_STR L"SUCCESS" /* * Prints a message. */ diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 4ccba22875..7bf51874c1 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -53,19 +53,20 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data) */ unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data) { - unsigned long label_len, option_len; + unsigned long label_len; unsigned long size; u8 *p; label_len = (u16_strlen(lo->label) + 1) * sizeof(u16); - option_len = strlen((char *)lo->optional_data); /* total size */ size = sizeof(lo->attributes); size += sizeof(lo->file_path_length); size += label_len; size += lo->file_path_length; - size += option_len + 1; + if (lo->optional_data) + size += (utf8_utf16_strlen((const char *)lo->optional_data) + + 1) * sizeof(u16); p = malloc(size); if (!p) return 0; @@ -84,10 +85,10 @@ unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data) memcpy(p, lo->file_path, lo->file_path_length); p += lo->file_path_length; - memcpy(p, lo->optional_data, option_len); - p += option_len; - *(char *)p = '\0'; - + if (lo->optional_data) { + utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data); + p += sizeof(u16); /* size of trailing \0 */ + } return size; } diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 601b0a2cb8..e5c46e9f08 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -423,10 +423,12 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) } /** - * efi_add_handle() - add a new object to the object list - * @obj: object to be added + * efi_add_handle() - add a new handle to the object list * - * The protocols list is initialized. The object handle is set. + * @handle: handle to be added + * + * The protocols list is initialized. The handle is added to the list of known + * UEFI objects. */ void efi_add_handle(efi_handle_t handle) { @@ -618,7 +620,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, } if ((type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) && - (is_valid_tpl(notify_tpl) != EFI_SUCCESS)) + (!notify_function || is_valid_tpl(notify_tpl) != EFI_SUCCESS)) return EFI_INVALID_PARAMETER; evt = calloc(1, sizeof(struct efi_event)); @@ -2626,6 +2628,9 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, efi_is_direct_boot = false; + image_obj->exit_data_size = exit_data_size; + image_obj->exit_data = exit_data; + /* call the image! */ if (setjmp(&image_obj->exit_jmp)) { /* @@ -2670,6 +2675,41 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, } /** + * efi_update_exit_data() - fill exit data parameters of StartImage() + * + * @image_obj image handle + * @exit_data_size size of the exit data buffer + * @exit_data buffer with data returned by UEFI payload + * Return: status code + */ +static efi_status_t efi_update_exit_data(struct efi_loaded_image_obj *image_obj, + efi_uintn_t exit_data_size, + u16 *exit_data) +{ + efi_status_t ret; + + /* + * If exit_data is not provided to StartImage(), exit_data_size must be + * ignored. + */ + if (!image_obj->exit_data) + return EFI_SUCCESS; + if (image_obj->exit_data_size) + *image_obj->exit_data_size = exit_data_size; + if (exit_data_size && exit_data) { + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, + exit_data_size, + (void **)image_obj->exit_data); + if (ret != EFI_SUCCESS) + return ret; + memcpy(*image_obj->exit_data, exit_data, exit_data_size); + } else { + image_obj->exit_data = NULL; + } + return EFI_SUCCESS; +} + +/** * efi_exit() - leave an EFI application or driver * @image_handle: handle of the application or driver that is exiting * @exit_status: status code @@ -2709,6 +2749,15 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, if (ret != EFI_SUCCESS) goto out; + /* Exit data is only foreseen in case of failure. */ + if (exit_status != EFI_SUCCESS) { + ret = efi_update_exit_data(image_obj, exit_data_size, + exit_data); + /* Exiting has priority. Don't return error to caller. */ + if (ret != EFI_SUCCESS) + EFI_PRINT("%s: out of memory\n", __func__); + } + /* Make sure entry/exit counts for EFI world cross-overs match */ EFI_EXIT(exit_status); diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 987cc6dc5f..776077cc35 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -452,7 +452,7 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) uint64_t r = 0; /* Sanity check */ - if (!memory || (memory & EFI_PAGE_MASK)) { + if (!memory || (memory & EFI_PAGE_MASK) || !pages) { printf("%s: illegal free 0x%llx, 0x%zx\n", __func__, memory, pages); return EFI_INVALID_PARAMETER; diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index b32a7b3f93..87db51cbb7 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -79,6 +79,7 @@ out: */ efi_status_t efi_init_obj_list(void) { + u64 os_indications_supported = 0; /* None */ efi_status_t ret = EFI_SUCCESS; /* Initialize once only */ @@ -90,6 +91,16 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + /* Indicate supported features */ + ret = EFI_CALL(efi_set_variable(L"OsIndicationsSupported", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(os_indications_supported), + &os_indications_supported)); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize system table */ ret = efi_initialize_system_table(); if (ret != EFI_SUCCESS) diff --git a/lib/efi_selftest/efi_selftest_miniapp_exit.c b/lib/efi_selftest/efi_selftest_miniapp_exit.c index b3ca109d81..6b5cfb01cf 100644 --- a/lib/efi_selftest/efi_selftest_miniapp_exit.c +++ b/lib/efi_selftest/efi_selftest_miniapp_exit.c @@ -9,7 +9,7 @@ */ #include <common.h> -#include <efi_api.h> +#include <efi_selftest.h> static efi_guid_t loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; @@ -66,15 +66,22 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, struct efi_system_table *systable) { struct efi_simple_text_output_protocol *con_out = systable->con_out; - efi_status_t ret = EFI_UNSUPPORTED; + efi_status_t ret; + u16 text[] = EFI_ST_SUCCESS_STR; con_out->output_string(con_out, L"EFI application calling Exit\n"); - if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) + if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) { + con_out->output_string(con_out, + L"Loaded image protocol missing\n"); ret = EFI_NOT_FOUND; + goto out; + } - /* The return value is checked by the calling test */ - systable->boottime->exit(handle, ret, 0, NULL); + /* This return value is expected by the calling test */ + ret = EFI_UNSUPPORTED; +out: + systable->boottime->exit(handle, ret, sizeof(text), text); /* * This statement should not be reached. diff --git a/lib/efi_selftest/efi_selftest_startimage_exit.c b/lib/efi_selftest/efi_selftest_startimage_exit.c index fa4b7d4a9b..96049dea86 100644 --- a/lib/efi_selftest/efi_selftest_startimage_exit.c +++ b/lib/efi_selftest/efi_selftest_startimage_exit.c @@ -123,6 +123,9 @@ static int execute(void) { efi_status_t ret; efi_handle_t handle; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; + u16 expected_text[] = EFI_ST_SUCCESS_STR; ret = boottime->load_image(false, image_handle, NULL, image, img.length, &handle); @@ -130,11 +133,21 @@ static int execute(void) efi_st_error("Failed to load image\n"); return EFI_ST_FAILURE; } - ret = boottime->start_image(handle, NULL, NULL); + ret = boottime->start_image(handle, &exit_data_size, &exit_data); if (ret != EFI_UNSUPPORTED) { efi_st_error("Wrong return value from application\n"); return EFI_ST_FAILURE; } + if (!exit_data || exit_data_size != sizeof(expected_text) || + efi_st_memcmp(exit_data, expected_text, sizeof(expected_text))) { + efi_st_error("Incorrect exit data\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(exit_data); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free exit data\n"); + return EFI_ST_FAILURE; + } return EFI_ST_SUCCESS; } diff --git a/lib/uuid.c b/lib/uuid.c index fa20ee39fc..2d4d6ef7e4 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -238,6 +238,8 @@ void gen_rand_uuid(unsigned char *uuid_bin) unsigned int *ptr = (unsigned int *)&uuid; int i; + srand(get_ticks() + rand()); + /* Set all fields randomly */ for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++) *(ptr + i) = cpu_to_be32(rand()); |