Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/814129/?format=api
{ "id": 814129, "url": "http://patchwork.ozlabs.org/api/patches/814129/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20170915080619.25250-3-xypron.glpk@gmx.de/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170915080619.25250-3-xypron.glpk@gmx.de>", "list_archive_url": null, "date": "2017-09-15T08:06:11", "name": "[U-Boot,02/10] efi_selftest: provide an EFI selftest application", "commit_ref": "623b3a579765f8e05723bd1eff6f8c7e56d33922", "pull_url": null, "state": "accepted", "archived": false, "hash": "7249daf776be8849d5a5e74c88df0d2e83490dda", "submitter": { "id": 61270, "url": "http://patchwork.ozlabs.org/api/people/61270/?format=api", "name": "Heinrich Schuchardt", "email": "xypron.glpk@gmx.de" }, "delegate": { "id": 3400, "url": "http://patchwork.ozlabs.org/api/users/3400/?format=api", "username": "agraf", "first_name": "Alexander", "last_name": "Graf", "email": "agraf@suse.de" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20170915080619.25250-3-xypron.glpk@gmx.de/mbox/", "series": [ { "id": 3244, "url": "http://patchwork.ozlabs.org/api/series/3244/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=3244", "date": "2017-09-15T08:06:10", "name": "efi_loader: event services & API test", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/3244/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/814129/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/814129/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)", "Received": [ "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3xtp1r1YwKz9sBZ\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 15 Sep 2017 18:08:32 +1000 (AEST)", "by lists.denx.de (Postfix, from userid 105)\n\tid 01ACFC21D7B; Fri, 15 Sep 2017 08:08:05 +0000 (UTC)", "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id 69F4EC21FA6;\n\tFri, 15 Sep 2017 08:07:48 +0000 (UTC)", "by lists.denx.de (Postfix, from userid 105)\n\tid 36207C21FBA; Fri, 15 Sep 2017 08:07:29 +0000 (UTC)", "from mout.gmx.net (mout.gmx.net [212.227.17.21])\n\tby lists.denx.de (Postfix) with ESMTPS id DB4E5C21FB1\n\tfor <u-boot@lists.denx.de>; Fri, 15 Sep 2017 08:07:25 +0000 (UTC)", "from laptop1.fritz.box ([94.197.120.111]) by mail.gmx.com (mrgmx102\n\t[212.227.17.174]) with ESMTPSA (Nemesis) id 0MNO33-1dlu1w0att-006xQW;\n\tFri, 15 Sep 2017 10:07:05 +0200" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-0.7 required=5.0 tests=FREEMAIL_FROM,\n\tRCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,\n\tRCVD_IN_MSPIKE_WL autolearn=unavailable\n\tautolearn_force=no version=3.4.0", "From": "Heinrich Schuchardt <xypron.glpk@gmx.de>", "To": "Alexander Graf <agraf@suse.de>", "Date": "Fri, 15 Sep 2017 10:06:11 +0200", "Message-Id": "<20170915080619.25250-3-xypron.glpk@gmx.de>", "X-Mailer": "git-send-email 2.11.0", "In-Reply-To": "<20170915080619.25250-1-xypron.glpk@gmx.de>", "References": "<20170915080619.25250-1-xypron.glpk@gmx.de>", "X-Provags-ID": "V03:K0:196n9BGDPTu2JuhboK0yMWzEKulHX6uyUcEwtVHTZbp9a1IQJcu\n\tR8ATftVtCMnrEtDrioBOoAcAtqcmkIX6VZYQLDJJOLe90SlgCPbD94RsTpq4c3PQy0MGMlG\n\tV0kIcA1+YYJboa8KSfRtN9J4b2NQJjQmrMLSUrxjpe6+9Mlz52greBq4pRdFq39elEcgXg5\n\tD/xp4hsat6THHkaP5RGUw==", "X-UI-Out-Filterresults": "notjunk:1; V01:K0:T2UO513Ak6U=:jLMVCFm1tWw7sOZiPxsGof\n\tBFgxsQ3/IOn+3Z9uncpI7Zuk04XaAV1IjQuwt0KlpHuFZv/pJGBwe8zm14/MzpUTZZtSm0NNb\n\tg1SVtGt378rAVOxLfVHMP7d4LQkxvdFyelp5E+CJ8LMDsqLEmDpE7sf6S6CAdWDnp9no+mzg/\n\tge6g4xfEdbSQOiB0wki/gWyzV5D3XVPGEGnjHHuzvkBkFKH9xKOnDFZdgsOgkGvPWMfLf+Lpz\n\tVT3OFbwdkIdB1O3KrJTc5t+LIL3DZO/yYtbrZRz3b+P6T6T6m2o98idpfBoKnPOY6epCCEJK9\n\taIJ7wslLCJaq/KV8FBwCWRdFWQvOzfUAMRewvJQSR3zOf35C2tzidB1/F3qD6UPGlJTVelPm1\n\tHXiYW7GZb6Fh/Ib2TpjN5Z83DgC+aJAP9BrKqdI44y/ddlyruBFzT8DNM7GZZy3L44MXfRw3B\n\teMHTS5y36TzqXTdYeT27wIhXeefwnBR3rTCd4GiP7yu8LT0zns8ZetCl/AXCJg6hzC9wLFGsa\n\tlFJiwTjQCTsun13THrf+WfeUrIkcchZdYORR+dVTTCnhgGl4zD7JZGkZzHoarOj81NXHdZy13\n\tkSAHqUVV7xhnD+5fPKoMfU6t9mp71VZMmual6lrgVZzIsycUCL/4O5hnyqPa8Eoe0igBp94Uw\n\tgHmwNCmRNWw2W/ilUxXri9WSarRpA7e7ag2EHgfofSH4XgxqqyA4FkqA5Q+gClSiwbrzKuN7A\n\tlEJ0D8XfRC6SajNudH+Sed5BYdzE+U+x6jdFaqrGx5ciT8v02BEJkJL7n2suQpPk763Rm6aPX\n\tDhnCmP3vElpEfWzgLipWLoJLrz5Cg==", "Cc": "=?utf-8?q?=C5=81ukasz_Majewski?= <l.majewski@samsung.com>,\n\tHeinrich Schuchardt <xypron.glpk@gmx.de>, Andy Shevchenko\n\t<andriy.shevchenko@linux.intel.com>, u-boot@lists.denx.de, Fabio Estevam\n\t<fabio.estevam@nxp.com>, Maxime Ripard <maxime.ripard@free-electrons.com>", "Subject": "[U-Boot] [PATCH 02/10] efi_selftest: provide an EFI selftest\n\tapplication", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.18", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>" }, "content": "A testing framework for the EFI API is provided.\nIt can be executed with the 'bootefi selftest' command.\n\nIt is coded in a way that at a later stage we may turn it\ninto a standalone EFI application. The current build system\ndoes not allow this yet.\n\nAll tests use a driver model and are run in three phases:\nsetup, execute, teardown.\n\nA test may be setup and executed at boottime,\nit may be setup at boottime and executed at runtime,\nor it may be setup and executed at runtime.\n\nAfter executing all tests the system is reset.\n\nSigned-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>\n---\n MAINTAINERS | 5 +-\n cmd/Kconfig | 2 +\n cmd/bootefi.c | 25 +++-\n include/efi_loader.h | 9 ++\n include/efi_selftest.h | 91 +++++++++++++\n lib/Makefile | 1 +\n lib/efi_selftest/Kconfig | 7 +\n lib/efi_selftest/Makefile | 17 +++\n lib/efi_selftest/efi_selftest.c | 219 ++++++++++++++++++++++++++++++++\n lib/efi_selftest/efi_selftest_console.c | 187 +++++++++++++++++++++++++++\n 10 files changed, 558 insertions(+), 5 deletions(-)\n create mode 100644 include/efi_selftest.h\n create mode 100644 lib/efi_selftest/Kconfig\n create mode 100644 lib/efi_selftest/Makefile\n create mode 100644 lib/efi_selftest/efi_selftest.c\n create mode 100644 lib/efi_selftest/efi_selftest_console.c", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 04acf2b89d..0b7b2bbeb2 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -259,8 +259,9 @@ EFI PAYLOAD\n M:\tAlexander Graf <agraf@suse.de>\n S:\tMaintained\n T:\tgit git://github.com/agraf/u-boot.git\n-F:\tinclude/efi_loader.h\n-F:\tlib/efi_loader/\n+F:\tinclude/efi*\n+F:\tlib/efi*\n+F:\ttest/py/tests/test_efi*\n F:\tcmd/bootefi.c\n \n FLATTENED DEVICE TREE\ndiff --git a/cmd/Kconfig b/cmd/Kconfig\nindex d6d130edfa..3ef9b16b08 100644\n--- a/cmd/Kconfig\n+++ b/cmd/Kconfig\n@@ -222,6 +222,8 @@ config CMD_BOOTEFI_HELLO\n \t for testing that EFI is working at a basic level, and for bringing\n \t up EFI support on a new architecture.\n \n+source lib/efi_selftest/Kconfig\n+\n config CMD_BOOTMENU\n \tbool \"bootmenu\"\n \tselect MENU\ndiff --git a/cmd/bootefi.c b/cmd/bootefi.c\nindex ffd50ba159..788f869479 100644\n--- a/cmd/bootefi.c\n+++ b/cmd/bootefi.c\n@@ -285,7 +285,6 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)\n \treturn efi_do_enter(&loaded_image_info, &systab, entry);\n }\n \n-\n /* Interpreter command to boot an arbitrary EFI image from memory */\n static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])\n {\n@@ -307,6 +306,22 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])\n \t\tmemcpy((char *)addr, __efi_helloworld_begin, size);\n \t} else\n #endif\n+#ifdef CONFIG_CMD_BOOTEFI_SELFTEST\n+\tif (!strcmp(argv[1], \"selftest\")) {\n+\t\t/*\n+\t\t * gd lives in a fixed register which may get clobbered while we\n+\t\t * execute the payload. So save it here and restore it on every\n+\t\t * callback entry\n+\t\t */\n+\t\tefi_save_gd();\n+\t\t/* Initialize and populate EFI object list */\n+\t\tif (!efi_obj_list_initalized)\n+\t\t\tefi_init_obj_list();\n+\t\tloaded_image_info.device_handle = bootefi_device_path;\n+\t\tloaded_image_info.file_path = bootefi_image_path;\n+\t\treturn efi_selftest(&loaded_image_info, &systab);\n+\t} else\n+#endif\n \t{\n \t\tsaddr = argv[1];\n \n@@ -336,8 +351,12 @@ static char bootefi_help_text[] =\n \t\" If specified, the device tree located at <fdt address> gets\\n\"\n \t\" exposed as EFI configuration table.\\n\"\n #ifdef CONFIG_CMD_BOOTEFI_HELLO\n-\t\"hello\\n\"\n-\t\" - boot a sample Hello World application stored within U-Boot\"\n+\t\"bootefi hello\\n\"\n+\t\" - boot a sample Hello World application stored within U-Boot\\n\"\n+#endif\n+#ifdef CONFIG_CMD_BOOTEFI_SELFTEST\n+\t\"bootefi selftest\\n\"\n+\t\" - boot an EFI selftest application stored within U-Boot\\n\"\n #endif\n \t;\n #endif\ndiff --git a/include/efi_loader.h b/include/efi_loader.h\nindex f27192555e..f74b33d589 100644\n--- a/include/efi_loader.h\n+++ b/include/efi_loader.h\n@@ -254,6 +254,15 @@ efi_status_t __efi_runtime EFIAPI efi_get_time(\n \t\t\tstruct efi_time_cap *capabilities);\n void efi_get_time_init(void);\n \n+#ifdef CONFIG_CMD_BOOTEFI_SELFTEST\n+/*\n+ * Entry point for the tests of the EFI API.\n+ * It is called by 'bootefi selftest'\n+ */\n+efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,\n+\t\t\t\t struct efi_system_table *systab);\n+#endif\n+\n #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */\n \n /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */\ndiff --git a/include/efi_selftest.h b/include/efi_selftest.h\nnew file mode 100644\nindex 0000000000..76304a2b2a\n--- /dev/null\n+++ b/include/efi_selftest.h\n@@ -0,0 +1,91 @@\n+/*\n+ * EFI application loader\n+ *\n+ * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>\n+ *\n+ * SPDX-License-Identifier: GPL-2.0+\n+ */\n+\n+#ifndef _EFI_SELFTEST_H\n+#define _EFI_SELFTEST_H\n+\n+#include <common.h>\n+#include <efi.h>\n+#include <efi_api.h>\n+#include <linker_lists.h>\n+\n+/*\n+ * Prints an error message.\n+ *\n+ * @...\tformat string followed by fields to print\n+ */\n+#define efi_st_error(...) \\\n+\tefi_st_printf(\"%s(%u):\\nERROR: \", __FILE__, __LINE__); \\\n+\tefi_st_printf(__VA_ARGS__) \\\n+\n+/*\n+ * A test may be setup and executed at boottime,\n+ * it may be setup at boottime and executed at runtime,\n+ * or it may be setup and executed at runtime.\n+ */\n+enum efi_test_phase {\n+\tEFI_EXECUTE_BEFORE_BOOTTIME_EXIT = 1,\n+\tEFI_SETUP_BEFORE_BOOTTIME_EXIT,\n+\tEFI_SETUP_AFTER_BOOTTIME_EXIT,\n+};\n+\n+extern struct efi_simple_text_output_protocol *con_out;\n+extern struct efi_simple_input_interface *con_in;\n+\n+/*\n+ * Exit the boot services.\n+ *\n+ * The size of the memory map is determined.\n+ * Pool memory is allocated to copy the memory map.\n+ * The memory amp is copied and the map key is obtained.\n+ * The map key is used to exit the boot services.\n+ */\n+void efi_st_exit_boot_services(void);\n+\n+/*\n+ * Print a pointer to an u16 string\n+ *\n+ * @pointer: pointer\n+ * @buf: pointer to buffer address\n+ * on return position of terminating zero word\n+ */\n+void efi_st_printf(const char *fmt, ...)\n+\t\t __attribute__ ((format (__printf__, 1, 2)));\n+\n+/*\n+ * Reads an Unicode character from the input device.\n+ *\n+ * @return: Unicode character\n+ */\n+u16 efi_st_get_key(void);\n+\n+/**\n+ * struct efi_unit_test - EFI unit test\n+ *\n+ * An efi_unit_test provides a interface to an EFI unit test.\n+ *\n+ * @name:\tname of unit test\n+ * @phase:\tspecifies when setup and execute are executed\n+ * @setup:\tset up the unit test\n+ * @teardown:\ttear down the unit test\n+ * @execute:\texecute the unit test\n+ */\n+struct efi_unit_test {\n+\tconst char *name;\n+\tconst enum efi_test_phase phase;\n+\tint (*setup)(const efi_handle_t handle,\n+\t\t const struct efi_system_table *systable);\n+\tint (*execute)(void);\n+\tint (*teardown)(void);\n+};\n+\n+/* Declare a new EFI unit test */\n+#define EFI_UNIT_TEST(__name)\t\t\t\t\t\t\\\n+\tll_entry_declare(struct efi_unit_test, __name, efi_unit_test)\n+\n+#endif /* _EFI_SELFTEST_H */\ndiff --git a/lib/Makefile b/lib/Makefile\nindex 15bba9eac2..8b339dfa22 100644\n--- a/lib/Makefile\n+++ b/lib/Makefile\n@@ -9,6 +9,7 @@ ifndef CONFIG_SPL_BUILD\n \n obj-$(CONFIG_EFI) += efi/\n obj-$(CONFIG_EFI_LOADER) += efi_loader/\n+obj-$(CONFIG_EFI_LOADER) += efi_selftest/\n obj-$(CONFIG_LZMA) += lzma/\n obj-$(CONFIG_LZO) += lzo/\n obj-$(CONFIG_BZIP2) += bzip2/\ndiff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig\nnew file mode 100644\nindex 0000000000..3b5f3a1230\n--- /dev/null\n+++ b/lib/efi_selftest/Kconfig\n@@ -0,0 +1,7 @@\n+config CMD_BOOTEFI_SELFTEST\n+\tbool \"Allow booting an EFI efi_selftest\"\n+\tdepends on CMD_BOOTEFI\n+\thelp\n+\t This adds an EFI test application to U-Boot that can be executed\n+\t with the 'bootefi selftest' command. It provides extended tests of\n+\t the EFI API implementation.\ndiff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile\nnew file mode 100644\nindex 0000000000..34f5ff1838\n--- /dev/null\n+++ b/lib/efi_selftest/Makefile\n@@ -0,0 +1,17 @@\n+:\n+# (C) Copyright 2017, Heinrich Schuchardt <xypron.glpk@gmx.de>\n+#\n+# SPDX-License-Identifier: GPL-2.0+\n+#\n+\n+# This file only gets included with CONFIG_EFI_LOADER set, so all\n+# object inclusion implicitly depends on it\n+\n+CFLAGS_efi_selftest.o := $(CFLAGS_EFI)\n+CFLAGS_REMOVE_efi_selftest.o := $(CFLAGS_NON_EFI)\n+CFLAGS_efi_selftest_console.o := $(CFLAGS_EFI)\n+CFLAGS_REMOVE_efi_selftest_console.o := $(CFLAGS_NON_EFI)\n+\n+obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \\\n+efi_selftest.o \\\n+efi_selftest_console.o\ndiff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c\nnew file mode 100644\nindex 0000000000..efec832e98\n--- /dev/null\n+++ b/lib/efi_selftest/efi_selftest.c\n@@ -0,0 +1,219 @@\n+/*\n+ * EFI efi_selftest\n+ *\n+ * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>\n+ *\n+ * SPDX-License-Identifier: GPL-2.0+\n+ */\n+\n+#include <efi_selftest.h>\n+#include <vsprintf.h>\n+\n+static const struct efi_system_table *systable;\n+static const struct efi_boot_services *boottime;\n+static const struct efi_runtime_services *runtime;\n+static efi_handle_t handle;\n+static u16 reset_message[] = L\"Selftest completed\";\n+\n+/*\n+ * Exit the boot services.\n+ *\n+ * The size of the memory map is determined.\n+ * Pool memory is allocated to copy the memory map.\n+ * The memory amp is copied and the map key is obtained.\n+ * The map key is used to exit the boot services.\n+ */\n+void efi_st_exit_boot_services(void)\n+{\n+\tunsigned long map_size = 0;\n+\tunsigned long map_key;\n+\tunsigned long desc_size;\n+\tu32 desc_version;\n+\tefi_status_t ret;\n+\tstruct efi_mem_desc *memory_map;\n+\n+\tret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,\n+\t\t\t\t &desc_version);\n+\tif (ret != EFI_BUFFER_TOO_SMALL) {\n+\t\tefi_st_printf(\"ERROR: GetMemoryMap did not return \"\n+\t\t\t \"EFI_BUFFER_TOO_SMALL\\n\");\n+\t\treturn;\n+\t}\n+\t/* Allocate extra space for newly allocated memory */\n+\tmap_size += sizeof(struct efi_mem_desc);\n+\tret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,\n+\t\t\t\t (void **)&memory_map);\n+\tif (ret != EFI_SUCCESS) {\n+\t\tefi_st_printf(\"ERROR: AllocatePool did not return \"\n+\t\t\t \"EFI_SUCCESS\\n\");\n+\t\treturn;\n+\t}\n+\tret = boottime->get_memory_map(&map_size, memory_map, &map_key,\n+\t\t\t\t &desc_size, &desc_version);\n+\tif (ret != EFI_SUCCESS) {\n+\t\tefi_st_printf(\"ERROR: GetMemoryMap did not return \"\n+\t\t\t \"EFI_SUCCESS\\n\");\n+\t\treturn;\n+\t}\n+\tret = boottime->exit_boot_services(handle, map_key);\n+\tif (ret != EFI_SUCCESS) {\n+\t\tefi_st_printf(\"ERROR: ExitBootServices did not return \"\n+\t\t\t \"EFI_SUCCESS\\n\");\n+\t\treturn;\n+\t}\n+\tefi_st_printf(\"\\nBoot services terminated\\n\");\n+}\n+\n+/*\n+ * Set up a test.\n+ *\n+ * @test\tthe test to be executed\n+ * @failures\tcounter that will be incremented if a failure occurs\n+ */\n+static int setup(struct efi_unit_test *test, unsigned int *failures)\n+{\n+\tint ret;\n+\n+\tif (!test->setup)\n+\t\treturn 0;\n+\tefi_st_printf(\"\\nSetting up '%s'\\n\", test->name);\n+\tret = test->setup(handle, systable);\n+\tif (ret) {\n+\t\tefi_st_printf(\"ERROR: Setting up '%s' failed\\n\", test->name);\n+\t\t++*failures;\n+\t} else {\n+\t\tefi_st_printf(\"Setting up '%s' succeeded\\n\", test->name);\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * Execute a test.\n+ *\n+ * @test\tthe test to be executed\n+ * @failures\tcounter that will be incremented if a failure occurs\n+ */\n+static int execute(struct efi_unit_test *test, unsigned int *failures)\n+{\n+\tint ret;\n+\n+\tif (!test->execute)\n+\t\treturn 0;\n+\tefi_st_printf(\"\\nExecuting '%s'\\n\", test->name);\n+\tret = test->execute();\n+\tif (ret) {\n+\t\tefi_st_printf(\"ERROR: Executing '%s' failed\\n\", test->name);\n+\t\t++*failures;\n+\t} else {\n+\t\tefi_st_printf(\"Executing '%s' succeeded\\n\", test->name);\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * Tear down a test.\n+ *\n+ * @test\tthe test to be torn down\n+ * @failures\tcounter that will be incremented if a failure occurs\n+ */\n+static int teardown(struct efi_unit_test *test, unsigned int *failures)\n+{\n+\tint ret;\n+\n+\tif (!test->teardown)\n+\t\treturn 0;\n+\tefi_st_printf(\"\\nTearing down '%s'\\n\", test->name);\n+\tret = test->teardown();\n+\tif (ret) {\n+\t\tefi_st_printf(\"ERROR: Tearing down '%s' failed\\n\", test->name);\n+\t\t++*failures;\n+\t} else {\n+\t\tefi_st_printf(\"Tearing down '%s' succeeded\\n\", test->name);\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * Execute selftest of the EFI API\n+ *\n+ * This is the main entry point of the EFI selftest application.\n+ *\n+ * All tests use a driver model and are run in three phases:\n+ * setup, execute, teardown.\n+ *\n+ * A test may be setup and executed at boottime,\n+ * it may be setup at boottime and executed at runtime,\n+ * or it may be setup and executed at runtime.\n+ *\n+ * After executing all tests the system is reset.\n+ *\n+ * @image_handle:\thandle of the loaded EFI image\n+ * @systab:\t\tEFI system table\n+ */\n+efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,\n+\t\t\t\t struct efi_system_table *systab)\n+{\n+\tstruct efi_unit_test *test;\n+\tunsigned int failures = 0;\n+\n+\tsystable = systab;\n+\tboottime = systable->boottime;\n+\truntime = systable->runtime;\n+\thandle = image_handle;\n+\tcon_out = systable->con_out;\n+\tcon_in = systable->con_in;\n+\n+\tefi_st_printf(\"\\nTesting EFI API implementation\\n\");\n+\n+\tefi_st_printf(\"\\nNumber of tests to execute: %u\\n\",\n+\t\t ll_entry_count(struct efi_unit_test, efi_unit_test));\n+\n+\t/* Execute boottime tests */\n+\tfor (test = ll_entry_start(struct efi_unit_test, efi_unit_test);\n+\t test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {\n+\t\tif (test->phase == EFI_EXECUTE_BEFORE_BOOTTIME_EXIT) {\n+\t\t\tsetup(test, &failures);\n+\t\t\texecute(test, &failures);\n+\t\t\tteardown(test, &failures);\n+\t\t}\n+\t}\n+\n+\t/* Execute mixed tests */\n+\tfor (test = ll_entry_start(struct efi_unit_test, efi_unit_test);\n+\t test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {\n+\t\tif (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT)\n+\t\t\tsetup(test, &failures);\n+\t}\n+\n+\tefi_st_exit_boot_services();\n+\n+\tfor (test = ll_entry_start(struct efi_unit_test, efi_unit_test);\n+\t test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {\n+\t\tif (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT) {\n+\t\t\texecute(test, &failures);\n+\t\t\tteardown(test, &failures);\n+\t\t}\n+\t}\n+\n+\t/* Execute runtime tests */\n+\tfor (test = ll_entry_start(struct efi_unit_test, efi_unit_test);\n+\t test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {\n+\t\tif (test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT) {\n+\t\t\tsetup(test, &failures);\n+\t\t\texecute(test, &failures);\n+\t\t\tteardown(test, &failures);\n+\t\t}\n+\t}\n+\n+\t/* Give feedback */\n+\tefi_st_printf(\"\\nSummary: %u failures\\n\\n\", failures);\n+\n+\t/* Reset system */\n+\tefi_st_printf(\"Preparing for reset. Press any key.\\n\");\n+\tefi_st_get_key();\n+\truntime->reset_system(EFI_RESET_WARM, EFI_NOT_READY,\n+\t\t\t sizeof(reset_message), reset_message);\n+\tefi_st_printf(\"\\nERROR: reset failed.\\n\");\n+\n+\treturn EFI_UNSUPPORTED;\n+}\ndiff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c\nnew file mode 100644\nindex 0000000000..7b5b724a61\n--- /dev/null\n+++ b/lib/efi_selftest/efi_selftest_console.c\n@@ -0,0 +1,187 @@\n+/*\n+ * EFI efi_selftest\n+ *\n+ * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>\n+ *\n+ * SPDX-License-Identifier: GPL-2.0+\n+ */\n+\n+#include <efi_selftest.h>\n+#include <vsprintf.h>\n+\n+struct efi_simple_text_output_protocol *con_out;\n+struct efi_simple_input_interface *con_in;\n+\n+/*\n+ * Print a pointer to an u16 string\n+ *\n+ * @pointer: pointer\n+ * @buf: pointer to buffer address\n+ * on return position of terminating zero word\n+ */\n+static void pointer(void *pointer, u16 **buf)\n+{\n+\tint i;\n+\tu16 c;\n+\tuintptr_t p = (uintptr_t)pointer;\n+\tu16 *pos = *buf;\n+\n+\tfor (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {\n+\t\tc = (p >> i) & 0x0f;\n+\t\tc += '0';\n+\t\tif (c > '9')\n+\t\t\tc += 'a' - '9' - 1;\n+\t\t*pos++ = c;\n+\t}\n+\t*pos = 0;\n+\t*buf = pos;\n+}\n+\n+/*\n+ * Print an unsigned 32bit value as decimal number to an u16 string\n+ *\n+ * @value: value to be printed\n+ * @buf: pointer to buffer address\n+ * on return position of terminating zero word\n+ */\n+static void uint2dec(u32 value, u16 **buf)\n+{\n+\tu16 *pos = *buf;\n+\tint i;\n+\tu16 c;\n+\tu64 f;\n+\n+\t/*\n+\t * Increment by .5 and multiply with\n+\t * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC\n+\t * to move the first digit to bit 60-63.\n+\t */\n+\tf = 0x225C17D0;\n+\tf += (0x9B5A52DULL * value) >> 28;\n+\tf += 0x44B82FA0ULL * value;\n+\n+\tfor (i = 0; i < 10; ++i) {\n+\t\t/* Write current digit */\n+\t\tc = f >> 60;\n+\t\tif (c || pos != *buf)\n+\t\t\t*pos++ = c + '0';\n+\t\t/* Eliminate current digit */\n+\t\tf &= 0xfffffffffffffff;\n+\t\t/* Get next digit */\n+\t\tf *= 0xaULL;\n+\t}\n+\tif (pos == *buf)\n+\t\t*pos++ = '0';\n+\t*pos = 0;\n+\t*buf = pos;\n+}\n+\n+/*\n+ * Print a signed 32bit value as decimal number to an u16 string\n+ *\n+ * @value: value to be printed\n+ * @buf: pointer to buffer address\n+ * on return position of terminating zero word\n+ */\n+static void int2dec(s32 value, u16 **buf)\n+{\n+\tu32 u;\n+\tu16 *pos = *buf;\n+\n+\tif (value < 0) {\n+\t\t*pos++ = '-';\n+\t\tu = -value;\n+\t} else {\n+\t\tu = value;\n+\t}\n+\tuint2dec(u, &pos);\n+\t*buf = pos;\n+}\n+\n+/*\n+ * Print a formatted string to the EFI console\n+ *\n+ * @fmt: format string\n+ * @...: optional arguments\n+ */\n+void efi_st_printf(const char *fmt, ...)\n+{\n+\tva_list args;\n+\tu16 buf[160];\n+\tconst char *c;\n+\tu16 *pos = buf;\n+\tconst char *s;\n+\n+\tva_start(args, fmt);\n+\n+\tc = fmt;\n+\tfor (; *c; ++c) {\n+\t\tswitch (*c) {\n+\t\tcase '\\\\':\n+\t\t\t++c;\n+\t\t\tswitch (*c) {\n+\t\t\tcase '\\0':\n+\t\t\t\t--c;\n+\t\t\t\tbreak;\n+\t\t\tcase 'n':\n+\t\t\t\t*pos++ = '\\n';\n+\t\t\t\tbreak;\n+\t\t\tcase 'r':\n+\t\t\t\t*pos++ = '\\r';\n+\t\t\t\tbreak;\n+\t\t\tcase 't':\n+\t\t\t\t*pos++ = '\\t';\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\t*pos++ = *c;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase '%':\n+\t\t\t++c;\n+\t\t\tswitch (*c) {\n+\t\t\tcase '\\0':\n+\t\t\t\t--c;\n+\t\t\t\tbreak;\n+\t\t\tcase 'd':\n+\t\t\t\tint2dec(va_arg(args, s32), &pos);\n+\t\t\t\tbreak;\n+\t\t\tcase 'p':\n+\t\t\t\tpointer(va_arg(args, void*), &pos);\n+\t\t\t\tbreak;\n+\t\t\tcase 's':\n+\t\t\t\ts = va_arg(args, const char *);\n+\t\t\t\tfor (; *s; ++s)\n+\t\t\t\t\t*pos++ = *s;\n+\t\t\t\tbreak;\n+\t\t\tcase 'u':\n+\t\t\t\tuint2dec(va_arg(args, u32), &pos);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\t*pos++ = *c;\n+\t\t}\n+\t}\n+\tva_end(args);\n+\t*pos = 0;\n+\tcon_out->output_string(con_out, buf);\n+}\n+\n+/*\n+ * Reads an Unicode character from the input device.\n+ *\n+ * @return: Unicode character\n+ */\n+u16 efi_st_get_key(void)\n+{\n+\tstruct efi_input_key input_key;\n+\tefi_status_t ret;\n+\n+\t/* Wait for next key */\n+\tdo {\n+\t\tret = con_in->read_key_stroke(con_in, &input_key);\n+\t} while (ret == EFI_NOT_READY);\n+\treturn input_key.unicode_char;\n+}\n", "prefixes": [ "U-Boot", "02/10" ] }