diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 5 | ||||
-rw-r--r-- | lib/aes.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 34 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 8 | ||||
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 135 | ||||
-rw-r--r-- | lib/efi_loader/efi_console.c | 6 | ||||
-rw-r--r-- | lib/efi_loader/efi_dt_fixup.c | 166 | ||||
-rw-r--r-- | lib/efi_loader/efi_file.c | 317 | ||||
-rw-r--r-- | lib/efi_loader/efi_image_loader.c | 80 | ||||
-rw-r--r-- | lib/efi_loader/efi_load_options.c | 149 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_root_node.c | 14 | ||||
-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_loader/helloworld.c | 167 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 11 | ||||
-rw-r--r-- | lib/efi_selftest/dtbdump.c | 390 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_console.c | 3 | ||||
-rw-r--r-- | lib/efi_selftest/initrddump.c | 449 | ||||
-rw-r--r-- | lib/string.c | 14 | ||||
-rw-r--r-- | lib/uuid.c | 35 | ||||
-rw-r--r-- | lib/zlib/deflate.c | 2 | ||||
-rw-r--r-- | lib/zlib/trees.c | 2 |
24 files changed, 1673 insertions, 372 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index a704568443..b35a71ac36 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -210,6 +210,7 @@ config BITREVERSE config TRACE bool "Support for tracing of function calls and timing" imply CMD_TRACE + select TIMER_EARLY help Enables function tracing within U-Boot. This allows recording of call traces including timing information. The command can write data to @@ -695,8 +696,8 @@ config LIB_DATE config LIB_ELF bool help - Supoort basic elf loading/validating functions. - This supports fir 32 bit and 64 bit versions. + Support basic elf loading/validating functions. + This supports for 32 bit and 64 bit versions. endmenu @@ -619,7 +619,7 @@ void aes_decrypt(u32 key_len, u8 *in, u8 *expkey, u8 *out) static void debug_print_vector(char *name, u32 num_bytes, u8 *data) { #ifdef DEBUG - printf("%s [%d] @0x%08x", name, num_bytes, (u32)data); + printf("%s [%d] @0x%p", name, num_bytes, data); print_buffer(0, data, 1, num_bytes, 16); #endif } 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); diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 426552bfa0..7d6ea30102 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 d90e3eb768..953b264d9d 100644 --- a/lib/efi_selftest/dtbdump.c +++ b/lib/efi_selftest/dtbdump.c @@ -8,10 +8,12 @@ #include <common.h> #include <efi_api.h> +#include <efi_dt_fixup.h> #define BUFFER_SIZE 64 #define ESC 0x17 -#define DEFAULT_FILENAME L"dtb.dtb" + +#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) static struct efi_simple_text_output_protocol *cerr; static struct efi_simple_text_output_protocol *cout; @@ -21,9 +23,79 @@ static const efi_guid_t fdt_guid = EFI_FDT_GUID; 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 efi_handle_t handle; +static struct efi_system_table *systable; +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 + */ +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); +} + +/** + * 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; + } + } +} /** - * input() - read string from console + * efi_input() - read string from console * * @buffer: input buffer * @buffer_size: buffer size @@ -39,6 +111,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) /* 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) @@ -48,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; @@ -57,11 +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 */ + print(L"\r\n"); return EFI_SUCCESS; default: break; @@ -73,7 +147,8 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) pos < buffer_size - 1) { *outbuf = key.unicode_char; buffer[pos++] = key.unicode_char; - cout->output_string(cout, outbuf); + buffer[pos] = 0; + print(outbuf); } } } @@ -117,60 +192,228 @@ void *get_dtb(struct efi_system_table *systable) } /** - * efi_main() - entry point of the EFI application. + * skip_whitespace() - skip over leading whitespace * - * @handle: handle of the loaded image - * @systable: system table - * @return: status code + * @pos: UTF-16 string + * Return: pointer to first non-whitespace */ -efi_status_t EFIAPI efi_main(efi_handle_t handle, - struct efi_system_table *systable) +u16 *skip_whitespace(u16 *pos) { - efi_uintn_t ret; - u16 filename[BUFFER_SIZE] = {0}; - efi_uintn_t dtb_size; + 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 + */ +bool starts_with(u16 *string, u16 *keyword) +{ + for (; *keyword; ++string, ++keyword) { + if (*string != *keyword) + return false; + } + return true; +} + +/** + * do_help() - print help + */ +void do_help(void) +{ + 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"); +} + +/** + * do_load() - load and install device-tree + * + * @filename: file name + * Return: status code + */ +efi_status_t do_load(u16 *filename) +{ + struct efi_dt_fixup_protocol *dt_fixup_prot; struct efi_loaded_image *loaded_image; struct efi_simple_file_system_protocol *file_system; - struct efi_file_handle *root, *file; + struct efi_file_handle *root = NULL, *file = NULL; + u64 addr = 0; + struct efi_file_info *info; struct fdt_header *dtb; + efi_uintn_t buffer_size; + efi_uintn_t pages; + efi_status_t ret, ret2; - cerr = systable->std_err; - cout = systable->con_out; - cin = systable->con_in; - bs = systable->boottime; + 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\r\n"); + return ret; + } - cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); - cout->clear_screen(cout); - cout->set_attribute(cout, EFI_YELLOW | EFI_BACKGROUND_BLACK); - cout->output_string(cout, L"DTB Dump\n\n"); - cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); + 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"); + return ret; + } + /* 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; + } + + /* Open file */ + ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); + if (ret != EFI_SUCCESS) { + 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\r\n"); + goto out; + } + ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info); + if (ret != EFI_SUCCESS) { + 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\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\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\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\r\n"); + goto out; + } + /* Fixup file, expecting EFI_BUFFER_TOO_SMALL */ + ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size, + EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY | + EFI_DT_INSTALL_TABLE); + if (ret == EFI_BUFFER_TOO_SMALL) { + /* Read file into larger buffer */ + ret = bs->free_pages(addr, pages); + if (ret != EFI_SUCCESS) + 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\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\r\n"); + goto out; + } + ret = file->read(file, &buffer_size, dtb); + if (ret != EFI_SUCCESS) { + error(L"Can't read file\r\n"); + goto out; + } + buffer_size = pages << EFI_PAGE_SHIFT; + ret = dt_fixup_prot->fixup( + dt_fixup_prot, dtb, &buffer_size, + EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY | + EFI_DT_INSTALL_TABLE); + } + if (ret == EFI_SUCCESS) + print(L"device-tree installed\r\n"); + else + 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\r\n"); + } + if (file) { + ret2 = file->close(file); + if (ret2 != EFI_SUCCESS) + error(L"Can't close file\r\n"); + } + if (root) { + ret2 = root->close(root); + if (ret2 != EFI_SUCCESS) + error(L"Can't close volume\r\n"); + } + return ret; +} + +/** + * do_save() - save current device-tree + * + * @filename: file name + * Return: status code + */ +efi_status_t do_save(u16 *filename) +{ + struct efi_loaded_image *loaded_image; + struct efi_simple_file_system_protocol *file_system; + efi_uintn_t dtb_size; + struct efi_file_handle *root, *file; + struct fdt_header *dtb; + efi_uintn_t ret; dtb = get_dtb(systable); if (!dtb) { - cerr->output_string(cout, L"DTB not found\n"); + error(L"DTB not found\r\n"); return EFI_NOT_FOUND; } if (f2h(dtb->magic) != FDT_MAGIC) { - cerr->output_string(cout, L"Wrong device tree magic\n"); + error(L"Wrong device tree magic\r\n"); return EFI_NOT_FOUND; } dtb_size = f2h(dtb->totalsize); - cout->output_string(cout, L"Filename (" DEFAULT_FILENAME ")?\n"); - ret = efi_input(filename, sizeof(filename)); - if (ret != EFI_SUCCESS) - return ret; - if (!*filename) - memcpy(filename, DEFAULT_FILENAME, sizeof(DEFAULT_FILENAME)); - - cout->output_string(cout, L"\n"); + 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) { - cerr->output_string(cout, - L"Loaded image protocol not found\n"); + error(L"Loaded image protocol not found\r\n"); return ret; } @@ -180,17 +423,30 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, (void **)&file_system, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - cerr->output_string( - cout, 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) { - cerr->output_string(cerr, 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 | @@ -199,17 +455,65 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, /* Write file */ ret = file->write(file, &dtb_size, dtb); if (ret != EFI_SUCCESS) - cerr->output_string(cerr, L"Failed to write file\n"); + error(L"Failed to write file\r\n"); file->close(file); } else { - cerr->output_string(cerr, 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; } + +/** + * 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"DTB 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(pos + 5); + 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; +} diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index 0219bd70e0..ffd88a1e26 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 0000000000..c23a05c718 --- /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; +} diff --git a/lib/string.c b/lib/string.c index ae7835f600..73b984123d 100644 --- a/lib/string.c +++ b/lib/string.c @@ -567,7 +567,19 @@ void * memmove(void * dest,const void *src,size_t count) { char *tmp, *s; - if (dest <= src) { + if (dest <= src || (src + count) <= dest) { + /* + * Use the fast memcpy implementation (ARCH optimized or lib/string.c) when it is possible: + * - when dest is before src (assuming that memcpy is doing forward-copying) + * - when destination don't overlap the source buffer (src + count <= dest) + * + * WARNING: the first optimisation cause an issue, when __HAVE_ARCH_MEMCPY is defined, + * __HAVE_ARCH_MEMMOVE is not defined and if the memcpy ARCH-specific + * implementation is not doing a forward-copying. + * + * No issue today because memcpy is doing a forward-copying in lib/string.c and for ARM32 + * architecture; no other arches use __HAVE_ARCH_MEMCPY without __HAVE_ARCH_MEMMOVE. + */ memcpy(dest, src, count); } else { tmp = (char *) dest + count; diff --git a/lib/uuid.c b/lib/uuid.c index e62d5ca264..5bc68674d0 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -15,6 +15,8 @@ #include <asm/io.h> #include <part_efi.h> #include <malloc.h> +#include <dm/uclass.h> +#include <rng.h> /* * UUID - Universally Unique IDentifier - 128 bits unique number. @@ -96,7 +98,8 @@ static const struct { {"linux", PARTITION_LINUX_FILE_SYSTEM_DATA_GUID}, {"raid", PARTITION_LINUX_RAID_GUID}, {"swap", PARTITION_LINUX_SWAP_GUID}, - {"lvm", PARTITION_LINUX_LVM_GUID} + {"lvm", PARTITION_LINUX_LVM_GUID}, + {"u-boot-env", PARTITION_U_BOOT_ENVIRONMENT}, }; /* @@ -122,20 +125,19 @@ int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin) * uuid_guid_get_str() - this function get string for GUID. * * @param guid_bin - pointer to string with partition type guid [16B] - * @param guid_str - pointer to allocated partition type string [7B] + * + * Returns NULL if the type GUID is not known. */ -int uuid_guid_get_str(const unsigned char *guid_bin, char *guid_str) +const char *uuid_guid_get_str(const unsigned char *guid_bin) { int i; - *guid_str = 0; for (i = 0; i < ARRAY_SIZE(list_guid); i++) { if (!memcmp(list_guid[i].guid.b, guid_bin, 16)) { - strcpy(guid_str, list_guid[i].string); - return 0; + return list_guid[i].string; } } - return -ENODEV; + return NULL; } #endif @@ -249,9 +251,22 @@ void gen_rand_uuid(unsigned char *uuid_bin) { u32 ptr[4]; struct uuid *uuid = (struct uuid *)ptr; - int i; - - srand(get_ticks() + rand()); + int i, ret; + struct udevice *devp; + u32 randv = 0; + + if (IS_ENABLED(CONFIG_DM_RNG)) { + ret = uclass_get_device(UCLASS_RNG, 0, &devp); + if (ret) { + ret = dm_rng_read(devp, &randv, sizeof(randv)); + if (ret < 0) + randv = 0; + } + } + if (randv) + srand(randv); + else + srand(get_ticks() + rand()); /* Set all fields randomly */ for (i = 0; i < 4; i++) diff --git a/lib/zlib/deflate.c b/lib/zlib/deflate.c index 1fe58d5da6..63473359e4 100644 --- a/lib/zlib/deflate.c +++ b/lib/zlib/deflate.c @@ -1284,7 +1284,7 @@ local void check_match(s, start, match, length) } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); + do { putc(s->window[start++]); } while (--length != 0); } } #else diff --git a/lib/zlib/trees.c b/lib/zlib/trees.c index 3e09517ed0..700c62f6d7 100644 --- a/lib/zlib/trees.c +++ b/lib/zlib/trees.c @@ -38,7 +38,7 @@ #include "deflate.h" #ifdef DEBUG -# include <ctype.h> +# include <linux/ctype.h> #endif /* =========================================================================== |