[PATCH v2 0/3] efi_loader: rework ResetSystem()

If the UEFI runtime service ResetSystem() is not implemented at runtime, it should return instead of hanging in an endless loop.
Provide tests for ResetSystem() at before and after ExitBootServices().
If ResetSystem() is not implemented at runtime, use do_reset() after UEFI unit tests to reset the system.
Heinrich Schuchardt (3): efi_loader: ResetSystem() should not hang efi_selftest: add a test for ResetSystem() efi_selftest: substitute ResetSystem() by do_reset()
lib/efi_loader/efi_runtime.c | 7 ++-- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest.c | 10 ++++- lib/efi_selftest/efi_selftest_reset.c | 58 +++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_reset.c
-- 2.28.0

If ResetSystem() is not implemented at runtime, it should return instead of hanging in an endless loop. This allows the operating system to reset the system by other means as Linux does. It also matches what EDK II suggests in comments for functions ResetShutdown() and ResetWarm() in OvmfPkg/Library/ResetSystemLib/ResetSystemLib.c.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2: new patch --- lib/efi_loader/efi_runtime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 78fd8014d9..dea2b4e5ee 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -365,7 +365,9 @@ out: * efi_reset_system() - reset system * * This function implements the ResetSystem() runtime service after - * SetVirtualAddressMap() is called. It only executes an endless loop. + * SetVirtualAddressMap() is called. As this placeholder cannot reset the + * system it simply return to the caller. + * * Boards may override the helpers below to implement reset functionality. * * See the Unified Extensible Firmware Interface (UEFI) specification for @@ -381,8 +383,7 @@ void __weak __efi_runtime EFIAPI efi_reset_system( efi_status_t reset_status, unsigned long data_size, void *reset_data) { - /* Nothing we can do */ - while (1) { } + return; }
/** -- 2.28.0

On Sat, Aug 22, 2020 at 12:40 AM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
If ResetSystem() is not implemented at runtime, it should return instead of hanging in an endless loop. This allows the operating system to reset the system by other means as Linux does. It also matches what EDK II suggests in comments for functions ResetShutdown() and ResetWarm() in OvmfPkg/Library/ResetSystemLib/ResetSystemLib.c.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: new patch
lib/efi_loader/efi_runtime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 78fd8014d9..dea2b4e5ee 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -365,7 +365,9 @@ out:
- efi_reset_system() - reset system
- This function implements the ResetSystem() runtime service after
- SetVirtualAddressMap() is called. It only executes an endless loop.
- SetVirtualAddressMap() is called. As this placeholder cannot reset the
- system it simply return to the caller.
- Boards may override the helpers below to implement reset functionality.
- See the Unified Extensible Firmware Interface (UEFI) specification for
@@ -381,8 +383,7 @@ void __weak __efi_runtime EFIAPI efi_reset_system( efi_status_t reset_status, unsigned long data_size, void *reset_data) {
/* Nothing we can do */
while (1) { }
return;
}
/**
2.28.0
Reviewed-by: Atish Patra atish.patra@wdc.com

The unit test will reset the system by calling the ResetSystem() runtime service before or after ExitBootServices() according to the users choice by setting environment variable efi_selftest to:
* 'reset system' or * 'reset system runtime'.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2: allow testing after ExitBootServices() --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_reset.c | 58 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_reset.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 45ce6859b8..85fe8e1216 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -31,6 +31,7 @@ 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_textinput.o \ efi_selftest_textinputex.o \ diff --git a/lib/efi_selftest/efi_selftest_reset.c b/lib/efi_selftest/efi_selftest_reset.c new file mode 100644 index 0000000000..8b6ac24cb1 --- /dev/null +++ b/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, +}; -- 2.28.0

If ResetSystem() is not implemented at runtime, call do_reset() after test completion.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2: new patch --- lib/efi_selftest/efi_selftest.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 5b01610eca..6eec8ae2a7 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -5,6 +5,7 @@ * Copyright (c) 2017 Heinrich Schuchardt xypron.glpk@gmx.de */
+#include <command.h> #include <efi_selftest.h> #include <vsprintf.h>
@@ -309,8 +310,13 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, /* Reset system */ efi_st_printf("Preparing for reset. Press any key...\n"); efi_st_get_key(); - runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, - sizeof(reset_message), reset_message); + + if (IS_ENABLED(CONFIG_EFI_HAVE_RUNTIME_RESET)) + runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, + sizeof(reset_message), reset_message); + else + do_reset(NULL, 0, 0, NULL); + efi_st_printf("\n"); efi_st_error("Reset failed\n");
-- 2.28.0
participants (2)
-
Atish Patra
-
Heinrich Schuchardt