summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/bootefi.c15
-rw-r--r--cmd/efidebug.c106
-rw-r--r--cmd/gpt.c12
-rw-r--r--cmd/nvedit_efi.c5
-rw-r--r--disk/part_efi.c6
-rw-r--r--include/efi_loader.h7
-rw-r--r--include/efi_selftest.h2
-rw-r--r--lib/efi_loader/efi_bootmgr.c15
-rw-r--r--lib/efi_loader/efi_boottime.c57
-rw-r--r--lib/efi_loader/efi_memory.c2
-rw-r--r--lib/efi_loader/efi_setup.c11
-rw-r--r--lib/efi_selftest/efi_selftest_miniapp_exit.c17
-rw-r--r--lib/efi_selftest/efi_selftest_startimage_exit.c15
-rw-r--r--lib/uuid.c2
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;
}
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 638870352f..33cda51396 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -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());