Index: head/usr.sbin/efibootmgr/efibootmgr.8 =================================================================== --- head/usr.sbin/efibootmgr/efibootmgr.8 +++ head/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 @@ 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 Index: head/usr.sbin/efibootmgr/efibootmgr.c =================================================================== --- head/usr.sbin/efibootmgr/efibootmgr.c +++ head/usr.sbin/efibootmgr/efibootmgr.c @@ -67,6 +67,8 @@ #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 @@ 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 @@ {"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 @@ { 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 @@ 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 @@ } +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,7 +892,15 @@ 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) { printf("BootNext : %04x\n", le16dec(data)); @@ -987,6 +1046,23 @@ 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 @@ 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); }