aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorD Scott Phillips <scottph@FreeBSD.org>2020-08-26 02:05:58 +0000
committerD Scott Phillips <scottph@FreeBSD.org>2020-08-26 02:05:58 +0000
commit83c4237258d3574b28a63c9182b7d95c428cd8ef (patch)
treebdffcf3c29dadcdfb51e3ab7b6427c4f990d43f5
parentb71d94209ed23306b688433a4ad0fc55e1a20a60 (diff)
downloadsrc-83c4237258d3574b28a63c9182b7d95c428cd8ef.tar.gz
src-83c4237258d3574b28a63c9182b7d95c428cd8ef.zip
efibootmgr: Add option to request booting to the firmware user interface
The OsIndications UEFI variable can request the firware to stop at its UI instead of continuing with boot. Add flags for setting and clearing this request. Reviewed by: manu, bcr (manpages) Approved by: scottl (implicit) MFC after: 1 week Sponsored by: Ampere Computing, Inc. Differential Revision: https://reviews.freebsd.org/D25839
Notes
Notes: svn path=/head/; revision=364795
-rw-r--r--usr.sbin/efibootmgr/efibootmgr.89
-rw-r--r--usr.sbin/efibootmgr/efibootmgr.c82
2 files changed, 89 insertions, 2 deletions
diff --git a/usr.sbin/efibootmgr/efibootmgr.8 b/usr.sbin/efibootmgr/efibootmgr.8
index 3bd476231dbb..7627db19f050 100644
--- a/usr.sbin/efibootmgr/efibootmgr.8
+++ b/usr.sbin/efibootmgr/efibootmgr.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 23, 2020
+.Dd August 25, 2020
.Dt EFIBOOTMGR 8
.Os
.Sh NAME
@@ -55,6 +55,10 @@
.Op Fl d
.Op Fl p
.Nm
+.Fl F
+.Nm
+.Fl f
+.Nm
.Fl n
.Fl b Ar bootnum
.Nm
@@ -137,6 +141,9 @@ is specified, the UEFI device path to the ESP is reported instead.
If
.Fl p -unix-path
is specified, the mount point of the ESP is reported instead.
+.It Fl f -fw-ui , Fl F -no-fw-ui
+Set or clear the request to the system firmware to stop in its user
+interface on the next boot.
.It Fl k -kernel Ar kernel
The path to and name of the kernel.
.It Fl l -loader Ar loader
diff --git a/usr.sbin/efibootmgr/efibootmgr.c b/usr.sbin/efibootmgr/efibootmgr.c
index e51d2a9efa8b..b0d5bfa9dbb9 100644
--- a/usr.sbin/efibootmgr/efibootmgr.c
+++ b/usr.sbin/efibootmgr/efibootmgr.c
@@ -67,6 +67,8 @@ __FBSDID("$FreeBSD$");
#define BAD_LENGTH ((size_t)-1)
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
+
typedef struct _bmgr_opts {
char *env;
char *loader;
@@ -83,6 +85,8 @@ typedef struct _bmgr_opts {
bool dry_run;
bool device_path;
bool esp_device;
+ bool fw_ui;
+ bool no_fw_ui;
bool has_bootnum;
bool once;
int cp_src;
@@ -110,6 +114,8 @@ static struct option lopts[] = {
{"dry-run", no_argument, NULL, 'D'},
{"env", required_argument, NULL, 'e'},
{"esp", no_argument, NULL, 'E'},
+ {"fw-ui", no_argument, NULL, 'f'},
+ {"no-fw-ui", no_argument, NULL, 'F'},
{"help", no_argument, NULL, 'h'},
{"kernel", required_argument, NULL, 'k'},
{"label", required_argument, NULL, 'L'},
@@ -197,7 +203,7 @@ parse_args(int argc, char *argv[])
{
int ch;
- while ((ch = getopt_long(argc, argv, "AaBb:C:cdDe:Ehk:L:l:NnOo:pTt:v",
+ while ((ch = getopt_long(argc, argv, "AaBb:C:cdDe:EFfhk:L:l:NnOo:pTt:v",
lopts, NULL)) != -1) {
switch (ch) {
case 'A':
@@ -232,6 +238,12 @@ parse_args(int argc, char *argv[])
case 'E':
opts.esp_device = true;
break;
+ case 'F':
+ opts.no_fw_ui = true;
+ break;
+ case 'f':
+ opts.fw_ui = true;
+ break;
case 'h':
default:
errx(1, "%s", USAGE);
@@ -825,6 +837,45 @@ print_boot_var(const char *name, bool verbose, bool curboot)
}
+static bool
+os_indication_supported(uint64_t indication)
+{
+ uint8_t *data;
+ size_t size;
+ uint32_t attrs;
+ int ret;
+
+ ret = efi_get_variable(EFI_GLOBAL_GUID, "OsIndicationsSupported", &data,
+ &size, &attrs);
+ if (ret < 0)
+ return false;
+ return (le64dec(data) & indication) == indication;
+}
+
+static uint64_t
+os_indications(void)
+{
+ uint8_t *data;
+ size_t size;
+ uint32_t attrs;
+ int ret;
+
+ ret = efi_get_variable(EFI_GLOBAL_GUID, "OsIndications", &data, &size,
+ &attrs);
+ if (ret < 0)
+ return 0;
+ return le64dec(data);
+}
+
+static int
+os_indications_set(uint64_t mask, uint64_t val)
+{
+ uint8_t new[sizeof(uint64_t)];
+
+ le64enc(&new, (os_indications() & ~mask) | (val & mask));
+ return set_bootvar("OsIndications", new, sizeof(new));
+}
+
/* Cmd epilogue, or just the default with no args.
* The order is [bootnext] bootcurrent, timeout, order, and the bootvars [-v]
*/
@@ -841,6 +892,14 @@ print_boot_vars(bool verbose)
uint32_t attrs;
int ret, bolen;
uint16_t *boot_order = NULL, current;
+ bool boot_to_fw_ui;
+
+ if (os_indication_supported(EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
+ boot_to_fw_ui =
+ (os_indications() & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0;
+ printf("Boot to FW : %s\n", boot_to_fw_ui != 0 ?
+ "true" : "false");
+ }
ret = efi_get_variable(EFI_GLOBAL_GUID, "BootNext", &data, &size, &attrs);
if (ret > 0) {
@@ -987,6 +1046,23 @@ report_esp_device(bool do_dp, bool do_unix)
exit(0);
}
+static void
+set_boot_to_fw_ui(bool to_fw)
+{
+ int ret;
+
+ if (!os_indication_supported(EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
+ if (to_fw)
+ errx(1, "boot to fw ui not supported");
+ else
+ return;
+ }
+ ret = os_indications_set(EFI_OS_INDICATIONS_BOOT_TO_FW_UI,
+ to_fw ? ~0 : 0);
+ if (ret < 0)
+ errx(1, "failed to set boot to fw ui");
+}
+
int
main(int argc, char *argv[])
{
@@ -1021,6 +1097,10 @@ main(int argc, char *argv[])
handle_timeout(opts.timeout);
else if (opts.esp_device)
report_esp_device(opts.device_path, opts.unix_path);
+ else if (opts.fw_ui)
+ set_boot_to_fw_ui(true);
+ else if (opts.no_fw_ui)
+ set_boot_to_fw_ui(false);
print_boot_vars(opts.verbose);
}