sysreset: Add SYSRESET_TO_FIRMWARE_UI with reset -u support

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>
This commit is contained in:
Simon Glass
2025-08-29 07:54:17 -06:00
parent 1ad04a7895
commit 96adc477be
7 changed files with 44 additions and 1 deletions

View File

@@ -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"
);

View File

@@ -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
------------

View File

@@ -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;

View File

@@ -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();

View File

@@ -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,

View File

@@ -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;

View File

@@ -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,