aboutsummaryrefslogtreecommitdiff
path: root/lib/efi_loader
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_loader')
-rw-r--r--lib/efi_loader/Kconfig34
-rw-r--r--lib/efi_loader/Makefile8
-rw-r--r--lib/efi_loader/efi_bootmgr.c135
-rw-r--r--lib/efi_loader/efi_console.c6
-rw-r--r--lib/efi_loader/efi_dt_fixup.c166
-rw-r--r--lib/efi_loader/efi_file.c317
-rw-r--r--lib/efi_loader/efi_image_loader.c80
-rw-r--r--lib/efi_loader/efi_load_options.c149
-rw-r--r--lib/efi_loader/efi_memory.c2
-rw-r--r--lib/efi_loader/efi_root_node.c14
-rw-r--r--lib/efi_loader/efi_unicode_collation.c39
-rw-r--r--lib/efi_loader/efi_var_mem.c13
-rw-r--r--lib/efi_loader/efi_variable_tee.c2
-rw-r--r--lib/efi_loader/helloworld.c167
14 files changed, 823 insertions, 309 deletions
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index fdf245dea3..e729f727df 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -27,6 +27,14 @@ config EFI_LOADER
if EFI_LOADER
+config CMD_BOOTEFI_BOOTMGR
+ bool "UEFI Boot Manager"
+ default y
+ help
+ Select this option if you want to select the UEFI binary to be booted
+ via UEFI variables Boot####, BootOrder, and BootNext. This enables the
+ 'bootefi bootmgr' command.
+
config EFI_SETUP_EARLY
bool
default n
@@ -200,6 +208,21 @@ config EFI_DEVICE_PATH_TO_TEXT
The device path to text protocol converts device nodes and paths to
human readable strings.
+config EFI_DEVICE_PATH_UTIL
+ bool "Device path utilities protocol"
+ default y
+ help
+ The device path utilities protocol creates and manipulates device
+ paths and device nodes. It is required to run the EFI Shell.
+
+config EFI_DT_FIXUP
+ bool "Device tree fixup protocol"
+ depends on !GENERATE_ACPI_TABLE
+ default y
+ help
+ The EFI device-tree fix-up protocol provides a function to let the
+ firmware apply fix-ups. This may be used by boot loaders.
+
config EFI_LOADER_HII
bool "HII protocols"
default y
@@ -229,17 +252,6 @@ config EFI_UNICODE_CAPITALIZATION
set, only the the correct handling of the letters of the codepage
used by the FAT file system is ensured.
-config EFI_UNICODE_COLLATION_PROTOCOL
- bool "Deprecated version of the Unicode collation protocol"
- default n
- help
- In EFI 1.10 a version of the Unicode collation protocol using ISO
- 639-2 language codes existed. This protocol is not part of the UEFI
- specification any longer. Unfortunately it is required to run the
- UEFI Self Certification Test (SCT) II, version 2.6, 2017.
-
- Choose this option for testing only. It is bound to be removed.
-
endif
config EFI_LOADER_BOUNCE_BUFFER
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 462d4d9ac4..10b42e8847 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -21,17 +21,21 @@ targets += helloworld.o
endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
-obj-y += efi_bootmgr.o
+obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
obj-y += efi_boottime.o
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
obj-y += efi_console.o
obj-y += efi_device_path.o
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
-obj-y += efi_device_path_utilities.o
+obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o
+ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
+obj-y += efi_dt_fixup.o
+endif
obj-y += efi_file.o
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
obj-y += efi_image_loader.o
+obj-y += efi_load_options.o
obj-y += efi_memory.o
obj-y += efi_root_node.o
obj-y += efi_runtime.o
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index d3be2f94c6..25f5cebfdb 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -31,141 +31,6 @@ static const struct efi_runtime_services *rs;
*/
/**
- * efi_set_load_options() - set the load options of a loaded image
- *
- * @handle: the image handle
- * @load_options_size: size of load options
- * @load_options: pointer to load options
- * Return: status code
- */
-efi_status_t efi_set_load_options(efi_handle_t handle,
- efi_uintn_t load_options_size,
- void *load_options)
-{
- struct efi_loaded_image *loaded_image_info;
- efi_status_t ret;
-
- ret = EFI_CALL(systab.boottime->open_protocol(
- handle,
- &efi_guid_loaded_image,
- (void **)&loaded_image_info,
- efi_root, NULL,
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
- if (ret != EFI_SUCCESS)
- return EFI_INVALID_PARAMETER;
-
- loaded_image_info->load_options = load_options;
- loaded_image_info->load_options_size = load_options_size;
-
- return EFI_CALL(systab.boottime->close_protocol(handle,
- &efi_guid_loaded_image,
- efi_root, NULL));
-}
-
-
-/**
- * efi_deserialize_load_option() - parse serialized data
- *
- * Parse serialized data describing a load option and transform it to the
- * efi_load_option structure.
- *
- * @lo: pointer to target
- * @data: serialized data
- * @size: size of the load option, on return size of the optional data
- * Return: status code
- */
-efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
- efi_uintn_t *size)
-{
- efi_uintn_t len;
-
- len = sizeof(u32);
- if (*size < len + 2 * sizeof(u16))
- return EFI_INVALID_PARAMETER;
- lo->attributes = get_unaligned_le32(data);
- data += len;
- *size -= len;
-
- len = sizeof(u16);
- lo->file_path_length = get_unaligned_le16(data);
- data += len;
- *size -= len;
-
- lo->label = (u16 *)data;
- len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
- if (lo->label[len])
- return EFI_INVALID_PARAMETER;
- len = (len + 1) * sizeof(u16);
- if (*size < len)
- return EFI_INVALID_PARAMETER;
- data += len;
- *size -= len;
-
- len = lo->file_path_length;
- if (*size < len)
- return EFI_INVALID_PARAMETER;
- lo->file_path = (struct efi_device_path *)data;
- if (efi_dp_check_length(lo->file_path, len) < 0)
- return EFI_INVALID_PARAMETER;
- data += len;
- *size -= len;
-
- lo->optional_data = data;
-
- return EFI_SUCCESS;
-}
-
-/**
- * efi_serialize_load_option() - serialize load option
- *
- * Serialize efi_load_option structure into byte stream for BootXXXX.
- *
- * @data: buffer for serialized data
- * @lo: load option
- * Return: size of allocated buffer
- */
-unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
-{
- unsigned long label_len;
- unsigned long size;
- u8 *p;
-
- label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
-
- /* total size */
- size = sizeof(lo->attributes);
- size += sizeof(lo->file_path_length);
- size += label_len;
- size += lo->file_path_length;
- if (lo->optional_data)
- size += (utf8_utf16_strlen((const char *)lo->optional_data)
- + 1) * sizeof(u16);
- p = malloc(size);
- if (!p)
- return 0;
-
- /* copy data */
- *data = p;
- memcpy(p, &lo->attributes, sizeof(lo->attributes));
- p += sizeof(lo->attributes);
-
- memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
- p += sizeof(lo->file_path_length);
-
- memcpy(p, lo->label, label_len);
- p += label_len;
-
- memcpy(p, lo->file_path, lo->file_path_length);
- p += lo->file_path_length;
-
- if (lo->optional_data) {
- utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
- p += sizeof(u16); /* size of trailing \0 */
- }
- return size;
-}
-
-/**
* get_var() - get UEFI variable
*
* It is the caller's duty to free the returned buffer.
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 705109596e..edcfce7bec 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -141,12 +141,12 @@ static int term_read_reply(int *n, int num, char end_char)
*/
static efi_status_t EFIAPI efi_cout_output_string(
struct efi_simple_text_output_protocol *this,
- const efi_string_t string)
+ const u16 *string)
{
struct simple_text_output_mode *con = &efi_con_mode;
struct cout_mode *mode = &efi_cout_modes[con->mode];
char *buf, *pos;
- u16 *p;
+ const u16 *p;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %p", this, string);
@@ -230,7 +230,7 @@ out:
*/
static efi_status_t EFIAPI efi_cout_test_string(
struct efi_simple_text_output_protocol *this,
- const efi_string_t string)
+ const u16 *string)
{
EFI_ENTRY("%p, %p", this, string);
return EFI_EXIT(EFI_SUCCESS);
diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c
new file mode 100644
index 0000000000..3850ab3b0f
--- /dev/null
+++ b/lib/efi_loader/efi_dt_fixup.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI_DT_FIXUP_PROTOCOL
+ *
+ * Copyright (c) 2020 Heinrich Schuchardt
+ */
+
+#include <common.h>
+#include <efi_dt_fixup.h>
+#include <efi_loader.h>
+#include <mapmem.h>
+
+const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID;
+
+/**
+ * efi_reserve_memory() - add reserved memory to memory map
+ *
+ * @addr: start address of the reserved memory range
+ * @size: size of the reserved memory range
+ * @nomap: indicates that the memory range shall not be accessed by the
+ * UEFI payload
+ */
+static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
+{
+ int type;
+ efi_uintn_t ret;
+
+ /* Convert from sandbox address space. */
+ addr = (uintptr_t)map_sysmem(addr, 0);
+
+ if (nomap)
+ type = EFI_RESERVED_MEMORY_TYPE;
+ else
+ type = EFI_BOOT_SERVICES_DATA;
+
+ ret = efi_add_memory_map(addr, size, type);
+ if (ret != EFI_SUCCESS)
+ log_err("Reserved memory mapping failed addr %llx size %llx\n",
+ addr, size);
+}
+
+/**
+ * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
+ *
+ * The mem_rsv entries of the FDT are added to the memory map. Any failures are
+ * ignored because this is not critical and we would rather continue to try to
+ * boot.
+ *
+ * @fdt: Pointer to device tree
+ */
+void efi_carve_out_dt_rsv(void *fdt)
+{
+ int nr_rsv, i;
+ u64 addr, size;
+ int nodeoffset, subnode;
+
+ nr_rsv = fdt_num_mem_rsv(fdt);
+
+ /* Look for an existing entry and add it to the efi mem map. */
+ for (i = 0; i < nr_rsv; i++) {
+ if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
+ continue;
+ efi_reserve_memory(addr, size, false);
+ }
+
+ /* process reserved-memory */
+ nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
+ if (nodeoffset >= 0) {
+ subnode = fdt_first_subnode(fdt, nodeoffset);
+ while (subnode >= 0) {
+ fdt_addr_t fdt_addr;
+ fdt_size_t fdt_size;
+
+ /* check if this subnode has a reg property */
+ fdt_addr = fdtdec_get_addr_size_auto_parent(
+ fdt, nodeoffset, subnode,
+ "reg", 0, &fdt_size, false);
+ /*
+ * The /reserved-memory node may have children with
+ * a size instead of a reg property.
+ */
+ if (fdt_addr != FDT_ADDR_T_NONE &&
+ fdtdec_get_is_enabled(fdt, subnode)) {
+ bool nomap;
+
+ nomap = !!fdt_getprop(fdt, subnode, "no-map",
+ NULL);
+ efi_reserve_memory(fdt_addr, fdt_size, nomap);
+ }
+ subnode = fdt_next_subnode(fdt, subnode);
+ }
+ }
+}
+
+/**
+ * efi_dt_fixup() - fix up device tree
+ *
+ * This function implements the Fixup() service of the
+ * EFI Device Tree Fixup Protocol.
+ *
+ * @this: instance of the protocol
+ * @dtb: device tree provided by caller
+ * @buffer_size: size of buffer for the device tree including free space
+ * @flags: bit field designating action to be performed
+ * Return: status code
+ */
+static efi_status_t __maybe_unused EFIAPI
+efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb,
+ efi_uintn_t *buffer_size, u32 flags)
+{
+ efi_status_t ret;
+ size_t required_size;
+ bootm_headers_t img = { 0 };
+
+ EFI_ENTRY("%p, %p, %p, %d", this, dtb, buffer_size, flags);
+
+ if (this != &efi_dt_fixup_prot || !dtb || !buffer_size ||
+ !flags || (flags & ~EFI_DT_ALL)) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+ if (fdt_check_header(dtb)) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+ if (flags & EFI_DT_APPLY_FIXUPS) {
+ required_size = fdt_off_dt_strings(dtb) +
+ fdt_size_dt_strings(dtb) +
+ 0x3000;
+ } else {
+ required_size = fdt_totalsize(dtb);
+ }
+ if (required_size > *buffer_size) {
+ *buffer_size = required_size;
+ ret = EFI_BUFFER_TOO_SMALL;
+ goto out;
+ }
+ fdt_set_totalsize(dtb, *buffer_size);
+
+ if (flags & EFI_DT_APPLY_FIXUPS) {
+ if (image_setup_libfdt(&img, dtb, 0, NULL)) {
+ log_err("failed to process device tree\n");
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+ }
+ if (flags & EFI_DT_RESERVE_MEMORY)
+ efi_carve_out_dt_rsv(dtb);
+
+ if (EFI_DT_INSTALL_TABLE) {
+ ret = efi_install_configuration_table(&efi_guid_fdt, dtb);
+ if (ret != EFI_SUCCESS) {
+ log_err("ERROR: failed to install device tree\n");
+ goto out;
+ }
+ }
+
+ ret = EFI_SUCCESS;
+out:
+ return EFI_EXIT(ret);
+}
+
+struct efi_dt_fixup_protocol efi_dt_fixup_prot = {
+ .revision = EFI_DT_FIXUP_PROTOCOL_REVISION,
+ .fixup = efi_dt_fixup
+};
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 72b7ec1e63..8ece8e71ee 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -246,18 +246,16 @@ error:
return NULL;
}
-static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
- struct efi_file_handle **new_handle,
- u16 *file_name, u64 open_mode, u64 attributes)
+static efi_status_t efi_file_open_int(struct efi_file_handle *this,
+ struct efi_file_handle **new_handle,
+ u16 *file_name, u64 open_mode,
+ u64 attributes)
{
- struct file_handle *fh = to_fh(file);
+ struct file_handle *fh = to_fh(this);
efi_status_t ret;
- EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
- file_name, open_mode, attributes);
-
/* Check parameters */
- if (!file || !new_handle || !file_name) {
+ if (!this || !new_handle || !file_name) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
@@ -292,6 +290,75 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
ret = EFI_NOT_FOUND;
}
out:
+ return ret;
+}
+
+/**
+ * efi_file_open_()
+ *
+ * This function implements the Open service of the File Protocol.
+ * See the UEFI spec for details.
+ *
+ * @this: EFI_FILE_PROTOCOL instance
+ * @new_handle: on return pointer to file handle
+ * @file_name: file name
+ * @open_mode: mode to open the file (read, read/write, create/read/write)
+ * @attributes: attributes for newly created file
+ */
+static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *this,
+ struct efi_file_handle **new_handle,
+ u16 *file_name, u64 open_mode,
+ u64 attributes)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", this, new_handle,
+ file_name, open_mode, attributes);
+
+ ret = efi_file_open_int(this, new_handle, file_name, open_mode,
+ attributes);
+
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_file_open_ex() - open file asynchronously
+ *
+ * This function implements the OpenEx service of the File Protocol.
+ * See the UEFI spec for details.
+ *
+ * @this: EFI_FILE_PROTOCOL instance
+ * @new_handle: on return pointer to file handle
+ * @file_name: file name
+ * @open_mode: mode to open the file (read, read/write, create/read/write)
+ * @attributes: attributes for newly created file
+ * @token: transaction token
+ */
+static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *this,
+ struct efi_file_handle **new_handle,
+ u16 *file_name, u64 open_mode,
+ u64 attributes,
+ struct efi_file_io_token *token)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu, %p", this, new_handle,
+ file_name, open_mode, attributes, token);
+
+ if (!token) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ret = efi_file_open_int(this, new_handle, file_name, open_mode,
+ attributes);
+
+ if (ret == EFI_SUCCESS && token->event) {
+ token->status = EFI_SUCCESS;
+ efi_signal_event(token->event);
+ }
+
+out:
return EFI_EXIT(ret);
}
@@ -441,19 +508,15 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
return EFI_SUCCESS;
}
-static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
- efi_uintn_t *buffer_size, void *buffer)
+static efi_status_t efi_file_read_int(struct efi_file_handle *this,
+ efi_uintn_t *buffer_size, void *buffer)
{
- struct file_handle *fh = to_fh(file);
+ struct file_handle *fh = to_fh(this);
efi_status_t ret = EFI_SUCCESS;
u64 bs;
- EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
-
- if (!buffer_size) {
- ret = EFI_INVALID_PARAMETER;
- goto error;
- }
+ if (!this || !buffer_size || !buffer)
+ return EFI_INVALID_PARAMETER;
bs = *buffer_size;
if (fh->isdir)
@@ -465,34 +528,77 @@ static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
else
*buffer_size = SIZE_MAX;
-error:
+ return ret;
+}
+
+/**
+ * efi_file_read() - read file
+ *
+ * This function implements the Read() service of the EFI_FILE_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this: file protocol instance
+ * @buffer_size: number of bytes to read
+ * @buffer: read buffer
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *this,
+ efi_uintn_t *buffer_size, void *buffer)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
+
+ ret = efi_file_read_int(this, buffer_size, buffer);
+
return EFI_EXIT(ret);
}
/**
- * efi_file_write() - write to file
+ * efi_file_read_ex() - read file asynchonously
*
- * This function implements the Write() service of the EFI_FILE_PROTOCOL.
+ * This function implements the ReadEx() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
- * @file: file handle
- * @buffer_size: number of bytes to write
- * @buffer: buffer with the bytes to write
+ * @this: file protocol instance
+ * @token: transaction token
* Return: status code
*/
-static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
- efi_uintn_t *buffer_size,
- void *buffer)
+static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *this,
+ struct efi_file_io_token *token)
{
- struct file_handle *fh = to_fh(file);
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p", this, token);
+
+ if (!token) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ret = efi_file_read_int(this, &token->buffer_size, token->buffer);
+
+ if (ret == EFI_SUCCESS && token->event) {
+ token->status = EFI_SUCCESS;
+ efi_signal_event(token->event);
+ }
+
+out:
+ return EFI_EXIT(ret);
+}
+
+static efi_status_t efi_file_write_int(struct efi_file_handle *this,
+ efi_uintn_t *buffer_size, void *buffer)
+{
+ struct file_handle *fh = to_fh(this);
efi_status_t ret = EFI_SUCCESS;
loff_t actwrite;
- EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
-
- if (!file || !buffer_size || !buffer) {
+ if (!this || !buffer_size || !buffer) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
@@ -521,6 +627,67 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
fh->offset += actwrite;
out:
+ return ret;
+}
+
+/**
+ * efi_file_write() - write to file
+ *
+ * This function implements the Write() service of the EFI_FILE_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this: file protocol instance
+ * @buffer_size: number of bytes to write
+ * @buffer: buffer with the bytes to write
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *this,
+ efi_uintn_t *buffer_size,
+ void *buffer)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
+
+ ret = efi_file_write_int(this, buffer_size, buffer);
+
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_file_write_ex() - write to file
+ *
+ * This function implements the WriteEx() service of the EFI_FILE_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this: file protocol instance
+ * @token: transaction token
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *this,
+ struct efi_file_io_token *token)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p", this, token);
+
+ if (!token) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ret = efi_file_write_int(this, &token->buffer_size, token->buffer);
+
+ if (ret == EFI_SUCCESS && token->event) {
+ token->status = EFI_SUCCESS;
+ efi_signal_event(token->event);
+ }
+
+out:
return EFI_EXIT(ret);
}
@@ -761,36 +928,84 @@ out:
return EFI_EXIT(ret);
}
-static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
+/**
+ * efi_file_flush_int() - flush file
+ *
+ * This is the internal implementation of the Flush() and FlushEx() services of
+ * the EFI_FILE_PROTOCOL.
+ *
+ * @this: file protocol instance
+ * Return: status code
+ */
+static efi_status_t efi_file_flush_int(struct efi_file_handle *this)
{
- EFI_ENTRY("%p", file);
- return EFI_EXIT(EFI_SUCCESS);
-}
+ struct file_handle *fh = to_fh(this);
-static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *file,
- struct efi_file_handle **new_handle,
- u16 *file_name, u64 open_mode, u64 attributes,
- struct efi_file_io_token *token)
-{
- return EFI_UNSUPPORTED;
-}
+ if (!this)
+ return EFI_INVALID_PARAMETER;
-static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *file,
- struct efi_file_io_token *token)
-{
- return EFI_UNSUPPORTED;
+ if (!(fh->open_mode & EFI_FILE_MODE_WRITE))
+ return EFI_ACCESS_DENIED;
+
+ /* TODO: flush for file position after end of file */
+ return EFI_SUCCESS;
}
-static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *file,
- struct efi_file_io_token *token)
+/**
+ * efi_file_flush() - flush file
+ *
+ * This function implements the Flush() service of the EFI_FILE_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this: file protocol instance
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *this)
{
- return EFI_UNSUPPORTED;
+ efi_status_t ret;
+
+ EFI_ENTRY("%p", this);
+
+ ret = efi_file_flush_int(this);
+
+ return EFI_EXIT(ret);
}
-static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *file,
- struct efi_file_io_token *token)
+/**
+ * efi_file_flush_ex() - flush file
+ *
+ * This function implements the FlushEx() service of the EFI_FILE_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this: file protocol instance
+ * @token: transaction token
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *this,
+ struct efi_file_io_token *token)
{
- return EFI_UNSUPPORTED;
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p", this, token);
+
+ if (!token) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ret = efi_file_flush_int(this);
+
+ if (ret == EFI_SUCCESS && token->event) {
+ token->status = EFI_SUCCESS;
+ efi_signal_event(token->event);
+ }
+
+out:
+ return EFI_EXIT(ret);
}
static const struct efi_file_handle efi_file_handle_protocol = {
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index 94f76ef6b8..d4dd9e9433 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -675,6 +675,46 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
}
#endif /* CONFIG_EFI_SECURE_BOOT */
+
+/**
+ * efi_check_pe() - check if a memory buffer contains a PE-COFF image
+ *
+ * @buffer: buffer to check
+ * @size: size of buffer
+ * @nt_header: on return pointer to NT header of PE-COFF image
+ * Return: EFI_SUCCESS if the buffer contains a PE-COFF image
+ */
+efi_status_t efi_check_pe(void *buffer, size_t size, void **nt_header)
+{
+ IMAGE_DOS_HEADER *dos = buffer;
+ IMAGE_NT_HEADERS32 *nt;
+
+ if (size < sizeof(*dos))
+ return EFI_INVALID_PARAMETER;
+
+ /* Check for DOS magix */
+ if (dos->e_magic != IMAGE_DOS_SIGNATURE)
+ return EFI_INVALID_PARAMETER;
+
+ /*
+ * Check if the image section header fits into the file. Knowing that at
+ * least one section header follows we only need to check for the length
+ * of the 64bit header which is longer than the 32bit header.
+ */
+ if (size < dos->e_lfanew + sizeof(IMAGE_NT_HEADERS32))
+ return EFI_INVALID_PARAMETER;
+ nt = (IMAGE_NT_HEADERS32 *)((u8 *)buffer + dos->e_lfanew);
+
+ /* Check for PE-COFF magic */
+ if (nt->Signature != IMAGE_NT_SIGNATURE)
+ return EFI_INVALID_PARAMETER;
+
+ if (nt_header)
+ *nt_header = nt;
+
+ return EFI_SUCCESS;
+}
+
/**
* efi_load_pe() - relocate EFI binary
*
@@ -705,36 +745,10 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
int supported = 0;
efi_status_t ret;
- /* Sanity check for a file header */
- if (efi_size < sizeof(*dos)) {
- log_err("Truncated DOS Header\n");
- ret = EFI_LOAD_ERROR;
- goto err;
- }
-
- dos = efi;
- if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
- log_err("Invalid DOS Signature\n");
- ret = EFI_LOAD_ERROR;
- goto err;
- }
-
- /*
- * Check if the image section header fits into the file. Knowing that at
- * least one section header follows we only need to check for the length
- * of the 64bit header which is longer than the 32bit header.
- */
- if (efi_size < dos->e_lfanew + sizeof(IMAGE_NT_HEADERS64)) {
- log_err("Invalid offset for Extended Header\n");
- ret = EFI_LOAD_ERROR;
- goto err;
- }
-
- nt = (void *) ((char *)efi + dos->e_lfanew);
- if (nt->Signature != IMAGE_NT_SIGNATURE) {
- log_err("Invalid NT Signature\n");
- ret = EFI_LOAD_ERROR;
- goto err;
+ ret = efi_check_pe(efi, efi_size, (void **)&nt);
+ if (ret != EFI_SUCCESS) {
+ log_err("Not a PE-COFF file\n");
+ return EFI_LOAD_ERROR;
}
for (i = 0; machines[i]; i++)
@@ -746,8 +760,7 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
if (!supported) {
log_err("Machine type 0x%04x is not supported\n",
nt->FileHeader.Machine);
- ret = EFI_LOAD_ERROR;
- goto err;
+ return EFI_LOAD_ERROR;
}
num_sections = nt->FileHeader.NumberOfSections;
@@ -757,8 +770,7 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
if (efi_size < ((void *)sections + sizeof(sections[0]) * num_sections
- efi)) {
log_err("Invalid number of sections: %d\n", num_sections);
- ret = EFI_LOAD_ERROR;
- goto err;
+ return EFI_LOAD_ERROR;
}
/* Authenticate an image */
diff --git a/lib/efi_loader/efi_load_options.c b/lib/efi_loader/efi_load_options.c
new file mode 100644
index 0000000000..68cd85ba2e
--- /dev/null
+++ b/lib/efi_loader/efi_load_options.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI boot manager
+ *
+ * Copyright (c) 2018 AKASHI Takahiro, et.al.
+ */
+
+#define LOG_CATEGORY LOGC_EFI
+
+#include <common.h>
+#include <charset.h>
+#include <log.h>
+#include <malloc.h>
+#include <efi_loader.h>
+#include <asm/unaligned.h>
+
+/**
+ * efi_set_load_options() - set the load options of a loaded image
+ *
+ * @handle: the image handle
+ * @load_options_size: size of load options
+ * @load_options: pointer to load options
+ * Return: status code
+ */
+efi_status_t efi_set_load_options(efi_handle_t handle,
+ efi_uintn_t load_options_size,
+ void *load_options)
+{
+ struct efi_loaded_image *loaded_image_info;
+ efi_status_t ret;
+
+ ret = EFI_CALL(systab.boottime->open_protocol(
+ handle,
+ &efi_guid_loaded_image,
+ (void **)&loaded_image_info,
+ efi_root, NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
+ if (ret != EFI_SUCCESS)
+ return EFI_INVALID_PARAMETER;
+
+ loaded_image_info->load_options = load_options;
+ loaded_image_info->load_options_size = load_options_size;
+
+ return EFI_CALL(systab.boottime->close_protocol(handle,
+ &efi_guid_loaded_image,
+ efi_root, NULL));
+}
+
+/**
+ * efi_deserialize_load_option() - parse serialized data
+ *
+ * Parse serialized data describing a load option and transform it to the
+ * efi_load_option structure.
+ *
+ * @lo: pointer to target
+ * @data: serialized data
+ * @size: size of the load option, on return size of the optional data
+ * Return: status code
+ */
+efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
+ efi_uintn_t *size)
+{
+ efi_uintn_t len;
+
+ len = sizeof(u32);
+ if (*size < len + 2 * sizeof(u16))
+ return EFI_INVALID_PARAMETER;
+ lo->attributes = get_unaligned_le32(data);
+ data += len;
+ *size -= len;
+
+ len = sizeof(u16);
+ lo->file_path_length = get_unaligned_le16(data);
+ data += len;
+ *size -= len;
+
+ lo->label = (u16 *)data;
+ len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
+ if (lo->label[len])
+ return EFI_INVALID_PARAMETER;
+ len = (len + 1) * sizeof(u16);
+ if (*size < len)
+ return EFI_INVALID_PARAMETER;
+ data += len;
+ *size -= len;
+
+ len = lo->file_path_length;
+ if (*size < len)
+ return EFI_INVALID_PARAMETER;
+ lo->file_path = (struct efi_device_path *)data;
+ if (efi_dp_check_length(lo->file_path, len) < 0)
+ return EFI_INVALID_PARAMETER;
+ data += len;
+ *size -= len;
+
+ lo->optional_data = data;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_serialize_load_option() - serialize load option
+ *
+ * Serialize efi_load_option structure into byte stream for BootXXXX.
+ *
+ * @data: buffer for serialized data
+ * @lo: load option
+ * Return: size of allocated buffer
+ */
+unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
+{
+ unsigned long label_len;
+ unsigned long size;
+ u8 *p;
+
+ label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
+
+ /* total size */
+ size = sizeof(lo->attributes);
+ size += sizeof(lo->file_path_length);
+ size += label_len;
+ size += lo->file_path_length;
+ if (lo->optional_data)
+ size += (utf8_utf16_strlen((const char *)lo->optional_data)
+ + 1) * sizeof(u16);
+ p = malloc(size);
+ if (!p)
+ return 0;
+
+ /* copy data */
+ *data = p;
+ memcpy(p, &lo->attributes, sizeof(lo->attributes));
+ p += sizeof(lo->attributes);
+
+ memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
+ p += sizeof(lo->file_path_length);
+
+ memcpy(p, lo->label, label_len);
+ p += label_len;
+
+ memcpy(p, lo->file_path, lo->file_path_length);
+ p += lo->file_path_length;
+
+ 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_memory.c b/lib/efi_loader/efi_memory.c
index 11e755363e..a3106aba7f 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -541,8 +541,6 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
ret = efi_add_memory_map_pg(memory, pages, EFI_CONVENTIONAL_MEMORY,
false);
- /* Merging of adjacent free regions is missing */
-
if (ret != EFI_SUCCESS)
return EFI_NOT_FOUND;
diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c
index b17db312f7..739c6867f4 100644
--- a/lib/efi_loader/efi_root_node.c
+++ b/lib/efi_loader/efi_root_node.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <malloc.h>
+#include <efi_dt_fixup.h>
#include <efi_loader.h>
const efi_guid_t efi_u_boot_guid = U_BOOT_GUID;
@@ -57,16 +58,17 @@ efi_status_t efi_root_node_register(void)
&efi_guid_device_path_to_text_protocol,
(void *)&efi_device_path_to_text,
#endif
+#ifdef CONFIG_EFI_DEVICE_PATH_UTIL
/* Device path utilities protocol */
&efi_guid_device_path_utilities_protocol,
(void *)&efi_device_path_utilities,
-#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL2)
-#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL)
- /* Deprecated Unicode collation protocol */
- &efi_guid_unicode_collation_protocol,
- (void *)&efi_unicode_collation_protocol,
#endif
- /* Current Unicode collation protocol */
+#ifdef CONFIG_EFI_DT_FIXUP
+ /* Device-tree fix-up protocol */
+ &efi_guid_dt_fixup_protocol,
+ (void *)&efi_dt_fixup_prot,
+#endif
+#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL2)
&efi_guid_unicode_collation_protocol2,
(void *)&efi_unicode_collation_protocol2,
#endif
diff --git a/lib/efi_loader/efi_unicode_collation.c b/lib/efi_loader/efi_unicode_collation.c
index 6655c68092..f6c875bc33 100644
--- a/lib/efi_loader/efi_unicode_collation.c
+++ b/lib/efi_loader/efi_unicode_collation.c
@@ -38,7 +38,7 @@ const efi_guid_t efi_guid_unicode_collation_protocol2 =
* @s2: second string
*
* This function implements the StriColl() service of the
- * EFI_UNICODE_COLLATION_PROTOCOL.
+ * EFI_UNICODE_COLLATION_PROTOCOL2.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
@@ -179,7 +179,7 @@ static bool metai_match(const u16 *string, const u16 *pattern)
* - [<char1>-<char2>] matches any character in the range
*
* This function implements the MetaMatch() service of the
- * EFI_UNICODE_COLLATION_PROTOCOL.
+ * EFI_UNICODE_COLLATION_PROTOCOL2.
*
* Return: true if the string is matched.
*/
@@ -204,7 +204,7 @@ static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this,
* same number of words this does not pose a problem.
*
* This function implements the StrLwr() service of the
- * EFI_UNICODE_COLLATION_PROTOCOL.
+ * EFI_UNICODE_COLLATION_PROTOCOL2.
*/
static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
u16 *string)
@@ -225,7 +225,7 @@ static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
* same number of words this does not pose a problem.
*
* This function implements the StrUpr() service of the
- * EFI_UNICODE_COLLATION_PROTOCOL.
+ * EFI_UNICODE_COLLATION_PROTOCOL2.
*/
static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
u16 *string)
@@ -245,7 +245,7 @@ static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
* @string: converted string
*
* This function implements the FatToStr() service of the
- * EFI_UNICODE_COLLATION_PROTOCOL.
+ * EFI_UNICODE_COLLATION_PROTOCOL2.
*/
static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
efi_uintn_t fat_size, char *fat, u16 *string)
@@ -276,7 +276,7 @@ static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
* @fat: converted string
*
* This function implements the StrToFat() service of the
- * EFI_UNICODE_COLLATION_PROTOCOL.
+ * EFI_UNICODE_COLLATION_PROTOCOL2.
*
* Return: true if an illegal character was substituted by '_'.
*/
@@ -337,30 +337,3 @@ const struct efi_unicode_collation_protocol efi_unicode_collation_protocol2 = {
.str_to_fat = efi_str_to_fat,
.supported_languages = "en",
};
-
-/*
- * In EFI 1.10 a version of the Unicode collation protocol using ISO 639-2
- * language codes existed. This protocol is not part of the UEFI specification
- * any longer. Unfortunately it is required to run the UEFI Self Certification
- * Test (SCT) II, version 2.6, 2017. So we implement it here for the sole
- * purpose of running the SCT. It can be removed when a compliant SCT is
- * available.
- */
-#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL)
-
-/* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */
-const efi_guid_t efi_guid_unicode_collation_protocol =
- EFI_UNICODE_COLLATION_PROTOCOL_GUID;
-
-const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = {
- .stri_coll = efi_stri_coll,
- .metai_match = efi_metai_match,
- .str_lwr = efi_str_lwr,
- .str_upr = efi_str_upr,
- .fat_to_str = efi_fat_to_str,
- .str_to_fat = efi_str_to_fat,
- /* ISO 639-2 language code */
- .supported_languages = "eng",
-};
-
-#endif
diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c
index d155f25f60..3d335a8274 100644
--- a/lib/efi_loader/efi_var_mem.c
+++ b/lib/efi_loader/efi_var_mem.c
@@ -10,7 +10,13 @@
#include <efi_variable.h>
#include <u-boot/crc.h>
-struct efi_var_file __efi_runtime_data *efi_var_buf;
+/*
+ * The variables efi_var_file and efi_var_entry must be static to avoid
+ * referencing them via the global offset table (section .got). The GOT
+ * is neither mapped as EfiRuntimeServicesData nor do we support its
+ * relocation during SetVirtualAddressMap().
+ */
+static struct efi_var_file __efi_runtime_data *efi_var_buf;
static struct efi_var_entry __efi_runtime_data *efi_current_var;
/**
@@ -339,3 +345,8 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
return EFI_SUCCESS;
}
+
+void efi_var_buf_update(struct efi_var_file *var_buf)
+{
+ memcpy(efi_var_buf, var_buf, EFI_VAR_BUF_SIZE);
+}
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index b8808fdeca..51920bcb51 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -702,7 +702,7 @@ void efi_variables_boot_exit_notify(void)
if (ret != EFI_SUCCESS)
log_err("Can't populate EFI variables. No runtime variables will be available\n");
else
- memcpy(efi_var_buf, var_buf, len);
+ efi_var_buf_update(var_buf);
free(var_buf);
/* Update runtime service table */
diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c
index 9ae2ee3389..5c8b7a96f9 100644
--- a/lib/efi_loader/helloworld.c
+++ b/lib/efi_loader/helloworld.c
@@ -1,43 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * EFI hello world
+ * Hello world EFI application
*
- * Copyright (c) 2016 Google, Inc
- * Written by Simon Glass <sjg@chromium.org>
+ * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
*
- * This program demonstrates calling a boottime service.
- * It writes a greeting and the load options to the console.
+ * This test program is used to test the invocation of an EFI application.
+ * It writes
+ *
+ * * a greeting
+ * * the firmware's UEFI version
+ * * the installed configuration tables
+ * * the boot device's device path and the file path
+ *
+ * to the console.
*/
-#include <common.h>
#include <efi_api.h>
static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static const efi_guid_t device_path_to_text_protocol_guid =
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
+static const efi_guid_t device_path_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
static const efi_guid_t fdt_guid = EFI_FDT_GUID;
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
+static struct efi_system_table *systable;
+static struct efi_boot_services *boottime;
+static struct efi_simple_text_output_protocol *con_out;
+
/**
- * efi_main() - entry point of the EFI application.
- *
- * @handle: handle of the loaded image
- * @systable: system table
- * @return: status code
+ * print_uefi_revision() - print UEFI revision number
*/
-efi_status_t EFIAPI efi_main(efi_handle_t handle,
- struct efi_system_table *systable)
+static void print_uefi_revision(void)
{
- struct efi_simple_text_output_protocol *con_out = systable->con_out;
- struct efi_boot_services *boottime = systable->boottime;
- struct efi_loaded_image *loaded_image;
- efi_status_t ret;
- efi_uintn_t i;
u16 rev[] = L"0.0.0";
- /* UEFI requires CR LF */
- con_out->output_string(con_out, L"Hello, world!\r\n");
-
- /* Print the revision number */
rev[0] = (systable->hdr.revision >> 16) + '0';
rev[4] = systable->hdr.revision & 0xffff;
for (; rev[4] >= 10;) {
@@ -53,15 +51,15 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
con_out->output_string(con_out, L"Running on UEFI ");
con_out->output_string(con_out, rev);
con_out->output_string(con_out, L"\r\n");
+}
+
+/**
+ * print_config_tables() - print configuration tables
+ */
+static void print_config_tables(void)
+{
+ efi_uintn_t i;
- /* Get the loaded image protocol */
- ret = boottime->handle_protocol(handle, &loaded_image_guid,
- (void **)&loaded_image);
- if (ret != EFI_SUCCESS) {
- con_out->output_string
- (con_out, L"Cannot open loaded image protocol\r\n");
- goto out;
- }
/* Find configuration tables */
for (i = 0; i < systable->nr_tables; ++i) {
if (!memcmp(&systable->tables[i].guid, &fdt_guid,
@@ -77,6 +75,16 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
con_out->output_string
(con_out, L"Have SMBIOS table\r\n");
}
+}
+
+/**
+ * print_load_options() - print load options
+ *
+ * @systable: system table
+ * @con_out: simple text output protocol
+ */
+void print_load_options(struct efi_loaded_image *loaded_image)
+{
/* Output the load options */
con_out->output_string(con_out, L"Load options: ");
if (loaded_image->load_options_size && loaded_image->load_options)
@@ -85,6 +93,105 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
else
con_out->output_string(con_out, L"<none>");
con_out->output_string(con_out, L"\r\n");
+}
+
+/**
+ * print_device_path() - print device path
+ *
+ * @device_path: device path to print
+ * @dp2txt: device path to text protocol
+ */
+efi_status_t print_device_path(struct efi_device_path *device_path,
+ struct efi_device_path_to_text_protocol *dp2txt)
+{
+ u16 *string;
+ efi_status_t ret;
+
+ if (!device_path) {
+ con_out->output_string(con_out, L"<none>\r\n");
+ return EFI_SUCCESS;
+ }
+
+ string = dp2txt->convert_device_path_to_text(device_path, true, false);
+ if (!string) {
+ con_out->output_string
+ (con_out, L"Cannot convert device path to text\r\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ con_out->output_string(con_out, string);
+ con_out->output_string(con_out, L"\r\n");
+ ret = boottime->free_pool(string);
+ if (ret != EFI_SUCCESS) {
+ con_out->output_string(con_out, L"Cannot free pool memory\r\n");
+ return ret;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_main() - entry point of the EFI application.
+ *
+ * @handle: handle of the loaded image
+ * @systab: system table
+ * @return: status code
+ */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
+ struct efi_system_table *systab)
+{
+ struct efi_loaded_image *loaded_image;
+ struct efi_device_path_to_text_protocol *device_path_to_text;
+ struct efi_device_path *device_path;
+ efi_status_t ret;
+
+ systable = systab;
+ boottime = systable->boottime;
+ con_out = systable->con_out;
+
+ /* UEFI requires CR LF */
+ con_out->output_string(con_out, L"Hello, world!\r\n");
+
+ print_uefi_revision();
+ print_config_tables();
+
+ /* Get the loaded image protocol */
+ ret = boottime->handle_protocol(handle, &loaded_image_guid,
+ (void **)&loaded_image);
+ if (ret != EFI_SUCCESS) {
+ con_out->output_string
+ (con_out, L"Cannot open loaded image protocol\r\n");
+ goto out;
+ }
+ print_load_options(loaded_image);
+
+ /* Get the device path to text protocol */
+ ret = boottime->locate_protocol(&device_path_to_text_protocol_guid,
+ NULL, (void **)&device_path_to_text);
+ if (ret != EFI_SUCCESS) {
+ con_out->output_string
+ (con_out, L"Cannot open device path to text protocol\r\n");
+ goto out;
+ }
+ if (!loaded_image->device_handle) {
+ con_out->output_string
+ (con_out, L"Missing device handle\r\n");
+ goto out;
+ }
+ ret = boottime->handle_protocol(loaded_image->device_handle,
+ &device_path_guid,
+ (void **)&device_path);
+ if (ret != EFI_SUCCESS) {
+ con_out->output_string
+ (con_out, L"Missing devide path for device handle\r\n");
+ goto out;
+ }
+ con_out->output_string(con_out, L"Boot device: ");
+ ret = print_device_path(device_path, device_path_to_text);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ con_out->output_string(con_out, L"File path: ");
+ ret = print_device_path(loaded_image->file_path, device_path_to_text);
+ if (ret != EFI_SUCCESS)
+ goto out;
out:
boottime->exit(handle, ret, 0, NULL);