diff options
author | Tom Rini | 2021-01-20 10:49:23 -0500 |
---|---|---|
committer | Tom Rini | 2021-01-20 10:49:23 -0500 |
commit | 404bbc809da50fcf0b63566803d5061f80d93885 (patch) | |
tree | 8c1ab4fbb0e4a5a929b53f4d702e4acb3b001611 | |
parent | 63f2607bc8012f5f0e20005a7bc2285ebb5248d4 (diff) | |
parent | 53e54bf50d285597c1553cdf2bd0e646fcd4dd60 (diff) |
Merge tag 'efi-2021-04-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
Pull request for UEFI sub-system for efi-2021-04-rc1-2
* Provide a test tool for initial RAM disk provided via load file2 protocol.
* Make more items configurable to reduce code size:
* Boot manager
* EFI_DT_FIXUP_PROTOCOL
* EFI_DEVICE_PATH_UTILITIES_PROTOCOL
* Bug fixes
* avoid EFI runtime symbols in global symbol table
-rw-r--r-- | cmd/bootefi.c | 13 | ||||
-rw-r--r-- | cmd/efidebug.c | 8 | ||||
-rw-r--r-- | include/config_distro_bootcmd.h | 12 | ||||
-rw-r--r-- | include/efi_api.h | 4 | ||||
-rw-r--r-- | include/efi_loader.h | 5 | ||||
-rw-r--r-- | include/efi_variable.h | 11 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 34 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 5 | ||||
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 135 | ||||
-rw-r--r-- | lib/efi_loader/efi_dt_fixup.c | 34 | ||||
-rw-r--r-- | lib/efi_loader/efi_load_options.c | 149 | ||||
-rw-r--r-- | lib/efi_loader/efi_root_node.c | 10 | ||||
-rw-r--r-- | lib/efi_loader/efi_unicode_collation.c | 39 | ||||
-rw-r--r-- | lib/efi_loader/efi_var_mem.c | 13 | ||||
-rw-r--r-- | lib/efi_loader/efi_variable_tee.c | 2 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 11 | ||||
-rw-r--r-- | lib/efi_selftest/dtbdump.c | 148 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_console.c | 3 | ||||
-rw-r--r-- | lib/efi_selftest/initrddump.c | 449 |
19 files changed, 820 insertions, 265 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index fe70eec6258..c8eb5c32b07 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -631,10 +631,12 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, else if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; - if (!strcmp(argv[1], "bootmgr")) - return do_efibootmgr(); + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { + if (!strcmp(argv[1], "bootmgr")) + return do_efibootmgr(); + } #ifdef CONFIG_CMD_BOOTEFI_SELFTEST - else if (!strcmp(argv[1], "selftest")) + if (!strcmp(argv[1], "selftest")) return do_efi_selftest(); #endif @@ -657,11 +659,14 @@ static char bootefi_help_text[] = " Use environment variable efi_selftest to select a single test.\n" " Use 'setenv efi_selftest list' to enumerate all tests.\n" #endif +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR "bootefi bootmgr [fdt address]\n" " - load and boot EFI payload based on BootOrder/BootXXXX variables.\n" "\n" " If specified, the device tree located at <fdt address> gets\n" - " exposed as EFI configuration table.\n"; + " exposed as EFI configuration table.\n" +#endif + ; #endif U_BOOT_CMD( diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 6de81cab008..9a2d4ddd5ef 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1367,8 +1367,8 @@ static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag, * * efidebug test bootmgr */ -static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, - int argc, char * const argv[]) +static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, + int argc, char * const argv[]) { efi_handle_t image; efi_uintn_t exit_data_size = 0; @@ -1392,8 +1392,10 @@ static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, } static struct cmd_tbl cmd_efidebug_test_sub[] = { +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr, "", ""), +#endif }; /** @@ -1581,8 +1583,10 @@ static char efidebug_help_text[] = " - show UEFI memory map\n" "efidebug tables\n" " - show UEFI configuration tables\n" +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR "efidebug test bootmgr\n" " - run simple bootmgr for test\n" +#endif "efidebug query [-nv][-bs][-rt][-at]\n" " - show size of UEFI variables store\n"; #endif diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h index c9862260a38..2627c2a6a54 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -123,14 +123,20 @@ #endif #endif - -#define BOOTENV_SHARED_EFI \ +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR +#define BOOTENV_EFI_BOOTMGR \ "boot_efi_bootmgr=" \ "if fdt addr ${fdt_addr_r}; then " \ "bootefi bootmgr ${fdt_addr_r};" \ "else " \ "bootefi bootmgr;" \ - "fi\0" \ + "fi\0" +#else +#define BOOTENV_EFI_BOOTMGR +#endif + +#define BOOTENV_SHARED_EFI \ + BOOTENV_EFI_BOOTMGR \ \ "boot_efi_binary=" \ "load ${devtype} ${devnum}:${distro_bootpart} " \ diff --git a/include/efi_api.h b/include/efi_api.h index df9bee2ae43..48e48a6263b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1693,10 +1693,6 @@ struct efi_driver_binding_protocol { efi_handle_t driver_binding_handle; }; -/* Deprecated version of the Unicode collation protocol */ -#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ - EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ - 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) /* Current version of the Unicode collation protocol */ #define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ diff --git a/include/efi_loader.h b/include/efi_loader.h index e53d286b9d1..f470bbd636f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -147,9 +147,6 @@ extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; /* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; -/* deprecated version of the EFI_UNICODE_COLLATION_PROTOCOL */ -extern const struct efi_unicode_collation_protocol - efi_unicode_collation_protocol; /* current version of the EFI_UNICODE_COLLATION_PROTOCOL */ extern const struct efi_unicode_collation_protocol efi_unicode_collation_protocol2; @@ -564,7 +561,7 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); * @size: size in bytes * Return: size in pages */ -#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) +#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); /* More specific EFI memory allocator, called by EFI payloads */ diff --git a/include/efi_variable.h b/include/efi_variable.h index bf5076233e4..4623a641427 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -306,4 +306,15 @@ efi_status_t __efi_runtime EFIAPI efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *guid); +/** + * efi_var_buf_update() - udpate memory buffer for variables + * + * @var_buf: source buffer + * + * This function copies to the memory buffer for UEFI variables. Call this + * function in ExitBootServices() if memory backed variables are only used + * at runtime to fill the buffer. + */ +void efi_var_buf_update(struct efi_var_file *var_buf); + #endif diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index fdf245dea30..e729f727df1 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 412fa882455..10b42e8847b 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -21,20 +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 d3be2f94c60..25f5cebfdb6 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_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index 5f0ae5c3383..3850ab3b0fe 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -10,16 +10,6 @@ #include <efi_loader.h> #include <mapmem.h> -static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, - void *dtb, - efi_uintn_t *buffer_size, - u32 flags); - -struct efi_dt_fixup_protocol efi_dt_fixup_prot = { - .revision = EFI_DT_FIXUP_PROTOCOL_REVISION, - .fixup = efi_dt_fixup -}; - const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID; /** @@ -102,10 +92,21 @@ void efi_carve_out_dt_rsv(void *fdt) } } -static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, - void *dtb, - efi_uintn_t *buffer_size, - u32 flags) +/** + * 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; @@ -158,3 +159,8 @@ static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, 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_load_options.c b/lib/efi_loader/efi_load_options.c new file mode 100644 index 00000000000..68cd85ba2ee --- /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_root_node.c b/lib/efi_loader/efi_root_node.c index b411a12cf66..739c6867f41 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -58,21 +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(GENERATE_ACPI_TABLE) +#endif +#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) -#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 */ &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 6655c68092e..f6c875bc33c 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 d155f25f60e..3d335a82746 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 b8808fdecad..51920bcb51a 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_selftest/Makefile b/lib/efi_selftest/Makefile index 426552bfa01..7d6ea30102e 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) +CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI) obj-y += \ efi_selftest.o \ @@ -78,8 +80,13 @@ efi_selftest_miniapp_exception.efi \ efi_selftest_miniapp_exit.efi \ efi_selftest_miniapp_return.efi -always += \ -dtbdump.efi +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) +always += dtbdump.efi +endif + +ifdef CONFIG_EFI_LOAD_FILE2_INITRD +always += initrddump.efi +endif $(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \ diff --git a/lib/efi_selftest/dtbdump.c b/lib/efi_selftest/dtbdump.c index efef759863e..953b264d9d4 100644 --- a/lib/efi_selftest/dtbdump.c +++ b/lib/efi_selftest/dtbdump.c @@ -29,6 +29,16 @@ static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID; static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; /** + * print() - print string + * + * @string: text + */ +static void print(u16 *string) +{ + cout->output_string(cout, string); +} + +/** * error() - print error string * * @string: error text @@ -36,12 +46,56 @@ static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; static void error(u16 *string) { cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK); - cout->output_string(cout, string); + print(string); cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); } /** - * input() - read string from console + * efi_input_yn() - get answer to yes/no question + * + * Return: + * y or Y + * EFI_SUCCESS + * n or N + * EFI_ACCESS_DENIED + * ESC + * EFI_ABORTED + */ +static efi_status_t efi_input_yn(void) +{ + struct efi_input_key key = {0}; + efi_uintn_t index; + efi_status_t ret; + + /* Drain the console input */ + ret = cin->reset(cin, true); + for (;;) { + ret = bs->wait_for_event(1, &cin->wait_for_key, &index); + if (ret != EFI_SUCCESS) + continue; + ret = cin->read_key_stroke(cin, &key); + if (ret != EFI_SUCCESS) + continue; + switch (key.scan_code) { + case 0x17: /* Escape */ + return EFI_ABORTED; + default: + break; + } + /* Convert to lower case */ + switch (key.unicode_char | 0x20) { + case 'y': + return EFI_SUCCESS; + case 'n': + return EFI_ACCESS_DENIED; + default: + break; + } + } +} + +/** + * efi_input() - read string from console * * @buffer: input buffer * @buffer_size: buffer size @@ -67,7 +121,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) continue; switch (key.scan_code) { case 0x17: /* Escape */ - cout->output_string(cout, L"\nAborted\n"); + print(L"\r\nAborted\r\n"); return EFI_ABORTED; default: break; @@ -76,12 +130,12 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) case 0x08: /* Backspace */ if (pos) { buffer[pos--] = 0; - cout->output_string(cout, L"\b \b"); + print(L"\b \b"); } break; case 0x0a: /* Linefeed */ case 0x0d: /* Carriage return */ - cout->output_string(cout, L"\n"); + print(L"\r\n"); return EFI_SUCCESS; default: break; @@ -94,7 +148,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) *outbuf = key.unicode_char; buffer[pos++] = key.unicode_char; buffer[pos] = 0; - cout->output_string(cout, outbuf); + print(outbuf); } } } @@ -171,9 +225,9 @@ bool starts_with(u16 *string, u16 *keyword) */ void do_help(void) { - error(L"load <dtb> - load device-tree from file\n"); - error(L"save <dtb> - save device-tree to file\n"); - error(L"exit - exit the shell\n"); + error(L"load <dtb> - load device-tree from file\r\n"); + error(L"save <dtb> - save device-tree to file\r\n"); + error(L"exit - exit the shell\r\n"); } /** @@ -198,7 +252,7 @@ efi_status_t do_load(u16 *filename) ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL, (void **)&dt_fixup_prot); if (ret != EFI_SUCCESS) { - error(L"Device-tree fix-up protocol not found\n"); + error(L"Device-tree fix-up protocol not found\r\n"); return ret; } @@ -208,7 +262,7 @@ efi_status_t do_load(u16 *filename) (void **)&loaded_image, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Loaded image protocol not found\n"); + error(L"Loaded image protocol not found\r\n"); return ret; } /* Open the simple file system protocol */ @@ -217,57 +271,57 @@ efi_status_t do_load(u16 *filename) (void **)&file_system, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Failed to open simple file system protocol\n"); + error(L"Failed to open simple file system protocol\r\n"); goto out; } /* Open volume */ ret = file_system->open_volume(file_system, &root); if (ret != EFI_SUCCESS) { - error(L"Failed to open volume\n"); + error(L"Failed to open volume\r\n"); goto out; } /* Open file */ ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); if (ret != EFI_SUCCESS) { - error(L"File not found\n"); + error(L"File not found\r\n"); goto out; } /* Get file size */ buffer_size = 0; ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL); if (ret != EFI_BUFFER_TOO_SMALL) { - error(L"Can't get file info size\n"); + error(L"Can't get file info size\r\n"); goto out; } ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info); if (ret != EFI_SUCCESS) { - error(L"Out of memory\n"); + error(L"Out of memory\r\n"); goto out; } ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info); if (ret != EFI_SUCCESS) { - error(L"Can't get file info\n"); + error(L"Can't get file info\r\n"); goto out; } buffer_size = info->file_size; pages = efi_size_in_pages(buffer_size); ret = bs->free_pool(info); if (ret != EFI_SUCCESS) - error(L"Can't free memory pool\n"); + error(L"Can't free memory pool\r\n"); /* Read file */ ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_ACPI_RECLAIM_MEMORY, pages, &addr); if (ret != EFI_SUCCESS) { - error(L"Out of memory\n"); + error(L"Out of memory\r\n"); goto out; } dtb = (struct fdt_header *)(uintptr_t)addr; ret = file->read(file, &buffer_size, dtb); if (ret != EFI_SUCCESS) { - error(L"Can't read file\n"); + error(L"Can't read file\r\n"); goto out; } /* Fixup file, expecting EFI_BUFFER_TOO_SMALL */ @@ -278,24 +332,24 @@ efi_status_t do_load(u16 *filename) /* Read file into larger buffer */ ret = bs->free_pages(addr, pages); if (ret != EFI_SUCCESS) - error(L"Can't free memory pages\n"); + error(L"Can't free memory pages\r\n"); pages = efi_size_in_pages(buffer_size); ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_ACPI_RECLAIM_MEMORY, pages, &addr); if (ret != EFI_SUCCESS) { - error(L"Out of memory\n"); + error(L"Out of memory\r\n"); goto out; } dtb = (struct fdt_header *)(uintptr_t)addr; ret = file->setpos(file, 0); if (ret != EFI_SUCCESS) { - error(L"Can't position file\n"); + error(L"Can't position file\r\n"); goto out; } ret = file->read(file, &buffer_size, dtb); if (ret != EFI_SUCCESS) { - error(L"Can't read file\n"); + error(L"Can't read file\r\n"); goto out; } buffer_size = pages << EFI_PAGE_SHIFT; @@ -305,24 +359,24 @@ efi_status_t do_load(u16 *filename) EFI_DT_INSTALL_TABLE); } if (ret == EFI_SUCCESS) - cout->output_string(cout, L"device-tree installed\n"); + print(L"device-tree installed\r\n"); else - error(L"Device-tree fix-up failed\n"); + error(L"Device-tree fix-up failed\r\n"); out: if (addr) { ret2 = bs->free_pages(addr, pages); if (ret2 != EFI_SUCCESS) - error(L"Can't free memory pages\n"); + error(L"Can't free memory pages\r\n"); } if (file) { ret2 = file->close(file); if (ret2 != EFI_SUCCESS) - error(L"Can't close file\n"); + error(L"Can't close file\r\n"); } if (root) { ret2 = root->close(root); if (ret2 != EFI_SUCCESS) - error(L"Can't close volume\n"); + error(L"Can't close volume\r\n"); } return ret; } @@ -344,11 +398,11 @@ efi_status_t do_save(u16 *filename) dtb = get_dtb(systable); if (!dtb) { - error(L"DTB not found\n"); + error(L"DTB not found\r\n"); return EFI_NOT_FOUND; } if (f2h(dtb->magic) != FDT_MAGIC) { - error(L"Wrong device tree magic\n"); + error(L"Wrong device tree magic\r\n"); return EFI_NOT_FOUND; } dtb_size = f2h(dtb->totalsize); @@ -359,7 +413,7 @@ efi_status_t do_save(u16 *filename) (void **)&loaded_image, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Loaded image protocol not found\n"); + error(L"Loaded image protocol not found\r\n"); return ret; } @@ -369,16 +423,30 @@ efi_status_t do_save(u16 *filename) (void **)&file_system, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Failed to open simple file system protocol\n"); + error(L"Failed to open simple file system protocol\r\n"); return ret; } /* Open volume */ ret = file_system->open_volume(file_system, &root); if (ret != EFI_SUCCESS) { - error(L"Failed to open volume\n"); + error(L"Failed to open volume\r\n"); return ret; } + /* Check if file already exists */ + ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); + if (ret == EFI_SUCCESS) { + file->close(file); + print(L"Overwrite existing file (y/n)? "); + ret = efi_input_yn(); + print(L"\r\n"); + if (ret != EFI_SUCCESS) { + root->close(root); + error(L"Aborted by user\r\n"); + return ret; + } + } + /* Create file */ ret = root->open(root, &file, filename, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | @@ -387,16 +455,16 @@ efi_status_t do_save(u16 *filename) /* Write file */ ret = file->write(file, &dtb_size, dtb); if (ret != EFI_SUCCESS) - error(L"Failed to write file\n"); + error(L"Failed to write file\r\n"); file->close(file); } else { - error(L"Failed to open file\n"); + error(L"Failed to open file\r\n"); } root->close(root); if (ret == EFI_SUCCESS) { - cout->output_string(cout, filename); - cout->output_string(cout, L" written\n"); + print(filename); + print(L" written\r\n"); } return ret; @@ -422,7 +490,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle, cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); cout->clear_screen(cout); cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK); - cout->output_string(cout, L"DTB Dump\n========\n\n"); + print(L"DTB Dump\r\n========\r\n\r\n"); cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); for (;;) { @@ -430,7 +498,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle, u16 *pos; efi_uintn_t ret; - cout->output_string(cout, L"=> "); + print(L"=> "); ret = efi_input(command, sizeof(command)); if (ret == EFI_ABORTED) break; diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index 0219bd70e05..ffd88a1e26d 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -46,11 +46,10 @@ static void mac(void *pointer, u16 **buf) /* * printx() - print hexadecimal number to an u16 string * - * @pointer: pointer + * @p: value to print * @prec: minimum number of digits to print * @buf: pointer to buffer address, * on return position of terminating zero word - * @size: size of value to be printed in bytes */ static void printx(u64 p, int prec, u16 **buf) { diff --git a/lib/efi_selftest/initrddump.c b/lib/efi_selftest/initrddump.c new file mode 100644 index 00000000000..c23a05c718f --- /dev/null +++ b/lib/efi_selftest/initrddump.c @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * initrddump.efi saves the initial RAM disk provided via the + * EFI_LOAD_FILE2_PROTOCOL. + */ + +#include <common.h> +#include <efi_api.h> +#include <efi_load_initrd.h> + +#define BUFFER_SIZE 64 +#define ESC 0x17 + +#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) + +static struct efi_system_table *systable; +static struct efi_boot_services *bs; +static struct efi_simple_text_output_protocol *cerr; +static struct efi_simple_text_output_protocol *cout; +static struct efi_simple_text_input_protocol *cin; +static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; +static const efi_guid_t guid_simple_file_system_protocol = + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; +static efi_handle_t handle; + +/* + * Device path defined by Linux to identify the handle providing the + * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk. + */ +static const struct efi_initrd_dp initrd_dp = { + .vendor = { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR_PATH, + sizeof(initrd_dp.vendor), + }, + EFI_INITRD_MEDIA_GUID, + }, + .end = { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(initrd_dp.end), + } +}; + +/** + * print() - print string + * + * @string: text + */ +static void print(u16 *string) +{ + cout->output_string(cout, string); +} + +/** + * error() - print error string + * + * @string: error text + */ +static void error(u16 *string) +{ + cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK); + print(string); + cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); +} + +/* + * printx() - print hexadecimal number + * + * @val: value to print; + * @prec: minimum number of digits to print + */ +static void printx(u64 val, u32 prec) +{ + int i; + u16 c; + u16 buf[16]; + u16 *pos = buf; + + for (i = 2 * sizeof(val) - 1; i >= 0; --i) { + c = (val >> (4 * i)) & 0x0f; + if (c || pos != buf || !i || i < prec) { + c += '0'; + if (c > '9') + c += 'a' - '9' - 1; + *pos++ = c; + } + } + *pos = 0; + print(buf); +} + +/** + * efi_input_yn() - get answer to yes/no question + * + * Return: + * y or Y + * EFI_SUCCESS + * n or N + * EFI_ACCESS_DENIED + * ESC + * EFI_ABORTED + */ +static efi_status_t efi_input_yn(void) +{ + struct efi_input_key key = {0}; + efi_uintn_t index; + efi_status_t ret; + + /* Drain the console input */ + ret = cin->reset(cin, true); + for (;;) { + ret = bs->wait_for_event(1, &cin->wait_for_key, &index); + if (ret != EFI_SUCCESS) + continue; + ret = cin->read_key_stroke(cin, &key); + if (ret != EFI_SUCCESS) + continue; + switch (key.scan_code) { + case 0x17: /* Escape */ + return EFI_ABORTED; + default: + break; + } + /* Convert to lower case */ + switch (key.unicode_char | 0x20) { + case 'y': + return EFI_SUCCESS; + case 'n': + return EFI_ACCESS_DENIED; + default: + break; + } + } +} + +/** + * efi_input() - read string from console + * + * @buffer: input buffer + * @buffer_size: buffer size + * Return: status code + */ +static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) +{ + struct efi_input_key key = {0}; + efi_uintn_t index; + efi_uintn_t pos = 0; + u16 outbuf[2] = L" "; + efi_status_t ret; + + /* Drain the console input */ + ret = cin->reset(cin, true); + *buffer = 0; + for (;;) { + ret = bs->wait_for_event(1, &cin->wait_for_key, &index); + if (ret != EFI_SUCCESS) + continue; + ret = cin->read_key_stroke(cin, &key); + if (ret != EFI_SUCCESS) + continue; + switch (key.scan_code) { + case 0x17: /* Escape */ + print(L"\r\nAborted\r\n"); + return EFI_ABORTED; + default: + break; + } + switch (key.unicode_char) { + case 0x08: /* Backspace */ + if (pos) { + buffer[pos--] = 0; + print(L"\b \b"); + } + break; + case 0x0a: /* Linefeed */ + case 0x0d: /* Carriage return */ + print(L"\r\n"); + return EFI_SUCCESS; + default: + break; + } + /* Ignore surrogate codes */ + if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF) + continue; + if (key.unicode_char >= 0x20 && + pos < buffer_size - 1) { + *outbuf = key.unicode_char; + buffer[pos++] = key.unicode_char; + buffer[pos] = 0; + print(outbuf); + } + } +} + +/** + * skip_whitespace() - skip over leading whitespace + * + * @pos: UTF-16 string + * Return: pointer to first non-whitespace + */ +static u16 *skip_whitespace(u16 *pos) +{ + for (; *pos && *pos <= 0x20; ++pos) + ; + return pos; +} + +/** + * starts_with() - check if @string starts with @keyword + * + * @string: string to search for keyword + * @keyword: keyword to be searched + * Return: true fi @string starts with the keyword + */ +static bool starts_with(u16 *string, u16 *keyword) +{ + for (; *keyword; ++string, ++keyword) { + if (*string != *keyword) + return false; + } + return true; +} + +/** + * do_help() - print help + */ +static void do_help(void) +{ + error(L"load - show length and CRC32 of initial RAM disk\r\n"); + error(L"save <initrd> - save initial RAM disk to file\r\n"); + error(L"exit - exit the shell\r\n"); +} + +/** + * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL + * + * @initrd: on return buffer with initial RAM disk + * @initrd_size: size of initial RAM disk + * Return: status code + */ +static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size) +{ + struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp; + struct efi_load_file_protocol *load_file2_prot; + u64 buffer; + efi_handle_t handle; + efi_status_t ret; + + *initrd = NULL; + *initrd_size = 0; + ret = bs->locate_device_path(&load_file2_guid, &dp, &handle); + if (ret != EFI_SUCCESS) { + error(L"Load File2 protocol not found\r\n"); + return ret; + } + ret = bs->handle_protocol(handle, &load_file2_guid, + (void **)&load_file2_prot); + ret = load_file2_prot->load_file(load_file2_prot, dp, false, + initrd_size, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + error(L"Load File2 protocol does not provide file length\r\n"); + return EFI_LOAD_ERROR; + } + ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA, + efi_size_in_pages(*initrd_size), &buffer); + if (ret != EFI_SUCCESS) { + error(L"Out of memory\r\n"); + return ret; + } + *initrd = (void *)buffer; + ret = load_file2_prot->load_file(load_file2_prot, dp, false, + initrd_size, *initrd); + if (ret != EFI_SUCCESS) { + error(L"Load File2 protocol failed to provide file\r\n"); + bs->free_pages(buffer, efi_size_in_pages(*initrd_size)); + return EFI_LOAD_ERROR; + } + return ret; +} + +/** + * do_load() - load initial RAM disk and display CRC32 and length + * + * @filename: file name + * Return: status code + */ +static efi_status_t do_load(void) +{ + void *initrd; + efi_uintn_t initrd_size; + u32 crc32; + efi_uintn_t ret; + + ret = get_initrd(&initrd, &initrd_size); + if (ret != EFI_SUCCESS) + return ret; + print(L"length: 0x"); + printx(initrd_size, 1); + print(L"\r\n"); + + ret = bs->calculate_crc32(initrd, initrd_size, &crc32); + if (ret != EFI_SUCCESS) { + error(L"Calculating CRC32 failed\r\n"); + return EFI_LOAD_ERROR; + } + print(L"crc32: 0x"); + printx(crc32, 8); + print(L"\r\n"); + + return EFI_SUCCESS; +} + +/** + * do_save() - save initial RAM disk + * + * @filename: file name + * Return: status code + */ +static efi_status_t do_save(u16 *filename) +{ + struct efi_loaded_image *loaded_image; + struct efi_simple_file_system_protocol *file_system; + struct efi_file_handle *root, *file; + void *initrd; + efi_uintn_t initrd_size; + efi_uintn_t ret; + + ret = get_initrd(&initrd, &initrd_size); + if (ret != EFI_SUCCESS) + return ret; + + filename = skip_whitespace(filename); + + ret = bs->open_protocol(handle, &loaded_image_guid, + (void **)&loaded_image, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + error(L"Loaded image protocol not found\r\n"); + goto out; + } + + /* Open the simple file system protocol */ + ret = bs->open_protocol(loaded_image->device_handle, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + error(L"Failed to open simple file system protocol\r\n"); + goto out; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + error(L"Failed to open volume\r\n"); + goto out; + } + /* Check if file already exists */ + ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); + if (ret == EFI_SUCCESS) { + file->close(file); + print(L"Overwrite existing file (y/n)? "); + ret = efi_input_yn(); + print(L"\r\n"); + if (ret != EFI_SUCCESS) { + root->close(root); + error(L"Aborted by user\r\n"); + goto out; + } + } + + /* Create file */ + ret = root->open(root, &file, filename, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE); + if (ret == EFI_SUCCESS) { + /* Write file */ + ret = file->write(file, &initrd_size, initrd); + if (ret != EFI_SUCCESS) { + error(L"Failed to write file\r\n"); + } else { + print(filename); + print(L" written\r\n"); + } + file->close(file); + } else { + error(L"Failed to open file\r\n"); + } + root->close(root); + +out: + if (initrd) + bs->free_pages((uintptr_t)initrd, + efi_size_in_pages(initrd_size)); + return ret; +} + +/** + * 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 image_handle, + struct efi_system_table *systab) +{ + handle = image_handle; + systable = systab; + cerr = systable->std_err; + cout = systable->con_out; + cin = systable->con_in; + bs = systable->boottime; + + cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); + cout->clear_screen(cout); + cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK); + print(L"INITRD Dump\r\n========\r\n\r\n"); + cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); + + for (;;) { + u16 command[BUFFER_SIZE]; + u16 *pos; + efi_uintn_t ret; + + print(L"=> "); + ret = efi_input(command, sizeof(command)); + if (ret == EFI_ABORTED) + break; + pos = skip_whitespace(command); + if (starts_with(pos, L"exit")) + break; + else if (starts_with(pos, L"load")) + do_load(); + else if (starts_with(pos, L"save ")) + do_save(pos + 5); + else + do_help(); + } + + cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); + cout->clear_screen(cout); + return EFI_SUCCESS; +} |