
From: Simon Glass <sjg@chromium.org> Add new SYSRESET_TO_FIRMWARE_UI reset type to allow resetting directly to firmware UI. This is implemented via the reset command's new -u flag. For the EFI app, this sets the EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit in the OsIndications variable before performing a warm reset, causing the firmware to boot to its setup interface. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/boot.c | 1 + doc/usage/cmd/reset.rst | 9 ++++++++- drivers/sysreset/sysreset-uclass.c | 3 +++ drivers/sysreset/sysreset_sandbox.c | 1 + include/sysreset.h | 2 ++ lib/efi_client/efi_app.c | 27 +++++++++++++++++++++++++++ test/dm/sysreset.c | 2 ++ 7 files changed, 44 insertions(+), 1 deletion(-) diff --git a/cmd/boot.c b/cmd/boot.c index 832ad08c319..01b4bd76826 100644 --- a/cmd/boot.c +++ b/cmd/boot.c @@ -61,6 +61,7 @@ U_BOOT_CMD( "Perform RESET of the CPU", "- cold boot without level specifier\n" "reset -h - hotreset if implemented\n" + "reset -u - reset to firmware UI if implemented\n" "reset -w - warm reset if implemented" ); diff --git a/doc/usage/cmd/reset.rst b/doc/usage/cmd/reset.rst index 3a43db204e5..190f3281d78 100644 --- a/doc/usage/cmd/reset.rst +++ b/doc/usage/cmd/reset.rst @@ -11,7 +11,7 @@ Synopsis :: - reset [-w] + reset [-w] [-u] Description ----------- @@ -26,6 +26,13 @@ DDR and peripherals, on some boards also resets external PMIC. Do a hot reset, if supported, which returns back to the program which started U-Boot. +-u + Reset to firmware UI (EFI app only). Sets the + EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit in the OsIndications variable and + performs a warm reset, causing the firmware to boot directly to its + setup/configuration interface. + + Return value ------------ diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index db81c9b5779..5c9b7c6a4f2 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -132,6 +132,9 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) case 'h': reset_type = SYSRESET_HOT; break; + case 'u': + reset_type = SYSRESET_TO_FIRMWARE_UI; + break; case 'w': reset_type = SYSRESET_WARM; break; diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c index 522050eb4bf..d126fad0372 100644 --- a/drivers/sysreset/sysreset_sandbox.c +++ b/drivers/sysreset/sysreset_sandbox.c @@ -66,6 +66,7 @@ static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type) sandbox_exit(); case SYSRESET_POWER: case SYSRESET_HOT: + case SYSRESET_TO_FIRMWARE_UI: if (!state->sysreset_allowed[type]) return -EACCES; sandbox_exit(); diff --git a/include/sysreset.h b/include/sysreset.h index f231d4e8bc4..16a16952026 100644 --- a/include/sysreset.h +++ b/include/sysreset.h @@ -23,6 +23,8 @@ enum sysreset_t { SYSRESET_POWER_OFF, /** @SYSRESET_HOT: exit out of U-Boot (e.g. from EFI app) */ SYSRESET_HOT, + /** @SYSRESET_TO_FIRMWARE_UI: reset to firmware UI */ + SYSRESET_TO_FIRMWARE_UI, /** @SYSRESET_COUNT: number of available reset types */ SYSRESET_COUNT, diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c index 88e04f1084b..1afccc8c8c7 100644 --- a/lib/efi_client/efi_app.c +++ b/lib/efi_client/efi_app.c @@ -16,6 +16,7 @@ #include <efi.h> #include <efi_api.h> #include <efi_stub.h> +#include <efi_variable.h> #include <errno.h> #include <fdt_simplefb.h> #include <image.h> @@ -253,6 +254,32 @@ static int efi_sysreset_request(struct udevice *dev, enum sysreset_t type) struct efi_priv *priv = efi_get_priv(); switch (type) { + case SYSRESET_TO_FIRMWARE_UI: { + efi_status_t ret; + u64 osind; + + /* Read current OsIndications value */ + osind = 0; + ret = efi_get_variable_int(u"OsIndications", + &efi_global_variable_guid, + NULL, NULL, &osind, NULL); + if (ret && ret != EFI_NOT_FOUND) + log_warning("Failed to read OsIndications: %lx\n", ret); + + /* Set the boot-to-firmware-UI bit */ + osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + ret = efi_set_variable_int(u"OsIndications", + &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(osind), &osind, false); + if (ret) { + log_err("Failed to set OsIndications: %lx\n", ret); + return -EIO; + } + fallthrough; + } case SYSRESET_WARM: priv->run->reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL); break; diff --git a/test/dm/sysreset.c b/test/dm/sysreset.c index a30d035b9a6..0afd19ff52f 100644 --- a/test/dm/sysreset.c +++ b/test/dm/sysreset.c @@ -77,11 +77,13 @@ static int dm_test_sysreset_walk(struct unit_test_state *uts) state->sysreset_allowed[SYSRESET_POWER] = false; state->sysreset_allowed[SYSRESET_POWER_OFF] = false; state->sysreset_allowed[SYSRESET_HOT] = false; + state->sysreset_allowed[SYSRESET_TO_FIRMWARE_UI] = false; ut_asserteq(-EACCES, sysreset_walk(SYSRESET_WARM)); ut_asserteq(-EACCES, sysreset_walk(SYSRESET_COLD)); ut_asserteq(-EACCES, sysreset_walk(SYSRESET_POWER)); ut_asserteq(-EACCES, sysreset_walk(SYSRESET_POWER_OFF)); ut_asserteq(-EACCES, sysreset_walk(SYSRESET_HOT)); + ut_asserteq(-EACCES, sysreset_walk(SYSRESET_TO_FIRMWARE_UI)); /* * Enable cold system reset - this should make cold system reset work, -- 2.43.0