diff options
Diffstat (limited to 'roms/u-boot/lib/efi_selftest')
54 files changed, 12291 insertions, 0 deletions
diff --git a/roms/u-boot/lib/efi_selftest/.gitignore b/roms/u-boot/lib/efi_selftest/.gitignore new file mode 100644 index 000000000..5b25169e6 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/.gitignore @@ -0,0 +1,3 @@ +efi_miniapp_*.h +*.efi +*.so diff --git a/roms/u-boot/lib/efi_selftest/Kconfig b/roms/u-boot/lib/efi_selftest/Kconfig new file mode 100644 index 000000000..ca6243610 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/Kconfig @@ -0,0 +1,12 @@ +config CMD_BOOTEFI_SELFTEST + bool "UEFI unit tests" + depends on CMD_BOOTEFI + imply PARTITIONS + imply DOS_PARTITION + imply FAT + imply FAT_WRITE + imply CMD_POWEROFF if PSCI_RESET || SYSRESET_PSCI + help + This adds a UEFI test application to U-Boot that can be executed + via the 'bootefi selftest' command. It provides extended tests of + the UEFI API implementation. diff --git a/roms/u-boot/lib/efi_selftest/Makefile b/roms/u-boot/lib/efi_selftest/Makefile new file mode 100644 index 000000000..9ff6e1760 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/Makefile @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2017, Heinrich Schuchardt <xypron.glpk@gmx.de> + +# This file only gets included with CONFIG_EFI_LOADER set, so all +# object inclusion implicitly depends on it + +asflags-y += -DHOST_ARCH="$(HOST_ARCH)" +ccflags-y += -DHOST_ARCH="$(HOST_ARCH)" + +CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI) +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 \ +efi_selftest_bitblt.o \ +efi_selftest_config_table.o \ +efi_selftest_controllers.o \ +efi_selftest_console.o \ +efi_selftest_crc32.o \ +efi_selftest_devicepath_util.o \ +efi_selftest_events.o \ +efi_selftest_event_groups.o \ +efi_selftest_exception.o \ +efi_selftest_exitbootservices.o \ +efi_selftest_gop.o \ +efi_selftest_load_file.o \ +efi_selftest_loaded_image.o \ +efi_selftest_loadimage.o \ +efi_selftest_manageprotocols.o \ +efi_selftest_mem.o \ +efi_selftest_memory.o \ +efi_selftest_open_protocol.o \ +efi_selftest_register_notify.o \ +efi_selftest_reset.o \ +efi_selftest_set_virtual_address_map.o \ +efi_selftest_startimage_exit.o \ +efi_selftest_startimage_return.o \ +efi_selftest_textinput.o \ +efi_selftest_textinputex.o \ +efi_selftest_textoutput.o \ +efi_selftest_tpl.o \ +efi_selftest_util.o \ +efi_selftest_variables.o \ +efi_selftest_variables_runtime.o \ +efi_selftest_watchdog.o + +obj-$(CONFIG_NET) += efi_selftest_snp.o + +obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o +obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \ +efi_selftest_unicode_collation.o + +obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o +obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o +obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_selftest_rng.o +obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o +obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_selftest_tcg2.o + +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) +obj-y += efi_selftest_fdt.o +endif + +ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy) +obj-y += efi_selftest_block_device.o +endif + +obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o + +targets += \ +efi_miniapp_file_image_exception.h \ +efi_miniapp_file_image_exit.h \ +efi_miniapp_file_image_return.h \ +efi_selftest_miniapp_exception.efi \ +efi_selftest_miniapp_exit.efi \ +efi_selftest_miniapp_return.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 > \ + $(obj)/efi_miniapp_file_image_exception.h + +$(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \ + $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ + $(obj)/efi_miniapp_file_image_return.h + +$(obj)/efi_selftest_exception.o: $(obj)/efi_miniapp_file_image_exception.h + +$(obj)/efi_selftest_load_file.o: $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h diff --git a/roms/u-boot/lib/efi_selftest/dtbdump.c b/roms/u-boot/lib/efi_selftest/dtbdump.c new file mode 100644 index 000000000..f6ddaa307 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/dtbdump.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * dtbdump.efi saves the device tree provided as a configuration table + * to a file. + */ + +#include <common.h> +#include <efi_api.h> +#include <efi_dt_fixup.h> +#include <part.h> +#include <linux/libfdt.h> + +#define BUFFER_SIZE 64 +#define ESC 0x17 + +#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; +static struct efi_simple_text_input_protocol *cin; +static struct efi_boot_services *bs; +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; +static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_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; + } + } +} + +/** + * 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); + } + } +} + +/* + * Convert FDT value to host endianness. + * + * @val FDT value + * @return converted value + */ +static u32 f2h(fdt32_t val) +{ + char *buf = (char *)&val; + char i; + + /* Swap the bytes */ + i = buf[0]; buf[0] = buf[3]; buf[3] = i; + i = buf[1]; buf[1] = buf[2]; buf[2] = i; + return *(u32 *)buf; +} + +/** + * get_dtb() - get device tree + * + * @systable: system table + * Return: device tree or NULL + */ +void *get_dtb(struct efi_system_table *systable) +{ + void *dtb = NULL; + efi_uintn_t i; + + for (i = 0; i < systable->nr_tables; ++i) { + if (!memcmp(&systable->tables[i].guid, &fdt_guid, + sizeof(efi_guid_t))) { + dtb = systable->tables[i].table; + break; + } + } + return dtb; +} + +/** + * skip_whitespace() - skip over leading whitespace + * + * @pos: UTF-16 string + * Return: pointer to first non-whitespace + */ +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 + */ +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"); +} + +/** + * open_file_system() - open simple file system protocol + * + * file_system: interface of the simple file system protocol + * Return: status code + */ +static efi_status_t +open_file_system(struct efi_simple_file_system_protocol **file_system) +{ + struct efi_loaded_image *loaded_image; + efi_status_t ret; + efi_handle_t *handle_buffer = NULL; + efi_uintn_t count; + + 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 on the same partition */ + 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) + return ret; + + /* Open the simple file system protocol on the UEFI system partition */ + ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid, + NULL, &count, &handle_buffer); + if (ret == EFI_SUCCESS && handle_buffer) + ret = bs->open_protocol(handle_buffer[0], + &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"); + if (handle) + bs->free_pool(handle_buffer); + + return ret; +} + +/** + * 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_simple_file_system_protocol *file_system; + 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; + + 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; + } + + filename = skip_whitespace(filename); + + ret = open_file_system(&file_system); + if (ret != EFI_SUCCESS) + 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_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) { + error(L"DTB not found\r\n"); + return EFI_NOT_FOUND; + } + if (f2h(dtb->magic) != FDT_MAGIC) { + error(L"Wrong device tree magic\r\n"); + return EFI_NOT_FOUND; + } + dtb_size = f2h(dtb->totalsize); + + filename = skip_whitespace(filename); + + ret = open_file_system(&file_system); + if (ret != EFI_SUCCESS) + return ret; + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + 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 | + EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE); + if (ret == EFI_SUCCESS) { + /* Write file */ + ret = file->write(file, &dtb_size, dtb); + if (ret != EFI_SUCCESS) + error(L"Failed to write file\r\n"); + file->close(file); + } else { + error(L"Failed to open file\r\n"); + } + root->close(root); + + if (ret == EFI_SUCCESS) { + 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/roms/u-boot/lib/efi_selftest/efi_freestanding.c b/roms/u-boot/lib/efi_selftest/efi_freestanding.c new file mode 100644 index 000000000..4b6c27e99 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_freestanding.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Library for freestanding binary + * + * Copyright 2019, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * GCC requires that freestanding programs provide memcpy(), memmove(), + * memset(), and memcmp(). + */ + +#include "../efi_loader/efi_freestanding.c" diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest.c b/roms/u-boot/lib/efi_selftest/efi_selftest.c new file mode 100644 index 000000000..39ee2edf5 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest.c @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI efi_selftest + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <command.h> +#include <efi_selftest.h> +#include <vsprintf.h> + +/* Constants for test step bitmap */ +#define EFI_ST_SETUP 1 +#define EFI_ST_EXECUTE 2 +#define EFI_ST_TEARDOWN 4 + +static const struct efi_system_table *systable; +static const struct efi_boot_services *boottime; +static const struct efi_runtime_services *runtime; +static efi_handle_t handle; +static u16 reset_message[] = L"Selftest completed"; +static int *setup_status; + +/* + * Exit the boot services. + * + * The size of the memory map is determined. + * Pool memory is allocated to copy the memory map. + * The memory map is copied and the map key is obtained. + * The map key is used to exit the boot services. + */ +void efi_st_exit_boot_services(void) +{ + efi_uintn_t map_size = 0; + efi_uintn_t map_key; + efi_uintn_t desc_size; + u32 desc_version; + efi_status_t ret; + struct efi_mem_desc *memory_map; + + /* Do not detach devices in ExitBootServices. We need the console. */ + efi_st_keep_devices = true; + + ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error( + "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); + return; + } + /* Allocate extra space for newly allocated memory */ + map_size += sizeof(struct efi_mem_desc); + ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + (void **)&memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); + return; + } + ret = boottime->get_memory_map(&map_size, memory_map, &map_key, + &desc_size, &desc_version); + if (ret != EFI_SUCCESS) { + efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); + return; + } + ret = boottime->exit_boot_services(handle, map_key); + if (ret != EFI_SUCCESS) { + efi_st_error("ExitBootServices did not return EFI_SUCCESS\n"); + return; + } + efi_st_printc(EFI_WHITE, "\nBoot services terminated\n"); +} + +/* + * Set up a test. + * + * @test the test to be executed + * @failures counter that will be incremented if a failure occurs + * @return EFI_ST_SUCCESS for success + */ +static int setup(struct efi_unit_test *test, unsigned int *failures) +{ + int ret; + + if (!test->setup) + return EFI_ST_SUCCESS; + efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); + ret = test->setup(handle, systable); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("Setting up '%s' failed\n", test->name); + ++*failures; + } else { + efi_st_printc(EFI_LIGHTGREEN, + "Setting up '%s' succeeded\n", test->name); + } + return ret; +} + +/* + * Execute a test. + * + * @test the test to be executed + * @failures counter that will be incremented if a failure occurs + * @return EFI_ST_SUCCESS for success + */ +static int execute(struct efi_unit_test *test, unsigned int *failures) +{ + int ret; + + if (!test->execute) + return EFI_ST_SUCCESS; + efi_st_printc(EFI_LIGHTBLUE, "\nExecuting '%s'\n", test->name); + ret = test->execute(); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("Executing '%s' failed\n", test->name); + ++*failures; + } else { + efi_st_printc(EFI_LIGHTGREEN, + "Executing '%s' succeeded\n", test->name); + } + return ret; +} + +/* + * Tear down a test. + * + * @test the test to be torn down + * @failures counter that will be incremented if a failure occurs + * @return EFI_ST_SUCCESS for success + */ +static int teardown(struct efi_unit_test *test, unsigned int *failures) +{ + int ret; + + if (!test->teardown) + return EFI_ST_SUCCESS; + efi_st_printc(EFI_LIGHTBLUE, "\nTearing down '%s'\n", test->name); + ret = test->teardown(); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("Tearing down '%s' failed\n", test->name); + ++*failures; + } else { + efi_st_printc(EFI_LIGHTGREEN, + "Tearing down '%s' succeeded\n", test->name); + } + return ret; +} + +/* + * Check that a test requiring reset exists. + * + * @testname: name of the test + * @return: test, or NULL if not found + */ +static bool need_reset(const u16 *testname) +{ + struct efi_unit_test *test; + + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (testname && efi_st_strcmp_16_8(testname, test->name)) + continue; + if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT || + test->phase == EFI_SETTING_VIRTUAL_ADDRESS_MAP) + return true; + } + return false; +} + +/* + * Check that a test exists. + * + * @testname: name of the test + * @return: test, or NULL if not found + */ +static struct efi_unit_test *find_test(const u16 *testname) +{ + struct efi_unit_test *test; + + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (!efi_st_strcmp_16_8(testname, test->name)) + return test; + } + efi_st_printf("\nTest '%ps' not found\n", testname); + return NULL; +} + +/* + * List all available tests. + */ +static void list_all_tests(void) +{ + struct efi_unit_test *test; + + /* List all tests */ + efi_st_printf("\nAvailable tests:\n"); + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + efi_st_printf("'%s'%s\n", test->name, + test->on_request ? " - on request" : ""); + } +} + +/* + * Execute test steps of one phase. + * + * @testname name of a single selected test or NULL + * @phase test phase + * @steps steps to execute (mask with bits from EFI_ST_...) + * failures returns EFI_ST_SUCCESS if all test steps succeeded + */ +void efi_st_do_tests(const u16 *testname, unsigned int phase, + unsigned int steps, unsigned int *failures) +{ + int i = 0; + struct efi_unit_test *test; + + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); + ++test, ++i) { + if (testname ? + efi_st_strcmp_16_8(testname, test->name) : test->on_request) + continue; + if (test->phase != phase) + continue; + if (steps & EFI_ST_SETUP) + setup_status[i] = setup(test, failures); + if (steps & EFI_ST_EXECUTE && setup_status[i] == EFI_ST_SUCCESS) + execute(test, failures); + if (steps & EFI_ST_TEARDOWN) + teardown(test, failures); + } +} + +/* + * Execute selftest of the EFI API + * + * This is the main entry point of the EFI selftest application. + * + * All tests use a driver model and are run in three phases: + * setup, execute, teardown. + * + * A test may be setup and executed at boottime, + * it may be setup at boottime and executed at runtime, + * or it may be setup and executed at runtime. + * + * After executing all tests the system is reset. + * + * @image_handle: handle of the loaded EFI image + * @systab: EFI system table + */ +efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, + struct efi_system_table *systab) +{ + unsigned int failures = 0; + const u16 *testname = NULL; + struct efi_loaded_image *loaded_image; + efi_status_t ret; + + systable = systab; + boottime = systable->boottime; + runtime = systable->runtime; + handle = image_handle; + con_out = systable->con_out; + con_in = systable->con_in; + + ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, + (void **)&loaded_image); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot open loaded image protocol\n"); + return ret; + } + + if (loaded_image->load_options) + testname = (u16 *)loaded_image->load_options; + + if (testname) { + if (!efi_st_strcmp_16_8(testname, "list") || + !find_test(testname)) { + list_all_tests(); + /* + * TODO: + * Once the Exit boottime service is correctly + * implemented we should call + * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); + * here, cf. + * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html + */ + return EFI_SUCCESS; + } + } + + efi_st_printc(EFI_WHITE, "\nTesting EFI API implementation\n"); + + if (testname) + efi_st_printc(EFI_WHITE, "\nSelected test: '%ps'\n", testname); + else + efi_st_printc(EFI_WHITE, "\nNumber of tests to execute: %u\n", + ll_entry_count(struct efi_unit_test, + efi_unit_test)); + + /* Allocate buffer for setup results */ + ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) * + ll_entry_count(struct efi_unit_test, + efi_unit_test), + (void **)&setup_status); + if (ret != EFI_SUCCESS) { + efi_st_error("Allocate pool failed\n"); + return ret; + } + + /* Execute boottime tests */ + efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, + &failures); + + if (!need_reset(testname)) { + if (failures) + ret = EFI_PROTOCOL_ERROR; + + /* Give feedback */ + efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", + failures); + return ret; + } + + /* Execute mixed tests */ + efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, + EFI_ST_SETUP, &failures); + efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP, + EFI_ST_SETUP, &failures); + + efi_st_exit_boot_services(); + + efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, + EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); + /* Execute test setting the virtual address map */ + efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP, + EFI_ST_EXECUTE | EFI_ST_TEARDOWN, + &failures); + + /* Give feedback */ + efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures); + + /* Reset system */ + efi_st_printf("Preparing for reset. Press any key...\n"); + efi_st_get_key(); + + if (IS_ENABLED(CONFIG_EFI_HAVE_RUNTIME_RESET)) { + runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, + sizeof(reset_message), reset_message); + } else { + efi_restore_gd(); + do_reset(NULL, 0, 0, NULL); + } + + efi_st_printf("\n"); + efi_st_error("Reset failed\n"); + + return EFI_UNSUPPORTED; +} diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_bitblt.c b/roms/u-boot/lib/efi_selftest/efi_selftest_bitblt.c new file mode 100644 index 000000000..fb33150c4 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_bitblt.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_bitblt + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the block image transfer in the graphical output protocol. + * An animated submarine is shown. + */ + +#include <efi_selftest.h> + +#define WIDTH 200 +#define HEIGHT 120 +#define DEPTH 60 + +static const struct efi_gop_pixel BLACK = { 0, 0, 0, 0}; +static const struct efi_gop_pixel RED = { 0, 0, 255, 0}; +static const struct efi_gop_pixel ORANGE = { 0, 128, 255, 0}; +static const struct efi_gop_pixel YELLOW = { 0, 255, 255, 0}; +static const struct efi_gop_pixel GREEN = { 0, 255, 0, 0}; +static const struct efi_gop_pixel DARK_BLUE = {128, 0, 0, 0}; +static const struct efi_gop_pixel LIGHT_BLUE = {255, 192, 192, 0}; + +static struct efi_boot_services *boottime; +static efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static struct efi_gop *gop; +static struct efi_gop_pixel *bitmap; +static struct efi_event *event; +static efi_uintn_t xpos; + +static void ellipse(efi_uintn_t x, efi_uintn_t y, + efi_uintn_t x0, efi_uintn_t y0, + efi_uintn_t x1, efi_uintn_t y1, + const struct efi_gop_pixel col, struct efi_gop_pixel *pix) +{ + efi_uintn_t xm = x0 + x1; + efi_uintn_t ym = y0 + y1; + efi_uintn_t dx = x1 - x0 + 1; + efi_uintn_t dy = y1 - y0 + 1; + + if (dy * dy * (2 * x - xm) * (2 * x - xm) + + dx * dx * (2 * y - ym) * (2 * y - ym) <= dx * dx * dy * dy) + *pix = col; +} + +static void rectangle(efi_uintn_t x, efi_uintn_t y, + efi_uintn_t x0, efi_uintn_t y0, + efi_uintn_t x1, efi_uintn_t y1, + const struct efi_gop_pixel col, struct efi_gop_pixel *pix) +{ + if (x >= x0 && y >= y0 && x <= x1 && y <= y1) + *pix = col; +} + +/* + * Notification function, copies image to video. + * The position is incremented in each call. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + efi_uintn_t *pos = context; + efi_uintn_t dx, sx, width; + + if (!pos) + return; + + /* Increment position */ + *pos += 5; + if (*pos >= WIDTH + gop->mode->info->width) + *pos = 0; + + width = WIDTH; + dx = *pos - WIDTH; + sx = 0; + if (*pos >= gop->mode->info->width) { + width = WIDTH + gop->mode->info->width - *pos; + } else if (*pos < WIDTH) { + dx = 0; + sx = WIDTH - *pos; + width = *pos; + } + + /* Copy image to video */ + gop->blt(gop, bitmap, EFI_BLT_BUFFER_TO_VIDEO, sx, 0, dx, DEPTH, + width, HEIGHT, WIDTH * sizeof(struct efi_gop_pixel)); +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + struct efi_gop_pixel pix; + efi_uintn_t x, y; + + boottime = systable->boottime; + + /* Create event */ + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, (void *)&xpos, + &event); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + /* Get graphical output protocol */ + ret = boottime->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret != EFI_SUCCESS) { + gop = NULL; + efi_st_printf("Graphical output protocol is not available.\n"); + return EFI_ST_SUCCESS; + } + + /* Prepare image of submarine */ + ret = boottime->allocate_pool(EFI_LOADER_DATA, + sizeof(struct efi_gop_pixel) * + WIDTH * HEIGHT, (void **)&bitmap); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return EFI_ST_FAILURE; + } + for (y = 0; y < HEIGHT; ++y) { + for (x = 0; x < WIDTH; ++x) { + pix = DARK_BLUE; + + /* Propeller */ + ellipse(x, y, 35, 55, 43, 75, BLACK, &pix); + ellipse(x, y, 36, 56, 42, 74, LIGHT_BLUE, &pix); + + ellipse(x, y, 35, 75, 43, 95, BLACK, &pix); + ellipse(x, y, 36, 76, 42, 94, LIGHT_BLUE, &pix); + + /* Shaft */ + rectangle(x, y, 35, 73, 100, 77, BLACK, &pix); + + /* Periscope */ + ellipse(x, y, 120, 10, 160, 50, BLACK, &pix); + ellipse(x, y, 121, 11, 159, 59, YELLOW, &pix); + ellipse(x, y, 130, 20, 150, 40, BLACK, &pix); + ellipse(x, y, 131, 21, 149, 49, DARK_BLUE, &pix); + rectangle(x, y, 135, 10, 160, 50, DARK_BLUE, &pix); + ellipse(x, y, 132, 10, 138, 20, BLACK, &pix); + ellipse(x, y, 133, 11, 139, 19, RED, &pix); + + /* Rudder */ + ellipse(x, y, 45, 40, 75, 70, BLACK, &pix); + ellipse(x, y, 46, 41, 74, 69, ORANGE, &pix); + ellipse(x, y, 45, 80, 75, 109, BLACK, &pix); + ellipse(x, y, 46, 81, 74, 108, RED, &pix); + + /* Bridge */ + ellipse(x, y, 100, 30, 120, 50, BLACK, &pix); + ellipse(x, y, 101, 31, 119, 49, GREEN, &pix); + ellipse(x, y, 140, 30, 160, 50, BLACK, &pix); + ellipse(x, y, 141, 31, 159, 49, GREEN, &pix); + rectangle(x, y, 110, 30, 150, 50, BLACK, &pix); + rectangle(x, y, 110, 31, 150, 50, GREEN, &pix); + + /* Hull */ + ellipse(x, y, 50, 40, 199, 109, BLACK, &pix); + ellipse(x, y, 51, 41, 198, 108, LIGHT_BLUE, &pix); + + /* Port holes */ + ellipse(x, y, 79, 57, 109, 82, BLACK, &pix); + ellipse(x, y, 80, 58, 108, 81, LIGHT_BLUE, &pix); + ellipse(x, y, 83, 61, 105, 78, BLACK, &pix); + ellipse(x, y, 84, 62, 104, 77, YELLOW, &pix); + /* + * This port hole is created by copying + * ellipse(x, y, 119, 57, 149, 82, BLACK, &pix); + * ellipse(x, y, 120, 58, 148, 81, LIGHT_BLUE, &pix); + * ellipse(x, y, 123, 61, 145, 78, BLACK, &pix); + * ellipse(x, y, 124, 62, 144, 77, YELLOW, &pix); + */ + ellipse(x, y, 159, 57, 189, 82, BLACK, &pix); + ellipse(x, y, 160, 58, 188, 81, LIGHT_BLUE, &pix); + ellipse(x, y, 163, 61, 185, 78, BLACK, &pix); + ellipse(x, y, 164, 62, 184, 77, YELLOW, &pix); + + bitmap[WIDTH * y + x] = pix; + } + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + if (bitmap) { + ret = boottime->free_pool(bitmap); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + if (event) { + ret = boottime->close_event(event); + event = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u32 max_mode; + efi_status_t ret; + struct efi_gop_mode_info *info; + + if (!gop) + return EFI_ST_SUCCESS; + + if (!gop->mode) { + efi_st_error("EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE missing\n"); + return EFI_ST_FAILURE; + } + info = gop->mode->info; + max_mode = gop->mode->max_mode; + if (!max_mode) { + efi_st_error("No graphical mode available\n"); + return EFI_ST_FAILURE; + } + + /* Fill background */ + ret = gop->blt(gop, bitmap, EFI_BLT_VIDEO_FILL, 0, 0, 0, 0, + info->width, info->height, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_VIDEO_FILL failed\n"); + return EFI_ST_FAILURE; + } + + /* Copy image to video */ + ret = gop->blt(gop, bitmap, EFI_BLT_BUFFER_TO_VIDEO, 0, 0, 0, DEPTH, + WIDTH, HEIGHT, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_BUFFER_TO_VIDEO failed\n"); + return EFI_ST_FAILURE; + } + + /* Copy left port hole */ + ret = gop->blt(gop, bitmap, EFI_BLT_VIDEO_TO_VIDEO, + 79, 57 + DEPTH, 119, 57 + DEPTH, + 31, 26, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_VIDEO_TO_VIDEO failed\n"); + return EFI_ST_FAILURE; + } + + /* Copy port holes back to buffer */ + ret = gop->blt(gop, bitmap, EFI_BLT_VIDEO_TO_BLT_BUFFER, + 94, 57 + DEPTH, 94, 57, + 90, 26, WIDTH * sizeof(struct efi_gop_pixel)); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_VIDEO_TO_BLT_BUFFER failed\n"); + return EFI_ST_FAILURE; + } + + /* Set 250ms timer */ + xpos = WIDTH; + ret = boottime->set_timer(event, EFI_TIMER_PERIODIC, 250000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + + con_out->set_cursor_position(con_out, 0, 0); + con_out->set_attribute(con_out, EFI_WHITE | EFI_BACKGROUND_BLUE); + efi_st_printf("The submarine should have three yellow port holes.\n"); + efi_st_printf("Press any key to continue"); + efi_st_get_key(); + con_out->set_attribute(con_out, EFI_LIGHTGRAY); + efi_st_printf("\n"); + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(bitblt) = { + .name = "block image transfer", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, + .on_request = true, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_block_device.c b/roms/u-boot/lib/efi_selftest/efi_selftest_block_device.c new file mode 100644 index 000000000..15f03751a --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_block_device.c @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_block + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the driver for block IO devices. + * A disk image is created in memory. + * A handle is created for the new block IO device. + * The block I/O protocol is installed on the handle. + * ConnectController is used to setup partitions and to install the simple + * file protocol. + * A known file is read from the file system and verified. + */ + +#include <efi_selftest.h> +#include "efi_selftest_disk_image.h" +#include <asm/cache.h> + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +static struct efi_boot_services *boottime; + +static const efi_guid_t block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID; +static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; +static const efi_guid_t guid_simple_file_system_protocol = + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID; +static efi_guid_t guid_vendor = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xb7, 0xb8); + +static struct efi_device_path *dp; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed disk image */ +struct compressed_disk_image { + size_t length; + struct line lines[]; +}; + +static const struct compressed_disk_image img = EFI_ST_DISK_IMG; + +/* Decompressed disk image */ +static u8 *image; + +/* + * Reset service of the block IO protocol. + * + * @this block IO protocol + * @return status code + */ +static efi_status_t EFIAPI reset( + struct efi_block_io *this, + char extended_verification) +{ + return EFI_SUCCESS; +} + +/* + * Read service of the block IO protocol. + * + * @this block IO protocol + * @media_id media id + * @lba start of the read in logical blocks + * @buffer_size number of bytes to read + * @buffer target buffer + * @return status code + */ +static efi_status_t EFIAPI read_blocks( + struct efi_block_io *this, u32 media_id, u64 lba, + efi_uintn_t buffer_size, void *buffer) +{ + u8 *start; + + if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length) + return EFI_INVALID_PARAMETER; + start = image + (lba << LB_BLOCK_SIZE); + + boottime->copy_mem(buffer, start, buffer_size); + + return EFI_SUCCESS; +} + +/* + * Write service of the block IO protocol. + * + * @this block IO protocol + * @media_id media id + * @lba start of the write in logical blocks + * @buffer_size number of bytes to read + * @buffer source buffer + * @return status code + */ +static efi_status_t EFIAPI write_blocks( + struct efi_block_io *this, u32 media_id, u64 lba, + efi_uintn_t buffer_size, void *buffer) +{ + u8 *start; + + if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length) + return EFI_INVALID_PARAMETER; + start = image + (lba << LB_BLOCK_SIZE); + + boottime->copy_mem(start, buffer, buffer_size); + + return EFI_SUCCESS; +} + +/* + * Flush service of the block IO protocol. + * + * @this block IO protocol + * @return status code + */ +static efi_status_t EFIAPI flush_blocks(struct efi_block_io *this) +{ + return EFI_SUCCESS; +} + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +static struct efi_block_io_media media; + +static struct efi_block_io block_io = { + .media = &media, + .reset = reset, + .read_blocks = read_blocks, + .write_blocks = write_blocks, + .flush_blocks = flush_blocks, +}; + +/* Handle for the block IO device */ +static efi_handle_t disk_handle; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + struct efi_device_path_vendor vendor_node; + struct efi_device_path end_node; + + boottime = systable->boottime; + + decompress(&image); + + block_io.media->block_size = 1 << LB_BLOCK_SIZE; + block_io.media->last_block = (img.length >> LB_BLOCK_SIZE) - 1; + + ret = boottime->install_protocol_interface( + &disk_handle, &block_io_protocol_guid, + EFI_NATIVE_INTERFACE, &block_io); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install block I/O protocol\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->allocate_pool(EFI_LOADER_DATA, + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return EFI_ST_FAILURE; + } + vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; + vendor_node.dp.length = sizeof(struct efi_device_path_vendor); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor, + sizeof(efi_guid_t)); + boottime->copy_mem(dp, &vendor_node, + sizeof(struct efi_device_path_vendor)); + end_node.type = DEVICE_PATH_TYPE_END; + end_node.sub_type = DEVICE_PATH_SUB_TYPE_END; + end_node.length = sizeof(struct efi_device_path); + + boottime->copy_mem((char *)dp + sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + ret = boottime->install_protocol_interface(&disk_handle, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t r = EFI_ST_SUCCESS; + + if (disk_handle) { + r = boottime->uninstall_protocol_interface(disk_handle, + &guid_device_path, + dp); + if (r != EFI_SUCCESS) { + efi_st_error("Uninstall device path failed\n"); + return EFI_ST_FAILURE; + } + r = boottime->uninstall_protocol_interface( + disk_handle, &block_io_protocol_guid, + &block_io); + if (r != EFI_SUCCESS) { + efi_st_error( + "Failed to uninstall block I/O protocol\n"); + return EFI_ST_FAILURE; + } + } + + if (image) { + r = boottime->free_pool(image); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return r; +} + +/* + * Get length of device path without end tag. + * + * @dp device path + * @return length of device path in bytes + */ +static efi_uintn_t dp_size(struct efi_device_path *dp) +{ + struct efi_device_path *pos = dp; + + while (pos->type != DEVICE_PATH_TYPE_END) + pos = (struct efi_device_path *)((char *)pos + pos->length); + return (char *)pos - (char *)dp; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t no_handles, i, len; + efi_handle_t *handles; + efi_handle_t handle_partition = NULL; + struct efi_device_path *dp_partition; + struct efi_block_io *block_io_protocol; + struct efi_simple_file_system_protocol *file_system; + struct efi_file_handle *root, *file; + struct { + struct efi_file_system_info info; + u16 label[12]; + } system_info; + efi_uintn_t buf_size; + char buf[16] __aligned(ARCH_DMA_MINALIGN); + u32 part1_size; + u64 pos; + + /* Connect controller to virtual disk */ + ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to connect controller\n"); + return EFI_ST_FAILURE; + } + + /* Get the handle for the partition */ + ret = boottime->locate_handle_buffer( + BY_PROTOCOL, &guid_device_path, NULL, + &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate handles\n"); + return EFI_ST_FAILURE; + } + len = dp_size(dp); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp_partition, + NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open device path protocol\n"); + return EFI_ST_FAILURE; + } + if (len >= dp_size(dp_partition)) + continue; + if (memcmp(dp, dp_partition, len)) + continue; + handle_partition = handles[i]; + break; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free pool memory\n"); + return EFI_ST_FAILURE; + } + if (!handle_partition) { + efi_st_error("Partition handle not found\n"); + return EFI_ST_FAILURE; + } + + /* Open the block_io_protocol */ + ret = boottime->open_protocol(handle_partition, + &block_io_protocol_guid, + (void **)&block_io_protocol, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open block IO protocol\n"); + return EFI_ST_FAILURE; + } + /* Get size of first MBR partition */ + memcpy(&part1_size, image + 0x1ca, sizeof(u32)); + if (block_io_protocol->media->last_block != part1_size - 1) { + efi_st_error("Last LBA of partition %x, expected %x\n", + (unsigned int)block_io_protocol->media->last_block, + part1_size - 1); + return EFI_ST_FAILURE; + } + /* Open the simple file system protocol */ + ret = boottime->open_protocol(handle_partition, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open simple file system protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open volume\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(system_info); + ret = root->getinfo(root, &guid_file_system_info, &buf_size, + &system_info); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get file system info\n"); + return EFI_ST_FAILURE; + } + if (system_info.info.block_size != 512) { + efi_st_error("Wrong block size %u, expected 512\n", + system_info.info.block_size); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) { + efi_st_todo( + "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", + system_info.info.volume_label); + } + + /* Read file */ + ret = root->open(root, &file, L"hello.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + ret = file->setpos(file, 1); + if (ret != EFI_SUCCESS) { + efi_st_error("SetPosition failed\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 12) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (memcmp(buf, "ello world!", 11)) { + efi_st_error("Unexpected file content\n"); + return EFI_ST_FAILURE; + } + ret = file->getpos(file, &pos); + if (ret != EFI_SUCCESS) { + efi_st_error("GetPosition failed\n"); + return EFI_ST_FAILURE; + } + if (pos != 13) { + efi_st_error("GetPosition returned %u, expected 13\n", + (unsigned int)pos); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + +#ifdef CONFIG_FAT_WRITE + /* Write file */ + ret = root->open(root, &file, L"u-boot.txt", EFI_FILE_MODE_READ | + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = 7; + boottime->set_mem(buf, sizeof(buf), 0); + boottime->copy_mem(buf, "U-Boot", buf_size); + ret = file->write(file, &buf_size, buf); + if (ret != EFI_SUCCESS || buf_size != 7) { + efi_st_error("Failed to write file\n"); + return EFI_ST_FAILURE; + } + ret = file->getpos(file, &pos); + if (ret != EFI_SUCCESS) { + efi_st_error("GetPosition failed\n"); + return EFI_ST_FAILURE; + } + if (pos != 7) { + efi_st_error("GetPosition returned %u, expected 7\n", + (unsigned int)pos); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + + /* Verify file */ + boottime->set_mem(buf, sizeof(buf), 0); + ret = root->open(root, &file, L"u-boot.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 7) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (memcmp(buf, "U-Boot", 7)) { + efi_st_error("Unexpected file content %s\n", buf); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } +#else + efi_st_todo("CONFIG_FAT_WRITE is not set\n"); +#endif /* CONFIG_FAT_WRITE */ + + /* Close volume */ + ret = root->close(root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close volume\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(blkdev) = { + .name = "block device", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_config_table.c b/roms/u-boot/lib/efi_selftest/efi_selftest_config_table.c new file mode 100644 index 000000000..2bf12b5bb --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_config_table.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_config_tables + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the following service: + * InstallConfigurationTable. + */ + +#include <efi_selftest.h> +#include <u-boot/crc.h> + +static const struct efi_system_table *sys_table; +static struct efi_boot_services *boottime; + +static efi_guid_t table_guid = + EFI_GUID(0xff1c3f9e, 0x795b, 0x1529, 0xf1, 0x55, + 0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75); + +/* + * Notification function, increments the notification count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * Check CRC32 of a table. + */ +static int check_table(const void *table) +{ + efi_status_t ret; + u32 crc32, res; + /* Casting from constant to not constant */ + struct efi_table_hdr *hdr = (struct efi_table_hdr *)table; + + crc32 = hdr->crc32; + /* + * Setting the CRC32 of the 'const' table to zero is easier than + * copying + */ + hdr->crc32 = 0; + ret = boottime->calculate_crc32(table, hdr->headersize, &res); + /* Reset table CRC32 so it stays constant */ + hdr->crc32 = crc32; + if (ret != EFI_ST_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (res != crc32) { + efi_st_error("Incorrect CRC32\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + sys_table = systable; + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * A table is installed, updated, removed. The table entry and the + * triggering of events is checked. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + unsigned int counter = 0; + struct efi_event *event; + void *table; + const unsigned int tables[2]; + efi_uintn_t i; + efi_uintn_t tabcnt; + efi_uintn_t table_count = sys_table->nr_tables; + + ret = boottime->create_event_ex(0, TPL_NOTIFY, + notify, (void *)&counter, + &table_guid, &event); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + + /* Try to delete non-existent table */ + ret = boottime->install_configuration_table(&table_guid, NULL); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Failed to detect missing table\n"); + return EFI_ST_FAILURE; + } + if (counter) { + efi_st_error("Notification function was called.\n"); + return EFI_ST_FAILURE; + } + /* Check if the event was signaled */ + ret = boottime->check_event(event); + if (ret == EFI_SUCCESS) { + efi_st_error("Event was signaled on EFI_NOT_FOUND\n"); + return EFI_ST_FAILURE; + } + if (counter != 1) { + efi_st_error("Notification function was not called.\n"); + return EFI_ST_FAILURE; + } + if (table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + + /* Install table */ + ret = boottime->install_configuration_table(&table_guid, + (void *)&tables[0]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on insert\n"); + return EFI_ST_FAILURE; + } + if (++table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) + table = sys_table->tables[i].table; + } + if (!table) { + efi_st_error("Installed table not found\n"); + return EFI_ST_FAILURE; + } + if (table != &tables[0]) { + efi_st_error("Incorrect table address\n"); + return EFI_ST_FAILURE; + } + if (check_table(sys_table) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + + /* Update table */ + ret = boottime->install_configuration_table(&table_guid, + (void *)&tables[1]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to update table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on update\n"); + return EFI_ST_FAILURE; + } + if (table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + tabcnt = 0; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) { + table = sys_table->tables[i].table; + ++tabcnt; + } + } + if (!table) { + efi_st_error("Installed table not found\n"); + return EFI_ST_FAILURE; + } + if (tabcnt > 1) { + efi_st_error("Duplicate table GUID\n"); + return EFI_ST_FAILURE; + } + if (table != &tables[1]) { + efi_st_error("Incorrect table address\n"); + return EFI_ST_FAILURE; + } + if (check_table(sys_table) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + + /* Delete table */ + ret = boottime->install_configuration_table(&table_guid, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to delete table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on delete\n"); + return EFI_ST_FAILURE; + } + if (--table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) { + table = sys_table->tables[i].table; + } + } + if (table) { + efi_st_error("Wrong table deleted\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->close_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event\n"); + return EFI_ST_FAILURE; + } + if (check_table(sys_table) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(configtables) = { + .name = "configuration tables", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_console.c b/roms/u-boot/lib/efi_selftest/efi_selftest_console.c new file mode 100644 index 000000000..ffd88a1e2 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_console.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI efi_selftest + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <efi_selftest.h> +#include <net.h> +#include <vsprintf.h> + +struct efi_simple_text_output_protocol *con_out; +struct efi_simple_text_input_protocol *con_in; + +/* + * Print a MAC address to an u16 string + * + * @pointer: mac address + * @buf: pointer to buffer address + * on return position of terminating zero word + */ +static void mac(void *pointer, u16 **buf) +{ + int i, j; + u16 c; + u8 *p = (u8 *)pointer; + u8 byte; + u16 *pos = *buf; + + for (i = 0; i < ARP_HLEN; ++i) { + if (i) + *pos++ = ':'; + byte = p[i]; + for (j = 4; j >= 0; j -= 4) { + c = (byte >> j) & 0x0f; + c += '0'; + if (c > '9') + c += 'a' - '9' - 1; + *pos++ = c; + } + } + *pos = 0; + *buf = pos; +} + +/* + * printx() - print hexadecimal number to an u16 string + * + * @p: value to print + * @prec: minimum number of digits to print + * @buf: pointer to buffer address, + * on return position of terminating zero word + */ +static void printx(u64 p, int prec, u16 **buf) +{ + int i; + u16 c; + u16 *pos = *buf; + + for (i = 2 * sizeof(p) - 1; i >= 0; --i) { + c = (p >> (4 * i)) & 0x0f; + if (c || pos != *buf || !i || i < prec) { + c += '0'; + if (c > '9') + c += 'a' - '9' - 1; + *pos++ = c; + } + } + *pos = 0; + *buf = pos; +} + +/* + * Print an unsigned 32bit value as decimal number to an u16 string + * + * @value: value to be printed + * @prec: minimum number of digits to display + * @buf: pointer to buffer address + * on return position of terminating zero word + */ +static void uint2dec(u32 value, int prec, u16 **buf) +{ + u16 *pos = *buf; + int i; + u16 c; + u64 f; + + /* + * Increment by .5 and multiply with + * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC + * to move the first digit to bit 60-63. + */ + f = 0x225C17D0; + f += (0x9B5A52DULL * value) >> 28; + f += 0x44B82FA0ULL * value; + + for (i = 0; i < 10; ++i) { + /* Write current digit */ + c = f >> 60; + if (c || pos != *buf || 10 - i <= prec) + *pos++ = c + '0'; + /* Eliminate current digit */ + f &= 0xfffffffffffffff; + /* Get next digit */ + f *= 0xaULL; + } + if (pos == *buf) + *pos++ = '0'; + *pos = 0; + *buf = pos; +} + +/* + * Print a signed 32bit value as decimal number to an u16 string + * + * @value: value to be printed + * @prec: minimum number of digits to display + * @buf: pointer to buffer address + * on return position of terminating zero word + */ +static void int2dec(s32 value, int prec, u16 **buf) +{ + u32 u; + u16 *pos = *buf; + + if (value < 0) { + *pos++ = '-'; + u = -value; + } else { + u = value; + } + uint2dec(u, prec, &pos); + *buf = pos; +} + +/* + * Print a colored formatted string to the EFI console + * + * @color color, see constants in efi_api.h, use -1 for no color + * @fmt format string + * @... optional arguments + */ +void efi_st_printc(int color, const char *fmt, ...) +{ + va_list args; + u16 buf[160]; + const char *c; + u16 *pos = buf; + const char *s; + u16 *u; + int prec; + + va_start(args, fmt); + + if (color >= 0) + con_out->set_attribute(con_out, (unsigned long)color); + c = fmt; + for (; *c; ++c) { + switch (*c) { + case '\\': + ++c; + switch (*c) { + case '\0': + --c; + break; + case 'n': + *pos++ = '\n'; + break; + case 'r': + *pos++ = '\r'; + break; + case 't': + *pos++ = '\t'; + break; + default: + *pos++ = *c; + } + break; + case '%': + ++c; + /* Parse precision */ + if (*c == '.') { + ++c; + prec = *c - '0'; + ++c; + } else { + prec = 0; + } + switch (*c) { + case '\0': + --c; + break; + case 'd': + int2dec(va_arg(args, s32), prec, &pos); + break; + case 'p': + ++c; + switch (*c) { + /* MAC address */ + case 'm': + mac(va_arg(args, void*), &pos); + break; + + /* u16 string */ + case 's': + u = va_arg(args, u16*); + if (pos > buf) { + *pos = 0; + con_out->output_string(con_out, + buf); + } + con_out->output_string(con_out, u); + pos = buf; + break; + default: + --c; + printx((uintptr_t)va_arg(args, void *), + 2 * sizeof(void *), &pos); + break; + } + break; + case 's': + s = va_arg(args, const char *); + for (; *s; ++s) + *pos++ = *s; + break; + case 'u': + uint2dec(va_arg(args, u32), prec, &pos); + break; + case 'x': + printx((u64)va_arg(args, unsigned int), + prec, &pos); + break; + default: + break; + } + break; + default: + *pos++ = *c; + } + } + va_end(args); + *pos = 0; + con_out->output_string(con_out, buf); + if (color >= 0) + con_out->set_attribute(con_out, EFI_LIGHTGRAY); +} + +/* + * Reads an Unicode character from the input device. + * + * @return: Unicode character + */ +u16 efi_st_get_key(void) +{ + struct efi_input_key input_key; + efi_status_t ret; + + /* Wait for next key */ + do { + ret = con_in->read_key_stroke(con_in, &input_key); + } while (ret == EFI_NOT_READY); + return input_key.unicode_char; +} diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_controllers.c b/roms/u-boot/lib/efi_selftest/efi_selftest_controllers.c new file mode 100644 index 000000000..38720bb63 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_controllers.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_controllers + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following protocol services: + * ConnectController, DisconnectController, + * InstallProtocol, ReinstallProtocol, UninstallProtocol, + * OpenProtocol, CloseProtcol, OpenProtocolInformation + */ + +#include <efi_selftest.h> + +#define NUMBER_OF_CHILD_CONTROLLERS 4 + +static int interface1 = 1; +static int interface2 = 2; +static struct efi_boot_services *boottime; +const efi_guid_t guid_driver_binding_protocol = + EFI_DRIVER_BINDING_PROTOCOL_GUID; +static efi_guid_t guid_controller = + EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42, + 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34); +static efi_guid_t guid_child_controller = + EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb, + 0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85); +static efi_handle_t handle_controller; +static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS]; +static efi_handle_t handle_driver; + +/* + * Count child controllers + * + * @handle handle on which child controllers are installed + * @protocol protocol for which the child controllers were installed + * @count number of child controllers + * @return status code + */ +static efi_status_t count_child_controllers(efi_handle_t handle, + efi_guid_t *protocol, + efi_uintn_t *count) +{ + efi_status_t ret; + efi_uintn_t entry_count; + struct efi_open_protocol_info_entry *entry_buffer; + + *count = 0; + ret = boottime->open_protocol_information(handle, protocol, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) + return ret; + if (!entry_count) + return EFI_SUCCESS; + while (entry_count) { + if (entry_buffer[--entry_count].attributes & + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) + ++*count; + } + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) + efi_st_error("Cannot free buffer\n"); + return ret; +} + +/* + * Check if the driver supports the controller. + * + * @this driver binding protocol + * @controller_handle handle of the controller + * @remaining_device_path path specifying the child controller + * @return status code + */ +static efi_status_t EFIAPI supported( + struct efi_driver_binding_protocol *this, + efi_handle_t controller_handle, + struct efi_device_path *remaining_device_path) +{ + efi_status_t ret; + void *interface; + + ret = boottime->open_protocol( + controller_handle, &guid_controller, + &interface, handle_driver, + controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER); + switch (ret) { + case EFI_ACCESS_DENIED: + case EFI_ALREADY_STARTED: + return ret; + case EFI_SUCCESS: + break; + default: + return EFI_UNSUPPORTED; + } + ret = boottime->close_protocol( + controller_handle, &guid_controller, + handle_driver, controller_handle); + if (ret != EFI_SUCCESS) + ret = EFI_UNSUPPORTED; + return ret; +} + +/* + * Create child controllers and attach driver. + * + * @this driver binding protocol + * @controller_handle handle of the controller + * @remaining_device_path path specifying the child controller + * @return status code + */ +static efi_status_t EFIAPI start( + struct efi_driver_binding_protocol *this, + efi_handle_t controller_handle, + struct efi_device_path *remaining_device_path) +{ + size_t i; + efi_status_t ret; + void *interface; + + /* Attach driver to controller */ + ret = boottime->open_protocol( + controller_handle, &guid_controller, + &interface, handle_driver, + controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER); + switch (ret) { + case EFI_ACCESS_DENIED: + case EFI_ALREADY_STARTED: + return ret; + case EFI_SUCCESS: + break; + default: + return EFI_UNSUPPORTED; + } + + /* Create child controllers */ + for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) { + /* Creating a new handle for the child controller */ + handle_child_controller[i] = 0; + ret = boottime->install_protocol_interface( + &handle_child_controller[i], &guid_child_controller, + EFI_NATIVE_INTERFACE, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol( + controller_handle, &guid_controller, + &interface, handle_child_controller[i], + handle_child_controller[i], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocol failed\n"); + return EFI_ST_FAILURE; + } + } + return ret; +} + +/* + * Remove a single child controller from the parent controller. + * + * @controller_handle parent controller + * @child_handle child controller + * @return status code + */ +static efi_status_t disconnect_child(efi_handle_t controller_handle, + efi_handle_t child_handle) +{ + efi_status_t ret; + + ret = boottime->close_protocol( + controller_handle, &guid_controller, + child_handle, child_handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot close protocol\n"); + return ret; + } + ret = boottime->uninstall_protocol_interface( + child_handle, &guid_child_controller, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot uninstall protocol interface\n"); + return ret; + } + return ret; +} + +/* + * Remove child controllers and disconnect the controller. + * + * @this driver binding protocol + * @controller_handle handle of the controller + * @number_of_children number of child controllers to remove + * @child_handle_buffer handles of the child controllers to remove + * @return status code + */ +static efi_status_t EFIAPI stop( + struct efi_driver_binding_protocol *this, + efi_handle_t controller_handle, + size_t number_of_children, + efi_handle_t *child_handle_buffer) +{ + efi_status_t ret; + efi_uintn_t count; + struct efi_open_protocol_info_entry *entry_buffer; + + /* Destroy provided child controllers */ + if (number_of_children) { + efi_uintn_t i; + + for (i = 0; i < number_of_children; ++i) { + ret = disconnect_child(controller_handle, + child_handle_buffer[i]); + if (ret != EFI_SUCCESS) + return ret; + } + return EFI_SUCCESS; + } + + /* Destroy all children */ + ret = boottime->open_protocol_information( + controller_handle, &guid_controller, + &entry_buffer, &count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return ret; + } + while (count) { + if (entry_buffer[--count].attributes & + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + ret = disconnect_child( + controller_handle, + entry_buffer[count].agent_handle); + if (ret != EFI_SUCCESS) + return ret; + } + } + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) + efi_st_error("Cannot free buffer\n"); + + /* Detach driver from controller */ + ret = boottime->close_protocol( + controller_handle, &guid_controller, + handle_driver, controller_handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot close protocol\n"); + return ret; + } + return EFI_SUCCESS; +} + +/* Driver binding protocol interface */ +static struct efi_driver_binding_protocol binding_interface = { + supported, + start, + stop, + 0xffffffff, + NULL, + NULL, + }; + +/* + * Setup unit test. + * + * @handle handle of the loaded image + * @systable system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + /* Create controller handle */ + ret = boottime->install_protocol_interface( + &handle_controller, &guid_controller, + EFI_NATIVE_INTERFACE, &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + /* Create driver handle */ + ret = boottime->install_protocol_interface( + &handle_driver, &guid_driver_binding_protocol, + EFI_NATIVE_INTERFACE, &binding_interface); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * The number of child controllers is checked after each of the following + * actions: + * + * Connect a controller to a driver. + * Disconnect and destroy a child controller. + * Disconnect and destroy the remaining child controllers. + * + * Connect a controller to a driver. + * Reinstall the driver protocol on the controller. + * Uninstall the driver protocol from the controller. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t count; + + /* Connect controller to driver */ + ret = boottime->connect_controller(handle_controller, NULL, NULL, 1); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to connect controller\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { + efi_st_error("Number of children %u != %u\n", + (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); + } + /* Destroy second child controller */ + ret = boottime->disconnect_controller(handle_controller, + handle_driver, + handle_child_controller[1]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to disconnect child controller\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) { + efi_st_error("Destroying single child controller failed\n"); + return EFI_ST_FAILURE; + } + /* Destroy remaining child controllers and disconnect controller */ + ret = boottime->disconnect_controller(handle_controller, NULL, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to disconnect controller\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret != EFI_SUCCESS || count) { + efi_st_error("Destroying child controllers failed\n"); + return EFI_ST_FAILURE; + } + + /* Connect controller to driver */ + ret = boottime->connect_controller(handle_controller, NULL, NULL, 1); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to connect controller\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { + efi_st_error("Number of children %u != %u\n", + (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); + } + /* Try to uninstall controller protocol using the wrong interface */ + ret = boottime->uninstall_protocol_interface(handle_controller, + &guid_controller, + &interface2); + if (ret == EFI_SUCCESS) { + efi_st_error( + "Interface not checked when uninstalling protocol\n"); + return EFI_ST_FAILURE; + } + /* Reinstall controller protocol */ + ret = boottime->reinstall_protocol_interface(handle_controller, + &guid_controller, + &interface1, + &interface2); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to reinstall protocols\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { + efi_st_error("Number of children %u != %u\n", + (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); + } + /* Uninstall controller protocol */ + ret = boottime->uninstall_protocol_interface(handle_controller, + &guid_controller, + &interface2); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to uninstall protocols\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret == EFI_SUCCESS) + efi_st_error("Uninstall failed\n"); + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(controllers) = { + .name = "controllers", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_crc32.c b/roms/u-boot/lib/efi_selftest/efi_selftest_crc32.c new file mode 100644 index 000000000..19153c759 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_crc32.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_crc32 + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the CalculateCrc32 bootservice and checks the + * headers of the system table, the boot services table, and the runtime + * services table before and after ExitBootServices(). + */ + +#include <efi_selftest.h> +#include <u-boot/crc.h> + +const struct efi_system_table *st; +efi_status_t (EFIAPI *bs_crc32)(const void *data, efi_uintn_t data_size, + u32 *crc32); + +static int check_table(const void *table) +{ + efi_status_t ret; + u32 crc32, res; + /* Casting from constant to not constant */ + struct efi_table_hdr *hdr = (struct efi_table_hdr *)table; + + if (!hdr->signature) { + efi_st_error("Missing header signature\n"); + return EFI_ST_FAILURE; + } + if (!hdr->revision) { + efi_st_error("Missing header revision\n"); + return EFI_ST_FAILURE; + } + if (hdr->headersize <= sizeof(struct efi_table_hdr)) { + efi_st_error("Incorrect headersize value\n"); + return EFI_ST_FAILURE; + } + if (hdr->reserved) { + efi_st_error("Reserved header field is not zero\n"); + return EFI_ST_FAILURE; + } + + crc32 = hdr->crc32; + /* + * Setting the crc32 of the 'const' table to zero is easier than + * copying + */ + hdr->crc32 = 0; + ret = bs_crc32(table, hdr->headersize, &res); + /* Reset table crc32 so it stays constant */ + hdr->crc32 = crc32; + if (ret != EFI_ST_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (res != crc32) { + efi_st_error("Incorrect CRC32\n"); + // return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Setup unit test. + * + * Check that CalculateCrc32 is working correctly. + * Check tables before ExitBootServices(). + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + u32 res; + + st = systable; + bs_crc32 = systable->boottime->calculate_crc32; + + /* Check that CalculateCrc32 is working */ + ret = bs_crc32("U-Boot", 6, &res); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (res != 0x134b0db4) { + efi_st_error("Incorrect CRC32\n"); + return EFI_ST_FAILURE; + } + + /* Check tables before ExitBootServices() */ + if (check_table(st) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + if (check_table(st->boottime) != EFI_ST_SUCCESS) { + efi_st_error("Checking boottime table\n"); + return EFI_ST_FAILURE; + } + if (check_table(st->runtime) != EFI_ST_SUCCESS) { + efi_st_error("Checking runtime table\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test + * + * Check tables after ExitBootServices() + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + if (check_table(st) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + if (check_table(st->runtime) != EFI_ST_SUCCESS) { + efi_st_error("Checking runtime table\n"); + return EFI_ST_FAILURE; + } + + /* + * We cannot call SetVirtualAddressMap() and recheck the runtime + * table afterwards because this would invalidate the addresses of the + * unit tests. + */ + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(crc32) = { + .name = "crc32", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_devicepath.c b/roms/u-boot/lib/efi_selftest/efi_selftest_devicepath.c new file mode 100644 index 000000000..d87b9f7dc --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_devicepath.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_devicepath + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following protocol services: + * DevicePathToText + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; + +static efi_handle_t handle1; +static efi_handle_t handle2; +static efi_handle_t handle3; + +struct interface { + void (EFIAPI * inc)(void); +} interface; + +static efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; + +static efi_guid_t guid_device_path_to_text_protocol = + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + +static efi_guid_t guid_protocol = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d); + +static efi_guid_t guid_vendor1 = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1); + +static efi_guid_t guid_vendor2 = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2); + +static efi_guid_t guid_vendor3 = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3); + +static u8 *dp1; +static u8 *dp2; +static u8 *dp3; + +static struct { + struct efi_device_path_sd_mmc_path sd1; + struct efi_device_path sep1; + struct efi_device_path_sd_mmc_path sd2; + struct efi_device_path sep2; + struct efi_device_path_sd_mmc_path sd3; + struct efi_device_path end; +} multi_part_dp = { + { + { + DEVICE_PATH_TYPE_MESSAGING_DEVICE, + DEVICE_PATH_SUB_TYPE_MSG_SD, + sizeof(struct efi_device_path_sd_mmc_path), + }, + 0, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_INSTANCE_END, + sizeof(struct efi_device_path), + }, + { + { + DEVICE_PATH_TYPE_MESSAGING_DEVICE, + DEVICE_PATH_SUB_TYPE_MSG_SD, + sizeof(struct efi_device_path_sd_mmc_path), + }, + 1, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_INSTANCE_END, + sizeof(struct efi_device_path), + }, + { + { + DEVICE_PATH_TYPE_MESSAGING_DEVICE, + DEVICE_PATH_SUB_TYPE_MSG_SD, + sizeof(struct efi_device_path_sd_mmc_path), + }, + 2, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path_to_text_protocol *device_path_to_text; + +/* + * Setup unit test. + * + * Create three handles. Install a new protocol on two of them and + * provide device paths. + * + * handle1 + * guid interface + * handle2 + * guid interface + * handle3 + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + struct efi_device_path_vendor vendor_node; + struct efi_device_path end_node; + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&guid_device_path_to_text_protocol, + NULL, (void **)&device_path_to_text); + if (ret != EFI_SUCCESS) { + device_path_to_text = NULL; + efi_st_error( + "Device path to text protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->allocate_pool(EFI_LOADER_DATA, + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp1); + if (ret != EFI_SUCCESS) + goto out_of_memory; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 * + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp2); + if (ret != EFI_SUCCESS) + goto out_of_memory; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 * + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp3); + if (ret != EFI_SUCCESS) + goto out_of_memory; + + vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; + vendor_node.dp.length = sizeof(struct efi_device_path_vendor); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor1, + sizeof(efi_guid_t)); + boottime->copy_mem(dp1, &vendor_node, + sizeof(struct efi_device_path_vendor)); + boottime->copy_mem(dp2, &vendor_node, + sizeof(struct efi_device_path_vendor)); + boottime->copy_mem(dp3, &vendor_node, + sizeof(struct efi_device_path_vendor)); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor2, + sizeof(efi_guid_t)); + boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor), + &vendor_node, sizeof(struct efi_device_path_vendor)); + boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor), + &vendor_node, sizeof(struct efi_device_path_vendor)); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor3, + sizeof(efi_guid_t)); + boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor), + &vendor_node, sizeof(struct efi_device_path_vendor)); + + end_node.type = DEVICE_PATH_TYPE_END; + end_node.sub_type = DEVICE_PATH_SUB_TYPE_END; + end_node.length = sizeof(struct efi_device_path); + boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + + ret = boottime->install_protocol_interface(&handle1, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle1, + &guid_protocol, + EFI_NATIVE_INTERFACE, + &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle2, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle2, + &guid_protocol, + EFI_NATIVE_INTERFACE, + &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle3, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp3); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; + +out_of_memory: + efi_st_error("Out of memory\n"); + return EFI_ST_FAILURE; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + + ret = boottime->uninstall_protocol_interface(handle1, + &guid_device_path, + dp1); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_protocol_interface(handle1, + &guid_protocol, + &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_protocol_interface(handle2, + &guid_device_path, + dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_protocol_interface(handle2, + &guid_protocol, + &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_protocol_interface(handle3, + &guid_device_path, + dp3); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (dp1) { + ret = boottime->free_pool(dp1); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + if (dp2) { + ret = boottime->free_pool(dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + if (dp3) { + ret = boottime->free_pool(dp3); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + */ +static int execute(void) +{ + struct efi_device_path *remaining_dp; + efi_handle_t handle; + /* + * This device path node ends with the letter 't' of 'u-boot'. + * The following '.bin' does not belong to the node but is + * helps to test the correct truncation. + */ + struct { + struct efi_device_path dp; + u16 text[12]; + } __packed dp_node = { + { DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path) + 12}, + L"u-boot.bin", + }; + u16 *string; + efi_status_t ret; + efi_uintn_t i, no_handles; + efi_handle_t *handles; + struct efi_device_path *dp; + + /* Display all available device paths */ + ret = boottime->locate_handle_buffer(BY_PROTOCOL, + &guid_device_path, + NULL, &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot retrieve device path protocols.\n"); + return EFI_ST_FAILURE; + } + + efi_st_printf("Installed device path protocols:\n"); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot open device path protocol.\n"); + return EFI_ST_FAILURE; + } + string = device_path_to_text->convert_device_path_to_text( + dp, true, false); + if (!string) { + efi_st_error("ConvertDevicePathToText failed\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("%ps\n", string); + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* + * CloseProtocol cannot be called without agent handle. + * There is no need to close the device path protocol. + */ + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* Test ConvertDevicePathToText */ + string = device_path_to_text->convert_device_path_to_text( + (struct efi_device_path *)dp2, true, false); + if (!string) { + efi_st_error("ConvertDevicePathToText failed\n"); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8( + string, + "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)") + ) { + efi_st_printf("dp2: %ps\n", string); + efi_st_error("Incorrect text from ConvertDevicePathToText\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + string = device_path_to_text->convert_device_path_to_text( + (struct efi_device_path *)&multi_part_dp, true, false); + if (efi_st_strcmp_16_8( + string, + "/SD(0),/SD(1),/SD(2)") + ) { + efi_st_printf("multi_part_dp: %ps\n", string); + efi_st_error("Incorrect text from ConvertDevicePathToText\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* Test ConvertDeviceNodeToText */ + string = device_path_to_text->convert_device_node_to_text( + (struct efi_device_path *)&dp_node, true, false); + if (!string) { + efi_st_error("ConvertDeviceNodeToText failed\n"); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(string, "u-boot")) { + efi_st_printf("dp_node: %ps\n", string); + efi_st_error( + "Incorrect conversion by ConvertDeviceNodeToText\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* Test LocateDevicePath */ + remaining_dp = (struct efi_device_path *)dp3; + ret = boottime->locate_device_path(&guid_protocol, &remaining_dp, + &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateDevicePath failed\n"); + return EFI_ST_FAILURE; + } + if (handle != handle2) { + efi_st_error("LocateDevicePath returned wrong handle\n"); + return EFI_ST_FAILURE; + } + string = device_path_to_text->convert_device_path_to_text(remaining_dp, + true, false); + if (!string) { + efi_st_error("ConvertDevicePathToText failed\n"); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(string, + "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)") + ) { + efi_st_printf("remaining device path: %ps\n", string); + efi_st_error("LocateDevicePath: wrong remaining device path\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(devicepath) = { + .name = "device path", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_devicepath_util.c b/roms/u-boot/lib/efi_selftest/efi_selftest_devicepath_util.c new file mode 100644 index 000000000..c846e057d --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_devicepath_util.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_devicepath_util + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the device path utilities protocol. + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; + +static efi_guid_t guid_device_path_utilities_protocol = + EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + +struct efi_device_path_utilities_protocol *dpu; + +/* + * Setup unit test. + * + * Locate the device path utilities protocol. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + int ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&guid_device_path_utilities_protocol, + NULL, (void **)&dpu); + if (ret != EFI_SUCCESS) { + dpu = NULL; + efi_st_error( + "Device path to text protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Create a device path consisting of a single media device node followed by an + * end node. + * + * @length: length of the media device node + * @dp: device path + * @return: status code + */ +static int create_single_node_device_path(unsigned int length, + struct efi_device_path **dp) +{ + struct efi_device_path *node; + efi_uintn_t len; + int ret; + + node = dpu->create_device_node(DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, length); + if (!node) { + efi_st_error("CreateDeviceNode failed\n"); + return EFI_ST_FAILURE; + } + *dp = dpu->append_device_node(NULL, node); + if (!*dp) { + efi_st_error("AppendDeviceNode failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(node); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(*dp); + if (len != length + 4) { + efi_st_error("Wrong device path length %u, expected %u\n", + (unsigned int)len, length); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * In the test device paths are created, copied, and concatenated. The device + * path length is used as a measure of success. + */ +static int execute(void) +{ + struct efi_device_path *dp1; + struct efi_device_path *dp2; + struct efi_device_path *dp3; + + efi_uintn_t len; + int ret; + + /* IsDevicePathMultiInstance(NULL) */ + if (dpu->is_device_path_multi_instance(NULL)) { + efi_st_error("IsDevicePathMultiInstance(NULL) returned true\n"); + return EFI_ST_FAILURE; + } + /* GetDevicePathSize(NULL) */ + len = dpu->get_device_path_size(NULL); + if (len) { + efi_st_error("Wrong device path length %u, expected 0\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + /* DuplicateDevicePath(NULL) */ + dp1 = dpu->duplicate_device_path(NULL); + if (dp1) { + efi_st_error("DuplicateDevicePath(NULL) failed\n"); + return EFI_ST_FAILURE; + } + /* AppendDevicePath(NULL, NULL) */ + dp1 = dpu->append_device_path(NULL, NULL); + if (!dp1) { + efi_st_error("AppendDevicePath(NULL, NULL) failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + if (len != 4) { + efi_st_error("Wrong device path length %u, expected 4\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp1); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* CreateDeviceNode */ + ret = create_single_node_device_path(21, &dp1); + if (ret != EFI_ST_SUCCESS) + return ret; + ret = create_single_node_device_path(17, &dp2); + if (ret != EFI_ST_SUCCESS) + return ret; + /* AppendDevicePath */ + dp3 = dpu->append_device_path(dp1, dp2); + if (!dp3) { + efi_st_error("AppendDevicePath failed\n"); + return EFI_ST_FAILURE; + } + if (dp3 == dp1 || dp3 == dp2) { + efi_st_error("AppendDevicePath reused buffer\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp3); + /* 21 + 17 + 4 */ + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 42\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* AppendDeviceNode */ + dp2 = dpu->append_device_node(dp1, dp3); + if (!dp2) { + efi_st_error("AppendDevicePath failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp2); + /* 21 + 21 + 4 */ + if (len != 46) { + printf("%s(%d) %s\n", __FILE__, __LINE__, __func__); + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp1); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* IsDevicePathMultiInstance */ + if (dpu->is_device_path_multi_instance(dp2)) { + printf("%s(%d) %s\n", __FILE__, __LINE__, __func__); + efi_st_error("IsDevicePathMultiInstance returned true\n"); + return EFI_ST_FAILURE; + } + /* AppendDevicePathInstance */ + dp1 = dpu->append_device_path_instance(dp2, dp3); + if (!dp1) { + efi_st_error("AppendDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + /* 46 + 42 */ + if (len != 88) { + efi_st_error("Wrong device path length %u, expected 88\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + /* IsDevicePathMultiInstance */ + if (!dpu->is_device_path_multi_instance(dp1)) { + efi_st_error("IsDevicePathMultiInstance returned false\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp3); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* GetNextDevicePathInstance */ + dp3 = dp1; + dp2 = dpu->get_next_device_path_instance(&dp1, &len); + if (!dp2) { + efi_st_error("GetNextDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + if (!dp1) { + efi_st_error("GetNextDevicePathInstance no 2nd instance\n"); + return EFI_ST_FAILURE; + } + if (len != 46) { + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 42\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + dp2 = dpu->get_next_device_path_instance(&dp1, &len); + if (!dp2) { + efi_st_error("GetNextDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + if (dp1) { + efi_st_error("GetNextDevicePathInstance did not signal end\n"); + return EFI_ST_FAILURE; + } + + /* Clean up */ + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp3); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(dputil) = { + .name = "device path utilities protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_disk_image.h b/roms/u-boot/lib/efi_selftest/efi_selftest_disk_image.h new file mode 100644 index 000000000..a0e058660 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_disk_image.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Non-zero 8 byte strings of a disk image + * + * Generated with tools/file2include + */ + +#define EFI_ST_DISK_IMG { 0x00010000, { \ + {0x000001b8, "\x21\x5d\x53\xd1\x00\x00\x00\x00"}, /* !]S..... */ \ + {0x000001c0, "\x02\x00\x01\x02\x02\x00\x01\x00"}, /* ........ */ \ + {0x000001c8, "\x00\x00\x7f\x00\x00\x00\x00\x00"}, /* ........ */ \ + {0x000001f8, "\x00\x00\x00\x00\x00\x00\x55\xaa"}, /* ......U. */ \ + {0x00000200, "\xeb\x3c\x90\x6d\x6b\x66\x73\x2e"}, /* .<.mkfs. */ \ + {0x00000208, "\x66\x61\x74\x00\x02\x04\x01\x00"}, /* fat..... */ \ + {0x00000210, "\x02\x00\x02\x7f\x00\xf8\x01\x00"}, /* ........ */ \ + {0x00000218, "\x20\x00\x40\x00\x00\x00\x00\x00"}, /* .@..... */ \ + {0x00000220, "\x00\x00\x00\x00\x80\x00\x29\xc4"}, /* ......). */ \ + {0x00000228, "\xc4\x88\x11\x55\x2d\x42\x4f\x4f"}, /* ...U-BOO */ \ + {0x00000230, "\x54\x20\x54\x45\x53\x54\x46\x41"}, /* T TESTFA */ \ + {0x00000238, "\x54\x31\x32\x20\x20\x20\x0e\x1f"}, /* T12 .. */ \ + {0x00000240, "\xbe\x5b\x7c\xac\x22\xc0\x74\x0b"}, /* .[|.".t. */ \ + {0x00000248, "\x56\xb4\x0e\xbb\x07\x00\xcd\x10"}, /* V....... */ \ + {0x00000250, "\x5e\xeb\xf0\x32\xe4\xcd\x16\xcd"}, /* ^..2.... */ \ + {0x00000258, "\x19\xeb\xfe\x54\x68\x69\x73\x20"}, /* ...This */ \ + {0x00000260, "\x69\x73\x20\x6e\x6f\x74\x20\x61"}, /* is not a */ \ + {0x00000268, "\x20\x62\x6f\x6f\x74\x61\x62\x6c"}, /* bootabl */ \ + {0x00000270, "\x65\x20\x64\x69\x73\x6b\x2e\x20"}, /* e disk. */ \ + {0x00000278, "\x20\x50\x6c\x65\x61\x73\x65\x20"}, /* Please */ \ + {0x00000280, "\x69\x6e\x73\x65\x72\x74\x20\x61"}, /* insert a */ \ + {0x00000288, "\x20\x62\x6f\x6f\x74\x61\x62\x6c"}, /* bootabl */ \ + {0x00000290, "\x65\x20\x66\x6c\x6f\x70\x70\x79"}, /* e floppy */ \ + {0x00000298, "\x20\x61\x6e\x64\x0d\x0a\x70\x72"}, /* and..pr */ \ + {0x000002a0, "\x65\x73\x73\x20\x61\x6e\x79\x20"}, /* ess any */ \ + {0x000002a8, "\x6b\x65\x79\x20\x74\x6f\x20\x74"}, /* key to t */ \ + {0x000002b0, "\x72\x79\x20\x61\x67\x61\x69\x6e"}, /* ry again */ \ + {0x000002b8, "\x20\x2e\x2e\x2e\x20\x0d\x0a\x00"}, /* ... ... */ \ + {0x000003f8, "\x00\x00\x00\x00\x00\x00\x55\xaa"}, /* ......U. */ \ + {0x00000400, "\xf8\xff\xff\x00\xf0\xff\x00\x00"}, /* ........ */ \ + {0x00000600, "\xf8\xff\xff\x00\xf0\xff\x00\x00"}, /* ........ */ \ + {0x00000800, "\x55\x2d\x42\x4f\x4f\x54\x20\x54"}, /* U-BOOT T */ \ + {0x00000808, "\x45\x53\x54\x08\x00\x00\xaa\x56"}, /* EST....V */ \ + {0x00000810, "\x84\x4c\x84\x4c\x00\x00\xaa\x56"}, /* .L.L...V */ \ + {0x00000818, "\x84\x4c\x00\x00\x00\x00\x00\x00"}, /* .L...... */ \ + {0x00000820, "\x41\x68\x00\x65\x00\x6c\x00\x6c"}, /* Ah.e.l.l */ \ + {0x00000828, "\x00\x6f\x00\x0f\x00\xf1\x2e\x00"}, /* .o...... */ \ + {0x00000830, "\x74\x00\x78\x00\x74\x00\x00\x00"}, /* t.x.t... */ \ + {0x00000838, "\xff\xff\x00\x00\xff\xff\xff\xff"}, /* ........ */ \ + {0x00000840, "\x48\x45\x4c\x4c\x4f\x20\x20\x20"}, /* HELLO */ \ + {0x00000848, "\x54\x58\x54\x20\x00\x64\xd7\x46"}, /* TXT .d.F */ \ + {0x00000850, "\x84\x4c\x84\x4c\x00\x00\xd7\x46"}, /* .L.L...F */ \ + {0x00000858, "\x84\x4c\x03\x00\x0d\x00\x00\x00"}, /* .L...... */ \ + {0x00005000, "\x48\x65\x6c\x6c\x6f\x20\x77\x6f"}, /* Hello wo */ \ + {0x00005008, "\x72\x6c\x64\x21\x0a\x00\x00\x00"}, /* rld!.... */ \ + {0, NULL} } } diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_esrt.c b/roms/u-boot/lib/efi_selftest/efi_selftest_esrt.c new file mode 100644 index 000000000..99251f22a --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_esrt.c @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Test ESRT tables support + * + * Copyright (C) 2021 Arm Ltd. + */ +#include <common.h> +#include <efi_loader.h> +#include <efi_selftest.h> + +// This value must not exceed 255. +// An FMP cannot contain more than 255 FW images. +#define TEST_ESRT_NUM_ENTRIES 255 + +static +struct efi_firmware_image_descriptor static_img_info[TEST_ESRT_NUM_ENTRIES]; + +static const struct efi_system_table *local_systable; + +static efi_handle_t fmp_handle; + +static const efi_guid_t efi_fmp_guid = + EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID; + +static void efi_test_esrt_init_info(void) +{ + for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) { + static_img_info[idx].image_index = idx; + + // Note: the 16 byte value present in + // static_img_info[idx].image_type_id is not strictly a GUID. + // The value is used for the sake of code testing. + static_img_info[idx].image_type_id.b[0] = idx; + + static_img_info[idx].image_id = 0; + static_img_info[idx].image_id_name = NULL; + static_img_info[idx].version = 0; + static_img_info[idx].version_name = NULL; + static_img_info[idx].size = 0; + static_img_info[idx].lowest_supported_image_version = 1; + static_img_info[idx].last_attempt_version = 2; + static_img_info[idx].last_attempt_status = 3; + static_img_info[idx].hardware_instance = 1; + } +} + +static efi_status_t +EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this, + efi_uintn_t *image_info_size, + struct efi_firmware_image_descriptor *image_info, + u32 *descriptor_version, + u8 *descriptor_count, + efi_uintn_t *descriptor_size, + u32 *package_version, + u16 **package_version_name) +{ + efi_status_t ret = EFI_SUCCESS; + + if (!image_info_size) + return EFI_INVALID_PARAMETER; + + if (descriptor_version) + *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; + if (descriptor_count) + *descriptor_count = TEST_ESRT_NUM_ENTRIES; + if (descriptor_size) + *descriptor_size = sizeof(*image_info); + if (package_version) + *package_version = 0xffffffff; + if (package_version_name) + *package_version_name = NULL; + + if (*image_info_size < sizeof(*image_info)) { + *image_info_size = *descriptor_size * *descriptor_count; + return EFI_BUFFER_TOO_SMALL; + } + + for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) + image_info[idx] = static_img_info[idx]; + + return ret; +} + +static struct efi_firmware_management_protocol efi_test_fmp = { + .get_image_info = efi_test_fmp_get_image_info, + .get_image = NULL, + .set_image = NULL, + .check_image = NULL, + .get_package_info = NULL, + .set_package_info = NULL, +}; + +static void *lib_test_get_esrt(void) +{ + for (int idx = 0; idx < local_systable->nr_tables; idx++) + if (!guidcmp(&efi_esrt_guid, &local_systable->tables[idx].guid)) + return local_systable->tables[idx].table; + + return NULL; +} + +/** + * lib_test_check_uuid_entry: Find an ESRT entry for which the fw_calss field matches + * the image_type_id in the @img_info. + * Ensure that all of the field in the ESRT entry have the same value as the corresponding + * fields in the @img_info. + * + * @esrt: pointer to the ESRT + * @img_info: an image_info_descriptor output by the FMP get_image_info + * + * @return: true if matching ESRT entry is found and if all the ESRT entry fields match the + * corresponding @img_info fields. + */ +static bool lib_test_check_uuid_entry(struct efi_system_resource_table *esrt, + struct efi_firmware_image_descriptor + *img_info) +{ + const u32 filled_entries = esrt->fw_resource_count; + struct efi_system_resource_entry *entry = esrt->entries; + + for (u32 idx = 0; idx < filled_entries; idx++) { + if (!guidcmp(&entry[idx].fw_class, &img_info->image_type_id)) { + if (entry[idx].fw_version != img_info->version) { + efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n", + &img_info->image_type_id); + return false; + } + + if (entry[idx].lowest_supported_fw_version != + img_info->lowest_supported_image_version) { + efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n", + &img_info->image_type_id); + return false; + } + + if (entry[idx].last_attempt_version != + img_info->last_attempt_version) { + efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n", + &img_info->image_type_id); + return false; + } + + if (entry[idx].last_attempt_status != + img_info->last_attempt_status) { + efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n", + &img_info->image_type_id); + return false; + } + + /* + * The entry with fw_class = img_uuid matches with the + * remainder fmp input. + */ + return true; + } + } + + /* There exists no entry with fw_class equal to img_uuid in the ESRT. */ + efi_st_error("ESRT no entry with fw_class= %pUl\n", &img_info->image_type_id); + + return false; +} + +/* + * Setup unit test. + * + * Initialize the test FMP datastructure. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + local_systable = systable; + + efi_test_esrt_init_info(); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Uninstall the test FMP. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret = EFI_SUCCESS; + struct efi_boot_services *bt; + + bt = local_systable->boottime; + + if (!bt) { + efi_st_error("Cannot find boottime services structure\n"); + return EFI_ST_FAILURE; + } + + ret = bt->uninstall_multiple_protocol_interfaces + (fmp_handle, &efi_fmp_guid, + &efi_test_fmp, NULL); + + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to uninstall FMP\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Perform the test + * + * The test consists of the following steps: + * + * 1) Obtain the ESRT + * 2) Record the number of ESRT entries prior to test start + * 3) Install the test FMP + * 4) Re-obtain the ESRT (the ESRT pointer may have changed with the FMP install) + * 5) verify that the ESRT entries have increased by the number of entries in the + * test FMP. + * 6) Traverse all the elements used as the test FMP input and verify that each + * has a corresponding ESRT entry and that the fields are correctly set. + * + * The failure of any of the above steps results in a test failure. + * + */ +static int execute(void) +{ + struct efi_system_resource_table *esrt; + efi_status_t ret = EFI_SUCCESS; + u32 base_entry_count; + u32 entry_delta; + struct efi_boot_services *bt; + + bt = local_systable->boottime; + + if (!bt) { + efi_st_error("Cannot find boottime services structure\n"); + return EFI_ST_FAILURE; + } + + esrt = lib_test_get_esrt(); + if (!esrt) { + efi_st_error("ESRT table not present\n"); + return EFI_ST_FAILURE; + } + base_entry_count = esrt->fw_resource_count; + + ret = bt->install_multiple_protocol_interfaces(&fmp_handle, + &efi_fmp_guid, + &efi_test_fmp, + NULL); + + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install FMP\n"); + return EFI_ST_FAILURE; + } + + esrt = lib_test_get_esrt(); + if (!esrt) { + efi_st_error("ESRT table not present\n"); + return EFI_ST_FAILURE; + } + + entry_delta = esrt->fw_resource_count - base_entry_count; + if (entry_delta != TEST_ESRT_NUM_ENTRIES) { + efi_st_error("ESRT mismatch in new entry count (%d), expected (%d).\n", + entry_delta, TEST_ESRT_NUM_ENTRIES); + return EFI_ST_FAILURE; + } + + for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) + if (!lib_test_check_uuid_entry(esrt, &static_img_info[idx])) { + efi_st_error("ESRT entry mismatch\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(esrt) = { + .name = "esrt", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_event_groups.c b/roms/u-boot/lib/efi_selftest/efi_selftest_event_groups.c new file mode 100644 index 000000000..6dcde5064 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_event_groups.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_event_groups + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the notification of group events and the + * following services: + * CreateEventEx, CloseEvent, SignalEvent, CheckEvent. + */ + +#include <efi_selftest.h> + +#define GROUP_SIZE 16 + +static struct efi_boot_services *boottime; +static efi_guid_t event_group = + EFI_GUID(0x2335905b, 0xc3b9, 0x4221, 0xa3, 0x71, + 0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91); + +/* + * Notification function, increments the notification count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Create multiple events in an event group. Signal each event once and check + * that all events are notified once in each round. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + unsigned int counter[GROUP_SIZE] = {0}; + struct efi_event *events[GROUP_SIZE]; + size_t i, j; + efi_status_t ret; + + for (i = 0; i < GROUP_SIZE; ++i) { + ret = boottime->create_event_ex(0, TPL_NOTIFY, + notify, (void *)&counter[i], + &event_group, &events[i]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + } + + for (i = 0; i < GROUP_SIZE; ++i) { + ret = boottime->signal_event(events[i]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to signal event\n"); + return EFI_ST_FAILURE; + } + for (j = 0; j < GROUP_SIZE; ++j) { + if (counter[j] != 2 * i + 1) { + efi_st_printf("i %u, j %u, count %u\n", + (unsigned int)i, (unsigned int)j, + (unsigned int)counter[j]); + efi_st_error("Notification function was not called\n"); + return EFI_ST_FAILURE; + } + /* Clear signaled state */ + ret = boottime->check_event(events[j]); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled\n"); + return EFI_ST_FAILURE; + } + if (counter[j] != 2 * i + 1) { + efi_st_printf("i %u, j %u, count %u\n", + (unsigned int)i, (unsigned int)j, + (unsigned int)counter[j]); + efi_st_error( + "Notification function was called\n"); + return EFI_ST_FAILURE; + } + /* Call notification function */ + ret = boottime->check_event(events[j]); + if (ret != EFI_NOT_READY) { + efi_st_error( + "Signaled state not cleared\n"); + return EFI_ST_FAILURE; + } + if (counter[j] != 2 * i + 2) { + efi_st_printf("i %u, j %u, count %u\n", + (unsigned int)i, (unsigned int)j, + (unsigned int)counter[j]); + efi_st_error( + "Notification function not called\n"); + return EFI_ST_FAILURE; + } + } + } + + for (i = 0; i < GROUP_SIZE; ++i) { + ret = boottime->close_event(events[i]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event\n"); + return EFI_ST_FAILURE; + } + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(eventgoups) = { + .name = "event groups", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_events.c b/roms/u-boot/lib/efi_selftest/efi_selftest_events.c new file mode 100644 index 000000000..1077cbdf9 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_events.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_events + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test uses timer events to check the implementation + * of the following boottime services: + * CreateEvent, CloseEvent, WaitForEvent, CheckEvent, SetTimer. + */ + +#include <efi_selftest.h> + +static struct efi_event *event_notify; +static struct efi_event *event_wait; +static unsigned int timer_ticks; +static struct efi_boot_services *boottime; + +/* + * Notification function, increments the notification count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * Setup unit test. + * + * Create two timer events. + * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, (void *)&timer_ticks, + &event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, + TPL_CALLBACK, notify, NULL, &event_wait); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Close the events created in setup. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + if (event_notify) { + ret = boottime->close_event(event_notify); + event_notify = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + if (event_wait) { + ret = boottime->close_event(event_wait); + event_wait = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Run a 10 ms periodic timer and check that it is called 10 times + * while waiting for 100 ms single shot timer. + * + * Run a 100 ms single shot timer and check that it is called once + * while waiting for 100 ms periodic timer for two periods. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_uintn_t index; + efi_status_t ret; + + /* Set 10 ms timer */ + timer_ticks = 0; + ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + /* Set 100 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + + /* Set some arbitrary non-zero value to make change detectable. */ + index = 5; + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->check_event(event_wait); + if (ret != EFI_NOT_READY) { + efi_st_error("Signaled state was not cleared.\n"); + efi_st_printf("ret = %u\n", (unsigned int)ret); + return EFI_ST_FAILURE; + } + if (index != 0) { + efi_st_error("WaitForEvent returned wrong index\n"); + return EFI_ST_FAILURE; + } + if (timer_ticks < 8 || timer_ticks > 12) { + efi_st_printf("Notification count periodic: %u\n", timer_ticks); + efi_st_error("Incorrect timing of events\n"); + return EFI_ST_FAILURE; + } + ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not cancel timer\n"); + return EFI_ST_FAILURE; + } + /* Set 10 ms timer */ + timer_ticks = 0; + ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + /* Set 100 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_PERIODIC, 1000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + if (timer_ticks != 1) { + efi_st_printf("Notification count single shot: %u\n", + timer_ticks); + efi_st_error("Single shot timer failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + if (timer_ticks != 1) { + efi_st_printf("Notification count stopped timer: %u\n", + timer_ticks); + efi_st_error("Stopped timer fired\n"); + return EFI_ST_FAILURE; + } + ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not cancel timer\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(events) = { + .name = "event services", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_exception.c b/roms/u-boot/lib/efi_selftest/efi_selftest_exception.c new file mode 100644 index 000000000..6e900a35d --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_exception.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_exception + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the handling of exceptions. + * + * The efi_selftest_miniapp_exception.efi application is loaded into memory + * and started. + */ + +#include <efi_selftest.h> +/* Include containing the UEFI application */ +#include "efi_miniapp_file_image_exception.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +/* File device path for LoadImage() */ +static struct { + struct efi_device_path dp; + u16 filename[8]; + struct efi_device_path end; +} dp = { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(dp.dp) + sizeof(dp.filename), + }, + L"bug.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(dp.end), + } +}; + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +/* Decompressed file image */ +static u8 *image; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Load and start the application image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + + ret = boottime->load_image(false, image_handle, &dp.dp, image, + img.length, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + ret = boottime->start_image(handle, NULL, NULL); + + efi_st_error("Exception not triggered\n"); + + return EFI_ST_FAILURE; +} + +EFI_UNIT_TEST(exception) = { + .name = "exception", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_exitbootservices.c b/roms/u-boot/lib/efi_selftest/efi_selftest_exitbootservices.c new file mode 100644 index 000000000..4fecd1b41 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_exitbootservices.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_exitbootservices + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks that the notification function of an + * EVT_SIGNAL_EXIT_BOOT_SERVICES event is called exactly once. + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; +static struct efi_event *event_notify; +static unsigned int notification_count; + +/* + * Notification function, increments the notification count. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + ++*count; +} + +/* + * Setup unit test. + * + * Create an EVT_SIGNAL_EXIT_BOOT_SERVICES event. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + notification_count = 0; + ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_CALLBACK, notify, + (void *)¬ification_count, + &event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES + * event has been called. + * + * Call ExitBootServices again and check that the notification function is + * not called again. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + if (notification_count != 1) { + efi_st_error("ExitBootServices was not notified\n"); + return EFI_ST_FAILURE; + } + efi_st_exit_boot_services(); + if (notification_count != 1) { + efi_st_error("ExitBootServices was notified twice\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(exitbootservices) = { + .name = "ExitBootServices", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_fdt.c b/roms/u-boot/lib/efi_selftest/efi_selftest_fdt.c new file mode 100644 index 000000000..eae98208f --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_fdt.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_pos + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. + * + * The following services are tested: + * OutputString, TestString, SetAttribute. + */ + +#include <efi_selftest.h> +#include <linux/libfdt.h> + +static const struct efi_system_table *systemtab; +static const struct efi_boot_services *boottime; +static const char *fdt; + +/* This should be sufficient for */ +#define BUFFERSIZE 0x100000 + +static const efi_guid_t fdt_guid = EFI_FDT_GUID; +static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID; + +/* + * Convert FDT value to host endianness. + * + * @val FDT value + * @return converted value + */ +static uint32_t f2h(fdt32_t val) +{ + char *buf = (char *)&val; + char i; + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* Swap the bytes */ + i = buf[0]; buf[0] = buf[3]; buf[3] = i; + i = buf[1]; buf[1] = buf[2]; buf[2] = i; +#endif + return *(uint32_t *)buf; +} + +/** + * get_property() - return value of a property of an FDT node + * + * A property of the root node or one of its direct children can be + * retrieved. + * + * @property name of the property + * @node name of the node or NULL for root node + * @return value of the property + */ +static char *get_property(const u16 *property, const u16 *node) +{ + struct fdt_header *header = (struct fdt_header *)fdt; + const fdt32_t *end; + const fdt32_t *pos; + const char *strings; + size_t level = 0; + const char *nodelabel = NULL; + + if (!header) { + efi_st_error("Missing device tree\n"); + return NULL; + } + + if (f2h(header->magic) != FDT_MAGIC) { + efi_st_error("Wrong device tree magic\n"); + return NULL; + } + + pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct)); + end = &pos[f2h(header->totalsize) >> 2]; + strings = fdt + f2h(header->off_dt_strings); + + for (; pos < end;) { + switch (f2h(pos[0])) { + case FDT_BEGIN_NODE: { + const char *c = (char *)&pos[1]; + size_t i; + + if (level == 1) + nodelabel = c; + ++level; + for (i = 0; c[i]; ++i) + ; + pos = &pos[2 + (i >> 2)]; + break; + } + case FDT_PROP: { + struct fdt_property *prop = (struct fdt_property *)pos; + const char *label = &strings[f2h(prop->nameoff)]; + efi_status_t ret; + + /* Check if this is the property to be returned */ + if (!efi_st_strcmp_16_8(property, label) && + ((level == 1 && !node) || + (level == 2 && node && + !efi_st_strcmp_16_8(node, nodelabel)))) { + char *str; + efi_uintn_t len = f2h(prop->len); + + if (!len) + return NULL; + /* + * The string might not be 0 terminated. + * It is safer to make a copy. + */ + ret = boottime->allocate_pool( + EFI_LOADER_DATA, len + 1, + (void **)&str); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + return NULL; + } + boottime->copy_mem(str, &pos[3], len); + str[len] = 0; + + return str; + } + + pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)]; + break; + } + case FDT_NOP: + ++pos; + break; + case FDT_END_NODE: + --level; + ++pos; + break; + case FDT_END: + return NULL; + default: + efi_st_error("Invalid device tree token\n"); + return NULL; + } + } + efi_st_error("Missing FDT_END token\n"); + return NULL; +} + +/** + * efi_st_get_config_table() - get configuration table + * + * @guid: GUID of the configuration table + * Return: pointer to configuration table or NULL + */ +static void *efi_st_get_config_table(const efi_guid_t *guid) +{ + size_t i; + + for (i = 0; i < systab.nr_tables; i++) { + if (!guidcmp(guid, &systemtab->tables[i].guid)) + return systemtab->tables[i].table; + } + return NULL; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + void *acpi; + + systemtab = systable; + boottime = systable->boottime; + + acpi = efi_st_get_config_table(&acpi_guid); + fdt = efi_st_get_config_table(&fdt_guid); + + if (!fdt) { + efi_st_error("Missing device tree\n"); + return EFI_ST_FAILURE; + } + if (acpi) { + efi_st_error("Found ACPI table and device tree\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + char *str; + efi_status_t ret; + + str = get_property(L"compatible", NULL); + if (str) { + efi_st_printf("compatible: %s\n", str); + ret = boottime->free_pool(str); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } else { + efi_st_error("Missing property 'compatible'\n"); + return EFI_ST_FAILURE; + } + str = get_property(L"serial-number", NULL); + if (str) { + efi_st_printf("serial-number: %s\n", str); + ret = boottime->free_pool(str); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + str = get_property(L"boot-hartid", L"chosen"); + if (IS_ENABLED(CONFIG_RISCV)) { + if (str) { + efi_st_printf("boot-hartid: %u\n", + f2h(*(fdt32_t *)str)); + ret = boottime->free_pool(str); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } else { + efi_st_error("boot-hartid not found\n"); + return EFI_ST_FAILURE; + } + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(fdt) = { + .name = "device tree", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_gop.c b/roms/u-boot/lib/efi_selftest/efi_selftest_gop.c new file mode 100644 index 000000000..d64294ac7 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_gop.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_gop + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the graphical output protocol. + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; +static efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static struct efi_gop *gop; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret != EFI_SUCCESS) { + gop = NULL; + efi_st_printf("Graphical output protocol is not available.\n"); + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + u32 i, max_mode; + efi_uintn_t size; + struct efi_gop_mode_info *info; + + if (!gop) + return EFI_ST_SUCCESS; + + if (!gop->mode) { + efi_st_error("EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE missing\n"); + return EFI_ST_FAILURE; + } + max_mode = gop->mode->max_mode; + if (!max_mode) { + efi_st_error("No graphical mode available\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("Number of available modes: %u\n", max_mode); + + for (i = 0; i < max_mode; ++i) { + ret = gop->query_mode(gop, i, &size, &info); + if (ret != EFI_SUCCESS) { + efi_st_printf("Could not query mode %u\n", i); + return EFI_ST_FAILURE; + } + efi_st_printf("Mode %u: %u x %u\n", + i, info->width, info->height); + ret = boottime->free_pool(info); + if (ret != EFI_SUCCESS) { + efi_st_printf("FreePool failed"); + return EFI_ST_FAILURE; + } + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(gop) = { + .name = "graphical output", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_hii.c b/roms/u-boot/lib/efi_selftest/efi_selftest_hii.c new file mode 100644 index 000000000..f4b70f795 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_hii.c @@ -0,0 +1,1060 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_hii + * + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + * + * Test HII database protocols + */ + +#include <efi_selftest.h> +#include "efi_selftest_hii_data.c" + +#define PRINT_TESTNAME efi_st_printf("%s:\n", __func__) + +static struct efi_boot_services *boottime; + +static const efi_guid_t hii_database_protocol_guid = + EFI_HII_DATABASE_PROTOCOL_GUID; +static const efi_guid_t hii_string_protocol_guid = + EFI_HII_STRING_PROTOCOL_GUID; + +static struct efi_hii_database_protocol *hii_database_protocol; +static struct efi_hii_string_protocol *hii_string_protocol; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + /* HII database protocol */ + ret = boottime->locate_protocol(&hii_database_protocol_guid, NULL, + (void **)&hii_database_protocol); + if (ret != EFI_SUCCESS) { + hii_database_protocol = NULL; + efi_st_error("HII database protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + /* HII string protocol */ + ret = boottime->locate_protocol(&hii_string_protocol_guid, NULL, + (void **)&hii_string_protocol); + if (ret != EFI_SUCCESS) { + hii_string_protocol = NULL; + efi_st_error("HII string protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * HII database protocol tests + */ + +/** + * test_hii_database_new_package_list() - test creation and removal of + * package list + * + * This test adds a new package list and then tries to remove it using + * the provided handle. + * + * @Return: status code + */ +static int test_hii_database_new_package_list(void) +{ + efi_hii_handle_t handle; + efi_status_t ret; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_database_protocol->remove_package_list(hii_database_protocol, + handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_update_package_list() - test update of package list + * + * This test adds a new package list and then tries to update it using + * another package list. + * + * @Return: status code + */ +static int test_hii_database_update_package_list(void) +{ + efi_hii_handle_t handle = NULL; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_database_protocol->update_package_list(hii_database_protocol, + handle, + (struct efi_hii_package_list_header *)packagelist2); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_database_list_package_lists() - test listing of package lists + * + * This test adds two package lists and then tries to enumerate them + * against different package types. We will get an array of handles. + * + * @Return: status code + */ +static int test_hii_database_list_package_lists(void) +{ + efi_hii_handle_t handle1 = NULL, handle2 = NULL, *handles; + efi_uintn_t handles_size; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle1); + if (ret != EFI_SUCCESS || !handle1) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist2, + NULL, &handle2); + if (ret != EFI_SUCCESS || !handle2) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + /* TYPE_ALL */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_ALL, NULL, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size, + (void **)&handles); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_ALL, NULL, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + goto out; + } + + /* STRINGS */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_STRINGS, NULL, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size, + (void **)&handles); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_STRINGS, NULL, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + goto out; + } + + /* GUID */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_GUID, &package_guid, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size, + (void **)&handles); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_GUID, &package_guid, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + + /* KEYBOARD_LAYOUT */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, NULL, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size, + (void **)&handles); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, NULL, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle1) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle1); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + if (handle2) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle2); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + + return result; +} + +/** + * test_hii_database_export_package_lists() - test export of package lists + * + * @Return: status code + */ +static int test_hii_database_export_package_lists(void) +{ + PRINT_TESTNAME; + /* export_package_lists() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_register_package_notify() - test registration of + * notification function + * + * @Return: status code + */ +static int test_hii_database_register_package_notify(void) +{ + PRINT_TESTNAME; + /* register_package_notify() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_unregister_package_notify() - test removal of + * notification function + * + * @Return: status code + */ +static int test_hii_database_unregister_package_notify(void) +{ + PRINT_TESTNAME; + /* unregsiter_package_notify() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_find_keyboard_layouts() - test listing of + * all the keyboard layouts in the system + * + * This test adds two package lists, each of which has two keyboard layouts + * and then tries to enumerate them. We will get an array of handles. + * + * @Return: status code + */ +static int test_hii_database_find_keyboard_layouts(void) +{ + efi_hii_handle_t handle1 = NULL, handle2 = NULL; + efi_guid_t *guids; + u16 guids_size; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle1); + if (ret != EFI_SUCCESS || !handle1) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist2, + NULL, &handle2); + if (ret != EFI_SUCCESS || !handle2) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + guids = NULL; + guids_size = 0; + ret = hii_database_protocol->find_keyboard_layouts( + hii_database_protocol, &guids_size, guids); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("find_keyboard_layouts returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, guids_size, + (void **)&guids); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_database_protocol->find_keyboard_layouts( + hii_database_protocol, &guids_size, guids); + if (ret != EFI_SUCCESS) { + efi_st_error("find_keyboard_layouts returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->free_pool(guids); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle1) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle1); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + if (handle2) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle2); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + + return result; +} + +/** + * test_hii_database_get_keyboard_layout() - test retrieval of keyboard layout + * + * This test adds two package lists, each of which has two keyboard layouts + * and then tries to get a handle to keyboard layout with a specific guid + * and the current one. + * + * @Return: status code + */ +static int test_hii_database_get_keyboard_layout(void) +{ + efi_hii_handle_t handle1 = NULL, handle2 = NULL; + struct efi_hii_keyboard_layout *kb_layout; + u16 kb_layout_size; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle1); + if (ret != EFI_SUCCESS || !handle1) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist2, + NULL, &handle2); + if (ret != EFI_SUCCESS || !handle2) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + /* specific keyboard_layout(guid11) */ + kb_layout = NULL; + kb_layout_size = 0; + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + &kb_layout_guid11, &kb_layout_size, kb_layout); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, kb_layout_size, + (void **)&kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + &kb_layout_guid11, &kb_layout_size, kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->free_pool(kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + goto out; + } + + /* current */ + kb_layout = NULL; + kb_layout_size = 0; + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + NULL, &kb_layout_size, kb_layout); + if (ret != EFI_INVALID_PARAMETER) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle1) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle1); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + if (handle2) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle2); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + + return result; +} + +/** + * test_hii_database_set_keyboard_layout() - test change of + * current keyboard layout + * + * @Return: status code + */ +static int test_hii_database_set_keyboard_layout(void) +{ + PRINT_TESTNAME; + /* set_keyboard_layout() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_get_package_list_handle() - test retrieval of + * driver associated with a package list + * + * This test adds a package list, and then tries to get a handle to driver + * which is associated with a package list. + * + * @Return: status code + */ +static int test_hii_database_get_package_list_handle(void) +{ + efi_hii_handle_t handle = NULL; + efi_handle_t driver_handle; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + driver_handle = (efi_handle_t)0x12345678; /* dummy */ + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + driver_handle, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + driver_handle = NULL; + ret = hii_database_protocol->get_package_list_handle( + hii_database_protocol, handle, &driver_handle); + if (ret != EFI_SUCCESS || driver_handle != (efi_handle_t)0x12345678) { + efi_st_error("get_package_list_handle returned %u, driver:%p\n", + (unsigned int)ret, driver_handle); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +static int test_hii_database_protocol(void) +{ + int ret; + + ret = test_hii_database_new_package_list(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_update_package_list(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_list_package_lists(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_export_package_lists(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_register_package_notify(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_unregister_package_notify(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_find_keyboard_layouts(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_get_keyboard_layout(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_set_keyboard_layout(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_get_package_list_handle(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +/* + * HII string protocol tests + */ + +/** + * test_hii_string_new_string() - test creation of a new string entry + * + * This test adds a package list, and then tries to add a new string + * entry for a specific language. + * + * @Return: status code + */ +static int test_hii_string_new_string(void) +{ + efi_hii_handle_t handle = NULL; + efi_string_id_t id; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_string_protocol->new_string(hii_string_protocol, handle, + &id, (u8 *)"en-US", + L"Japanese", L"Japanese", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("new_string returned %u\n", + (unsigned int)ret); + goto out; + } + efi_st_printf("new string id is %u\n", id); + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_get_string() - test retrieval of a string entry + * + * This test adds a package list, create a new string entry and then tries + * to get it with its string id. + * + * @Return: status code + */ +static int test_hii_string_get_string(void) +{ + efi_hii_handle_t handle = NULL; + efi_string_id_t id; + efi_string_t string; + efi_uintn_t string_len; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_string_protocol->new_string(hii_string_protocol, handle, + &id, (u8 *)"en-US", + L"Japanese", L"Japanese", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("new_string returned %u\n", + (unsigned int)ret); + goto out; + } + + string = NULL; + string_len = 0; + ret = hii_string_protocol->get_string(hii_string_protocol, + (u8 *)"en-US", handle, id, string, &string_len, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_string returned %u\n", + (unsigned int)ret); + goto out; + } + string_len += sizeof(u16); + ret = boottime->allocate_pool(EFI_LOADER_DATA, string_len, + (void **)&string); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_string_protocol->get_string(hii_string_protocol, + (u8 *)"en-US", handle, id, string, &string_len, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("get_string returned %u\n", + (unsigned int)ret); + goto out; + } + + if (efi_st_strcmp_16_8(string, "Japanese")) { + efi_st_error("get_string returned incorrect string\n"); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_set_string() - test change of a string entry + * + * This test adds a package list, create a new string entry and then tries + * to modify it. + * + * @Return: status code + */ +static int test_hii_string_set_string(void) +{ + efi_hii_handle_t handle = NULL; + efi_string_id_t id; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_string_protocol->new_string(hii_string_protocol, handle, + &id, (u8 *)"en-US", + L"Japanese", L"Japanese", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("new_string returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_string_protocol->set_string(hii_string_protocol, handle, + id, (u8 *)"en-US", + L"Nihongo", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("set_string returned %u\n", + (unsigned int)ret); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_get_languages() - test listing of languages + * + * This test adds a package list, and then tries to enumerate languages + * in it. We will get an string of language names. + * + * @Return: status code + */ +static int test_hii_string_get_languages(void) +{ + efi_hii_handle_t handle = NULL; + u8 *languages; + efi_uintn_t languages_len; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + languages = NULL; + languages_len = 0; + ret = hii_string_protocol->get_languages(hii_string_protocol, handle, + languages, &languages_len); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_languages returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, languages_len, + (void **)&languages); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_string_protocol->get_languages(hii_string_protocol, handle, + languages, &languages_len); + if (ret != EFI_SUCCESS) { + efi_st_error("get_languages returned %u\n", + (unsigned int)ret); + goto out; + } + + efi_st_printf("got languages are %s\n", languages); + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_get_secondary_languages() - test listing of secondary + * languages + * + * This test adds a package list, and then tries to enumerate secondary + * languages with a specific language. We will get an string of language names. + * + * @Return: status code + */ +static int test_hii_string_get_secondary_languages(void) +{ + efi_hii_handle_t handle = NULL; + u8 *languages; + efi_uintn_t languages_len; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + languages = NULL; + languages_len = 0; + ret = hii_string_protocol->get_secondary_languages(hii_string_protocol, + handle, (u8 *)"en-US", languages, &languages_len); + if (ret == EFI_NOT_FOUND) { + efi_st_printf("no secondary languages\n"); + result = EFI_ST_SUCCESS; + goto out; + } + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_secondary_languages returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, languages_len, + (void **)&languages); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_string_protocol->get_secondary_languages(hii_string_protocol, + handle, (u8 *)"en-US", languages, &languages_len); + if (ret != EFI_SUCCESS) { + efi_st_error("get_secondary_languages returned %u\n", + (unsigned int)ret); + goto out; + } + + efi_st_printf("got secondary languages are %s\n", languages); + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +static int test_hii_string_protocol(void) +{ + int ret; + + ret = test_hii_string_new_string(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_get_string(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_set_string(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_get_languages(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_get_secondary_languages(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success, EFI_ST_FAILURE for failure + */ +static int execute(void) +{ + int ret; + + /* HII database protocol */ + ret = test_hii_database_protocol(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + /* HII string protocol */ + ret = test_hii_string_protocol(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(hii) = { + .name = "HII database protocols", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_hii_data.c b/roms/u-boot/lib/efi_selftest/efi_selftest_hii_data.c new file mode 100644 index 000000000..d19f0682a --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_hii_data.c @@ -0,0 +1,453 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This file's test data is derived from UEFI SCT. + * The original copyright is attached below. + */ + +/* + * Copyright 2006 - 2016 Unified EFI, Inc.<BR> + * Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR> + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD + * License which accompanies this distribution. The full text of the license + * may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + */ + +#include <efi.h> + +#ifdef NOT_USED +/* + * TODO: These macro's are not used as they appear only in + * "#ifdef NOT_USED" clauses. In the future, define them elsewhere. + */ + +/* HII form */ +#define EFI_IFR_AND_OP 0x15 +#define EFI_IFR_END_OP 0x29 +#define EFI_IFR_BITWISE_AND_OP 0x35 + +/* HII image */ +#define EFI_HII_IIBT_END 0x00 +#define EFI_HII_IIBT_IMAGE_1BIT 0x10 +#endif + +/* HII keyboard layout */ +#define EFI_NULL_MODIFIER 0x0000 + +u8 packagelist1[] = { + // EFI_HII_PACKAGE_LIST_HEADER, length = 20 + // SimpleFont, Font, GUID, Form, String, Image, DevicePath, + // (74) (110) 20 (8) 78 (67) (8) + // KeyboardLayout, End + // 192 4 + + 0x89, 0xcd, 0xab, 0x03, 0xf4, 0x03, 0x44, 0x70, + 0x81, 0xde, 0x99, 0xb1, 0x81, 0x20, 0xf7, 0x68, //16: guid + 0x3a, 0x01, 0x00, 0x00, // 4: total 314(0x13a) +#ifdef NOT_USED /* TODO: simple font package not implemented yet */ + // + // Simple Font Package 1, length = 74 + // + 0x4A, 0x00, 0x00, + EFI_HII_PACKAGE_SIMPLE_FONTS, + 1, 0, + 1, 0, + 0x55, 0x0, 0x1, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 0x77, 0x0, 0x2, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, + // + // Font Package 1, length = 110 + // + 0x6e, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FONTS, // 1 + 0x5c, 0x00, 0x00, 0x00, // 4: size of header + 0x5c, 0x00, 0x00, 0x00, // 4: offset + 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0xf5, 0x00, 0xec, 0xec, //10+2(pads) + 0xff, 0x33, 0xff, 0x44, // 4: font style + 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, //64 + // + // Glyph block 1, length = 18 + // + EFI_HII_GIBT_GLYPH_DEFAULT, // 1 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x99, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, //16: BitMapData + EFI_HII_GIBT_END, // 1 +#endif + // + // Guid Package 1, length = 20 + // + 0x14, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_TYPE_GUID, // 1 + 0x5a, 0xc9, 0x87, 0x03, 0x3, 0xd7, 0x46, 0x23, + 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8, //16: guid +#ifdef NOT_USED /* TODO: form package not implemented yet */ + // + // EFI_HII_PACKAGE_FORMS, length = 8 + // + 0x08, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FORMS, // 1 + // + // Opcode 1, length = 4 + // + EFI_IFR_AND_OP, + 0x82, + EFI_IFR_END_OP, + 0x02, + // +#endif + // EFI_HII_PACKAGE_STRINGS, length = 78 + // + 0x4e, 0x00, 0x00, // 3: length(header) + EFI_HII_PACKAGE_STRINGS, // 1: type(header) + 0x3c, 0x00, 0x00, 0x00, // 4: header_size + 0x3c, 0x00, 0x00, 0x00, // 4: string_offset + 0x00, 0x00, 0x11, 0x22, 0x44, 0x55, 0x77, 0x89, //32: language_window + 0x11, 0x00, 0x11, 0x22, 0x44, 0x55, 0x87, 0x89, + 0x22, 0x00, 0x11, 0x22, 0x44, 0x55, 0x77, 0x89, + 0x33, 0x00, 0x11, 0x22, 0x44, 0x55, 0x77, 0x89, + 0x01, 0x00, // 2: language name + 0x65, 0x6e, 0x2d, 0x55, 0x53, 0x3b, 0x7a, 0x68, //14: language + 0x2d, 0x48, 0x61, 0x6e, 0x74, 0x00, // "en-US;zh-Hant" + EFI_HII_SIBT_STRING_UCS2, // 1 + 0x45, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, + 0x69, 0x00, 0x73, 0x00, 0x68, 0x00, 0x00, 0x00, //16: "English" + EFI_HII_SIBT_END, // 1 +#ifdef NOT_USED /* TODO: image package not implemented yet */ + // + // EFI_HII_PACKAGE_IMAGES, length = 67 + // + 0x43, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_IMAGES, // 1 + 0x0c, 0x00, 0x00, 0x00, // 4: image info offset + 0x39, 0x00, 0x00, 0x00, // 4: palette info offset + EFI_HII_IIBT_IMAGE_1BIT, // 1 + 0x01, + 0x0b, 0x00, + 0x13, 0x00, + 0x80, 0x00, + 0xc0, 0x00, + 0xe0, 0x00, + 0xf0, 0x00, + 0xf8, 0x00, + 0xfc, 0x00, + 0xfe, 0x00, + 0xff, 0x00, + 0xff, 0x80, + 0xff, 0xc0, + 0xff, 0xe0, + 0xfe, 0x00, + 0xef, 0x00, + 0xcf, 0x00, + 0x87, 0x80, + 0x07, 0x80, + 0x03, 0xc0, + 0x03, 0xc0, + 0x01, 0x80, //43 + EFI_HII_IIBT_END, // 1 + 0x01, 0x00, + 0x06, 0x00, + 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, //10 + // + // EFI_HII_PACKAGE_DEVICE_PATH, length = 8 + // + 0x08, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_DEVICE_PATH, // 1 + 0x01, 0x23, 0x45, 0x66, // 4: dummy device path protocol + // instance address +#endif + // + // Keyboard layout package 1, length = 192 + 0xc0, 0x00, 0x00, // 3: length(header) + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, // 1: type(header) + 0x02, 0x00, // 2: LayoutCount + // + // Layout 1, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0x95, 0xe4, 0x40, 0x8d, 0xaa, 0xe2, 0x6f, 0x4c, + 0x89, 0x70, 0x68, 0x85, 0x09, 0xee, 0xc7, 0xd2, //16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor_ + // string_offset + 0x02, // 1: descriptor_count + // + // Descriptor 1, length = 16 + // + 49, 0x00, 0x00, 0x00, // 4: key (EfiKeyD1) + 'q', 0x00, // 2: unicode + 'Q', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x00, // 2: modifier + 0x03, 0x00, // 2: affected_attribute + // + // Descriptor 2, length = 16 + // + 50, 0x00, 0x00, 0x00, // 4: key (EfiKeyD2) + 'w', 0x00, // 2: unicode + 'W', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x00, // 2: modifier + 0x3, 0x0, // 2: affected_attribute + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '1', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString + // + // Layout 2, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0x3e, 0x0b, 0xe6, 0x2a, 0xd6, 0xb9, 0xd8, 0x49, + 0x9a, 0x16, 0xc2, 0x48, 0xf1, 0xeb, 0xa8, 0xdb, //16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor_ + // string_offset + 0x02, // 1 Descriptor count + // + // Descriptor 1, length = 16 + // + 51, 0x0, 0x0, 0x0, // 4: key (EfiKeyD3) + 'e', 0x00, // 2: unicode + 'E', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x0, // 2: modifier + 0x3, 0x0, // 2: affected_attribute + // + // Descriptor 2, length = 16 + // + 52, 0x0, 0x0, 0x0, // 4: key (EfiKeyD4) + 'r', 0x00, // 2: unicode + 'R', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x0, // 2: modifier + 0x3, 0x0, // 2: affected_attribute + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '2', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString + // + // End of package list, length = 4 + // + 0x4, 0x00, 0x00, + EFI_HII_PACKAGE_END +}; + +u8 packagelist2[] = { + // EFI_HII_PACKAGE_LIST_HEADER, length = 20 + // SimpleFont, Font, GUID, KeyboardLayout, Form, End + // (74) (122) 20 192 (8) 4 + 0xd3, 0xde, 0x85, 0x86, 0xce, 0x1b, 0xf3, 0x43, + 0xa2, 0x0c, 0xa3, 0x06, 0xec, 0x69, 0x72, 0xdd, //16 + 0xec, 0x00, 0x00, 0x00, // 4: total 236(0xec) + +#ifdef NOT_USED /* TODO: simple font package not implemented yet */ + // + // Simple Font Package 2, length = 74 + // + 0x4A, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_SIMPLE_FONTS, // 1 + 1, 0, // 2 + 1, 0, // 2 + 0x33, 0x0, 0, 1, 2, 3, 4, 5, 0, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //22 + 0x44, 0x0, 0x2, 2, 3, 4, 5, 6, 0, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, //22 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 9, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, //22 + // + // Font Package 2, length = 122 + // + 0x7A, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FONTS, // 1 + 0x5C, 0x00, 0x00, 0x00, // 4: size of header + 0x5C, 0x00, 0x00, 0x00, // 4: dummy offset + 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0xf5, 0x00, 0xec, 0xec, //10+2(pads) + 0xff, 0x11, 0xff, 0x22, // 4: font style + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, //64 + // + // Glyph block 1, length = 30 + // + EFI_HII_GIBT_GLYPH, // 1 + 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0xf5, 0x00, //10 + 0xff, 0x01, // 2 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, //16: BitMapData + EFI_HII_GIBT_END, // 1 +#endif + // + // Guid Package 1, length = 20 + // + 0x14, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_TYPE_GUID, // 1 + 0x5a, 0xc9, 0x87, 0x03, 0x3, 0xd7, 0x46, 0x23, + 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8, //16: guid + // + // Keyboard layout package 2, length = 192 + 0xc0, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, // 1 + 0x02, 0x00, //0xec, 0xec, // 2: LayoutCount + // + // Layout 1, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0x1f, 0x6a, 0xf5, 0xe0, 0x6b, 0xdf, 0x7e, 0x4a, + 0xa3, 0x9a, 0xe7, 0xa5, 0x19, 0x15, 0x45, 0xd6,//16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor + // string offset + 0x02, // 1: descriptor_count + // + // Descriptor 1, length = 16 + // + 32, 0x00, 0x00, 0x00, // 4: key (EfiKeyC1) + 'a', 0x00, // 2: unicode + 'A', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unic + EFI_NULL_MODIFIER, 0x00, // 2: modifier + 0x03, 0x00, // 2: affected_attribute + // + // Descriptor 2, length = 16 + // + 33 /*EfiKeyC2*/, 0x00, 0x00, 0x00, + 's', 0x00, + 'S', 0x00, + 0x00, 0x00, + 0x00, 0x00, + EFI_NULL_MODIFIER, 0x00, + 0x3, 0x0, + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '3', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString + // + // Layout 2, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0xc9, 0x6a, 0xbe, 0x47, 0xcc, 0x54, 0xf9, 0x46, + 0xa2, 0x62, 0xd5, 0x3b, 0x25, 0x6a, 0xc, 0x34, //16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor + // string_offset + 0x02, // 1: descriptor_count + // + // Descriptor 1, length = 16 + // + 34 /*EfiKeyC3*/, 0x0, 0x0, 0x0, + 'd', 0x00, + 'D', 0x00, + 0x00, 0x00, + 0x00, 0x00, + EFI_NULL_MODIFIER, 0x0, + 0x3, 0x0, + // + // Descriptor 2, length = 16 + // + 35 /*EfiKeyC4*/, 0x0, 0x0, 0x0, + 'e', 0x00, + 'E', 0x00, + 0x00, 0x00, + 0x00, 0x00, + EFI_NULL_MODIFIER, 0x0, + 0x3, 0x0, + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '4', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString +#ifdef NOT_USED /* TODO: form package not implemented yet */ + // + // EFI_HII_PACKAGE_FORMS, length = 8 + // + 0x08, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FORMS, // 1 + // + // Opcode 1 + // + EFI_IFR_BITWISE_AND_OP, // 1 + 0x02, // 1 + EFI_IFR_END_OP, // 1 + 0x02, // 1 +#endif + // + // End of package list, length = 4 + // + 0x4, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_END // 1 +}; + +efi_guid_t packagelist_guid1 = + EFI_GUID(0x03abcd89, 0x03f4, 0x7044, + 0x81, 0xde, 0x99, 0xb1, 0x81, 0x20, 0xf7, 0x68); + +efi_guid_t packagelist_guid2 = + EFI_GUID(0x8685ded3, 0x1bce, 0x43f3, + 0xa2, 0x0c, 0xa3, 0x06, 0xec, 0x69, 0x72, 0xdd); + +efi_guid_t kb_layout_guid11 = + EFI_GUID(0x8d40e495, 0xe2aa, 0x4c6f, + 0x89, 0x70, 0x68, 0x85, 0x09, 0xee, 0xc7, 0xd2); + +efi_guid_t kb_layout_guid12 = + EFI_GUID(0x2ae60b3e, 0xb9d6, 0x49d8, + 0x9a, 0x16, 0xc2, 0x48, 0xf1, 0xeb, 0xa8, 0xdb); + +efi_guid_t kb_layout_guid21 = + EFI_GUID(0xe0f56a1f, 0xdf6b, 0x4a7e, + 0xa3, 0x9a, 0xe7, 0xa5, 0x19, 0x15, 0x45, 0xd6); + +efi_guid_t kb_layout_guid22 = + EFI_GUID(0x47be6ac9, 0x54cc, 0x46f9, + 0xa2, 0x62, 0xd5, 0x3b, 0x25, 0x6a, 0x0c, 0x34); + +efi_guid_t package_guid = + EFI_GUID(0x0387c95a, 0xd703, 0x2346, + 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8); diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_load_file.c b/roms/u-boot/lib/efi_selftest/efi_selftest_load_file.c new file mode 100644 index 000000000..4473e7c36 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_load_file.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_load_file + * + * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol + * by the LoadImage() service. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_exit.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +#define GUID_VENDOR \ + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \ + 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1) + +#define GUID_VENDOR2 \ + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \ + 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2) + +#define FILE_NAME_SIZE 16 + +static const efi_guid_t efi_st_guid_load_file_protocol = + EFI_LOAD_FILE_PROTOCOL_GUID; +static const efi_guid_t efi_st_guid_load_file2_protocol = + EFI_LOAD_FILE2_PROTOCOL_GUID; +static const efi_guid_t efi_st_guid_device_path = + EFI_DEVICE_PATH_PROTOCOL_GUID; + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; +static efi_handle_t handle_lf; +static efi_handle_t handle_lf2; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +static int load_file_call_count; +static int load_file2_call_count; + +/* Decompressed file image */ +static u8 *image; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path d; +} dp_lf_prot = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path_file_path f; + u16 file_name[FILE_NAME_SIZE]; + struct efi_device_path e; +} dp_lf_file = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR, + }, + { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16), + } + }, + L"\\lf.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path d; +} dp_lf2_prot = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR2, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path_file_path f; + u16 file_name[FILE_NAME_SIZE]; + struct efi_device_path e; +} dp_lf2_file = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR2, + }, + { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16), + } + }, + L"\\lf2.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL + * + * @this: instance of EFI_LOAD_FILE_PROTOCOL + * @file_path: remaining device path + * @boot_policy: true if called by boot manager + * @buffer_size: (required) buffer size + * @buffer: buffer to which the file is to be loaded + */ +efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this, + struct efi_device_path *file_path, + bool boot_policy, + efi_uintn_t *buffer_size, + void *buffer) +{ + ++load_file_call_count; + if (memcmp(file_path, dp_lf_file_remainder, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16) + + sizeof(struct efi_device_path))) { + efi_st_error("Wrong remaining device path\n"); + return EFI_NOT_FOUND; + } + if (this->load_file != load_file) { + efi_st_error("wrong this\n"); + return EFI_INVALID_PARAMETER; + } + if (*buffer_size < img.length) { + *buffer_size = img.length; + return EFI_BUFFER_TOO_SMALL; + } + memcpy(buffer, image, img.length); + *buffer_size = img.length; + return EFI_SUCCESS; +} + + +/* + * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL + * + * @this: instance of EFI_LOAD_FILE2_PROTOCOL + * @file_path: remaining device path + * @boot_policy: true if called by boot manager + * @buffer_size: (required) buffer size + * @buffer: buffer to which the file is to be loaded + */ +efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this, + struct efi_device_path *file_path, + bool boot_policy, + efi_uintn_t *buffer_size, + void *buffer) +{ + ++load_file2_call_count; + if (memcmp(file_path, dp_lf2_file_remainder, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16) + + sizeof(struct efi_device_path))) { + efi_st_error("Wrong remaining device path\n"); + return EFI_NOT_FOUND; + } + if (this->load_file != load_file2) { + efi_st_error("wrong this\n"); + return EFI_INVALID_PARAMETER; + } + if (boot_policy) { + efi_st_error("LOAD_FILE2 called with boot_policy = true"); + return EFI_INVALID_PARAMETER; + } + if (*buffer_size < img.length) { + *buffer_size = img.length; + return EFI_BUFFER_TOO_SMALL; + } + memcpy(buffer, image, img.length); + *buffer_size = img.length; + return EFI_SUCCESS; +} + +static struct efi_load_file_protocol lf_prot = {load_file}; +static struct efi_load_file_protocol lf2_prot = {load_file2}; + +/* + * Setup unit test. + * + * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + ret = boottime->install_multiple_protocol_interfaces( + &handle_lf, + &efi_st_guid_device_path, + &dp_lf_prot, + &efi_st_guid_load_file_protocol, + &lf_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_multiple_protocol_interfaces( + &handle_lf2, + &efi_st_guid_device_path, + &dp_lf2_prot, + &efi_st_guid_load_file2_protocol, + &lf2_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_teardown(void) +{ + efi_status_t ret = EFI_ST_SUCCESS; + + if (handle_lf) { + ret = boottime->uninstall_multiple_protocol_interfaces( + handle_lf, + &efi_st_guid_device_path, + &dp_lf_prot, + &efi_st_guid_load_file_protocol, + &lf_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error( + "UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + } + if (handle_lf2) { + ret = boottime->uninstall_multiple_protocol_interfaces( + handle_lf2, + &efi_st_guid_device_path, + &dp_lf2_prot, + &efi_st_guid_load_file2_protocol, + &lf2_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error( + "UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + } + + if (image) { + ret = boottime->free_pool(image); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return ret; +} + +/* + * Execute unit test. + * + * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the + * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; + u16 expected_text[] = EFI_ST_SUCCESS_STR; + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (load_file2_call_count || !load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + ret = boottime->unload_image(handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unload image\n"); + return EFI_ST_FAILURE; + } + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (load_file2_call_count || !load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + ret = boottime->unload_image(handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unload image\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_NOT_FOUND) { + efi_st_error( + "Boot manager should not use LOAD_FILE2_PROTOCOL\n"); + return EFI_ST_FAILURE; + } + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (!load_file2_call_count || load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->start_image(handle, &exit_data_size, &exit_data); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + if (!exit_data || exit_data_size != sizeof(expected_text) || + memcmp(exit_data, expected_text, sizeof(expected_text))) { + efi_st_error("Incorrect exit data\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(exit_data); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free exit data\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(load_file_protocol) = { + .name = "load file protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = efi_st_load_file_setup, + .execute = efi_st_load_file_execute, + .teardown = efi_st_load_file_teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_loaded_image.c b/roms/u-boot/lib/efi_selftest/efi_selftest_loaded_image.c new file mode 100644 index 000000000..5889ab126 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_loaded_image.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_loaded_image + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the Loaded Image Protocol. + */ + +#include <efi_selftest.h> + +static efi_guid_t loaded_image_protocol_guid = + EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, + 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b); +static struct efi_boot_services *boottime; +efi_handle_t image_handle; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + image_handle = img_handle; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Verify that the loaded image protocol is installed on the image handle. + * Verify that the loaded image protocol points to the system table. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t i, protocol_buffer_count = 0; + efi_guid_t **protocol_buffer = NULL; + bool found = false; + struct efi_loaded_image *loaded_image_protocol; + + /* + * Get the GUIDs of all protocols installed on the handle. + */ + ret = boottime->protocols_per_handle(image_handle, &protocol_buffer, + &protocol_buffer_count); + if (ret != EFI_SUCCESS) { + efi_st_error("ProtocolsPerHandle failed\n"); + return EFI_ST_FAILURE; + } + if (!protocol_buffer_count || !protocol_buffer) { + efi_st_error("ProtocolsPerHandle returned no protocol\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("%u protocols installed on image handle\n", + (unsigned int)protocol_buffer_count); + for (i = 0; i < protocol_buffer_count; ++i) { + if (memcmp(protocol_buffer[i], &loaded_image_protocol_guid, + sizeof(efi_guid_t))) + found = true; + } + if (!found) { + efi_st_printf("LoadedImageProtocol not found\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(protocol_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Open the loaded image protocol. + */ + ret = boottime->open_protocol(image_handle, &loaded_image_protocol_guid, + (void **)&loaded_image_protocol, NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (loaded_image_protocol->revision != + EFI_LOADED_IMAGE_PROTOCOL_REVISION) { + efi_st_printf("Incorrect revision\n"); + return EFI_ST_FAILURE; + } + if (!loaded_image_protocol->system_table || + loaded_image_protocol->system_table->hdr.signature != + EFI_SYSTEM_TABLE_SIGNATURE) { + efi_st_printf("System table reference missing\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(loadedimage) = { + .name = "loaded image", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_loadimage.c b/roms/u-boot/lib/efi_selftest/efi_selftest_loadimage.c new file mode 100644 index 000000000..06a87df86 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_loadimage.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_loadimage + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the LoadImage and StartImage boot service. + * + * The efi_selftest_miniapp_exit.efi application is loaded via a file device + * path and started. + */ + +#include <efi_selftest.h> +/* Include containing the efi_selftest_miniapp_exit.efi application */ +#include "efi_miniapp_file_image_exit.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +#define FILE_NAME L"app.efi" +#define VOLUME_NAME L"EfiDisk" + +static struct efi_boot_services *boottime; +static efi_handle_t handle_image; +static efi_handle_t handle_volume; + +static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; +static const efi_guid_t guid_simple_file_system_protocol = + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t guid_file_info = EFI_FILE_INFO_GUID; +static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +/* File info including file name */ +struct file_info { + struct efi_file_info info; + u16 file_name[sizeof(FILE_NAME)]; +}; + +/* File system info including volume name */ +struct file_system_info { + struct efi_file_system_info info; + u16 file_name[sizeof(VOLUME_NAME)]; +}; + +/* Compressed file image */ +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +/* Pointer to decompressed file image */ +static u8 *image; + +/* File info */ +static struct file_info priv_file_info = { + { + .size = sizeof(struct file_info), + .attribute = EFI_FILE_READ_ONLY, + }, + FILE_NAME, +}; + +/* Pointer to file info */ +struct efi_file_info *file_info = &priv_file_info.info; + +/* Volume device path */ +static struct { + struct efi_device_path_vendor vendor; + struct efi_device_path end; +} __packed dp_volume = { + .vendor = { + .dp = { + .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE, + .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR, + .length = sizeof(struct efi_device_path_vendor), + }, + .guid = EFI_GUID(0x4f9a0ebf, 0xa179, 0x88a6, 0x25, 0x68, + 0x10, 0x72, 0xb1, 0x93, 0x51, 0x71), + }, + .end = { + .type = DEVICE_PATH_TYPE_END, + .sub_type = DEVICE_PATH_SUB_TYPE_END, + .length = sizeof(struct efi_device_path), + } +}; + +/* File device path */ +static struct { + struct efi_device_path_vendor vendor; + struct efi_device_path path; + u16 file[sizeof(FILE_NAME)]; + struct efi_device_path end; +} __packed dp_file = { + .vendor = { + .dp = { + .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE, + .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR, + .length = sizeof(struct efi_device_path_vendor), + }, + .guid = EFI_GUID(0x4f9a0ebf, 0xa179, 0x88a6, 0x25, 0x68, + 0x10, 0x72, 0xb1, 0x93, 0x51, 0x71), + }, + .path = { + .type = DEVICE_PATH_TYPE_MEDIA_DEVICE, + .sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, + .length = sizeof(struct efi_device_path) + sizeof(dp_file.file), + }, + .file = FILE_NAME, + .end = { + .type = DEVICE_PATH_TYPE_END, + .sub_type = DEVICE_PATH_SUB_TYPE_END, + .length = sizeof(struct efi_device_path), + } +}; + +/* File system info */ +static struct file_system_info priv_file_system_info = { + { + .size = sizeof(struct file_system_info), + .read_only = true, + .volume_size = 0x100000, + .free_space = 0x0, + .block_size = 0x200, + }, + VOLUME_NAME +}; + +/* Pointer to file system info */ +static struct efi_file_system_info *file_system_info = + &priv_file_system_info.info; + +/* Forward definitions of file and file system functions */ +static efi_status_t EFIAPI open_volume + (struct efi_simple_file_system_protocol *this, + struct efi_file_handle **root); + +static efi_status_t EFIAPI open + (struct efi_file_handle *this, + struct efi_file_handle **new_handle, + u16 *file_name, u64 open_mode, u64 attributes); + +static efi_status_t EFIAPI close(struct efi_file_handle *this); + +static efi_status_t EFIAPI delete(struct efi_file_handle *this); + +static efi_status_t EFIAPI read + (struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer); + +static efi_status_t EFIAPI write + (struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer); + +static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos); + +static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos); + +static efi_status_t EFIAPI getinfo + (struct efi_file_handle *this, const efi_guid_t *info_type, + efi_uintn_t *buffer_size, void *buffer); + +static efi_status_t EFIAPI setinfo + (struct efi_file_handle *this, const efi_guid_t *info_type, + efi_uintn_t buffer_size, void *buffer); + +static efi_status_t EFIAPI flush(struct efi_file_handle *this); + +/* Internal information about status of file system */ +static struct { + /* Difference of volume open count minus volume close count */ + int volume_open_count; + /* Difference of file open count minus file close count */ + int file_open_count; + /* File size */ + u64 file_size; + /* Current position in file */ + u64 file_pos; +} priv; + +/* EFI_FILE_PROTOCOL for file */ +static struct efi_file_handle file = { + .rev = 0x00010000, + .open = open, + .close = close, + .delete = delete, + .read = read, + .write = write, + .getpos = getpos, + .setpos = setpos, + .getinfo = getinfo, + .setinfo = setinfo, + .flush = flush, +}; + +/* EFI_FILE_PROTOCOL for root directory */ +static struct efi_file_handle volume = { + .rev = 0x00010000, + .open = open, + .close = close, + .delete = delete, + .read = read, + .write = write, + .getpos = getpos, + .setpos = setpos, + .getinfo = getinfo, + .setinfo = setinfo, + .flush = flush, +}; + +/* EFI_SIMPLE_FILE_SYSTEM_PROTOCOL of the block device */ +struct efi_simple_file_system_protocol file_system = { + .rev = 0x00010000, + .open_volume = open_volume, +}; + +static efi_status_t EFIAPI open_volume + (struct efi_simple_file_system_protocol *this, + struct efi_file_handle **root) +{ + if (this != &file_system || !root) + return EFI_INVALID_PARAMETER; + + *root = &volume; + priv.volume_open_count++; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI open + (struct efi_file_handle *this, + struct efi_file_handle **new_handle, + u16 *file_name, u64 open_mode, u64 attributes) +{ + if (this != &volume) + return EFI_INVALID_PARAMETER; + + *new_handle = &file; + priv.file_pos = 0; + priv.file_open_count++; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI close(struct efi_file_handle *this) +{ + if (this == &file) + priv.file_open_count--; + else if (this == &volume) + priv.volume_open_count--; + else + return EFI_INVALID_PARAMETER; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI delete(struct efi_file_handle *this) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + return EFI_UNSUPPORTED; +} + +static efi_status_t EFIAPI read + (struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + if (priv.file_pos >= img.length) + *buffer_size = 0; + else if (priv.file_pos + *buffer_size > img.length) + *buffer_size = img.length - priv.file_pos; + + boottime->copy_mem(buffer, &image[priv.file_pos], *buffer_size); + priv.file_pos += *buffer_size; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI write + (struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + return EFI_UNSUPPORTED; +} + +static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + *pos = priv.file_pos; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + priv.file_pos = pos; + + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI getinfo + (struct efi_file_handle *this, const efi_guid_t *info_type, + efi_uintn_t *buffer_size, void *buffer) +{ + if (this == &file) { + if (memcmp(info_type, &guid_file_info, sizeof(efi_guid_t))) + return EFI_INVALID_PARAMETER; + if (*buffer_size >= sizeof(struct file_info)) { + boottime->copy_mem(buffer, file_info, + sizeof(struct file_info)); + } else { + *buffer_size = sizeof(struct file_info); + return EFI_BUFFER_TOO_SMALL; + } + } else if (this == &volume) { + if (memcmp(info_type, &guid_file_system_info, + sizeof(efi_guid_t))) + return EFI_INVALID_PARAMETER; + if (*buffer_size >= sizeof(struct file_system_info)) { + boottime->copy_mem(buffer, file_system_info, + sizeof(struct file_system_info)); + } else { + *buffer_size = sizeof(struct file_system_info); + return EFI_BUFFER_TOO_SMALL; + } + } else { + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI setinfo + (struct efi_file_handle *this, const efi_guid_t *info_type, + efi_uintn_t buffer_size, void *buffer) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + return EFI_UNSUPPORTED; +} + +static efi_status_t EFIAPI flush(struct efi_file_handle *this) +{ + if (this != &file) + return EFI_INVALID_PARAMETER; + + return EFI_UNSUPPORTED; +} + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + priv.file_size = img.length; + file_info->file_size = img.length; + return ret; +} + +/* + * Setup unit test. + * + * Decompress application image and provide a handle for the in memory block + * device. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + handle_image = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + ret = boottime->install_protocol_interface + (&handle_volume, &guid_device_path, EFI_NATIVE_INTERFACE, + &dp_volume); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install device path\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface + (&handle_volume, &guid_simple_file_system_protocol, + EFI_NATIVE_INTERFACE, &file_system); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install simple file system protocol\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Uninstall protocols and free memory. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret = EFI_ST_SUCCESS; + + if (handle_volume) { + ret = boottime->uninstall_protocol_interface + (handle_volume, &guid_simple_file_system_protocol, + &file_system); + if (ret != EFI_SUCCESS) { + efi_st_error + ("Failed to uninstall simple file system protocol\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_protocol_interface + (handle_volume, &guid_device_path, &dp_volume); + if (ret != EFI_SUCCESS) { + efi_st_error + ("Failed to uninstall device path protocol\n"); + return EFI_ST_FAILURE; + } + } + + if (image) { + ret = boottime->free_pool(image); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return ret; +} + +/* + * Execute unit test. + * + * Load and start the application image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + + ret = boottime->load_image(false, handle_image, &dp_file.vendor.dp, + NULL, 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + ret = boottime->start_image(handle, NULL, NULL); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + + if (priv.file_open_count) { + efi_st_error("File open count = %d, expected 0\n", + priv.file_open_count); + return EFI_ST_FAILURE; + } + if (priv.volume_open_count) { + efi_st_error("Volume open count = %d, expected 0\n", + priv.volume_open_count); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(loadimage) = { + .name = "load image from file", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_manageprotocols.c b/roms/u-boot/lib/efi_selftest/efi_selftest_manageprotocols.c new file mode 100644 index 000000000..8edb1e4d4 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_manageprotocols + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following protocol services: + * InstallProtocolInterface, UninstallProtocolInterface, + * InstallMultipleProtocolsInterfaces, UninstallMultipleProtocolsInterfaces, + * HandleProtocol, ProtocolsPerHandle, + * LocateHandle, LocateHandleBuffer. + */ + +#include <efi_selftest.h> + +/* + * The test currently does not actually call the interface function. + * So this is just a dummy structure. + */ +struct interface { + void (EFIAPI * inc)(void); +}; + +static struct efi_boot_services *boottime; +static efi_guid_t guid1 = + EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a, + 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf); +static efi_guid_t guid2 = + EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77, + 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f); +static efi_guid_t guid3 = + EFI_GUID(0x06d641a3, 0xf4e7, 0xe0c9, + 0xe7, 0x8d, 0x41, 0x2d, 0x72, 0xa6, 0xb1, 0x24); +static efi_handle_t handle1; +static efi_handle_t handle2; +static struct interface interface1; +static struct interface interface2; +static struct interface interface3; +static struct interface interface4; + +/* + * Find a handle in an array. + * + * @handle: handle to find + * @count: number of entries in the array + * @buffer: array to search + */ +efi_status_t find_in_buffer(efi_handle_t handle, size_t count, + efi_handle_t *buffer) +{ + size_t i; + + for (i = 0; i < count; ++i) { + if (buffer[i] == handle) + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + +/* + * Setup unit test. + * + * Create two handles and install two out of three protocol interfaces on each + * of them: + * + * handle1 + * guid1 interface1 + * guid3 interface3 + * handle2 + * guid1 interface4 + * guid2 interface2 + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + efi_handle_t handle; + + boottime = systable->boottime; + + ret = boottime->install_protocol_interface(&handle1, &guid3, + EFI_NATIVE_INTERFACE, + &interface3); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (!handle1) { + efi_st_error("InstallProtocolInterface failed to create handle\n"); + return EFI_ST_FAILURE; + } + handle = handle1; + ret = boottime->install_protocol_interface(&handle1, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (handle != handle1) { + efi_st_error("InstallProtocolInterface failed to use handle\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_multiple_protocol_interfaces(&handle2, + &guid1, &interface4, &guid2, &interface2, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + if (!handle2 || handle1 == handle2) { + efi_st_error("InstallMultipleProtocolInterfaces failed to create handle\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + */ +static int execute(void) +{ + struct interface *interface; + efi_status_t ret; + efi_handle_t *buffer; + size_t buffer_size; + efi_uintn_t count = 0; + efi_guid_t **prot_buffer; + efi_uintn_t prot_count; + + /* + * Test HandleProtocol + */ + ret = boottime->handle_protocol(handle1, &guid3, (void **)&interface); + if (ret != EFI_SUCCESS) { + efi_st_error("HandleProtocol failed to retrieve interface\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface3) { + efi_st_error("HandleProtocol returned wrong interface\n"); + return EFI_ST_FAILURE; + } + ret = boottime->handle_protocol(handle1, &guid2, (void **)&interface); + if (ret == EFI_SUCCESS) { + efi_st_error("HandleProtocol returned not installed interface\n"); + return EFI_ST_FAILURE; + } + + /* + * Test LocateHandleBuffer with AllHandles + */ + ret = boottime->locate_handle_buffer(ALL_HANDLES, NULL, NULL, + &count, &buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer with AllHandles failed\n"); + return EFI_ST_FAILURE; + } + buffer_size = count; + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle2, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + /* Release buffer */ + ret = boottime->free_pool(buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Test error handling in UninstallMultipleProtocols + * + * These are the installed protocol interfaces on handle 2: + * + * guid1 interface4 + * guid2 interface2 + * + * Try to uninstall more protocols than there are installed. This + * should return an error EFI_INVALID_PARAMETER. All deleted protocols + * should be reinstalled. + */ + ret = boottime->uninstall_multiple_protocol_interfaces( + handle2, + &guid1, &interface4, + &guid2, &interface2, + &guid3, &interface3, + NULL); + if (ret != EFI_INVALID_PARAMETER) { + printf("%lx", ret); + efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n"); + return EFI_ST_FAILURE; + } + + /* + * Test LocateHandleBuffer with ByProtocol + * + * These are the handles with a guid1 protocol interface installed: + * + * handle1, handle2 + */ + count = buffer_size; + ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, + &count, &buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + if (count != 2) { + efi_st_error("UninstallMultipleProtocolInterfaces deleted handle\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle2, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + /* Clear the buffer, we are reusing it it the next step. */ + boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + + /* + * Test LocateHandle with ByProtocol + */ + count = buffer_size * sizeof(efi_handle_t); + ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL, + &count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandle with ByProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (count / sizeof(efi_handle_t) != 2) { + efi_st_error("LocateHandle failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + buffer_size = count; + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandle failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle2, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandle failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + /* Release buffer */ + ret = boottime->free_pool(buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Test LocateProtocol + */ + ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface1 && interface != &interface4) { + efi_st_error("LocateProtocol failed to locate protocol\n"); + return EFI_ST_FAILURE; + } + + /* + * Test UninstallMultipleProtocols + */ + ret = boottime->uninstall_multiple_protocol_interfaces( + handle2, + &guid1, &interface4, + &guid2, &interface2, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + /* + * Check that the protocols are really uninstalled. + */ + count = buffer_size; + ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, + &count, &buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed\n"); + return EFI_ST_FAILURE; + } + if (count != 1) { + efi_st_error("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + + /* + * Test ProtocolsPerHandle + */ + ret = boottime->protocols_per_handle(handle1, + &prot_buffer, &prot_count); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + if (prot_count != 2) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + if (memcmp(prot_buffer[0], &guid1, 16) && + memcmp(prot_buffer[1], &guid1, 16)) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + if (memcmp(prot_buffer[0], &guid3, 16) && + memcmp(prot_buffer[1], &guid3, 16)) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + /* Release buffer */ + ret = boottime->free_pool(prot_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Uninstall remaining protocols + */ + ret = boottime->uninstall_protocol_interface(handle1, &guid1, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface); + if (ret == EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_protocol_interface(handle1, &guid3, + &interface3); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(protserv) = { + .name = "manage protocols", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_mem.c b/roms/u-boot/lib/efi_selftest/efi_selftest_mem.c new file mode 100644 index 000000000..51f0fec39 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_mem.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_memory + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following boottime services: + * CopyMem, SetMem, CalculateCrc32 + * + * The memory type used for the device tree is checked. + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; + +/** + * setup() - setup unit test + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * execute() - execute unit test + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u8 c1[] = "abcdefghijklmnop"; + u8 c2[] = "abcdefghijklmnop"; + u32 crc32; + efi_status_t ret; + + ret = boottime->calculate_crc32(c1, 16, &crc32); + if (ret != EFI_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (crc32 != 0x943ac093) { + efi_st_error("CalculateCrc32 returned wrong value\n"); + return EFI_ST_FAILURE; + } + boottime->copy_mem(&c1[5], &c1[3], 8); + if (memcmp(c1, "abcdedefghijknop", 16)) { + efi_st_error("CopyMem forward copy failed: %s\n", c1); + return EFI_ST_FAILURE; + } + boottime->copy_mem(&c2[3], &c2[5], 8); + if (memcmp(c2, "abcfghijklmlmnop", 16)) { + efi_st_error("CopyMem backward copy failed: %s\n", c2); + return EFI_ST_FAILURE; + } + boottime->set_mem(&c1[3], 8, 'x'); + if (memcmp(c1, "abcxxxxxxxxjknop", 16)) { + efi_st_error("SetMem failed: %s\n", c1); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(mem) = { + .name = "mem", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_memory.c b/roms/u-boot/lib/efi_selftest/efi_selftest_memory.c new file mode 100644 index 000000000..4d32a2800 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_memory.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_memory + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following boottime services: + * AllocatePages, FreePages, GetMemoryMap + * + * The memory type used for the device tree is checked. + */ + +#include <efi_selftest.h> + +#define EFI_ST_NUM_PAGES 8 + +static const efi_guid_t fdt_guid = EFI_FDT_GUID; +static struct efi_boot_services *boottime; +static u64 fdt_addr; + +/** + * setup() - setup unit test + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + size_t i; + + boottime = systable->boottime; + + for (i = 0; i < systable->nr_tables; ++i) { + if (!memcmp(&systable->tables[i].guid, &fdt_guid, + sizeof(efi_guid_t))) { + if (fdt_addr) { + efi_st_error("Duplicate device tree\n"); + return EFI_ST_FAILURE; + } + fdt_addr = (uintptr_t)systable->tables[i].table; + } + } + return EFI_ST_SUCCESS; +} + +/** + * find_in_memory_map() - check matching memory map entry exists + * + * @memory_map: memory map + * @desc_size: number of memory map entries + * @addr: physical address to find in the map + * @type: expected memory type + * Return: EFI_ST_SUCCESS for success + */ +static int find_in_memory_map(efi_uintn_t map_size, + struct efi_mem_desc *memory_map, + efi_uintn_t desc_size, + u64 addr, int memory_type) +{ + efi_uintn_t i; + bool found = false; + + for (i = 0; map_size; ++i, map_size -= desc_size) { + struct efi_mem_desc *entry = &memory_map[i]; + + if (entry->physical_start != entry->virtual_start) { + efi_st_error("Physical and virtual addresses do not match\n"); + return EFI_ST_FAILURE; + } + + if (addr >= entry->physical_start && + addr < entry->physical_start + + (entry->num_pages << EFI_PAGE_SHIFT)) { + if (found) { + efi_st_error("Duplicate memory map entry\n"); + return EFI_ST_FAILURE; + } + found = true; + if (memory_type != entry->type) { + efi_st_error + ("Wrong memory type %d, expected %d\n", + entry->type, memory_type); + return EFI_ST_FAILURE; + } + } + } + if (!found) { + efi_st_error("Missing memory map entry\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * execute() - execute unit test + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u64 p1; + u64 p2; + efi_uintn_t map_size = 0; + efi_uintn_t map_key; + efi_uintn_t desc_size; + u32 desc_version; + struct efi_mem_desc *memory_map; + efi_status_t ret; + + /* Allocate two page ranges with different memory type */ + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_CODE, + EFI_ST_NUM_PAGES, &p1); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + EFI_ST_NUM_PAGES, &p2); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Load memory map */ + ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error + ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); + return EFI_ST_FAILURE; + } + /* Allocate extra space for newly allocated memory */ + map_size += sizeof(struct efi_mem_desc); + ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + (void **)&memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->get_memory_map(&map_size, memory_map, &map_key, + &desc_size, &desc_version); + if (ret != EFI_SUCCESS) { + efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Check memory map entries */ + if (find_in_memory_map(map_size, memory_map, desc_size, p1, + EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + if (find_in_memory_map(map_size, memory_map, desc_size, p2, + EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + /* Free memory */ + ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Check memory reservation for the device tree */ + if (fdt_addr && + find_in_memory_map(map_size, memory_map, desc_size, fdt_addr, + EFI_ACPI_RECLAIM_MEMORY) != EFI_ST_SUCCESS) { + efi_st_error + ("Device tree not marked as ACPI reclaim memory\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(memory) = { + .name = "memory", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_exception.c b/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_exception.c new file mode 100644 index 000000000..59b7e5100 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_exception.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_miniapp_return + * + * Copyright (c) 2019 Heinrich Schuchardt + * + * This EFI application triggers an exception. + */ + +#include <common.h> +#include <efi_api.h> + +/* + * Entry point of the EFI application. + * + * @handle handle of the loaded image + * @systable system table + * @return status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *con_out = systable->con_out; + + con_out->output_string(con_out, + L"EFI application triggers exception.\n"); + +#if defined(CONFIG_ARM) + /* + * 0xe7f...f. is undefined in ARM mode + * 0xde.. is undefined in Thumb mode + */ + asm volatile (".word 0xe7f7defb\n"); +#elif defined(CONFIG_RISCV) + asm volatile (".word 0xffffffff\n"); +#elif defined(CONFIG_SANDBOX) + asm volatile (".word 0xffffffff\n"); +#elif defined(CONFIG_X86) + asm volatile (".word 0xffff\n"); +#endif + con_out->output_string(con_out, L"Exception not triggered.\n"); + return EFI_ABORTED; +} diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_exit.c b/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_exit.c new file mode 100644 index 000000000..6b5cfb01c --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_exit.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_miniapp_exit + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * This EFI application is run by the StartImage selftest. + * It uses the Exit boot service to return. + */ + +#include <common.h> +#include <efi_selftest.h> + +static efi_guid_t loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + +/** + * check_loaded_image_protocol() - check image_base/image_size + * + * Try to open the loaded image protocol. Check that this function is located + * between image_base and image_base + image_size. + * + * @image_handle: handle of the loaded image + * @systable: system table + * @return: status code + */ +static efi_status_t EFIAPI check_loaded_image_protocol + (efi_handle_t image_handle, struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *cout = systable->con_out; + struct efi_boot_services *boottime = systable->boottime; + struct efi_loaded_image *loaded_image_protocol; + efi_status_t ret; + + /* + * Open the loaded image protocol. + */ + ret = boottime->open_protocol + (image_handle, &loaded_image_protocol_guid, + (void **)&loaded_image_protocol, NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + cout->output_string(cout, + L"Could not open loaded image protocol"); + return ret; + } + if ((void *)check_loaded_image_protocol < + loaded_image_protocol->image_base || + (void *)check_loaded_image_protocol >= + loaded_image_protocol->image_base + + loaded_image_protocol->image_size) { + cout->output_string(cout, + L"Incorrect image_base or image_size\n"); + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; +} + +/** + * Entry point of the EFI application. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *con_out = systable->con_out; + efi_status_t ret; + u16 text[] = EFI_ST_SUCCESS_STR; + + con_out->output_string(con_out, L"EFI application calling Exit\n"); + + if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) { + con_out->output_string(con_out, + L"Loaded image protocol missing\n"); + ret = EFI_NOT_FOUND; + goto out; + } + + /* This return value is expected by the calling test */ + ret = EFI_UNSUPPORTED; +out: + systable->boottime->exit(handle, ret, sizeof(text), text); + + /* + * This statement should not be reached. + * To enable testing use a different return value. + */ + return EFI_SUCCESS; +} diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_return.c b/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_return.c new file mode 100644 index 000000000..5709e39ca --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_miniapp_return.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_miniapp_return + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * This EFI application is run by the StartImage selftest. + * It returns directly without calling the Exit boot service. + */ + +#include <common.h> +#include <efi_api.h> + +/* + * Entry point of the EFI application. + * + * @handle handle of the loaded image + * @systable system table + * @return status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *con_out = systable->con_out; + + con_out->output_string(con_out, + L"EFI application returning w/o calling Exit\n"); + + /* The return value is checked by the calling test */ + return EFI_INCOMPATIBLE_VERSION; +} diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_open_protocol.c b/roms/u-boot/lib/efi_selftest/efi_selftest_open_protocol.c new file mode 100644 index 000000000..e3f351df7 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_open_protocol.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_open_protocol + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks that open protocol information is correctly updated + * when calling: + * HandleProtocol, OpenProtocol, OpenProtocolInformation, CloseProtocol. + */ + +#include <efi_selftest.h> + +/* + * The test currently does not actually call the interface function. + * So this is just a dummy structure. + */ +struct interface { + void (EFIAPI *inc)(void); +}; + +static struct efi_boot_services *boottime; +static efi_guid_t guid1 = + EFI_GUID(0x492a0e38, 0x1442, 0xf819, + 0x14, 0xaa, 0x4b, 0x8d, 0x09, 0xfe, 0x5a, 0xb9); +static efi_handle_t handle1; +static struct interface interface1; + +/* + * Setup unit test. + * + * Create a handle and install a protocol interface on it. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->install_protocol_interface(&handle1, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (!handle1) { + efi_st_error + ("InstallProtocolInterface failed to create handle\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + + if (handle1) { + ret = boottime->uninstall_protocol_interface(handle1, &guid1, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Open the installed protocol twice via HandleProtocol() and once via + * OpenProtocol(EFI_OPEN_PROTOCOL_GET_PROTOCOL). Read the open protocol + * information and check the open counts. Finally close the protocol and + * check again. + */ +static int execute(void) +{ + void *interface; + struct efi_open_protocol_info_entry *entry_buffer; + efi_uintn_t entry_count; + efi_handle_t firmware_handle; + efi_status_t ret; + + ret = boottime->handle_protocol(handle1, &guid1, &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("HandleProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface1) { + efi_st_error("HandleProtocol returned wrong interface\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count != 1) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 1, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->handle_protocol(handle1, &guid1, &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("HandleProtocol failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count != 1) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 1, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + if (entry_buffer[0].open_count != 2) { + efi_st_error("Incorrect open count: expected 2 got %u\n", + entry_buffer[0].open_count); + return EFI_ST_FAILURE; + } + firmware_handle = entry_buffer[0].agent_handle; + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol(handle1, &guid1, &interface, + firmware_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocol failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count != 2) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 2, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + if (entry_buffer[0].open_count + entry_buffer[1].open_count != 3) { + efi_st_error("Incorrect open count: expected 3 got %u\n", + entry_buffer[0].open_count + + entry_buffer[1].open_count); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->close_protocol(handle1, &guid1, firmware_handle, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("CloseProtocol failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 0, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(openprot) = { + .name = "open protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_register_notify.c b/roms/u-boot/lib/efi_selftest/efi_selftest_register_notify.c new file mode 100644 index 000000000..ad763dd6c --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_register_notify.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_register_notify + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following protocol services: + * InstallProtocolInterface, UninstallProtocolInterface, + * RegisterProtocolNotify, CreateEvent, CloseEvent. + */ + +#include <efi_selftest.h> + +/* + * The test currently does not actually call the interface function. + * So this is just a dummy structure. + */ +struct interface { + void (EFIAPI * inc)(void); +}; + +struct context { + void *registration_key; + efi_uintn_t notify_count; + efi_uintn_t handle_count; + efi_handle_t *handles; +}; + +static struct efi_boot_services *boottime; +static efi_guid_t guid1 = + EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a, + 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf); +static efi_guid_t guid2 = + EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77, + 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f); +static struct context context; +static struct efi_event *event; + +/* + * Notification function, increments the notification count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + struct context *cp = context; + efi_status_t ret; + efi_uintn_t handle_count; + efi_handle_t *handles; + + cp->notify_count++; + + for (;;) { + ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL, + cp->registration_key, + &handle_count, &handles); + if (ret != EFI_SUCCESS) + break; + cp->handle_count += handle_count; + cp->handles = handles; + } +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->create_event(EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, &context, + &event); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->register_protocol_notify(&guid1, event, + &context.registration_key); + if (ret != EFI_SUCCESS) { + efi_st_error("could not register event\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + + if (event) { + ret = boottime->close_event(event); + event = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle1 = NULL, handle2 = NULL; + struct interface interface1, interface2; + + ret = boottime->install_protocol_interface(&handle1, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("could not install interface\n"); + return EFI_ST_FAILURE; + } + if (!context.notify_count) { + efi_st_error("install was not notified\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count > 1) { + efi_st_error("install was notified too often\n"); + return EFI_ST_FAILURE; + } + if (context.handle_count != 1) { + efi_st_error("LocateHandle failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(context.handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + context.notify_count = 0; + ret = boottime->install_protocol_interface(&handle1, &guid2, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("could not install interface\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count) { + efi_st_error("wrong protocol was notified\n"); + return EFI_ST_FAILURE; + } + context.notify_count = 0; + ret = boottime->reinstall_protocol_interface(handle1, &guid1, + &interface1, &interface2); + if (ret != EFI_SUCCESS) { + efi_st_error("could not reinstall interface\n"); + return EFI_ST_FAILURE; + } + if (!context.notify_count) { + efi_st_error("reinstall was not notified\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count > 1) { + efi_st_error("reinstall was notified too often\n"); + return EFI_ST_FAILURE; + } + if (context.handle_count != 2) { + efi_st_error("LocateHandle failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(context.handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + context.notify_count = 0; + ret = boottime->install_protocol_interface(&handle2, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("could not install interface\n"); + return EFI_ST_FAILURE; + } + if (!context.notify_count) { + efi_st_error("install was not notified\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count > 1) { + efi_st_error("install was notified too often\n"); + return EFI_ST_FAILURE; + } + if (context.handle_count != 3) { + efi_st_error("LocateHandle failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(context.handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->uninstall_multiple_protocol_interfaces + (handle1, &guid1, &interface2, + &guid2, &interface1, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_multiple_protocol_interfaces + (handle2, &guid1, &interface1, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(regprotnot) = { + .name = "register protocol notify", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_reset.c b/roms/u-boot/lib/efi_selftest/efi_selftest_reset.c new file mode 100644 index 000000000..8b6ac24cb --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_reset.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_reset + * + * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the following service at boot time or runtime: + * ResetSystem() + */ + +#include <efi_selftest.h> + +static struct efi_runtime_services *runtime; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + runtime = systable->runtime; + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u16 reset_data[] = L"Reset by selftest"; + + runtime->reset_system(EFI_RESET_COLD, EFI_SUCCESS, + sizeof(reset_data), reset_data); + efi_st_error("Reset failed.\n"); + return EFI_ST_FAILURE; +} + +EFI_UNIT_TEST(reset) = { + .name = "reset system", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; + +EFI_UNIT_TEST(resetrt) = { + .name = "reset system runtime", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_rng.c b/roms/u-boot/lib/efi_selftest/efi_selftest_rng.c new file mode 100644 index 000000000..fca9749d0 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_rng.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_rng + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the random number generator service. + */ + +#include <efi_selftest.h> +#include <efi_rng.h> + +#define RNG_LEN 9 + +static struct efi_boot_services *boottime; +static efi_guid_t efi_rng_guid = EFI_RNG_PROTOCOL_GUID; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Retrieve available RNG algorithms. + * Retrieve two random values and compare them. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t size; + struct efi_rng_protocol *rng; + efi_guid_t *algo_list; + u8 rnd1[RNG_LEN] __aligned(4), rnd2[RNG_LEN] __aligned(4); + int r; + + /* Get random number generator protocol */ + ret = boottime->locate_protocol(&efi_rng_guid, NULL, (void **)&rng); + if (ret != EFI_SUCCESS) { + efi_st_error( + "Random number generator protocol not available\n"); + return EFI_ST_FAILURE; + } + + ret = rng->get_info(rng, &size, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("Could not retrieve alorithm list size\n"); + return EFI_ST_FAILURE; + } + if (size < sizeof(efi_guid_t)) { + efi_st_error("Empty alorithm list\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->allocate_pool(EFI_LOADER_DATA, size, + (void **)&algo_list); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not allocate pool memory\n"); + return EFI_ST_FAILURE; + } + + ret = rng->get_info(rng, &size, algo_list); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not get info\n"); + return EFI_ST_FAILURE; + } + if (size < sizeof(efi_guid_t)) { + efi_st_error("Empty alorithm list\n"); + return EFI_ST_FAILURE; + } + + memset(rnd1, 0, RNG_LEN); + memset(rnd2, 0, RNG_LEN); + + ret = rng->get_rng(rng, NULL, RNG_LEN - 1, &rnd1[1]); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not get random value\n"); + return EFI_ST_FAILURE; + } + ret = rng->get_rng(rng, algo_list, RNG_LEN - 1, &rnd2[1]); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not get random value\n"); + return EFI_ST_FAILURE; + } + r = memcmp(rnd1, rnd2, RNG_LEN); + if (!r) { + efi_st_error("Two equal consecutive random numbers\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->free_pool(algo_list); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not free pool memory\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(rng) = { + .name = "random number generator", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_rtc.c b/roms/u-boot/lib/efi_selftest/efi_selftest_rtc.c new file mode 100644 index 000000000..6f7035dee --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_rtc.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_rtc + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the real time clock runtime services. + */ + +#include <efi_selftest.h> + +#define EFI_ST_NO_RTC "Could not read real time clock\n" +#define EFI_ST_NO_RTC_SET "Could not set real time clock\n" + +static struct efi_runtime_services *runtime; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + runtime = systable->runtime; + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Read and display current time. + * Set a new value and read it back. + * Set the real time clock back the current time. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_time tm_old; +#ifdef CONFIG_EFI_SET_TIME + struct efi_time tm, tm_new = { + .year = 2017, + .month = 5, + .day = 19, + .hour = 13, + .minute = 47, + .second = 53, + }; +#endif + + /* Display current time */ + ret = runtime->get_time(&tm_old, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error(EFI_ST_NO_RTC); + return EFI_ST_FAILURE; + } + efi_st_printf("Time according to real time clock: " + "%.4u-%.2u-%.2u %.2u:%.2u:%.2u\n", + tm_old.year, tm_old.month, tm_old.day, + tm_old.hour, tm_old.minute, tm_old.second); +#ifdef CONFIG_EFI_SET_TIME + ret = runtime->set_time(&tm_new); + if (ret != EFI_SUCCESS) { + efi_st_error(EFI_ST_NO_RTC_SET); + return EFI_ST_FAILURE; + } + ret = runtime->get_time(&tm, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error(EFI_ST_NO_RTC); + return EFI_ST_FAILURE; + } + if (tm.year != tm_new.year || + tm.month != tm_new.month || + tm.day != tm_new.day || + tm.hour != tm_new.hour || + tm.minute != tm_new.minute || + tm.second < tm_new.second || + tm.second > tm_new.second + 2) { + efi_st_error(EFI_ST_NO_RTC_SET); + return EFI_ST_FAILURE; + } + /* Set time back to old value */ + ret = runtime->set_time(&tm_old); + if (ret != EFI_SUCCESS) { + efi_st_error(EFI_ST_NO_RTC_SET); + return EFI_ST_FAILURE; + } +#endif + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(rtc) = { + .name = "real time clock", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/roms/u-boot/lib/efi_selftest/efi_selftest_set_virtual_address_map.c new file mode 100644 index 000000000..8e2e8ba17 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_set_virtual_address_map.c + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + * and the following services: SetVirtualAddressMap, ConvertPointer. + */ + +#include <efi_selftest.h> + +static const struct efi_boot_services *boottime; +static const struct efi_runtime_services *runtime; +static struct efi_event *event; +static struct efi_mem_desc *memory_map; +static efi_uintn_t map_size; +static efi_uintn_t desc_size; +static u32 desc_version; +static u64 page1; +static u64 page2; +static u32 notify_call_count; +static bool convert_pointer_failed; + +/** + * notify() - notification function + * + * This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event + * occurs. The correct output of ConvertPointer() is checked. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + void *addr; + efi_status_t ret; + + ++notify_call_count; + + addr = (void *)(uintptr_t)page1; + ret = runtime->convert_pointer(0, &addr); + if (ret != EFI_SUCCESS) { + efi_st_error("ConvertPointer failed\n"); + convert_pointer_failed = true; + return; + } + if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE) { + efi_st_error("ConvertPointer wrong address\n"); + convert_pointer_failed = true; + return; + } + + addr = (void *)(uintptr_t)page2; + ret = runtime->convert_pointer(0, &addr); + if (ret != EFI_SUCCESS) { + efi_st_error("ConvertPointer failed\n"); + convert_pointer_failed = true; + return; + } + if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE) { + efi_st_error("ConvertPointer wrong address\n"); + convert_pointer_failed = true; + } +} + +/** + * setup() - setup unit test + * + * The memory map is read. Boottime only entries are deleted. Two entries for + * newly allocated pages are added. For these virtual addresses deviating from + * the physical addresses are set. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_uintn_t map_key; + efi_status_t ret; + struct efi_mem_desc *end, *pos1, *pos2; + + boottime = systable->boottime; + runtime = systable->runtime; + + ret = boottime->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + TPL_CALLBACK, notify, NULL, + &event); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error( + "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); + return EFI_ST_FAILURE; + } + /* Allocate extra space for newly allocated memory */ + map_size += 3 * sizeof(struct efi_mem_desc); + ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + (void **)&memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->get_memory_map(&map_size, memory_map, &map_key, + &desc_size, &desc_version); + if (ret != EFI_SUCCESS) { + efi_st_error("GetMemoryMap failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_BOOT_SERVICES_DATA, 2, &page1); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_BOOT_SERVICES_DATA, 3, &page2); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages failed\n"); + return EFI_ST_FAILURE; + } + /* Remove entries not relevant for runtime from map */ + end = (struct efi_mem_desc *)((u8 *)memory_map + map_size); + for (pos1 = memory_map, pos2 = memory_map; + pos2 < end; ++pos2) { + switch (pos2->type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + continue; + } + memcpy(pos1, pos2, desc_size); + ++pos1; + } + + /* + * Add entries with virtual addresses deviating from the physical + * addresses. By choosing virtual address ranges within the allocated + * physical pages address space collisions are avoided. + */ + pos1->type = EFI_RUNTIME_SERVICES_DATA; + pos1->reserved = 0; + pos1->physical_start = page1; + pos1->virtual_start = page1 + EFI_PAGE_SIZE; + pos1->num_pages = 1; + pos1->attribute = EFI_MEMORY_RUNTIME; + ++pos1; + + pos1->type = EFI_RUNTIME_SERVICES_DATA; + pos1->reserved = 0; + pos1->physical_start = page2; + pos1->virtual_start = page2 + 2 * EFI_PAGE_SIZE; + pos1->num_pages = 1; + pos1->attribute = EFI_MEMORY_RUNTIME; + ++pos1; + + map_size = (u8 *)pos1 - (u8 *)memory_map; + + return EFI_ST_SUCCESS; +} + +/** + * execute() - execute unit test + * + * SetVirtualAddressMap() is called with the memory map prepared in setup(). + * + * The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via + * the call count of the notification function. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + + ret = runtime->set_virtual_address_map(map_size, desc_size, + desc_version, memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVirtualAddressMap failed\n"); + return EFI_ST_FAILURE; + } + if (notify_call_count != 1) { + efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n", + notify_call_count); + return EFI_ST_FAILURE; + } + if (convert_pointer_failed) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(virtaddrmap) = { + .name = "virtual address map", + .phase = EFI_SETTING_VIRTUAL_ADDRESS_MAP, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_snp.c b/roms/u-boot/lib/efi_selftest/efi_selftest_snp.c new file mode 100644 index 000000000..79f046780 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_snp.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_snp + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test covers the Simple Network Protocol as well as + * the CopyMem and SetMem boottime services. + * + * A DHCP discover message is sent. The test is successful if a + * DHCP reply is received. + * + * TODO: Once ConnectController and DisconnectController are implemented + * we should connect our code as controller. + */ + +#include <efi_selftest.h> +#include <net.h> + +/* + * MAC address for broadcasts + */ +static const u8 BROADCAST_MAC[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +struct dhcp_hdr { + u8 op; +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + u8 htype; +# define HWT_ETHER 1 + u8 hlen; +# define HWL_ETHER 6 + u8 hops; + u32 xid; + u16 secs; + u16 flags; +#define DHCP_FLAGS_UNICAST 0x0000 +#define DHCP_FLAGS_BROADCAST 0x0080 + u32 ciaddr; + u32 yiaddr; + u32 siaddr; + u32 giaddr; + u8 chaddr[16]; + u8 sname[64]; + u8 file[128]; +}; + +/* + * Message type option. + */ +#define DHCP_MESSAGE_TYPE 0x35 +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +struct dhcp { + struct ethernet_hdr eth_hdr; + struct ip_udp_hdr ip_udp; + struct dhcp_hdr dhcp_hdr; + u8 opt[128]; +} __packed; + +static struct efi_boot_services *boottime; +static struct efi_simple_network *net; +static struct efi_event *timer; +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; +/* IP packet ID */ +static unsigned int net_ip_id; + +/* + * Compute the checksum of the IP header. We cover even values of length only. + * We cannot use net/checksum.c due to different CFLAGS values. + * + * @buf: IP header + * @len: length of header in bytes + * @return: checksum + */ +static unsigned int efi_ip_checksum(const void *buf, size_t len) +{ + size_t i; + u32 sum = 0; + const u16 *pos = buf; + + for (i = 0; i < len; i += 2) + sum += *pos++; + + sum = (sum >> 16) + (sum & 0xffff); + sum += sum >> 16; + sum = ~sum & 0xffff; + + return sum; +} + +/* + * Transmit a DHCPDISCOVER message. + */ +static efi_status_t send_dhcp_discover(void) +{ + efi_status_t ret; + struct dhcp p = {}; + + /* + * Fill Ethernet header + */ + boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN); + boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address, + ARP_HLEN); + p.eth_hdr.et_protlen = htons(PROT_IP); + /* + * Fill IP header + */ + p.ip_udp.ip_hl_v = 0x45; + p.ip_udp.ip_len = htons(sizeof(struct dhcp) - + sizeof(struct ethernet_hdr)); + p.ip_udp.ip_id = htons(++net_ip_id); + p.ip_udp.ip_off = htons(IP_FLAGS_DFRAG); + p.ip_udp.ip_ttl = 0xff; /* time to live */ + p.ip_udp.ip_p = IPPROTO_UDP; + boottime->set_mem(&p.ip_udp.ip_dst, 4, 0xff); + p.ip_udp.ip_sum = efi_ip_checksum(&p.ip_udp, IP_HDR_SIZE); + + /* + * Fill UDP header + */ + p.ip_udp.udp_src = htons(68); + p.ip_udp.udp_dst = htons(67); + p.ip_udp.udp_len = htons(sizeof(struct dhcp) - + sizeof(struct ethernet_hdr) - + sizeof(struct ip_hdr)); + /* + * Fill DHCP header + */ + p.dhcp_hdr.op = BOOTREQUEST; + p.dhcp_hdr.htype = HWT_ETHER; + p.dhcp_hdr.hlen = HWL_ETHER; + p.dhcp_hdr.flags = htons(DHCP_FLAGS_UNICAST); + boottime->copy_mem(&p.dhcp_hdr.chaddr, + &net->mode->current_address, ARP_HLEN); + /* + * Fill options + */ + p.opt[0] = 0x63; /* DHCP magic cookie */ + p.opt[1] = 0x82; + p.opt[2] = 0x53; + p.opt[3] = 0x63; + p.opt[4] = DHCP_MESSAGE_TYPE; + p.opt[5] = 0x01; /* length */ + p.opt[6] = DHCPDISCOVER; + p.opt[7] = 0x39; /* maximum message size */ + p.opt[8] = 0x02; /* length */ + p.opt[9] = 0x02; /* 576 bytes */ + p.opt[10] = 0x40; + p.opt[11] = 0xff; /* end of options */ + + /* + * Transmit DHCPDISCOVER message. + */ + ret = net->transmit(net, 0, sizeof(struct dhcp), &p, NULL, NULL, 0); + if (ret != EFI_SUCCESS) + efi_st_error("Sending a DHCP request failed\n"); + else + efi_st_printf("DHCP Discover\n"); + return ret; +} + +/* + * Setup unit test. + * + * Create a 1 s periodic timer. + * Start the network driver. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + /* + * Create a timer event. + */ + ret = boottime->create_event(EVT_TIMER, TPL_CALLBACK, NULL, NULL, + &timer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + /* + * Set timer period to 1s. + */ + ret = boottime->set_timer(timer, EFI_TIMER_PERIODIC, 10000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to set timer\n"); + return EFI_ST_FAILURE; + } + /* + * Find an interface implementing the SNP protocol. + */ + ret = boottime->locate_protocol(&efi_net_guid, NULL, (void **)&net); + if (ret != EFI_SUCCESS) { + net = NULL; + efi_st_error("Failed to locate simple network protocol\n"); + return EFI_ST_FAILURE; + } + /* + * Check hardware address size. + */ + if (!net->mode) { + efi_st_error("Mode not provided\n"); + return EFI_ST_FAILURE; + } + if (net->mode->hwaddr_size != ARP_HLEN) { + efi_st_error("HwAddressSize = %u, expected %u\n", + net->mode->hwaddr_size, ARP_HLEN); + return EFI_ST_FAILURE; + } + /* + * Check that WaitForPacket event exists. + */ + if (!net->wait_for_packet) { + efi_st_error("WaitForPacket event missing\n"); + return EFI_ST_FAILURE; + } + if (net->mode->state == EFI_NETWORK_INITIALIZED) { + /* + * Shut down network adapter. + */ + ret = net->shutdown(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to shut down network adapter\n"); + return EFI_ST_FAILURE; + } + } + if (net->mode->state == EFI_NETWORK_STARTED) { + /* + * Stop network adapter. + */ + ret = net->stop(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to stop network adapter\n"); + return EFI_ST_FAILURE; + } + } + /* + * Start network adapter. + */ + ret = net->start(net); + if (ret != EFI_SUCCESS && ret != EFI_ALREADY_STARTED) { + efi_st_error("Failed to start network adapter\n"); + return EFI_ST_FAILURE; + } + if (net->mode->state != EFI_NETWORK_STARTED) { + efi_st_error("Failed to start network adapter\n"); + return EFI_ST_FAILURE; + } + /* + * Initialize network adapter. + */ + ret = net->initialize(net, 0, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to initialize network adapter\n"); + return EFI_ST_FAILURE; + } + if (net->mode->state != EFI_NETWORK_INITIALIZED) { + efi_st_error("Failed to initialize network adapter\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * A DHCP discover message is sent. The test is successful if a + * DHCP reply is received within 10 seconds. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_event *events[2]; + efi_uintn_t index; + union { + struct dhcp p; + u8 b[PKTSIZE]; + } buffer; + struct efi_mac_address srcaddr; + struct efi_mac_address destaddr; + size_t buffer_size; + u8 *addr; + + /* + * The timeout is to occur after 10 s. + */ + unsigned int timeout = 10; + + /* Setup may have failed */ + if (!net || !timer) { + efi_st_error("Cannot execute test after setup failure\n"); + return EFI_ST_FAILURE; + } + + /* + * Send DHCP discover message + */ + ret = send_dhcp_discover(); + if (ret != EFI_SUCCESS) + return EFI_ST_FAILURE; + + /* + * If we would call WaitForEvent only with the WaitForPacket event, + * our code would block until a packet is received which might never + * occur. By calling WaitFor event with both a timer event and the + * WaitForPacket event we can escape this blocking situation. + * + * If the timer event occurs before we have received a DHCP reply + * a further DHCP discover message is sent. + */ + events[0] = timer; + events[1] = net->wait_for_packet; + for (;;) { + u32 int_status; + + /* + * Wait for packet to be received or timer event. + */ + boottime->wait_for_event(2, events, &index); + if (index == 0) { + /* + * The timer event occurred. Check for timeout. + */ + --timeout; + if (!timeout) { + efi_st_error("Timeout occurred\n"); + return EFI_ST_FAILURE; + } + /* + * Send further DHCP discover message + */ + ret = send_dhcp_discover(); + if (ret != EFI_SUCCESS) + return EFI_ST_FAILURE; + continue; + } + /* + * Receive packet + */ + buffer_size = sizeof(buffer); + ret = net->get_status(net, &int_status, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get status"); + return EFI_ST_FAILURE; + } + if (!(int_status & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT)) { + efi_st_error("RX interrupt not set"); + return EFI_ST_FAILURE; + } + ret = net->receive(net, NULL, &buffer_size, &buffer, + &srcaddr, &destaddr, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to receive packet"); + return EFI_ST_FAILURE; + } + /* + * Check the packet is meant for this system. + * Unfortunately QEMU ignores the broadcast flag. + * So we have to check for broadcasts too. + */ + if (memcmp(&destaddr, &net->mode->current_address, ARP_HLEN) && + memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN)) + continue; + /* + * Check this is a DHCP reply + */ + if (buffer.p.eth_hdr.et_protlen != ntohs(PROT_IP) || + buffer.p.ip_udp.ip_hl_v != 0x45 || + buffer.p.ip_udp.ip_p != IPPROTO_UDP || + buffer.p.ip_udp.udp_src != ntohs(67) || + buffer.p.ip_udp.udp_dst != ntohs(68) || + buffer.p.dhcp_hdr.op != BOOTREPLY) + continue; + /* + * We successfully received a DHCP reply. + */ + break; + } + + /* + * Write a log message. + */ + addr = (u8 *)&buffer.p.ip_udp.ip_src; + efi_st_printf("DHCP reply received from %u.%u.%u.%u (%pm) ", + addr[0], addr[1], addr[2], addr[3], &srcaddr); + if (!memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN)) + efi_st_printf("as broadcast message.\n"); + else + efi_st_printf("as unicast message.\n"); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Close the timer event created in setup. + * Shut down the network adapter. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + int exit_status = EFI_ST_SUCCESS; + + if (timer) { + /* + * Stop timer. + */ + ret = boottime->set_timer(timer, EFI_TIMER_STOP, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to stop timer"); + exit_status = EFI_ST_FAILURE; + } + /* + * Close timer event. + */ + ret = boottime->close_event(timer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event"); + exit_status = EFI_ST_FAILURE; + } + } + if (net) { + /* + * Shut down network adapter. + */ + ret = net->shutdown(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to shut down network adapter\n"); + exit_status = EFI_ST_FAILURE; + } + if (net->mode->state != EFI_NETWORK_STARTED) { + efi_st_error("Failed to shutdown network adapter\n"); + return EFI_ST_FAILURE; + } + /* + * Stop network adapter. + */ + ret = net->stop(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to stop network adapter\n"); + exit_status = EFI_ST_FAILURE; + } + if (net->mode->state != EFI_NETWORK_STOPPED) { + efi_st_error("Failed to stop network adapter\n"); + return EFI_ST_FAILURE; + } + } + + return exit_status; +} + +EFI_UNIT_TEST(snp) = { + .name = "simple network protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +#ifdef CONFIG_SANDBOX + /* + * Running this test on the sandbox requires setting environment + * variable ethact to a network interface connected to a DHCP server and + * ethrotate to 'no'. + */ + .on_request = true, +#endif +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_startimage_exit.c b/roms/u-boot/lib/efi_selftest/efi_selftest_startimage_exit.c new file mode 100644 index 000000000..11207b816 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_startimage_exit.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_start_image + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the StartImage boot service. + * The efi_selftest_miniapp_exit.efi application is loaded into memory + * and started. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_exit.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +/* Decompressed file image */ +static u8 *image; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t r = EFI_ST_SUCCESS; + + if (image) { + r = boottime->free_pool(image); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return r; +} + +/* + * Execute unit test. + * + * Load and start the application image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; + u16 expected_text[] = EFI_ST_SUCCESS_STR; + + ret = boottime->load_image(false, image_handle, NULL, image, + img.length, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + ret = boottime->start_image(handle, &exit_data_size, &exit_data); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + if (!exit_data || exit_data_size != sizeof(expected_text) || + memcmp(exit_data, expected_text, sizeof(expected_text))) { + efi_st_error("Incorrect exit data\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(exit_data); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free exit data\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(startimage_exit) = { + .name = "start image exit", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_startimage_return.c b/roms/u-boot/lib/efi_selftest/efi_selftest_startimage_return.c new file mode 100644 index 000000000..fabf53d98 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_startimage_return.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_start_image + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the StartImage boot service. + * The efi_selftest_miniapp_return.efi application is loaded into memory + * and started. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_return.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +/* Decompressed file image */ +static u8 *image; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t r = EFI_ST_SUCCESS; + + if (image) { + r = boottime->free_pool(image); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return r; +} + +/* + * Execute unit test. + * + * Load and start the application image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + + ret = boottime->load_image(false, image_handle, NULL, image, + img.length, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + ret = boottime->start_image(handle, NULL, NULL); + if (ret != EFI_INCOMPATIBLE_VERSION) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(startimage) = { + .name = "start image return", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_tcg2.c b/roms/u-boot/lib/efi_selftest/efi_selftest_tcg2.c new file mode 100644 index 000000000..1399309ce --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_tcg2.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_devicepath + * + * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the EFI_TCG2_PROTOCOL + */ + +#include <efi_selftest.h> +#include <efi_tcg2.h> + +static struct efi_boot_services *boottime; +static const efi_guid_t guid_tcg2 = EFI_TCG2_PROTOCOL_GUID; + +/** + * efi_st_tcg2_setup() - setup test + * + * @handle: handle of the loaded image + * @systable: system table + * @return: status code + */ +static int efi_st_tcg2_setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/** + * efi_st_tcg2_execute() - execute test + * + * Call the GetCapability service of the EFI_TCG2_PROTOCOL. + * + * Return: status code + */ +static int efi_st_tcg2_execute(void) +{ + struct efi_tcg2_protocol *tcg2; + struct efi_tcg2_boot_service_capability capability; + efi_status_t ret; + + ret = boottime->locate_protocol(&guid_tcg2, NULL, (void **)&tcg2); + if (ret != EFI_SUCCESS) { + efi_st_error("TCG2 protocol is not available.\n"); + return EFI_ST_FAILURE; + } + capability.size = sizeof(struct efi_tcg2_boot_service_capability) - 1; + ret = tcg2->get_capability(tcg2, &capability); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("tcg2->get_capability on small buffer failed\n"); + return EFI_ST_FAILURE; + } + capability.size = sizeof(struct efi_tcg2_boot_service_capability); + ret = tcg2->get_capability(tcg2, &capability); + if (ret != EFI_SUCCESS) { + efi_st_error("tcg2->get_capability failed\n"); + return EFI_ST_FAILURE; + } + if (!capability.tpm_present_flag) { + efi_st_error("TPM not present\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("TPM supports 0x%.8x event logs\n", + capability.supported_event_logs); + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(tcg2) = { + .name = "tcg2", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = efi_st_tcg2_execute, + .setup = efi_st_tcg2_setup, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_textinput.c b/roms/u-boot/lib/efi_selftest/efi_selftest_textinput.c new file mode 100644 index 000000000..b90671cdd --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_textinput.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_textinput + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL. + * The Unicode character and the scan code are printed for text + * input. To run the test: + * + * setenv efi_selftest text input + * bootefi selftest + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct efi_input_key input_key = {0}; + efi_status_t ret; + efi_uintn_t index; + + /* Drain the console input */ + ret = con_in->reset(con_in, true); + if (ret != EFI_SUCCESS) { + efi_st_error("Reset failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in->read_key_stroke(con_in, &input_key); + if (ret != EFI_NOT_READY) { + efi_st_error("Empty buffer not reported\n"); + return EFI_ST_FAILURE; + } + + efi_st_printf("Waiting for your input\n"); + efi_st_printf("To terminate type 'x'\n"); + + for (;;) { + /* Wait for next key */ + ret = boottime->wait_for_event(1, &con_in->wait_for_key, + &index); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("WaitForEvent failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in->read_key_stroke(con_in, &input_key); + if (ret != EFI_SUCCESS) { + efi_st_error("ReadKeyStroke failed\n"); + return EFI_ST_FAILURE; + } + + /* Allow 5 minutes until time out */ + boottime->set_watchdog_timer(300, 0, 0, NULL); + + efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n", + (unsigned int)input_key.unicode_char, + efi_st_translate_char(input_key.unicode_char), + (unsigned int)input_key.scan_code, + efi_st_translate_code(input_key.scan_code)); + + switch (input_key.unicode_char) { + case 'x': + case 'X': + return EFI_ST_SUCCESS; + } + } +} + +EFI_UNIT_TEST(textinput) = { + .name = "text input", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_textinputex.c b/roms/u-boot/lib/efi_selftest/efi_selftest_textinputex.c new file mode 100644 index 000000000..de44224ce --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_textinputex.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_textinput + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + * The unicode character and the scan code are printed for text + * input. To run the test: + * + * setenv efi_selftest extended text input + * bootefi selftest + */ + +#include <efi_selftest.h> + +static const efi_guid_t text_input_ex_protocol_guid = + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; + +static struct efi_simple_text_input_ex_protocol *con_in_ex; + +static struct efi_boot_services *boottime; + +static void *efi_key_notify_handle; +static bool efi_running; + +/** + * efi_key_notify_function() - key notification function + * + * This function is called when the registered key is hit. + * + * @key_data: next key + * Return: status code + */ +static efi_status_t EFIAPI efi_key_notify_function + (struct efi_key_data *key_data) +{ + efi_running = false; + + return EFI_SUCCESS; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + struct efi_key_data key_data = { + .key = { + .scan_code = 0, + .unicode_char = 0x18 + }, + .key_state = { + .key_shift_state = EFI_SHIFT_STATE_VALID | + EFI_LEFT_CONTROL_PRESSED, + .key_toggle_state = EFI_TOGGLE_STATE_INVALID, + }, + }; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL, + (void **)&con_in_ex); + if (ret != EFI_SUCCESS) { + con_in_ex = NULL; + efi_st_error + ("Extended text input protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + ret = con_in_ex->register_key_notify(con_in_ex, &key_data, + efi_key_notify_function, + &efi_key_notify_handle); + if (ret != EFI_SUCCESS) { + efi_key_notify_handle = NULL; + efi_st_error + ("Notify function could not be registered.\n"); + return EFI_ST_FAILURE; + } + efi_running = true; + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Unregister notify function. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + ret = con_in_ex->unregister_key_notify + (con_in_ex, efi_key_notify_handle); + if (ret != EFI_SUCCESS) { + efi_st_error + ("Notify function could not be registered.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct efi_key_data input_key = { {0, 0}, {0, 0} }; + efi_status_t ret; + efi_uintn_t index; + + if (!con_in_ex) { + efi_st_printf("Setup failed\n"); + return EFI_ST_FAILURE; + } + + /* Drain the console input */ + ret = con_in_ex->reset(con_in_ex, true); + if (ret != EFI_SUCCESS) { + efi_st_error("Reset failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key); + if (ret != EFI_NOT_READY) { + efi_st_error("Empty buffer not reported\n"); + return EFI_ST_FAILURE; + } + + efi_st_printf("Waiting for your input\n"); + efi_st_printf("To terminate type 'CTRL+x'\n"); + + while (efi_running) { + /* Wait for next key */ + ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex, + &index); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("WaitForEvent failed\n"); + return EFI_ST_FAILURE; + } + ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key); + if (ret != EFI_SUCCESS) { + efi_st_error("ReadKeyStroke failed\n"); + return EFI_ST_FAILURE; + } + + /* Allow 5 minutes until time out */ + boottime->set_watchdog_timer(300, 0, 0, NULL); + + efi_st_printf("Unicode char %u (%ps), scan code %u (", + (unsigned int)input_key.key.unicode_char, + efi_st_translate_char(input_key.key.unicode_char), + (unsigned int)input_key.key.scan_code); + if (input_key.key_state.key_shift_state & + EFI_SHIFT_STATE_VALID) { + if (input_key.key_state.key_shift_state & + (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) + efi_st_printf("SHIFT+"); + if (input_key.key_state.key_shift_state & + (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED)) + efi_st_printf("ALT+"); + if (input_key.key_state.key_shift_state & + (EFI_LEFT_CONTROL_PRESSED | + EFI_RIGHT_CONTROL_PRESSED)) + efi_st_printf("CTRL+"); + if (input_key.key_state.key_shift_state & + (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED)) + efi_st_printf("META+"); + if (input_key.key_state.key_shift_state == + EFI_SHIFT_STATE_VALID) + efi_st_printf("+"); + } + + efi_st_printf("%ps)\n", + efi_st_translate_code(input_key.key.scan_code)); + + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(textinputex) = { + .name = "extended text input", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, + .on_request = true, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_textoutput.c b/roms/u-boot/lib/efi_selftest/efi_selftest_textoutput.c new file mode 100644 index 000000000..a87f65e19 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_textoutput.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_textoutput + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. + * + * The following services are tested: + * OutputString, TestString, SetAttribute. + */ + +#include <efi_selftest.h> + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + size_t foreground; + size_t background; + size_t attrib; + efi_status_t ret; + s16 col; + u16 cr[] = { 0x0d, 0x00 }; + u16 lf[] = { 0x0a, 0x00 }; + u16 brahmi[] = { /* 2 Brahmi letters */ + 0xD804, 0xDC05, + 0xD804, 0xDC22, + 0}; + + /* SetAttribute */ + efi_st_printf("\nColor palette\n"); + for (foreground = 0; foreground < 0x10; ++foreground) { + for (background = 0; background < 0x80; background += 0x10) { + attrib = foreground | background; + con_out->set_attribute(con_out, attrib); + efi_st_printf("%p", (void *)attrib); + } + con_out->set_attribute(con_out, 0); + efi_st_printf("\n"); + } + /* TestString */ + ret = con_out->test_string(con_out, + L" !\"#$%&'()*+,-./0-9:;<=>?@A-Z[\\]^_`a-z{|}~\n"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("TestString failed for ANSI characters\n"); + return EFI_ST_FAILURE; + } + /* OutputString */ + ret = con_out->output_string(con_out, + L"Testing cursor column update\n"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for ANSI characters"); + return EFI_ST_FAILURE; + } + col = con_out->mode->cursor_column; + ret = con_out->output_string(con_out, lf); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for line feed\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column != col) { + efi_st_error("Cursor column changed by line feed\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, cr); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for carriage return\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column) { + efi_st_error("Cursor column not 0 at beginning of line\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"123"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for ANSI characters\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column != 3) { + efi_st_error("Cursor column not incremented properly\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"\b"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for backspace\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column != 2) { + efi_st_error("Cursor column not decremented properly\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"\b\b"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for backspace\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column) { + efi_st_error("Cursor column not decremented properly\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"\b\b"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for backspace\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column) { + efi_st_error("Cursor column decremented past zero\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, brahmi); + if (ret != EFI_ST_SUCCESS) { + efi_st_todo("Unicode output not fully supported\n"); + } else if (con_out->mode->cursor_column != 2) { + efi_st_printf("Unicode not handled properly\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("\n"); + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(textoutput) = { + .name = "text output", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_tpl.c b/roms/u-boot/lib/efi_selftest/efi_selftest_tpl.c new file mode 100644 index 000000000..0c0e412ae --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_tpl.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_tpl + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test uses timer events to check the handling of + * task priority levels. + */ + +#include <efi_selftest.h> + +static struct efi_event *event_notify; +static struct efi_event *event_wait; +static unsigned int notification_count; +static struct efi_boot_services *boottime; + +/* + * Notification function, increments the notification count. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * Setup unit test. + * + * Create two timer events. + * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, + (void *)¬ification_count, + &event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, + TPL_NOTIFY, notify, NULL, &event_wait); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Close the events created in setup. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + if (event_notify) { + ret = boottime->close_event(event_notify); + event_notify = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + if (event_wait) { + ret = boottime->close_event(event_wait); + event_wait = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + boottime->restore_tpl(TPL_APPLICATION); + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Run a 10 ms periodic timer and check that it is called 10 times + * while waiting for 100 ms single shot timer. + * + * Raise the TPL level to the level of the 10 ms timer and observe + * that the notification function is not called again. + * + * Lower the TPL level and check that the queued notification + * function is called. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_uintn_t index; + efi_status_t ret; + efi_uintn_t old_tpl; + + /* Set 10 ms timer */ + notification_count = 0; + ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + /* Set 100 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + index = 5; + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->check_event(event_wait); + if (ret != EFI_NOT_READY) { + efi_st_error("Signaled state was not cleared.\n"); + efi_st_printf("ret = %u\n", (unsigned int)ret); + return EFI_ST_FAILURE; + } + if (index != 0) { + efi_st_error("WaitForEvent returned wrong index\n"); + return EFI_ST_FAILURE; + } + if (notification_count < 8 || notification_count > 12) { + efi_st_printf( + "Notification count with TPL level TPL_APPLICATION: %u\n", + notification_count); + efi_st_error("Incorrect timing of events\n"); + return EFI_ST_FAILURE; + } + ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not cancel timer\n"); + return EFI_ST_FAILURE; + } + /* Raise TPL level */ + old_tpl = boottime->raise_tpl(TPL_CALLBACK); + if (old_tpl != TPL_APPLICATION) { + efi_st_error("Initial TPL level was not TPL_APPLICATION"); + return EFI_ST_FAILURE; + } + /* Set 10 ms timer */ + notification_count = 0; + ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + /* Set 100 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + do { + ret = boottime->check_event(event_wait); + } while (ret == EFI_NOT_READY); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not check event\n"); + return EFI_ST_FAILURE; + } + if (notification_count != 0) { + efi_st_printf( + "Notification count with TPL level TPL_CALLBACK: %u\n", + notification_count); + efi_st_error("Suppressed timer fired\n"); + return EFI_ST_FAILURE; + } + /* Set 1 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + /* Restore the old TPL level */ + boottime->restore_tpl(TPL_APPLICATION); + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + if (notification_count < 1) { + efi_st_printf( + "Notification count with TPL level TPL_APPLICATION: %u\n", + notification_count); + efi_st_error("Queued timer event did not fire\n"); + return EFI_ST_FAILURE; + } + ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not cancel timer\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(tpl) = { + .name = "task priority levels", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_unaligned.c b/roms/u-boot/lib/efi_selftest/efi_selftest_unaligned.c new file mode 100644 index 000000000..1802948e6 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_unaligned.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_unaligned + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test unaligned memory access on ARMv7. + */ + +#include <efi_selftest.h> + +struct aligned_buffer { + char a[8] __aligned(8); +}; + +/* + * Return an u32 at a give address. + * If the address is not four byte aligned, an unaligned memory access + * occurs. + * + * @addr: address to read + * @return: value at the address + */ +static inline u32 deref(u32 *addr) +{ + int ret; + + asm( + "ldr %[out], [%[in]]\n\t" + : [out] "=r" (ret) + : [in] "r" (addr) + ); + return ret; +} + +/* + * Execute unit test. + * An unaligned memory access is executed. The result is checked. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct aligned_buffer buf = { + {0, 1, 2, 3, 4, 5, 6, 7}, + }; + void *v = &buf; + u32 r = 0; + + /* Read an unaligned address */ + r = deref(v + 1); + + /* UEFI only supports low endian systems */ + if (r != 0x04030201) { + efi_st_error("Unaligned access failed"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(unaligned) = { + .name = "unaligned memory access", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_unicode_collation.c b/roms/u-boot/lib/efi_selftest/efi_selftest_unicode_collation.c new file mode 100644 index 000000000..75294307d --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_unicode_collation.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_unicode_collation + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Test unicode collation protocol. + */ + +#include <efi_selftest.h> + +static const efi_guid_t unicode_collation_protocol_guid = + EFI_UNICODE_COLLATION_PROTOCOL2_GUID; + +static struct efi_boot_services *boottime; + +static struct efi_unicode_collation_protocol *unicode_collation_protocol; + +/** + * setup() - setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * ReturnValue: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&unicode_collation_protocol_guid, NULL, + (void **)&unicode_collation_protocol); + if (ret != EFI_SUCCESS) { + unicode_collation_protocol = NULL; + efi_st_error("Unicode collation protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_stri_coll(void) +{ + efi_intn_t ret; + u16 c1[] = L"first"; + u16 c2[] = L"FIRST"; + u16 c3[] = L"second"; + + ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol, + c1, c2); + if (ret) { + efi_st_error( + "stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c2, (int)ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol, + c1, c3); + if (ret >= 0) { + efi_st_error( + "stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c3, (int)ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol, + c3, c1); + if (ret <= 0) { + efi_st_error( + "stri_coll(\"%ps\", \"%ps\") = %d\n", c3, c1, (int)ret); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_metai_match(void) +{ + bool ret; + const u16 c[] = L"Das U-Boot"; + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"*"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[rstu] U-Boot"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[q-v] U-Boot"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da? U-Boot"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"D*Bo*t"); + if (!ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[xyz] U-Boot"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da[a-d] U-Boot"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"Da?? U-Boot"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + ret = unicode_collation_protocol->metai_match( + unicode_collation_protocol, c, L"D*Bo*tt"); + if (ret) { + efi_st_error("metai_match returned %u\n", ret); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_str_lwr(void) +{ + u16 c[] = L"U-Boot"; + + unicode_collation_protocol->str_lwr(unicode_collation_protocol, c); + if (efi_st_strcmp_16_8(c, "u-boot")) { + efi_st_error("str_lwr returned \"%ps\"\n", c); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_str_upr(void) +{ + u16 c[] = L"U-Boot"; + + unicode_collation_protocol->str_upr(unicode_collation_protocol, c); + if (efi_st_strcmp_16_8(c, "U-BOOT")) { + efi_st_error("str_lwr returned \"%ps\"\n", c); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_fat_to_str(void) +{ + u16 str[16]; + + boottime->set_mem(str, sizeof(str), 0); + unicode_collation_protocol->fat_to_str(unicode_collation_protocol, 6, + "U-BOOT", str); + if (efi_st_strcmp_16_8(str, "U-BOOT")) { + efi_st_error("fat_to_str returned \"%ps\"\n", str); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +static int test_str_to_fat(void) +{ + char fat[16]; + bool ret; + + boottime->set_mem(fat, sizeof(fat), 0); + ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol, + L"U -Boo.t", 6, fat); + if (ret || efi_st_strcmp_16_8(L"U-BOOT", fat)) { + efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat); + return EFI_ST_FAILURE; + } + + boottime->set_mem(fat, 16, 0); + ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol, + L"U\\Boot", 6, fat); + if (!ret || efi_st_strcmp_16_8(L"U_BOOT", fat)) { + efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/** + * execute() - Execute unit test. + * + * ReturnValue: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + int ret; + + if (!unicode_collation_protocol) { + efi_st_printf("Unicode collation protocol missing\n"); + return EFI_ST_FAILURE; + } + + ret = test_stri_coll(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_metai_match(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_str_lwr(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_str_upr(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_fat_to_str(); + if (ret != EFI_ST_SUCCESS) + return ret; + + ret = test_str_to_fat(); + if (ret != EFI_ST_SUCCESS) + return ret; + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(unicoll) = { + .name = "unicode collation", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, + .setup = setup, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_util.c b/roms/u-boot/lib/efi_selftest/efi_selftest_util.c new file mode 100644 index 000000000..ea73c2522 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_util.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_util + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * Utility functions + */ + +#include <efi_selftest.h> + +struct efi_st_translate { + u16 code; + u16 *text; +}; + +static struct efi_st_translate efi_st_control_characters[] = { + {0, L"Null"}, + {8, L"BS"}, + {9, L"TAB"}, + {10, L"LF"}, + {13, L"CR"}, + {0, NULL}, +}; + +static u16 efi_st_ch[] = L"' '"; +static u16 efi_st_unknown[] = L"unknown"; + +static struct efi_st_translate efi_st_scan_codes[] = { + {0x00, L"Null"}, + {0x01, L"Up"}, + {0x02, L"Down"}, + {0x03, L"Right"}, + {0x04, L"Left"}, + {0x05, L"Home"}, + {0x06, L"End"}, + {0x07, L"Insert"}, + {0x08, L"Delete"}, + {0x09, L"Page Up"}, + {0x0a, L"Page Down"}, + {0x0b, L"FN 1"}, + {0x0c, L"FN 2"}, + {0x0d, L"FN 3"}, + {0x0e, L"FN 4"}, + {0x0f, L"FN 5"}, + {0x10, L"FN 6"}, + {0x11, L"FN 7"}, + {0x12, L"FN 8"}, + {0x13, L"FN 9"}, + {0x14, L"FN 10"}, + {0x15, L"FN 11"}, + {0x16, L"FN 12"}, + {0x17, L"Escape"}, + {0x68, L"FN 13"}, + {0x69, L"FN 14"}, + {0x6a, L"FN 15"}, + {0x6b, L"FN 16"}, + {0x6c, L"FN 17"}, + {0x6d, L"FN 18"}, + {0x6e, L"FN 19"}, + {0x6f, L"FN 20"}, + {0x70, L"FN 21"}, + {0x71, L"FN 22"}, + {0x72, L"FN 23"}, + {0x73, L"FN 24"}, + {0x7f, L"Mute"}, + {0x80, L"Volume Up"}, + {0x81, L"Volume Down"}, + {0x100, L"Brightness Up"}, + {0x101, L"Brightness Down"}, + {0x102, L"Suspend"}, + {0x103, L"Hibernate"}, + {0x104, L"Toggle Display"}, + {0x105, L"Recovery"}, + {0x106, L"Reject"}, + {0x0, NULL}, +}; + +u16 *efi_st_translate_char(u16 code) +{ + struct efi_st_translate *tr; + + if (code >= ' ') { + efi_st_ch[1] = code; + return efi_st_ch; + } + for (tr = efi_st_control_characters; tr->text; ++tr) { + if (tr->code == code) + return tr->text; + } + return efi_st_unknown; +} + +u16 *efi_st_translate_code(u16 code) +{ + struct efi_st_translate *tr; + + for (tr = efi_st_scan_codes; tr->text; ++tr) { + if (tr->code == code) + return tr->text; + } + return efi_st_unknown; +} + +int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2) +{ + for (; *buf1 || *buf2; ++buf1, ++buf2) { + if (*buf1 != *buf2) + return *buf1 - *buf2; + } + return 0; +} diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_variables.c b/roms/u-boot/lib/efi_selftest/efi_selftest_variables.c new file mode 100644 index 000000000..2c16f3db6 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_variables.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_variables + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the runtime services for variables: + * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo. + */ + +#include <efi_selftest.h> + +#define EFI_ST_MAX_DATA_SIZE 16 +#define EFI_ST_MAX_VARNAME_SIZE 80 + +static struct efi_boot_services *boottime; +static struct efi_runtime_services *runtime; +static const efi_guid_t guid_vendor0 = + EFI_GUID(0x67029eb5, 0x0af2, 0xf6b1, + 0xda, 0x53, 0xfc, 0xb5, 0x66, 0xdd, 0x1c, 0xe6); +static const efi_guid_t guid_vendor1 = + EFI_GUID(0xff629290, 0x1fc1, 0xd73f, + 0x8f, 0xb1, 0x32, 0xf9, 0x0c, 0xa0, 0x42, 0xea); + +/* + * Setup unit test. + * + * @handle handle of the loaded image + * @systable system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + runtime = systable->runtime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t len; + u32 attr; + u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c, + 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,}; + u8 data[EFI_ST_MAX_DATA_SIZE]; + u16 varname[EFI_ST_MAX_VARNAME_SIZE]; + int flag; + efi_guid_t guid; + u64 max_storage, rem_storage, max_size; + + ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS, + &max_storage, &rem_storage, + &max_size); + if (ret != EFI_SUCCESS) { + efi_st_todo("QueryVariableInfo failed\n"); + } else if (!max_storage || !rem_storage || !max_size) { + efi_st_error("QueryVariableInfo: wrong info\n"); + return EFI_ST_FAILURE; + } + /* Set variable 0 */ + ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 3, v + 4); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + data[3] = 0xff; + len = 3; + ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + if (memcmp(data, v + 4, 3)) { + efi_st_error("GetVariable returned wrong value\n"); + return EFI_ST_FAILURE; + } + if (data[3] != 0xff) { + efi_st_error("GetVariable wrote past the end of the buffer\n"); + return EFI_ST_FAILURE; + } + /* Set variable 1 */ + ret = runtime->set_variable(L"efi_st_var1", &guid_vendor1, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 8, v); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + if (len != 8) { + efi_st_error("GetVariable returned wrong length %u\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + if (memcmp(data, v, 8)) { + efi_st_error("GetVariable returned wrong value\n"); + return EFI_ST_FAILURE; + } + /* Append variable 1 */ + ret = runtime->set_variable(L"efi_st_var1", &guid_vendor1, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_APPEND_WRITE, + 7, v + 8); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable(APPEND_WRITE) failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + if (len != 15) + efi_st_todo("GetVariable returned wrong length %u\n", + (unsigned int)len); + if (memcmp(data, v, len)) + efi_st_todo("GetVariable returned wrong value\n"); + /* Append variable 2 */ + ret = runtime->set_variable(L"efi_none", &guid_vendor1, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_APPEND_WRITE, + 15, v); + if (ret != EFI_NOT_FOUND) { + efi_st_error("SetVariable(APPEND_WRITE) with size 0 to non-existent variable returns wrong code\n"); + return EFI_ST_FAILURE; + } + /* Enumerate variables */ + boottime->set_mem(&guid, 16, 0); + *varname = 0; + flag = 0; + for (;;) { + len = EFI_ST_MAX_VARNAME_SIZE; + ret = runtime->get_next_variable_name(&len, varname, &guid); + if (ret == EFI_NOT_FOUND) + break; + if (ret != EFI_SUCCESS) { + efi_st_error("GetNextVariableName failed (%u)\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + if (!memcmp(&guid, &guid_vendor0, sizeof(efi_guid_t)) && + !efi_st_strcmp_16_8(varname, "efi_st_var0")) { + flag |= 1; + if (len != 24) { + efi_st_error("GetNextVariableName report wrong length %u, expected 24\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + } + if (!memcmp(&guid, &guid_vendor1, sizeof(efi_guid_t)) && + !efi_st_strcmp_16_8(varname, "efi_st_var1")) + flag |= 2; + } + if (flag != 3) { + efi_st_error( + "GetNextVariableName did not return all variables\n"); + return EFI_ST_FAILURE; + } + /* Delete variable 1 */ + ret = runtime->set_variable(L"efi_st_var1", &guid_vendor1, + 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1, + &attr, &len, data); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Variable was not deleted\n"); + return EFI_ST_FAILURE; + } + /* Delete variable 0 */ + ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0, + 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0, + &attr, &len, data); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Variable was not deleted\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(variables) = { + .name = "variables", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_variables_runtime.c b/roms/u-boot/lib/efi_selftest/efi_selftest_variables_runtime.c new file mode 100644 index 000000000..3226069c0 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_variables_runtime.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_variables_runtime + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the runtime services for variables after + * ExitBootServices(): + * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo. + */ + +#include <efi_selftest.h> + +#define EFI_ST_MAX_DATA_SIZE 16 +#define EFI_ST_MAX_VARNAME_SIZE 40 + +static struct efi_boot_services *boottime; +static struct efi_runtime_services *runtime; +static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID; + +/* + * Setup unit test. + * + * @handle handle of the loaded image + * @systable system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + runtime = systable->runtime; + + return EFI_ST_SUCCESS; +} + +/** + * execute() - execute unit test + * + * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t len; + u32 attr; + u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c, + 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,}; + u8 data[EFI_ST_MAX_DATA_SIZE]; + u16 varname[EFI_ST_MAX_VARNAME_SIZE]; + efi_guid_t guid; + u64 max_storage, rem_storage, max_size; + + ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS, + &max_storage, &rem_storage, + &max_size); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("QueryVariableInfo failed\n"); + return EFI_ST_FAILURE; + } + + ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 3, v + 4); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"PlatformLangCodes", &guid_vendor0, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + memset(&guid, 0, 16); + *varname = 0; + len = 2 * EFI_ST_MAX_VARNAME_SIZE; + ret = runtime->get_next_variable_name(&len, varname, &guid); + if (ret != EFI_SUCCESS) { + efi_st_error("GetNextVariableName failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(variables_run) = { + .name = "variables at runtime", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/roms/u-boot/lib/efi_selftest/efi_selftest_watchdog.c b/roms/u-boot/lib/efi_selftest/efi_selftest_watchdog.c new file mode 100644 index 000000000..cbc676172 --- /dev/null +++ b/roms/u-boot/lib/efi_selftest/efi_selftest_watchdog.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_watchdog + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * The 'watchdog timer' unit test checks that the watchdog timer + * will not cause a system restart during the timeout period after + * a timer reset. + * + * The 'watchdog reboot' unit test checks that the watchdog timer + * actually reboots the system after a timeout. The test is only + * executed on explicit request. Use the following commands: + * + * setenv efi_selftest watchdog reboot + * bootefi selftest + */ + +#include <efi_selftest.h> + +/* + * This is the communication structure for the notification function. + */ +struct notify_context { + /* Status code returned when resetting watchdog */ + efi_status_t status; + /* Number of invocations of the notification function */ + unsigned int timer_ticks; +}; + +static struct efi_event *event_notify; +static struct efi_event *event_wait; +static struct efi_boot_services *boottime; +static struct notify_context notification_context; +static bool watchdog_reset; + +/* + * Notification function, increments the notification count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the timeout + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + struct notify_context *notify_context = context; + efi_status_t ret = EFI_SUCCESS; + + if (!notify_context) + return; + + /* Reset watchdog timer to one second */ + ret = boottime->set_watchdog_timer(1, 0, 0, NULL); + if (ret != EFI_SUCCESS) + notify_context->status = ret; + /* Count number of calls */ + notify_context->timer_ticks++; +} + +/* + * Setup unit test. + * + * Create two timer events. + * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + notification_context.status = EFI_SUCCESS; + notification_context.timer_ticks = 0; + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, + (void *)¬ification_context, + &event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, + TPL_CALLBACK, notify, NULL, &event_wait); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute the test resetting the watchdog in a timely manner. No reboot occurs. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup_timer(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + watchdog_reset = true; + return setup(handle, systable); +} + +/* + * Execute the test without resetting the watchdog. A system reboot occurs. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup_reboot(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + watchdog_reset = false; + return setup(handle, systable); +} + +/* + * Tear down unit test. + * + * Close the events created in setup. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + /* Set the watchdog timer to the five minute default value */ + ret = boottime->set_watchdog_timer(300, 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Setting watchdog timer failed\n"); + return EFI_ST_FAILURE; + } + if (event_notify) { + ret = boottime->close_event(event_notify); + event_notify = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("Could not close event\n"); + return EFI_ST_FAILURE; + } + } + if (event_wait) { + ret = boottime->close_event(event_wait); + event_wait = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("Could not close event\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Run a 600 ms periodic timer that resets the watchdog to one second + * on every timer tick. + * + * Run a 1350 ms single shot timer and check that the 600ms timer has + * been called 2 times. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + size_t index; + efi_status_t ret; + + /* Set the watchdog timeout to one second */ + ret = boottime->set_watchdog_timer(1, 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Setting watchdog timer failed\n"); + return EFI_ST_FAILURE; + } + if (watchdog_reset) { + /* Set 600 ms timer */ + ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, + 6000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + } + /* Set 1350 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 13500000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + if (notification_context.status != EFI_SUCCESS) { + efi_st_error("Setting watchdog timer failed\n"); + return EFI_ST_FAILURE; + } + if (notification_context.timer_ticks != 2) { + efi_st_error("The timer was called %u times, expected 2.\n", + notification_context.timer_ticks); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(watchdog1) = { + .name = "watchdog timer", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup_timer, + .execute = execute, + .teardown = teardown, +}; + +EFI_UNIT_TEST(watchdog2) = { + .name = "watchdog reboot", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup_reboot, + .execute = execute, + .teardown = teardown, + .on_request = true, +}; diff --git a/roms/u-boot/lib/efi_selftest/initrddump.c b/roms/u-boot/lib/efi_selftest/initrddump.c new file mode 100644 index 000000000..325951b49 --- /dev/null +++ b/roms/u-boot/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 *)(uintptr_t)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; +} |