summaryrefslogtreecommitdiff
path: root/lib/efi_loader
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_loader')
-rw-r--r--lib/efi_loader/efi_bootmgr.c14
-rw-r--r--lib/efi_loader/efi_boottime.c148
-rw-r--r--lib/efi_loader/efi_device_path.c16
-rw-r--r--lib/efi_loader/efi_file.c12
-rw-r--r--lib/efi_loader/efi_image_loader.c67
5 files changed, 166 insertions, 91 deletions
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index a095df3f54..417016102b 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -14,10 +14,6 @@
static const struct efi_boot_services *bs;
static const struct efi_runtime_services *rs;
-#define LOAD_OPTION_ACTIVE 0x00000001
-#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
-#define LOAD_OPTION_HIDDEN 0x00000008
-
/*
* bootmgr implements the logic of trying to find a payload to boot
* based on the BootOrder + BootXXXX variables, and then loading it.
@@ -150,7 +146,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
debug("%s: trying to load \"%ls\" from %pD\n",
__func__, lo.label, lo.file_path);
- ret = efi_load_image_from_path(lo.file_path, &image);
+ ret = efi_load_image_from_path(lo.file_path, &image, &size);
if (ret != EFI_SUCCESS)
goto error;
@@ -178,14 +174,14 @@ void *efi_bootmgr_load(struct efi_device_path **device_path,
void *image = NULL;
int i, num;
- __efi_entry_check();
-
bs = systab.boottime;
rs = systab.runtime;
bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
- if (!bootorder)
+ if (!bootorder) {
+ printf("BootOrder not defined\n");
goto error;
+ }
num = size / sizeof(uint16_t);
for (i = 0; i < num; i++) {
@@ -198,7 +194,5 @@ void *efi_bootmgr_load(struct efi_device_path **device_path,
free(bootorder);
error:
- __efi_exit_check();
-
return image;
}
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index f74f989e0a..bd8b8a17ae 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -44,7 +44,8 @@ static bool efi_is_direct_boot = true;
static volatile void *efi_gd, *app_gd;
#endif
-static int entry_count;
+/* 1 if inside U-Boot code, 0 if inside EFI payload code */
+static int entry_count = 1;
static int nesting_level;
/* GUID of the device tree table */
const efi_guid_t efi_guid_fdt = EFI_FDT_GUID;
@@ -1497,15 +1498,18 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
/**
* efi_setup_loaded_image() - initialize a loaded image
- * @info: loaded image info to be passed to the entry point of the image
- * @obj: internal object associated with the loaded image
- * @device_path: device path of the loaded image
- * @file_path: file path of the loaded image
*
* Initialize a loaded_image_info and loaded_image_info object with correct
* protocols, boot-device, etc.
*
- * Return: status code
+ * In case of an error *handle_ptr and *info_ptr are set to NULL and an error
+ * code is returned.
+ *
+ * @device_path: device path of the loaded image
+ * @file_path: file path of the loaded image
+ * @handle_ptr: handle of the loaded image
+ * @info_ptr: loaded image protocol
+ * Return: status code
*/
efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
struct efi_device_path *file_path,
@@ -1513,8 +1517,12 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
struct efi_loaded_image **info_ptr)
{
efi_status_t ret;
- struct efi_loaded_image *info;
- struct efi_loaded_image_obj *obj;
+ struct efi_loaded_image *info = NULL;
+ struct efi_loaded_image_obj *obj = NULL;
+
+ /* In case of EFI_OUT_OF_RESOURCES avoid illegal free by caller. */
+ *handle_ptr = NULL;
+ *info_ptr = NULL;
info = calloc(1, sizeof(*info));
if (!info)
@@ -1528,11 +1536,6 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
/* Add internal object to object list */
efi_add_handle(&obj->header);
- if (info_ptr)
- *info_ptr = info;
- if (handle_ptr)
- *handle_ptr = obj;
-
info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
info->file_path = file_path;
info->system_table = &systab;
@@ -1578,58 +1581,87 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
goto failure;
#endif
+ if (info_ptr)
+ *info_ptr = info;
+ if (handle_ptr)
+ *handle_ptr = obj;
+
return ret;
failure:
printf("ERROR: Failure to install protocols for loaded image\n");
+ efi_delete_handle(&obj->header);
+ free(info);
return ret;
}
/**
* efi_load_image_from_path() - load an image using a file path
- * @file_path: the path of the image to load
- * @buffer: buffer containing the loaded image
*
- * Return: status code
+ * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the
+ * callers obligation to update the memory type as needed.
+ *
+ * @file_path: the path of the image to load
+ * @buffer: buffer containing the loaded image
+ * @size: size of the loaded image
+ * Return: status code
*/
efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
- void **buffer)
+ void **buffer, efi_uintn_t *size)
{
struct efi_file_info *info = NULL;
struct efi_file_handle *f;
static efi_status_t ret;
+ u64 addr;
efi_uintn_t bs;
+ /* In case of failure nothing is returned */
+ *buffer = NULL;
+ *size = 0;
+
+ /* Open file */
f = efi_file_from_path(file_path);
if (!f)
return EFI_DEVICE_ERROR;
+ /* 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) {
- info = malloc(bs);
- EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid,
- &bs, info));
- }
- if (ret != EFI_SUCCESS)
+ if (ret != EFI_BUFFER_TOO_SMALL) {
+ ret = EFI_DEVICE_ERROR;
goto error;
+ }
- ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer);
- if (ret)
+ info = malloc(bs);
+ EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs,
+ info));
+ if (ret != EFI_SUCCESS)
goto error;
+ /*
+ * When reading the file we do not yet know if it contains an
+ * application, a boottime driver, or a runtime driver. So here we
+ * allocate a buffer as EFI_BOOT_SERVICES_DATA. The caller has to
+ * update the reservation according to the image type.
+ */
bs = info->file_size;
- EFI_CALL(ret = f->read(f, &bs, *buffer));
-
-error:
- free(info);
- EFI_CALL(f->close(f));
-
+ ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_BOOT_SERVICES_DATA,
+ efi_size_in_pages(bs), &addr);
if (ret != EFI_SUCCESS) {
- efi_free_pool(*buffer);
- *buffer = NULL;
+ ret = EFI_OUT_OF_RESOURCES;
+ goto error;
}
+ /* Read file */
+ EFI_CALL(ret = f->read(f, &bs, (void *)(uintptr_t)addr));
+ if (ret != EFI_SUCCESS)
+ efi_free_pages(addr, efi_size_in_pages(bs));
+ *buffer = (void *)(uintptr_t)addr;
+ *size = bs;
+error:
+ EFI_CALL(f->close(f));
+ free(info);
return ret;
}
@@ -1656,6 +1688,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_uintn_t source_size,
efi_handle_t *image_handle)
{
+ struct efi_device_path *dp, *fp;
struct efi_loaded_image *info = NULL;
struct efi_loaded_image_obj **image_obj =
(struct efi_loaded_image_obj **)image_handle;
@@ -1675,36 +1708,51 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
}
if (!source_buffer) {
- struct efi_device_path *dp, *fp;
-
- ret = efi_load_image_from_path(file_path, &source_buffer);
+ ret = efi_load_image_from_path(file_path, &source_buffer,
+ &source_size);
if (ret != EFI_SUCCESS)
- goto failure;
+ goto error;
/*
* split file_path which contains both the device and
* file parts:
*/
efi_dp_split_file_path(file_path, &dp, &fp);
- ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
- if (ret != EFI_SUCCESS)
- goto failure;
} else {
/* In this case, file_path is the "device" path, i.e.
* something like a HARDWARE_DEVICE:MEMORY_MAPPED
*/
- ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info);
+ u64 addr;
+ void *dest_buffer;
+
+ ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_RUNTIME_SERVICES_CODE,
+ efi_size_in_pages(source_size), &addr);
if (ret != EFI_SUCCESS)
goto error;
+ dest_buffer = (void *)(uintptr_t)addr;
+ memcpy(dest_buffer, source_buffer, source_size);
+ source_buffer = dest_buffer;
+
+ dp = file_path;
+ fp = NULL;
}
- (*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info);
- if (!(*image_obj)->entry) {
- ret = EFI_UNSUPPORTED;
- goto failure;
- }
+ ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
+ if (ret != EFI_SUCCESS)
+ goto error_invalid_image;
+ ret = efi_load_pe(*image_obj, source_buffer, info);
+ if (ret != EFI_SUCCESS)
+ goto error_invalid_image;
+ /* Update the type of the allocated memory */
+ efi_add_memory_map((uintptr_t)source_buffer,
+ efi_size_in_pages(source_size),
+ info->image_code_type, false);
info->system_table = &systab;
info->parent_handle = parent_image;
return EFI_EXIT(EFI_SUCCESS);
-failure:
+error_invalid_image:
+ /* The image is invalid. Release all associated resources. */
+ efi_free_pages((uintptr_t)source_buffer,
+ efi_size_in_pages(source_size));
efi_delete_handle(*image_handle);
*image_handle = NULL;
free(info);
@@ -1725,9 +1773,9 @@ error:
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
- efi_uintn_t *exit_data_size,
- u16 **exit_data)
+efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
+ efi_uintn_t *exit_data_size,
+ u16 **exit_data)
{
struct efi_loaded_image_obj *image_obj =
(struct efi_loaded_image_obj *)image_handle;
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index d94982314a..98c36e798f 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -910,9 +910,17 @@ struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
return start;
}
-/*
- * Helper to split a full device path (containing both device and file
- * parts) into it's constituent parts.
+/**
+ * efi_dp_split_file_path() - split of relative file path from device path
+ *
+ * Given a device path indicating a file on a device, separate the device
+ * path in two: the device path of the actual device and the file path
+ * relative to this device.
+ *
+ * @full_path: device path including device and file path
+ * @device_path: path of the device
+ * @file_path: relative path of the file
+ * Return: status code
*/
efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
struct efi_device_path **device_path,
@@ -929,7 +937,7 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
p = efi_dp_next(p);
if (!p)
- return EFI_OUT_OF_RESOURCES;
+ return EFI_INVALID_PARAMETER;
}
fp = efi_dp_dup(p);
if (!fp)
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 4b4422205d..3a7323765b 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -641,6 +641,12 @@ static const struct efi_file_handle efi_file_handle_protocol = {
.flush = efi_file_flush,
};
+/**
+ * efi_file_from_path() - open file via device path
+ *
+ * @fp: device path
+ * @return: EFI_FILE_PROTOCOL for the file or NULL
+ */
struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
{
struct efi_simple_file_system_protocol *v;
@@ -655,10 +661,14 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
if (ret != EFI_SUCCESS)
return NULL;
- /* skip over device-path nodes before the file path: */
+ /* Skip over device-path nodes before the file path. */
while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH))
fp = efi_dp_next(fp);
+ /*
+ * Step through the nodes of the directory path until the actual file
+ * node is reached which is the final node in the device path.
+ */
while (fp) {
struct efi_device_path_file_path *fdp =
container_of(fp, struct efi_device_path_file_path, dp);
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index a18ce0a570..fe66e7b9ff 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -42,8 +42,8 @@ static int machines[] = {
#endif
0 };
-/*
- * Print information about a loaded image.
+/**
+ * efi_print_image_info() - print information about a loaded image
*
* If the program counter is located within the image the offset to the base
* address is shown.
@@ -51,7 +51,7 @@ static int machines[] = {
* @obj: EFI object
* @image: loaded image
* @pc: program counter (use NULL to suppress offset output)
- * @return: status code
+ * Return: status code
*/
static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj,
struct efi_loaded_image *image,
@@ -69,8 +69,8 @@ static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj,
return EFI_SUCCESS;
}
-/*
- * Print information about all loaded images.
+/**
+ * efi_print_image_infos() - print information about all loaded images
*
* @pc: program counter (use NULL to suppress offset output)
*/
@@ -90,6 +90,15 @@ void efi_print_image_infos(void *pc)
}
}
+/**
+ * efi_loader_relocate() - relocate UEFI binary
+ *
+ * @rel: pointer to the relocation table
+ * @rel_size: size of the relocation table in bytes
+ * @efi_reloc: actual load address of the image
+ * @pref_address: preferred load address of the image
+ * Return: status code
+ */
static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
unsigned long rel_size, void *efi_reloc,
unsigned long pref_address)
@@ -102,7 +111,7 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
return EFI_SUCCESS;
end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
- while (rel < end - 1 && rel->SizeOfBlock) {
+ while (rel < end && rel->SizeOfBlock) {
const uint16_t *relocs = (const uint16_t *)(rel + 1);
i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
while (i--) {
@@ -159,11 +168,12 @@ void __weak invalidate_icache_all(void)
/* If the system doesn't support icache_all flush, cross our fingers */
}
-/*
- * Determine the memory types to be used for code and data.
+/**
+ * efi_set_code_and_data_type() - determine the memory types to be used for code
+ * and data.
*
- * @loaded_image_info image descriptor
- * @image_type field Subsystem of the optional header for
+ * @loaded_image_info: image descriptor
+ * @image_type: field Subsystem of the optional header for
* Windows specific field
*/
static void efi_set_code_and_data_type(
@@ -193,13 +203,19 @@ static void efi_set_code_and_data_type(
}
}
-/*
+/**
+ * efi_load_pe() - relocate EFI binary
+ *
* This function loads all sections from a PE binary into a newly reserved
- * piece of memory. On successful load it then returns the entry point for
- * the binary. Otherwise NULL.
+ * piece of memory. On success the entry point is returned as handle->entry.
+ *
+ * @handle: loaded image handle
+ * @efi: pointer to the EFI binary
+ * @loaded_image_info: loaded image protocol
+ * Return: status code
*/
-void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
- struct efi_loaded_image *loaded_image_info)
+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+ struct efi_loaded_image *loaded_image_info)
{
IMAGE_NT_HEADERS32 *nt;
IMAGE_DOS_HEADER *dos;
@@ -210,7 +226,6 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
const IMAGE_BASE_RELOCATION *rel;
unsigned long rel_size;
int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
- void *entry;
uint64_t image_base;
uint64_t image_size;
unsigned long virt_size = 0;
@@ -219,13 +234,13 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
dos = efi;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
printf("%s: Invalid DOS Signature\n", __func__);
- return NULL;
+ return EFI_LOAD_ERROR;
}
nt = (void *) ((char *)efi + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE) {
printf("%s: Invalid NT Signature\n", __func__);
- return NULL;
+ return EFI_LOAD_ERROR;
}
for (i = 0; machines[i]; i++)
@@ -237,7 +252,7 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
if (!supported) {
printf("%s: Machine type 0x%04x is not supported\n",
__func__, nt->FileHeader.Machine);
- return NULL;
+ return EFI_LOAD_ERROR;
}
/* Calculate upper virtual address boundary */
@@ -263,9 +278,9 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
if (!efi_reloc) {
printf("%s: Could not allocate %lu bytes\n",
__func__, virt_size);
- return NULL;
+ return EFI_OUT_OF_RESOURCES;
}
- entry = efi_reloc + opt->AddressOfEntryPoint;
+ handle->entry = efi_reloc + opt->AddressOfEntryPoint;
rel_size = opt->DataDirectory[rel_idx].Size;
rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
virt_size = ALIGN(virt_size, opt->SectionAlignment);
@@ -279,16 +294,16 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
if (!efi_reloc) {
printf("%s: Could not allocate %lu bytes\n",
__func__, virt_size);
- return NULL;
+ return EFI_OUT_OF_RESOURCES;
}
- entry = efi_reloc + opt->AddressOfEntryPoint;
+ handle->entry = efi_reloc + opt->AddressOfEntryPoint;
rel_size = opt->DataDirectory[rel_idx].Size;
rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
virt_size = ALIGN(virt_size, opt->SectionAlignment);
} else {
printf("%s: Invalid optional header magic %x\n", __func__,
nt->OptionalHeader.Magic);
- return NULL;
+ return EFI_LOAD_ERROR;
}
/* Load sections into RAM */
@@ -306,7 +321,7 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
(unsigned long)image_base) != EFI_SUCCESS) {
efi_free_pages((uintptr_t) efi_reloc,
(virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT);
- return NULL;
+ return EFI_LOAD_ERROR;
}
/* Flush cache */
@@ -320,5 +335,5 @@ void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
handle->reloc_base = efi_reloc;
handle->reloc_size = virt_size;
- return entry;
+ return EFI_SUCCESS;
}