1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "bootspec-fundamental.h"
6 #include "device-path-util.h"
7 #include "devicetree.h"
9 #include "efivars-fundamental.h"
14 #include "part-discovery.h"
16 #include "proto/block-io.h"
17 #include "proto/device-path.h"
18 #include "proto/simple-text-io.h"
19 #include "random-seed.h"
21 #include "secure-boot.h"
29 /* Magic string for recognizing our own binaries */
30 #define SD_MAGIC "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"
31 DECLARE_NOALLOC_SECTION(".sdmagic", SD_MAGIC
);
33 /* Makes systemd-boot available from \EFI\Linux\ for testing purposes. */
34 DECLARE_NOALLOC_SECTION(
37 "VERSION=\"" GIT_VERSION
"\"\n"
38 "NAME=\"systemd-boot " GIT_VERSION
"\"\n");
40 DECLARE_SBAT(SBAT_BOOT_SECTION_TEXT
);
42 typedef enum LoaderType
{
46 LOADER_LINUX
, /* Boot loader spec type #1 entries */
47 LOADER_UNIFIED_LINUX
, /* Boot loader spec type #2 entries */
48 LOADER_SECURE_BOOT_KEYS
,
53 char16_t
*id
; /* The unique identifier for this entry (typically the filename of the file defining the entry) */
54 char16_t
*title_show
; /* The string to actually display (this is made unique before showing) */
55 char16_t
*title
; /* The raw (human readable) title string of the entry (not necessarily unique) */
56 char16_t
*sort_key
; /* The string to use as primary sort key, usually ID= from os-release, possibly suffixed */
57 char16_t
*version
; /* The raw (human readable) version string of the entry */
64 bool options_implied
; /* If true, these options are implied if we invoke the PE binary without any parameters (as in: UKI). If false we must specify these options explicitly. */
67 EFI_STATUS (*call
)(void);
71 char16_t
*current_name
;
79 size_t idx_default_efivar
;
80 uint64_t timeout_sec
; /* Actual timeout used (efi_main() override > efivar > config). */
81 uint64_t timeout_sec_config
;
82 uint64_t timeout_sec_efivar
;
83 char16_t
*entry_default_config
;
84 char16_t
*entry_default_efivar
;
85 char16_t
*entry_oneshot
;
86 char16_t
*entry_saved
;
92 bool reboot_for_bitlocker
;
93 secure_boot_enroll secure_boot_enroll
;
96 bool use_saved_entry_efivar
;
99 int64_t console_mode_efivar
;
102 /* These values have been chosen so that the transitions the user sees could employ unsigned over-/underflow
104 * efivar unset ↔ force menu ↔ no timeout/skip menu ↔ 1 s ↔ 2 s ↔ …
106 * Note: all the values below are ABI, so they are not allowed to change. The bootctl tool sets the numerical
107 * value of TIMEOUT_MENU_FORCE and TIMEOUT_MENU_HIDDEN, instead of the string for compatibility reasons.
109 * The other values may be set by systemd-boot itself and changing those will lead to functional regression
110 * when new version of systemd-boot is installed.
112 * All the 64bit values are not ABI and will never be written to an efi variable.
116 TIMEOUT_MAX
= UINT32_MAX
- 2U,
117 TIMEOUT_UNSET
= UINT32_MAX
- 1U,
118 TIMEOUT_MENU_FORCE
= UINT32_MAX
,
119 TIMEOUT_MENU_HIDDEN
= 0,
120 TIMEOUT_TYPE_MAX
= UINT32_MAX
,
121 TIMEOUT_MENU_DISABLED
= (uint64_t)UINT32_MAX
+ 1U,
122 TIMEOUT_TYPE_MAX64
= UINT64_MAX
,
130 static void cursor_left(size_t *cursor
, size_t *first
) {
136 else if ((*first
) > 0)
140 static void cursor_right(size_t *cursor
, size_t *first
, size_t x_max
, size_t len
) {
144 if ((*cursor
)+1 < x_max
)
146 else if ((*first
) + (*cursor
) < len
)
150 static bool line_edit(char16_t
**line_in
, size_t x_max
, size_t y_pos
) {
151 _cleanup_free_ char16_t
*line
= NULL
, *print
= NULL
;
152 size_t size
, len
, first
= 0, cursor
= 0, clear
= 0;
154 /* Edit the line and return true if it should be executed, false if not. */
158 len
= strlen16(*line_in
);
160 line
= xnew(char16_t
, size
);
161 print
= xnew(char16_t
, x_max
+ 1);
162 strcpy16(line
, strempty(*line_in
));
167 size_t j
, cursor_color
= EFI_TEXT_ATTR_SWAP(COLOR_EDIT
);
169 j
= MIN(len
- first
, x_max
);
170 memcpy(print
, line
+ first
, j
* sizeof(char16_t
));
171 while (clear
> 0 && j
< x_max
) {
177 /* See comment at edit_line() call site for why we start at 1. */
178 print_at(1, y_pos
, COLOR_EDIT
, print
);
182 print
[cursor
+1] = '\0';
184 print_at(cursor
+ 1, y_pos
, cursor_color
, print
+ cursor
);
185 cursor_color
= EFI_TEXT_ATTR_SWAP(cursor_color
);
187 err
= console_key_read(&key
, 750 * 1000);
188 if (!IN_SET(err
, EFI_SUCCESS
, EFI_TIMEOUT
, EFI_NOT_READY
))
191 print_at(cursor
+ 1, y_pos
, COLOR_EDIT
, print
+ cursor
);
192 } while (err
!= EFI_SUCCESS
);
195 case KEYPRESS(0, SCAN_ESC
, 0):
196 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'c'):
197 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'g'):
198 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('c')):
199 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('g')):
202 case KEYPRESS(0, SCAN_HOME
, 0):
203 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'a'):
204 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('a')):
205 /* beginning-of-line */
210 case KEYPRESS(0, SCAN_END
, 0):
211 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'e'):
212 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('e')):
214 cursor
= len
- first
;
215 if (cursor
+1 >= x_max
) {
217 first
= len
- (x_max
-1);
221 case KEYPRESS(0, SCAN_DOWN
, 0):
222 case KEYPRESS(EFI_ALT_PRESSED
, 0, 'f'):
223 case KEYPRESS(EFI_CONTROL_PRESSED
, SCAN_RIGHT
, 0):
225 while (line
[first
+ cursor
] == ' ')
226 cursor_right(&cursor
, &first
, x_max
, len
);
227 while (line
[first
+ cursor
] && line
[first
+ cursor
] != ' ')
228 cursor_right(&cursor
, &first
, x_max
, len
);
231 case KEYPRESS(0, SCAN_UP
, 0):
232 case KEYPRESS(EFI_ALT_PRESSED
, 0, 'b'):
233 case KEYPRESS(EFI_CONTROL_PRESSED
, SCAN_LEFT
, 0):
235 if ((first
+ cursor
) > 0 && line
[first
+ cursor
-1] == ' ') {
236 cursor_left(&cursor
, &first
);
237 while ((first
+ cursor
) > 0 && line
[first
+ cursor
] == ' ')
238 cursor_left(&cursor
, &first
);
240 while ((first
+ cursor
) > 0 && line
[first
+ cursor
-1] != ' ')
241 cursor_left(&cursor
, &first
);
244 case KEYPRESS(0, SCAN_RIGHT
, 0):
245 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'f'):
246 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('f')):
248 if (first
+ cursor
== len
)
250 cursor_right(&cursor
, &first
, x_max
, len
);
253 case KEYPRESS(0, SCAN_LEFT
, 0):
254 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'b'):
255 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('b')):
257 cursor_left(&cursor
, &first
);
260 case KEYPRESS(EFI_CONTROL_PRESSED
, SCAN_DELETE
, 0):
261 case KEYPRESS(EFI_ALT_PRESSED
, 0, 'd'):
266 for (k
= first
+ cursor
; k
< len
&& line
[k
] == ' '; k
++)
268 for (; k
< len
&& line
[k
] != ' '; k
++)
271 for (size_t i
= first
+ cursor
; i
+ clear
< len
; i
++)
272 line
[i
] = line
[i
+ clear
];
277 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'w'):
278 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('w')):
279 case KEYPRESS(EFI_ALT_PRESSED
, 0, '\b'):
280 /* backward-kill-word */
282 if ((first
+ cursor
) > 0 && line
[first
+ cursor
-1] == ' ') {
283 cursor_left(&cursor
, &first
);
285 while ((first
+ cursor
) > 0 && line
[first
+ cursor
] == ' ') {
286 cursor_left(&cursor
, &first
);
290 while ((first
+ cursor
) > 0 && line
[first
+ cursor
-1] != ' ') {
291 cursor_left(&cursor
, &first
);
295 for (size_t i
= first
+ cursor
; i
+ clear
< len
; i
++)
296 line
[i
] = line
[i
+ clear
];
301 case KEYPRESS(0, SCAN_DELETE
, 0):
302 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'd'):
303 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('d')):
306 if (first
+ cursor
== len
)
308 for (size_t i
= first
+ cursor
; i
< len
; i
++)
314 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'k'):
315 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('k')):
317 line
[first
+ cursor
] = '\0';
318 clear
= len
- (first
+ cursor
);
319 len
= first
+ cursor
;
322 case KEYPRESS(0, 0, '\n'):
323 case KEYPRESS(0, 0, '\r'):
324 case KEYPRESS(0, SCAN_F3
, 0): /* EZpad Mini 4s firmware sends malformed events */
325 case KEYPRESS(0, SCAN_F3
, '\r'): /* Teclast X98+ II firmware sends malformed events */
326 if (!streq16(line
, *line_in
)) {
328 *line_in
= TAKE_PTR(line
);
332 case KEYPRESS(0, 0, '\b'):
335 if (first
== 0 && cursor
== 0)
337 for (size_t i
= first
+ cursor
-1; i
< len
; i
++)
343 if (cursor
> 0 || first
== 0)
345 /* show full line if it fits */
351 /* jump left to see what we delete */
361 case KEYPRESS(0, 0, ' ') ... KEYPRESS(0, 0, '~'):
362 case KEYPRESS(0, 0, 0x80) ... KEYPRESS(0, 0, 0xffff):
365 for (size_t i
= len
; i
> first
+ cursor
; i
--)
367 line
[first
+ cursor
] = KEYCHAR(key
);
370 if (cursor
+1 < x_max
)
372 else if (first
+ cursor
< len
)
379 static size_t entry_lookup_key(Config
*config
, size_t start
, char16_t key
) {
385 /* select entry by number key */
386 if (key
>= '1' && key
<= '9') {
387 size_t i
= key
- '0';
388 if (i
> config
->n_entries
)
389 i
= config
->n_entries
;
393 /* find matching key in boot entries */
394 for (size_t i
= start
; i
< config
->n_entries
; i
++)
395 if (config
->entries
[i
]->key
== key
)
398 for (size_t i
= 0; i
< start
; i
++)
399 if (config
->entries
[i
]->key
== key
)
405 static char16_t
* update_timeout_efivar(Config
*config
, bool inc
) {
408 switch (config
->timeout_sec
) {
410 config
->timeout_sec
= inc
? TIMEOUT_MAX
: config
->timeout_sec
- 1;
413 config
->timeout_sec
= inc
? TIMEOUT_MENU_FORCE
: TIMEOUT_UNSET
;
415 case TIMEOUT_MENU_DISABLED
:
416 config
->timeout_sec
= inc
? TIMEOUT_MIN
: TIMEOUT_MENU_FORCE
;
418 case TIMEOUT_MENU_FORCE
:
419 config
->timeout_sec
= inc
? TIMEOUT_MENU_HIDDEN
: TIMEOUT_MENU_FORCE
;
421 case TIMEOUT_MENU_HIDDEN
:
422 config
->timeout_sec
= inc
? TIMEOUT_MIN
: TIMEOUT_MENU_FORCE
;
425 config
->timeout_sec
= config
->timeout_sec
+ (inc
? 1 : -1);
428 config
->timeout_sec_efivar
= config
->timeout_sec
;
430 switch (config
->timeout_sec
) {
432 return xstrdup16(u
"Menu timeout defined by configuration file.");
433 case TIMEOUT_MENU_DISABLED
:
434 assert_not_reached();
435 case TIMEOUT_MENU_FORCE
:
436 return xstrdup16(u
"Timeout disabled, menu will always be shown.");
437 case TIMEOUT_MENU_HIDDEN
:
438 return xstrdup16(u
"Menu hidden. Hold down key at bootup to show menu.");
440 return xasprintf("Menu timeout set to %u s.", (uint32_t)config
->timeout_sec_efivar
);
444 static bool unicode_supported(void) {
445 static int cache
= -1;
448 /* Basic unicode box drawing support is mandated by the spec, but it does
449 * not hurt to make sure it works. */
450 cache
= ST
->ConOut
->TestString(ST
->ConOut
, (char16_t
*) u
"─") == EFI_SUCCESS
;
455 static bool ps_continue(void) {
456 const char16_t
*sep
= unicode_supported() ? u
"───" : u
"---";
457 printf("\n%ls Press any key to continue, ESC or q to quit. %ls\n\n", sep
, sep
);
460 return console_key_read(&key
, UINT64_MAX
) == EFI_SUCCESS
&&
461 !IN_SET(key
, KEYPRESS(0, SCAN_ESC
, 0), KEYPRESS(0, 0, 'q'), KEYPRESS(0, 0, 'Q'));
464 static void print_timeout_status(const char *label
, uint64_t t
) {
468 case TIMEOUT_MENU_DISABLED
:
469 return (void) printf("%s: menu-disabled\n", label
);
470 case TIMEOUT_MENU_FORCE
:
471 return (void) printf("%s: menu-force\n", label
);
472 case TIMEOUT_MENU_HIDDEN
:
473 return (void) printf("%s: menu-hidden\n", label
);
475 return (void) printf("%s: %u s\n", label
, (uint32_t)t
);
479 static void print_status(Config
*config
, char16_t
*loaded_image_path
) {
481 uint32_t screen_width
= 0, screen_height
= 0;
482 SecureBootMode secure
;
483 _cleanup_free_ char16_t
*device_part_uuid
= NULL
;
487 clear_screen(COLOR_NORMAL
);
488 console_query_mode(&x_max
, &y_max
);
489 query_screen_resolution(&screen_width
, &screen_height
);
491 secure
= secure_boot_mode();
492 (void) efivar_get(MAKE_GUID_PTR(LOADER
), u
"LoaderDevicePartUUID", &device_part_uuid
);
494 printf(" systemd-boot version: " GIT_VERSION
"\n");
495 if (loaded_image_path
)
496 printf(" loaded image: %ls\n", loaded_image_path
);
497 if (device_part_uuid
)
498 printf(" loader partition UUID: %ls\n", device_part_uuid
);
499 printf(" architecture: " EFI_MACHINE_TYPE_NAME
"\n");
500 printf(" UEFI specification: %u.%02u\n", ST
->Hdr
.Revision
>> 16, ST
->Hdr
.Revision
& 0xffff);
501 printf(" firmware vendor: %ls\n", ST
->FirmwareVendor
);
502 printf(" firmware version: %u.%02u\n", ST
->FirmwareRevision
>> 16, ST
->FirmwareRevision
& 0xffff);
503 printf(" OS indications: %#" PRIx64
"\n", get_os_indications_supported());
504 printf(" secure boot: %ls (%ls)\n",
505 yes_no(IN_SET(secure
, SECURE_BOOT_USER
, SECURE_BOOT_DEPLOYED
)),
506 secure_boot_mode_to_string(secure
));
507 printf(" shim: %ls\n", yes_no(shim_loaded()));
508 printf(" TPM: %ls\n", yes_no(tpm_present()));
509 printf(" console mode: %i/%" PRIi64
" (%zux%zu @%ux%u)\n",
510 ST
->ConOut
->Mode
->Mode
, ST
->ConOut
->Mode
->MaxMode
- INT64_C(1),
511 x_max
, y_max
, screen_width
, screen_height
);
516 print_timeout_status(" timeout (config)", config
->timeout_sec_config
);
517 print_timeout_status(" timeout (EFI var)", config
->timeout_sec_efivar
);
519 if (config
->entry_default_config
)
520 printf(" default (config): %ls\n", config
->entry_default_config
);
521 if (config
->entry_default_efivar
)
522 printf(" default (EFI var): %ls\n", config
->entry_default_efivar
);
523 if (config
->entry_oneshot
)
524 printf(" default (one-shot): %ls\n", config
->entry_oneshot
);
525 if (config
->entry_saved
)
526 printf(" saved entry: %ls\n", config
->entry_saved
);
527 printf(" editor: %ls\n", yes_no(config
->editor
));
528 printf(" auto-entries: %ls\n", yes_no(config
->auto_entries
));
529 printf(" auto-firmware: %ls\n", yes_no(config
->auto_firmware
));
530 printf(" auto-poweroff: %ls\n", yes_no(config
->auto_poweroff
));
531 printf(" auto-reboot: %ls\n", yes_no(config
->auto_reboot
));
532 printf(" beep: %ls\n", yes_no(config
->beep
));
533 printf(" reboot-for-bitlocker: %ls\n", yes_no(config
->reboot_for_bitlocker
));
535 switch (config
->secure_boot_enroll
) {
537 printf(" secure-boot-enroll: off\n");
540 printf(" secure-boot-enroll: manual\n");
543 printf(" secure-boot-enroll: if-safe\n");
546 printf(" secure-boot-enroll: force\n");
549 assert_not_reached();
552 switch (config
->console_mode
) {
553 case CONSOLE_MODE_AUTO
:
554 printf(" console-mode (config): auto\n");
556 case CONSOLE_MODE_KEEP
:
557 printf(" console-mode (config): keep\n");
559 case CONSOLE_MODE_FIRMWARE_MAX
:
560 printf(" console-mode (config): max\n");
563 printf(" console-mode (config): %" PRIi64
"\n", config
->console_mode
);
567 /* EFI var console mode is always a concrete value or unset. */
568 if (config
->console_mode_efivar
!= CONSOLE_MODE_KEEP
)
569 printf("console-mode (EFI var): %" PRIi64
"\n", config
->console_mode_efivar
);
574 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
575 BootEntry
*entry
= config
->entries
[i
];
576 EFI_DEVICE_PATH
*dp
= NULL
;
577 _cleanup_free_ char16_t
*dp_str
= NULL
;
580 BS
->HandleProtocol(entry
->device
, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL
), (void **) &dp
) ==
582 (void) device_path_to_str(dp
, &dp_str
);
584 printf(" boot entry: %zu/%zu\n", i
+ 1, config
->n_entries
);
585 printf(" id: %ls\n", entry
->id
);
587 printf(" title: %ls\n", entry
->title
);
588 if (entry
->title_show
&& !streq16(entry
->title
, entry
->title_show
))
589 printf(" title show: %ls\n", entry
->title_show
);
591 printf(" sort key: %ls\n", entry
->sort_key
);
593 printf(" version: %ls\n", entry
->version
);
594 if (entry
->machine_id
)
595 printf(" machine-id: %ls\n", entry
->machine_id
);
597 printf(" device: %ls\n", dp_str
);
599 printf(" loader: %ls\n", entry
->loader
);
600 STRV_FOREACH(initrd
, entry
->initrd
)
601 printf(" initrd: %ls\n", *initrd
);
602 if (entry
->devicetree
)
603 printf(" devicetree: %ls\n", entry
->devicetree
);
605 printf(" options: %ls\n", entry
->options
);
606 printf(" internal call: %ls\n", yes_no(!!entry
->call
));
608 printf("counting boots: %ls\n", yes_no(entry
->tries_left
>= 0));
609 if (entry
->tries_left
>= 0) {
610 printf(" tries: %i left, %i done\n", entry
->tries_left
, entry
->tries_done
);
611 printf(" current path: %ls\\%ls\n", entry
->path
, entry
->current_name
);
612 printf(" next path: %ls\\%ls\n", entry
->path
, entry
->next_name
);
620 static EFI_STATUS
set_reboot_into_firmware(void) {
624 (void) efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE
), u
"OsIndications", &osind
);
625 osind
|= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
627 err
= efivar_set_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE
), u
"OsIndications", osind
, EFI_VARIABLE_NON_VOLATILE
);
628 if (err
!= EFI_SUCCESS
)
629 log_error_status(err
, "Error setting OsIndications: %m");
633 _noreturn_
static EFI_STATUS
poweroff_system(void) {
634 RT
->ResetSystem(EfiResetShutdown
, EFI_SUCCESS
, 0, NULL
);
635 assert_not_reached();
638 _noreturn_
static EFI_STATUS
reboot_system(void) {
639 RT
->ResetSystem(EfiResetCold
, EFI_SUCCESS
, 0, NULL
);
640 assert_not_reached();
643 static EFI_STATUS
reboot_into_firmware(void) {
646 err
= set_reboot_into_firmware();
647 if (err
!= EFI_SUCCESS
)
650 return reboot_system();
653 static bool menu_run(
655 BootEntry
**chosen_entry
,
656 char16_t
*loaded_image_path
) {
659 assert(chosen_entry
);
662 size_t visible_max
= 0;
663 size_t idx_highlight
= config
->idx_default
, idx_highlight_prev
= 0;
664 size_t idx
, idx_first
= 0, idx_last
= 0;
665 bool new_mode
= true, clear
= true;
666 bool refresh
= true, highlight
= false;
667 size_t x_start
= 0, y_start
= 0, y_status
= 0, x_max
, y_max
;
668 _cleanup_(strv_freep
) char16_t
**lines
= NULL
;
669 _cleanup_free_ char16_t
*clearline
= NULL
, *separator
= NULL
, *status
= NULL
;
670 uint64_t timeout_efivar_saved
= config
->timeout_sec_efivar
;
671 uint32_t timeout_remain
= config
->timeout_sec
== TIMEOUT_MENU_FORCE
? 0 : config
->timeout_sec
;
672 int64_t console_mode_initial
= ST
->ConOut
->Mode
->Mode
, console_mode_efivar_saved
= config
->console_mode_efivar
;
673 size_t default_efivar_saved
= config
->idx_default_efivar
;
676 ACTION_CONTINUE
, /* Continue with loop over user input */
677 ACTION_FIRMWARE_SETUP
, /* Ask for confirmation and reboot into firmware setup */
678 ACTION_POWEROFF
, /* Power off the machine */
679 ACTION_REBOOT
, /* Reboot the machine */
680 ACTION_RUN
, /* Execute a boot entry */
681 ACTION_QUIT
, /* Return to the firmware */
682 } action
= ACTION_CONTINUE
;
684 graphics_mode(false);
685 ST
->ConIn
->Reset(ST
->ConIn
, false);
686 ST
->ConOut
->EnableCursor(ST
->ConOut
, false);
688 /* draw a single character to make ClearScreen work on some firmware */
689 ST
->ConOut
->OutputString(ST
->ConOut
, (char16_t
*) u
" ");
691 err
= console_set_mode(config
->console_mode_efivar
!= CONSOLE_MODE_KEEP
?
692 config
->console_mode_efivar
: config
->console_mode
);
693 if (err
!= EFI_SUCCESS
) {
694 clear_screen(COLOR_NORMAL
);
695 log_error_status(err
, "Error switching console mode: %m");
698 size_t line_width
= 0, entry_padding
= 3;
699 while (IN_SET(action
, ACTION_CONTINUE
, ACTION_FIRMWARE_SETUP
)) {
703 console_query_mode(&x_max
, &y_max
);
705 /* account for padding+status */
706 visible_max
= y_max
- 2;
708 /* Drawing entries starts at idx_first until idx_last. We want to make
709 * sure that idx_highlight is centered, but not if we are close to the
710 * beginning/end of the entry list. Otherwise we would have a half-empty
712 if (config
->n_entries
<= visible_max
|| idx_highlight
<= visible_max
/ 2)
714 else if (idx_highlight
>= config
->n_entries
- (visible_max
/ 2))
715 idx_first
= config
->n_entries
- visible_max
;
717 idx_first
= idx_highlight
- (visible_max
/ 2);
718 idx_last
= idx_first
+ visible_max
- 1;
720 /* length of the longest entry */
722 for (size_t i
= 0; i
< config
->n_entries
; i
++)
723 line_width
= MAX(line_width
, strlen16(config
->entries
[i
]->title_show
));
724 line_width
= MIN(line_width
+ 2 * entry_padding
, x_max
);
726 /* offsets to center the entries on the screen */
727 x_start
= (x_max
- (line_width
)) / 2;
728 if (config
->n_entries
< visible_max
)
729 y_start
= ((visible_max
- config
->n_entries
) / 2) + 1;
733 /* Put status line after the entry list, but give it some breathing room. */
734 y_status
= MIN(y_start
+ MIN(visible_max
, config
->n_entries
) + 1, y_max
- 1);
736 lines
= strv_free(lines
);
737 clearline
= mfree(clearline
);
738 separator
= mfree(separator
);
740 /* menu entries title lines */
741 lines
= xnew(char16_t
*, config
->n_entries
+ 1);
743 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
744 size_t width
= line_width
- MIN(strlen16(config
->entries
[i
]->title_show
), line_width
);
745 size_t padding
= width
/ 2;
746 bool odd
= width
% 2;
748 /* Make sure there is space for => */
749 padding
= MAX((size_t) 2, padding
);
751 size_t print_width
= MIN(
752 strlen16(config
->entries
[i
]->title_show
),
753 line_width
- padding
* 2);
755 assert((padding
+ 1) <= INT_MAX
);
756 assert(print_width
<= INT_MAX
);
758 lines
[i
] = xasprintf(
761 (int) print_width
, config
->entries
[i
]->title_show
,
762 odd
? (int) (padding
+ 1) : (int) padding
, u
"");
764 lines
[config
->n_entries
] = NULL
;
766 clearline
= xnew(char16_t
, x_max
+ 1);
767 separator
= xnew(char16_t
, x_max
+ 1);
768 for (size_t i
= 0; i
< x_max
; i
++) {
770 separator
[i
] = unicode_supported() ? L
'─' : L
'-';
772 clearline
[x_max
] = 0;
773 separator
[x_max
] = 0;
780 clear_screen(COLOR_NORMAL
);
786 for (size_t i
= idx_first
; i
<= idx_last
&& i
< config
->n_entries
; i
++) {
787 print_at(x_start
, y_start
+ i
- idx_first
,
788 i
== idx_highlight
? COLOR_HIGHLIGHT
: COLOR_ENTRY
,
790 if (i
== config
->idx_default_efivar
)
792 y_start
+ i
- idx_first
,
793 i
== idx_highlight
? COLOR_HIGHLIGHT
: COLOR_ENTRY
,
794 unicode_supported() ? u
" ►" : u
"=>");
797 } else if (highlight
) {
798 print_at(x_start
, y_start
+ idx_highlight_prev
- idx_first
, COLOR_ENTRY
, lines
[idx_highlight_prev
]);
799 print_at(x_start
, y_start
+ idx_highlight
- idx_first
, COLOR_HIGHLIGHT
, lines
[idx_highlight
]);
800 if (idx_highlight_prev
== config
->idx_default_efivar
)
802 y_start
+ idx_highlight_prev
- idx_first
,
804 unicode_supported() ? u
" ►" : u
"=>");
805 if (idx_highlight
== config
->idx_default_efivar
)
807 y_start
+ idx_highlight
- idx_first
,
809 unicode_supported() ? u
" ►" : u
"=>");
813 if (timeout_remain
> 0) {
815 status
= xasprintf("Boot in %u s.", timeout_remain
);
819 /* If we draw the last char of the last line, the screen will scroll and break our
820 * input. Therefore, draw one less character then we could for the status message.
821 * Note that the same does not apply for the separator line as it will never be drawn
822 * on the last line. */
823 size_t len
= strnlen16(status
, x_max
- 1);
824 size_t x
= (x_max
- len
) / 2;
826 print_at(0, y_status
, COLOR_NORMAL
, clearline
+ x_max
- x
);
827 ST
->ConOut
->OutputString(ST
->ConOut
, status
);
828 ST
->ConOut
->OutputString(ST
->ConOut
, clearline
+ 1 + x
+ len
);
830 len
= MIN(MAX(len
, line_width
) + 2 * entry_padding
, x_max
);
831 x
= (x_max
- len
) / 2;
832 print_at(x
, y_status
- 1, COLOR_NORMAL
, separator
+ x_max
- len
);
834 print_at(0, y_status
- 1, COLOR_NORMAL
, clearline
);
835 print_at(0, y_status
, COLOR_NORMAL
, clearline
+ 1); /* See comment above. */
838 /* Beep several times so that the selected entry can be distinguished. */
840 beep(idx_highlight
+ 1);
842 err
= console_key_read(&key
, timeout_remain
> 0 ? 1000 * 1000 : UINT64_MAX
);
843 if (err
== EFI_NOT_READY
)
844 /* No input device returned a key, try again. This
845 * normally should not happen. */
847 if (err
== EFI_TIMEOUT
) {
848 assert(timeout_remain
> 0);
850 if (timeout_remain
== 0) {
858 if (err
!= EFI_SUCCESS
) {
865 /* clear status after keystroke */
866 status
= mfree(status
);
868 idx_highlight_prev
= idx_highlight
;
870 if (action
== ACTION_FIRMWARE_SETUP
) {
871 if (IN_SET(key
, KEYPRESS(0, 0, '\r'), KEYPRESS(0, 0, '\n')) &&
872 set_reboot_into_firmware() == EFI_SUCCESS
)
875 /* Any key other than newline or a failed attempt cancel the request. */
876 action
= ACTION_CONTINUE
;
881 case KEYPRESS(0, SCAN_UP
, 0):
882 case KEYPRESS(0, 0, 'k'):
883 case KEYPRESS(0, 0, 'K'):
884 if (idx_highlight
> 0)
888 case KEYPRESS(0, SCAN_DOWN
, 0):
889 case KEYPRESS(0, 0, 'j'):
890 case KEYPRESS(0, 0, 'J'):
891 if (idx_highlight
< config
->n_entries
-1)
895 case KEYPRESS(0, SCAN_HOME
, 0):
896 case KEYPRESS(EFI_ALT_PRESSED
, 0, '<'):
897 if (idx_highlight
> 0) {
903 case KEYPRESS(0, SCAN_END
, 0):
904 case KEYPRESS(EFI_ALT_PRESSED
, 0, '>'):
905 if (idx_highlight
< config
->n_entries
-1) {
907 idx_highlight
= config
->n_entries
-1;
911 case KEYPRESS(0, SCAN_PAGE_UP
, 0):
912 if (idx_highlight
> visible_max
)
913 idx_highlight
-= visible_max
;
918 case KEYPRESS(0, SCAN_PAGE_DOWN
, 0):
919 idx_highlight
+= visible_max
;
920 if (idx_highlight
> config
->n_entries
-1)
921 idx_highlight
= config
->n_entries
-1;
924 case KEYPRESS(0, 0, '\n'):
925 case KEYPRESS(0, 0, '\r'):
926 case KEYPRESS(0, SCAN_F3
, 0): /* EZpad Mini 4s firmware sends malformed events */
927 case KEYPRESS(0, SCAN_F3
, '\r'): /* Teclast X98+ II firmware sends malformed events */
928 case KEYPRESS(0, SCAN_RIGHT
, 0):
932 case KEYPRESS(0, SCAN_F1
, 0):
933 case KEYPRESS(0, 0, 'h'):
934 case KEYPRESS(0, 0, 'H'):
935 case KEYPRESS(0, 0, '?'):
936 /* This must stay below 80 characters! Q/v/Ctrl+l/f deliberately not advertised. */
937 status
= xasprintf("(d)efault (t/T)imeout (e)dit (r/R)esolution (p)rint %s%s(h)elp",
938 config
->auto_poweroff
? "" : "(O)ff ",
939 config
->auto_reboot
? "" : "re(B)oot ");
942 case KEYPRESS(0, 0, 'Q'):
943 action
= ACTION_QUIT
;
946 case KEYPRESS(0, 0, 'd'):
947 case KEYPRESS(0, 0, 'D'):
948 if (config
->idx_default_efivar
!= idx_highlight
) {
949 free(config
->entry_default_efivar
);
950 config
->entry_default_efivar
= xstrdup16(config
->entries
[idx_highlight
]->id
);
951 config
->idx_default_efivar
= idx_highlight
;
952 status
= xstrdup16(u
"Default boot entry selected.");
954 config
->entry_default_efivar
= mfree(config
->entry_default_efivar
);
955 config
->idx_default_efivar
= IDX_INVALID
;
956 status
= xstrdup16(u
"Default boot entry cleared.");
958 config
->use_saved_entry_efivar
= false;
962 case KEYPRESS(0, 0, '-'):
963 case KEYPRESS(0, 0, 'T'):
964 status
= update_timeout_efivar(config
, false);
967 case KEYPRESS(0, 0, '+'):
968 case KEYPRESS(0, 0, 't'):
969 status
= update_timeout_efivar(config
, true);
972 case KEYPRESS(0, 0, 'e'):
973 case KEYPRESS(0, 0, 'E'):
974 /* only the options of configured entries can be edited */
975 if (!config
->editor
||
976 !IN_SET(config
->entries
[idx_highlight
]->type
, LOADER_EFI
, LOADER_LINUX
, LOADER_UNIFIED_LINUX
)) {
977 status
= xstrdup16(u
"Entry does not support editing the command line.");
981 /* Unified kernels that are signed as a whole will not accept command line options
982 * when secure boot is enabled unless there is none embedded in the image. Do not try
983 * to pretend we can edit it to only have it be ignored. */
984 if (config
->entries
[idx_highlight
]->type
== LOADER_UNIFIED_LINUX
&&
985 secure_boot_enabled() &&
986 config
->entries
[idx_highlight
]->options
) {
987 status
= xstrdup16(u
"Entry not editable in SecureBoot mode.");
991 /* The edit line may end up on the last line of the screen. And even though we're
992 * not telling the firmware to advance the line, it still does in this one case,
993 * causing a scroll to happen that screws with our beautiful boot loader output.
994 * Since we cannot paint the last character of the edit line, we simply start
995 * at x-offset 1 for symmetry. */
996 print_at(1, y_status
, COLOR_EDIT
, clearline
+ 2);
997 if (line_edit(&config
->entries
[idx_highlight
]->options
, x_max
- 2, y_status
))
999 print_at(1, y_status
, COLOR_NORMAL
, clearline
+ 2);
1001 /* The options string was now edited, hence we have to pass it to the invoked
1003 config
->entries
[idx_highlight
]->options_implied
= false;
1006 case KEYPRESS(0, 0, 'v'):
1008 "systemd-boot " GIT_VERSION
" (" EFI_MACHINE_TYPE_NAME
"), "
1009 "UEFI Specification %u.%02u, Vendor %ls %u.%02u",
1010 ST
->Hdr
.Revision
>> 16,
1011 ST
->Hdr
.Revision
& 0xffff,
1013 ST
->FirmwareRevision
>> 16,
1014 ST
->FirmwareRevision
& 0xffff);
1017 case KEYPRESS(0, 0, 'p'):
1018 case KEYPRESS(0, 0, 'P'):
1019 print_status(config
, loaded_image_path
);
1023 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, 'l'):
1024 case KEYPRESS(EFI_CONTROL_PRESSED
, 0, CHAR_CTRL('l')):
1025 case 'L': /* only uppercase, do not conflict with lower-case 'l' which picks first Linux entry */
1029 case KEYPRESS(0, 0, 'r'):
1030 err
= console_set_mode(CONSOLE_MODE_NEXT
);
1031 if (err
!= EFI_SUCCESS
)
1032 status
= xasprintf_status(err
, "Error changing console mode: %m");
1034 config
->console_mode_efivar
= ST
->ConOut
->Mode
->Mode
;
1036 "Console mode changed to %" PRIi64
".",
1037 config
->console_mode_efivar
);
1042 case KEYPRESS(0, 0, 'R'):
1043 config
->console_mode_efivar
= CONSOLE_MODE_KEEP
;
1044 err
= console_set_mode(config
->console_mode
== CONSOLE_MODE_KEEP
?
1045 console_mode_initial
: config
->console_mode
);
1046 if (err
!= EFI_SUCCESS
)
1047 status
= xasprintf_status(err
, "Error resetting console mode: %m");
1050 "Console mode reset to %s default.",
1051 config
->console_mode
== CONSOLE_MODE_KEEP
?
1053 "configuration file");
1057 case KEYPRESS(0, 0, 'f'):
1058 case KEYPRESS(0, 0, 'F'):
1059 case KEYPRESS(0, SCAN_F2
, 0): /* Most vendors. */
1060 case KEYPRESS(0, SCAN_F10
, 0): /* HP and Lenovo. */
1061 case KEYPRESS(0, SCAN_DELETE
, 0): /* Same as F2. */
1062 case KEYPRESS(0, SCAN_ESC
, 0): /* HP. */
1063 if (FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI
)) {
1064 action
= ACTION_FIRMWARE_SETUP
;
1065 /* Let's make sure the user really wants to do this. */
1066 status
= xstrdup16(u
"Press Enter to reboot into firmware interface.");
1068 status
= xstrdup16(u
"Reboot into firmware interface not supported.");
1071 case KEYPRESS(0, 0, 'O'): /* Only uppercase, so that it can't be hit so easily fat-fingered,
1072 * but still works safely over serial. */
1073 action
= ACTION_POWEROFF
;
1076 case KEYPRESS(0, 0, 'B'): /* ditto */
1077 action
= ACTION_REBOOT
;
1081 /* jump with a hotkey directly to a matching entry */
1082 idx
= entry_lookup_key(config
, idx_highlight
+1, KEYCHAR(key
));
1083 if (idx
== IDX_INVALID
)
1085 idx_highlight
= idx
;
1089 if (idx_highlight
> idx_last
) {
1090 idx_last
= idx_highlight
;
1091 idx_first
= 1 + idx_highlight
- visible_max
;
1093 } else if (idx_highlight
< idx_first
) {
1094 idx_first
= idx_highlight
;
1095 idx_last
= idx_highlight
+ visible_max
-1;
1099 if (!refresh
&& idx_highlight
!= idx_highlight_prev
)
1103 /* Update EFI vars after we left the menu to reduce NVRAM writes. */
1105 if (default_efivar_saved
!= config
->idx_default_efivar
)
1106 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryDefault", config
->entry_default_efivar
, EFI_VARIABLE_NON_VOLATILE
);
1108 if (console_mode_efivar_saved
!= config
->console_mode_efivar
) {
1109 if (config
->console_mode_efivar
== CONSOLE_MODE_KEEP
)
1110 efivar_unset(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigConsoleMode", EFI_VARIABLE_NON_VOLATILE
);
1112 efivar_set_uint_string(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigConsoleMode",
1113 config
->console_mode_efivar
, EFI_VARIABLE_NON_VOLATILE
);
1116 if (timeout_efivar_saved
!= config
->timeout_sec_efivar
) {
1117 switch (config
->timeout_sec_efivar
) {
1119 efivar_unset(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigTimeout", EFI_VARIABLE_NON_VOLATILE
);
1121 case TIMEOUT_MENU_DISABLED
:
1122 assert_not_reached();
1123 case TIMEOUT_MENU_FORCE
:
1124 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigTimeout", u
"menu-force", EFI_VARIABLE_NON_VOLATILE
);
1126 case TIMEOUT_MENU_HIDDEN
:
1127 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigTimeout", u
"menu-hidden", EFI_VARIABLE_NON_VOLATILE
);
1130 assert(config
->timeout_sec_efivar
< UINT32_MAX
);
1131 efivar_set_uint_string(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigTimeout",
1132 config
->timeout_sec_efivar
, EFI_VARIABLE_NON_VOLATILE
);
1137 case ACTION_CONTINUE
:
1138 assert_not_reached();
1139 case ACTION_POWEROFF
:
1142 case ACTION_FIRMWARE_SETUP
:
1149 *chosen_entry
= config
->entries
[idx_highlight
];
1150 clear_screen(COLOR_NORMAL
);
1151 return action
== ACTION_RUN
;
1154 static void config_add_entry(Config
*config
, BootEntry
*entry
) {
1158 /* This is just for paranoia. */
1159 assert(config
->n_entries
< IDX_MAX
);
1161 if ((config
->n_entries
& 15) == 0) {
1162 config
->entries
= xrealloc(
1164 sizeof(void *) * config
->n_entries
,
1165 sizeof(void *) * (config
->n_entries
+ 16));
1167 config
->entries
[config
->n_entries
++] = entry
;
1170 static BootEntry
* boot_entry_free(BootEntry
*entry
) {
1175 free(entry
->title_show
);
1177 free(entry
->sort_key
);
1178 free(entry
->version
);
1179 free(entry
->machine_id
);
1180 free(entry
->loader
);
1181 free(entry
->devicetree
);
1182 free(entry
->options
);
1183 strv_free(entry
->initrd
);
1185 free(entry
->current_name
);
1186 free(entry
->next_name
);
1188 return mfree(entry
);
1191 DEFINE_TRIVIAL_CLEANUP_FUNC(BootEntry
*, boot_entry_free
);
1193 static void config_defaults_load_from_file(Config
*config
, char *content
) {
1201 while ((line
= line_get_key_value(content
, " \t", &pos
, &key
, &value
)))
1202 if (streq8(key
, "timeout")) {
1203 if (streq8(value
, "menu-disabled"))
1204 config
->timeout_sec_config
= TIMEOUT_MENU_DISABLED
;
1205 else if (streq8(value
, "menu-force"))
1206 config
->timeout_sec_config
= TIMEOUT_MENU_FORCE
;
1207 else if (streq8(value
, "menu-hidden"))
1208 config
->timeout_sec_config
= TIMEOUT_MENU_HIDDEN
;
1211 if (!parse_number8(value
, &u
, NULL
) || u
> TIMEOUT_TYPE_MAX
) {
1212 log_error("Error parsing 'timeout' config option, ignoring: %s",
1216 config
->timeout_sec_config
= u
;
1218 config
->timeout_sec
= config
->timeout_sec_config
;
1220 } else if (streq8(key
, "default")) {
1221 if (value
[0] == '@' && !strcaseeq8(value
, "@saved")) {
1222 log_error("Unsupported special entry identifier, ignoring: %s", value
);
1225 free(config
->entry_default_config
);
1226 config
->entry_default_config
= xstr8_to_16(value
);
1228 } else if (streq8(key
, "editor")) {
1229 if (!parse_boolean(value
, &config
->editor
))
1230 log_error("Error parsing 'editor' config option, ignoring: %s", value
);
1232 } else if (streq8(key
, "auto-entries")) {
1233 if (!parse_boolean(value
, &config
->auto_entries
))
1234 log_error("Error parsing 'auto-entries' config option, ignoring: %s", value
);
1236 } else if (streq8(key
, "auto-firmware")) {
1237 if (!parse_boolean(value
, &config
->auto_firmware
))
1238 log_error("Error parsing 'auto-firmware' config option, ignoring: %s", value
);
1240 } else if (streq8(key
, "auto-poweroff")) {
1241 if (!parse_boolean(value
, &config
->auto_poweroff
))
1242 log_error("Error parsing 'auto-poweroff' config option, ignoring: %s", value
);
1244 } else if (streq8(key
, "auto-reboot")) {
1245 if (!parse_boolean(value
, &config
->auto_reboot
))
1246 log_error("Error parsing 'auto-reboot' config option, ignoring: %s", value
);
1248 } else if (streq8(key
, "beep")) {
1249 if (!parse_boolean(value
, &config
->beep
))
1250 log_error("Error parsing 'beep' config option, ignoring: %s", value
);
1252 } else if (streq8(key
, "reboot-for-bitlocker")) {
1253 if (!parse_boolean(value
, &config
->reboot_for_bitlocker
))
1254 log_error("Error parsing 'reboot-for-bitlocker' config option, ignoring: %s",
1257 } else if (streq8(key
, "secure-boot-enroll")) {
1258 if (streq8(value
, "manual"))
1259 config
->secure_boot_enroll
= ENROLL_MANUAL
;
1260 else if (streq8(value
, "force"))
1261 config
->secure_boot_enroll
= ENROLL_FORCE
;
1262 else if (streq8(value
, "if-safe"))
1263 config
->secure_boot_enroll
= ENROLL_IF_SAFE
;
1264 else if (streq8(value
, "off"))
1265 config
->secure_boot_enroll
= ENROLL_OFF
;
1267 log_error("Error parsing 'secure-boot-enroll' config option, ignoring: %s",
1270 } else if (streq8(key
, "console-mode")) {
1271 if (streq8(value
, "auto"))
1272 config
->console_mode
= CONSOLE_MODE_AUTO
;
1273 else if (streq8(value
, "max"))
1274 config
->console_mode
= CONSOLE_MODE_FIRMWARE_MAX
;
1275 else if (streq8(value
, "keep"))
1276 config
->console_mode
= CONSOLE_MODE_KEEP
;
1279 if (!parse_number8(value
, &u
, NULL
) || u
> CONSOLE_MODE_RANGE_MAX
) {
1280 log_error("Error parsing 'console-mode' config option, ignoring: %s",
1284 config
->console_mode
= u
;
1289 static void boot_entry_parse_tries(
1291 const char16_t
*path
,
1292 const char16_t
*file
,
1293 const char16_t
*suffix
) {
1301 * Parses a suffix of two counters (one going down, one going up) in the form "+LEFT-DONE" from the end of the
1302 * filename (but before the .efi/.conf suffix), where the "-DONE" part is optional and may be left out (in
1303 * which case that counter as assumed to be zero, i.e. the missing part is synonymous to "-0").
1305 * Names we grok, and the series they result in:
1307 * foobar+3.efi → foobar+2-1.efi → foobar+1-2.efi → foobar+0-3.efi → STOP!
1308 * foobar+4-0.efi → foobar+3-1.efi → foobar+2-2.efi → foobar+1-3.efi → foobar+0-4.efi → STOP!
1311 const char16_t
*counter
= NULL
;
1313 char16_t
*plus
= strchr16(counter
?: file
, '+');
1315 /* We want the last "+". */
1322 /* No boot counter found. */
1326 uint64_t tries_left
, tries_done
= 0;
1327 size_t prefix_len
= counter
- file
;
1329 if (!parse_number16(counter
, &tries_left
, &counter
) || tries_left
> INT_MAX
)
1332 /* Parse done counter only if present. */
1333 if (*counter
== '-' && (!parse_number16(counter
+ 1, &tries_done
, &counter
) || tries_done
> INT_MAX
))
1336 /* Boot counter in the middle of the name? */
1337 if (!streq16(counter
, suffix
))
1340 entry
->tries_left
= tries_left
;
1341 entry
->tries_done
= tries_done
;
1342 entry
->path
= xstrdup16(path
);
1343 entry
->current_name
= xstrdup16(file
);
1344 entry
->next_name
= xasprintf(
1345 "%.*ls%" PRIu64
"-%" PRIu64
"%ls",
1348 LESS_BY(tries_left
, 1u),
1349 MIN(tries_done
+ 1, (uint64_t) INT_MAX
),
1353 static EFI_STATUS
boot_entry_bump_counters(BootEntry
*entry
) {
1354 _cleanup_free_ char16_t
* old_path
= NULL
, *new_path
= NULL
;
1355 _cleanup_(file_closep
) EFI_FILE
*handle
= NULL
;
1356 _cleanup_free_ EFI_FILE_INFO
*file_info
= NULL
;
1357 size_t file_info_size
;
1362 if (entry
->tries_left
< 0)
1365 if (!entry
->path
|| !entry
->current_name
|| !entry
->next_name
)
1368 _cleanup_(file_closep
) EFI_FILE
*root
= NULL
;
1369 err
= open_volume(entry
->device
, &root
);
1370 if (err
!= EFI_SUCCESS
)
1371 return log_error_status(err
, "Error opening entry root path: %m");
1373 old_path
= xasprintf("%ls\\%ls", entry
->path
, entry
->current_name
);
1375 err
= root
->Open(root
, &handle
, old_path
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
, 0ULL);
1376 if (err
!= EFI_SUCCESS
)
1377 return log_error_status(err
, "Error opening boot entry: %m");
1379 err
= get_file_info(handle
, &file_info
, &file_info_size
);
1380 if (err
!= EFI_SUCCESS
)
1381 return log_error_status(err
, "Error getting boot entry file info: %m");
1383 /* And rename the file */
1384 strcpy16(file_info
->FileName
, entry
->next_name
);
1385 err
= handle
->SetInfo(handle
, MAKE_GUID_PTR(EFI_FILE_INFO
), file_info_size
, file_info
);
1386 if (err
!= EFI_SUCCESS
)
1387 return log_error_status(
1388 err
, "Failed to rename '%ls' to '%ls', ignoring: %m", old_path
, entry
->next_name
);
1390 /* Flush everything to disk, just in case… */
1391 err
= handle
->Flush(handle
);
1392 if (err
!= EFI_SUCCESS
)
1393 return log_error_status(err
, "Error flushing boot entry file info: %m");
1395 /* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on
1397 new_path
= xasprintf("%ls\\%ls", entry
->path
, entry
->next_name
);
1398 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderBootCountPath", new_path
, 0);
1400 /* If the file we just renamed is the loader path, then let's update that. */
1401 if (streq16(entry
->loader
, old_path
)) {
1402 free(entry
->loader
);
1403 entry
->loader
= TAKE_PTR(new_path
);
1409 static void boot_entry_add_type1(
1413 const char16_t
*path
,
1414 const char16_t
*file
,
1416 const char16_t
*loaded_image_path
) {
1418 _cleanup_(boot_entry_freep
) BootEntry
*entry
= NULL
;
1420 size_t pos
= 0, n_initrd
= 0;
1431 entry
= xnew(BootEntry
, 1);
1432 *entry
= (BootEntry
) {
1437 while ((line
= line_get_key_value(content
, " \t", &pos
, &key
, &value
)))
1438 if (streq8(key
, "title")) {
1440 entry
->title
= xstr8_to_16(value
);
1442 } else if (streq8(key
, "sort-key")) {
1443 free(entry
->sort_key
);
1444 entry
->sort_key
= xstr8_to_16(value
);
1446 } else if (streq8(key
, "version")) {
1447 free(entry
->version
);
1448 entry
->version
= xstr8_to_16(value
);
1450 } else if (streq8(key
, "machine-id")) {
1451 free(entry
->machine_id
);
1452 entry
->machine_id
= xstr8_to_16(value
);
1454 } else if (streq8(key
, "linux")) {
1455 free(entry
->loader
);
1456 entry
->type
= LOADER_LINUX
;
1457 entry
->loader
= xstr8_to_path(value
);
1460 } else if (streq8(key
, "efi")) {
1461 entry
->type
= LOADER_EFI
;
1462 free(entry
->loader
);
1463 entry
->loader
= xstr8_to_path(value
);
1465 /* do not add an entry for ourselves */
1466 if (strcaseeq16(entry
->loader
, loaded_image_path
)) {
1467 entry
->type
= LOADER_UNDEFINED
;
1471 } else if (streq8(key
, "architecture")) {
1472 /* do not add an entry for an EFI image of architecture not matching with that of the image */
1473 if (!streq8(value
, EFI_MACHINE_TYPE_NAME
)) {
1474 entry
->type
= LOADER_UNDEFINED
;
1478 } else if (streq8(key
, "devicetree")) {
1479 free(entry
->devicetree
);
1480 entry
->devicetree
= xstr8_to_path(value
);
1482 } else if (streq8(key
, "initrd")) {
1483 entry
->initrd
= xrealloc(
1485 n_initrd
== 0 ? 0 : (n_initrd
+ 1) * sizeof(uint16_t *),
1486 (n_initrd
+ 2) * sizeof(uint16_t *));
1487 entry
->initrd
[n_initrd
++] = xstr8_to_path(value
);
1488 entry
->initrd
[n_initrd
] = NULL
;
1490 } else if (streq8(key
, "options")) {
1491 _cleanup_free_ char16_t
*new = NULL
;
1493 new = xstr8_to_16(value
);
1494 if (entry
->options
) {
1495 char16_t
*s
= xasprintf("%ls %ls", entry
->options
, new);
1496 free(entry
->options
);
1499 entry
->options
= TAKE_PTR(new);
1502 if (entry
->type
== LOADER_UNDEFINED
)
1505 /* check existence */
1506 _cleanup_(file_closep
) EFI_FILE
*handle
= NULL
;
1507 err
= root_dir
->Open(root_dir
, &handle
, entry
->loader
, EFI_FILE_MODE_READ
, 0ULL);
1508 if (err
!= EFI_SUCCESS
)
1511 entry
->device
= device
;
1512 entry
->id
= xstrdup16(file
);
1513 strtolower16(entry
->id
);
1515 config_add_entry(config
, entry
);
1517 boot_entry_parse_tries(entry
, path
, file
, u
".conf");
1521 static EFI_STATUS
efivar_get_timeout(const char16_t
*var
, uint64_t *ret_value
) {
1522 _cleanup_free_ char16_t
*value
= NULL
;
1528 err
= efivar_get(MAKE_GUID_PTR(LOADER
), var
, &value
);
1529 if (err
!= EFI_SUCCESS
)
1532 if (streq16(value
, u
"menu-disabled")) {
1533 *ret_value
= TIMEOUT_MENU_DISABLED
;
1536 if (streq16(value
, u
"menu-force")) {
1537 *ret_value
= TIMEOUT_MENU_FORCE
;
1540 if (streq16(value
, u
"menu-hidden")) {
1541 *ret_value
= TIMEOUT_MENU_HIDDEN
;
1546 if (!parse_number16(value
, &timeout
, NULL
))
1547 return EFI_INVALID_PARAMETER
;
1549 *ret_value
= MIN(timeout
, TIMEOUT_TYPE_MAX
);
1553 static void config_load_defaults(Config
*config
, EFI_FILE
*root_dir
) {
1554 _cleanup_free_
char *content
= NULL
;
1555 size_t content_size
, value
= 0; /* avoid false maybe-uninitialized warning */
1560 *config
= (Config
) {
1562 .auto_entries
= true,
1563 .auto_firmware
= true,
1564 .secure_boot_enroll
= ENROLL_IF_SAFE
,
1565 .idx_default_efivar
= IDX_INVALID
,
1566 .console_mode
= CONSOLE_MODE_KEEP
,
1567 .console_mode_efivar
= CONSOLE_MODE_KEEP
,
1568 .timeout_sec_config
= TIMEOUT_UNSET
,
1569 .timeout_sec_efivar
= TIMEOUT_UNSET
,
1572 err
= file_read(root_dir
, u
"\\loader\\loader.conf", 0, 0, &content
, &content_size
);
1573 if (err
== EFI_SUCCESS
) {
1574 /* First, measure. */
1575 err
= tpm_log_tagged_event(
1576 TPM2_PCR_BOOT_LOADER_CONFIG
,
1577 POINTER_TO_PHYSICAL_ADDRESS(content
),
1579 LOADER_CONF_EVENT_TAG_ID
,
1581 /* ret_measured= */ NULL
);
1582 if (err
!= EFI_SUCCESS
)
1583 log_error_status(err
, "Error measuring loader.conf into TPM: %m");
1586 config_defaults_load_from_file(config
, content
);
1589 err
= efivar_get_timeout(u
"LoaderConfigTimeout", &config
->timeout_sec_efivar
);
1590 if (err
== EFI_SUCCESS
)
1591 config
->timeout_sec
= config
->timeout_sec_efivar
;
1592 else if (err
!= EFI_NOT_FOUND
)
1593 log_error_status(err
, "Error reading LoaderConfigTimeout EFI variable: %m");
1595 err
= efivar_get_timeout(u
"LoaderConfigTimeoutOneShot", &config
->timeout_sec
);
1596 if (err
== EFI_SUCCESS
) {
1597 /* Unset variable now, after all it's "one shot". */
1598 (void) efivar_unset(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigTimeoutOneShot", EFI_VARIABLE_NON_VOLATILE
);
1600 config
->force_menu
= true; /* force the menu when this is set */
1601 } else if (err
!= EFI_NOT_FOUND
)
1602 log_error_status(err
, "Error reading LoaderConfigTimeoutOneShot EFI variable: %m");
1604 err
= efivar_get_uint_string(MAKE_GUID_PTR(LOADER
), u
"LoaderConfigConsoleMode", &value
);
1605 if (err
== EFI_SUCCESS
)
1606 config
->console_mode_efivar
= value
;
1608 err
= efivar_get(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryOneShot", &config
->entry_oneshot
);
1609 if (err
== EFI_SUCCESS
)
1610 /* Unset variable now, after all it's "one shot". */
1611 (void) efivar_unset(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryOneShot", EFI_VARIABLE_NON_VOLATILE
);
1613 (void) efivar_get(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryDefault", &config
->entry_default_efivar
);
1615 strtolower16(config
->entry_default_config
);
1616 strtolower16(config
->entry_default_efivar
);
1617 strtolower16(config
->entry_oneshot
);
1618 strtolower16(config
->entry_saved
);
1620 config
->use_saved_entry
= streq16(config
->entry_default_config
, u
"@saved");
1621 config
->use_saved_entry_efivar
= streq16(config
->entry_default_efivar
, u
"@saved");
1622 if (config
->use_saved_entry
|| config
->use_saved_entry_efivar
)
1623 (void) efivar_get(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryLastBooted", &config
->entry_saved
);
1626 static void config_load_type1_entries(
1630 const char16_t
*loaded_image_path
) {
1632 _cleanup_(file_closep
) EFI_FILE
*entries_dir
= NULL
;
1633 _cleanup_free_ EFI_FILE_INFO
*f
= NULL
;
1641 /* Adds Boot Loader Type #1 entries (i.e. /loader/entries/….conf) */
1643 err
= open_directory(root_dir
, u
"\\loader\\entries", &entries_dir
);
1644 if (err
!= EFI_SUCCESS
)
1648 _cleanup_free_
char *content
= NULL
;
1650 err
= readdir(entries_dir
, &f
, &f_size
);
1651 if (err
!= EFI_SUCCESS
|| !f
)
1654 if (f
->FileName
[0] == '.')
1656 if (FLAGS_SET(f
->Attribute
, EFI_FILE_DIRECTORY
))
1659 if (!endswith_no_case(f
->FileName
, u
".conf"))
1661 if (startswith(f
->FileName
, u
"auto-"))
1664 err
= file_read(entries_dir
, f
->FileName
, 0, 0, &content
, NULL
);
1665 if (err
== EFI_SUCCESS
)
1666 boot_entry_add_type1(config
, device
, root_dir
, u
"\\loader\\entries", f
->FileName
, content
, loaded_image_path
);
1670 static int boot_entry_compare(const BootEntry
*a
, const BootEntry
*b
) {
1676 /* Order entries that have no tries left to the end of the list */
1677 r
= CMP(a
->tries_left
== 0, b
->tries_left
== 0);
1681 /* If there's a sort key defined for *both* entries, then we do new-style ordering, i.e. by
1682 * sort-key/machine-id/version, with a final fallback to id. If there's no sort key for either, we do
1683 * old-style ordering, i.e. by id only. If one has sort key and the other does not, we put new-style
1684 * before old-style. */
1685 r
= CMP(!a
->sort_key
, !b
->sort_key
);
1686 if (r
!= 0) /* one is old-style, one new-style */
1689 if (a
->sort_key
&& b
->sort_key
) {
1690 r
= strcmp16(a
->sort_key
, b
->sort_key
);
1694 /* If multiple installations of the same OS are around, group by machine ID */
1695 r
= strcmp16(a
->machine_id
, b
->machine_id
);
1699 /* If the sort key was defined, then order by version now (downwards, putting the newest first) */
1700 r
= -strverscmp_improved(a
->version
, b
->version
);
1705 /* Now order by ID. The version is likely part of the ID, thus note that this will generatelly put
1706 * the newer versions earlier. Specifying a sort key explicitly is preferable, because it gives an
1707 * explicit sort order. */
1708 r
= -strverscmp_improved(a
->id
, b
->id
);
1712 if (a
->tries_left
< 0 || b
->tries_left
< 0)
1715 /* If both items have boot counting, and otherwise are identical, put the entry with more tries left first */
1716 r
= -CMP(a
->tries_left
, b
->tries_left
);
1720 /* If they have the same number of tries left, then let the one win which was tried fewer times so far */
1721 return CMP(a
->tries_done
, b
->tries_done
);
1724 static size_t config_find_entry(Config
*config
, const char16_t
*pattern
) {
1727 /* We expect pattern and entry IDs to be already case folded. */
1732 for (size_t i
= 0; i
< config
->n_entries
; i
++)
1733 if (efi_fnmatch(pattern
, config
->entries
[i
]->id
))
1739 static void config_select_default_entry(Config
*config
) {
1744 i
= config_find_entry(config
, config
->entry_oneshot
);
1745 if (i
!= IDX_INVALID
) {
1746 config
->idx_default
= i
;
1750 i
= config_find_entry(config
, config
->use_saved_entry_efivar
? config
->entry_saved
: config
->entry_default_efivar
);
1751 if (i
!= IDX_INVALID
) {
1752 config
->idx_default
= i
;
1753 config
->idx_default_efivar
= i
;
1757 if (config
->use_saved_entry
)
1758 /* No need to do the same thing twice. */
1759 i
= config
->use_saved_entry_efivar
? IDX_INVALID
: config_find_entry(config
, config
->entry_saved
);
1761 i
= config_find_entry(config
, config
->entry_default_config
);
1762 if (i
!= IDX_INVALID
) {
1763 config
->idx_default
= i
;
1767 /* select the first suitable entry */
1768 for (i
= 0; i
< config
->n_entries
; i
++)
1769 if (config
->entries
[i
]->type
!= LOADER_AUTO
&& !config
->entries
[i
]->call
) {
1770 config
->idx_default
= i
;
1774 /* If no configured entry to select from was found, enable the menu. */
1775 config
->idx_default
= 0;
1776 if (config
->timeout_sec
== 0)
1777 config
->timeout_sec
= 10;
1780 static bool entries_unique(BootEntry
**entries
, bool *unique
, size_t n_entries
) {
1781 bool is_unique
= true;
1786 for (size_t i
= 0; i
< n_entries
; i
++)
1787 for (size_t k
= i
+ 1; k
< n_entries
; k
++) {
1788 if (!streq16(entries
[i
]->title_show
, entries
[k
]->title_show
))
1791 is_unique
= unique
[i
] = unique
[k
] = false;
1797 /* generate unique titles, avoiding non-distinguishable menu entries */
1798 static void generate_boot_entry_titles(Config
*config
) {
1801 bool unique
[config
->n_entries
];
1804 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
1805 assert(!config
->entries
[i
]->title_show
);
1807 config
->entries
[i
]->title_show
= xstrdup16(config
->entries
[i
]->title
?: config
->entries
[i
]->id
);
1810 if (entries_unique(config
->entries
, unique
, config
->n_entries
))
1813 /* add version to non-unique titles */
1814 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
1820 if (!config
->entries
[i
]->version
)
1823 _cleanup_free_ char16_t
*t
= config
->entries
[i
]->title_show
;
1824 config
->entries
[i
]->title_show
= xasprintf("%ls (%ls)", t
, config
->entries
[i
]->version
);
1827 if (entries_unique(config
->entries
, unique
, config
->n_entries
))
1830 /* add machine-id to non-unique titles */
1831 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
1837 if (!config
->entries
[i
]->machine_id
)
1840 _cleanup_free_ char16_t
*t
= config
->entries
[i
]->title_show
;
1841 config
->entries
[i
]->title_show
= xasprintf("%ls (%.8ls)", t
, config
->entries
[i
]->machine_id
);
1844 if (entries_unique(config
->entries
, unique
, config
->n_entries
))
1847 /* add file name to non-unique titles */
1848 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
1852 _cleanup_free_ char16_t
*t
= config
->entries
[i
]->title_show
;
1853 config
->entries
[i
]->title_show
= xasprintf("%ls (%ls)", t
, config
->entries
[i
]->id
);
1857 static bool is_sd_boot(EFI_FILE
*root_dir
, const char16_t
*loader_path
) {
1859 static const char * const sections
[] = {
1863 size_t offset
= 0, size
= 0, read
;
1864 _cleanup_free_
char *content
= NULL
;
1867 assert(loader_path
);
1869 err
= pe_file_locate_sections(root_dir
, loader_path
, sections
, &offset
, &size
);
1870 if (err
!= EFI_SUCCESS
|| size
!= sizeof(SD_MAGIC
))
1873 err
= file_read(root_dir
, loader_path
, offset
, size
, &content
, &read
);
1874 if (err
!= EFI_SUCCESS
|| size
!= read
)
1877 return memcmp(content
, SD_MAGIC
, sizeof(SD_MAGIC
)) == 0;
1880 static BootEntry
* config_add_entry_loader_auto(
1884 const char16_t
*loaded_image_path
,
1887 const char16_t
*title
,
1888 const char16_t
*loader
) {
1896 if (!config
->auto_entries
)
1900 loader
= u
"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME
".efi";
1902 /* We are trying to add the default EFI loader here,
1903 * but we do not want to do that if that would be us.
1905 * If the default loader is not us, it might be shim. It would
1906 * chainload GRUBX64.EFI in that case, which might be us. */
1907 if (strcaseeq16(loader
, loaded_image_path
) ||
1908 is_sd_boot(root_dir
, loader
) ||
1909 is_sd_boot(root_dir
, u
"\\EFI\\BOOT\\GRUB" EFI_MACHINE_TYPE_NAME u
".EFI"))
1913 /* check existence */
1914 _cleanup_(file_closep
) EFI_FILE
*handle
= NULL
;
1915 EFI_STATUS err
= root_dir
->Open(root_dir
, &handle
, (char16_t
*) loader
, EFI_FILE_MODE_READ
, 0ULL);
1916 if (err
!= EFI_SUCCESS
)
1919 BootEntry
*entry
= xnew(BootEntry
, 1);
1920 *entry
= (BootEntry
) {
1921 .id
= xstrdup16(id
),
1922 .type
= LOADER_AUTO
,
1923 .title
= xstrdup16(title
),
1925 .loader
= xstrdup16(loader
),
1931 config_add_entry(config
, entry
);
1935 static void config_add_entry_osx(Config
*config
) {
1937 size_t n_handles
= 0;
1938 _cleanup_free_ EFI_HANDLE
*handles
= NULL
;
1942 if (!config
->auto_entries
)
1945 err
= BS
->LocateHandleBuffer(
1946 ByProtocol
, MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
), NULL
, &n_handles
, &handles
);
1947 if (err
!= EFI_SUCCESS
)
1950 for (size_t i
= 0; i
< n_handles
; i
++) {
1951 _cleanup_(file_closep
) EFI_FILE
*root
= NULL
;
1953 if (open_volume(handles
[i
], &root
) != EFI_SUCCESS
)
1956 if (config_add_entry_loader_auto(
1964 u
"\\System\\Library\\CoreServices\\boot.efi"))
1969 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
1970 static EFI_STATUS
boot_windows_bitlocker(void) {
1971 _cleanup_free_ EFI_HANDLE
*handles
= NULL
;
1975 // FIXME: Experimental for now. Should be generalized, and become a per-entry option that can be
1976 // enabled independently of BitLocker, and without a BootXXXX entry pre-existing.
1978 /* BitLocker key cannot be sealed without a TPM present. */
1980 return EFI_NOT_FOUND
;
1982 err
= BS
->LocateHandleBuffer(
1983 ByProtocol
, MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL
), NULL
, &n_handles
, &handles
);
1984 if (err
!= EFI_SUCCESS
)
1987 /* Look for BitLocker magic string on all block drives. */
1989 for (size_t i
= 0; i
< n_handles
; i
++) {
1990 EFI_BLOCK_IO_PROTOCOL
*block_io
;
1991 err
= BS
->HandleProtocol(handles
[i
], MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL
), (void **) &block_io
);
1992 if (err
!= EFI_SUCCESS
|| block_io
->Media
->BlockSize
< 512 || block_io
->Media
->BlockSize
> 4096)
1996 err
= block_io
->ReadBlocks(block_io
, block_io
->Media
->MediaId
, 0, sizeof(buf
), buf
);
1997 if (err
!= EFI_SUCCESS
)
2000 if (memcmp(buf
+ 3, "-FVE-FS-", STRLEN("-FVE-FS-")) == 0) {
2006 /* If no BitLocker drive was found, we can just chainload bootmgfw.efi directly. */
2008 return EFI_NOT_FOUND
;
2010 _cleanup_free_
uint16_t *boot_order
= NULL
;
2011 size_t boot_order_size
;
2013 /* There can be gaps in Boot#### entries. Instead of iterating over the full
2014 * EFI var list or uint16_t namespace, just look for "Windows Boot Manager" in BootOrder. */
2015 err
= efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE
), u
"BootOrder", (char **) &boot_order
, &boot_order_size
);
2016 if (err
!= EFI_SUCCESS
|| boot_order_size
% sizeof(uint16_t) != 0)
2019 for (size_t i
= 0; i
< boot_order_size
/ sizeof(uint16_t); i
++) {
2020 _cleanup_free_
char *buf
= NULL
;
2023 _cleanup_free_ char16_t
*name
= xasprintf("Boot%04x", boot_order
[i
]);
2024 err
= efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE
), name
, &buf
, &buf_size
);
2025 if (err
!= EFI_SUCCESS
)
2028 /* Boot#### are EFI_LOAD_OPTION. But we really are only interested
2029 * for the description, which is at this offset. */
2030 size_t offset
= sizeof(uint32_t) + sizeof(uint16_t);
2031 if (buf_size
< offset
+ sizeof(char16_t
))
2034 if (streq16((char16_t
*) (buf
+ offset
), u
"Windows Boot Manager")) {
2035 err
= efivar_set_raw(
2036 MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE
),
2039 sizeof(boot_order
[i
]),
2040 EFI_VARIABLE_NON_VOLATILE
);
2041 if (err
!= EFI_SUCCESS
)
2043 RT
->ResetSystem(EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
2044 assert_not_reached();
2048 return EFI_NOT_FOUND
;
2052 static void config_add_entry_windows(Config
*config
, EFI_HANDLE
*device
, EFI_FILE
*root_dir
) {
2053 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
2054 _cleanup_free_
char *bcd
= NULL
;
2055 char16_t
*title
= NULL
;
2063 if (!config
->auto_entries
)
2066 /* Try to find a better title. */
2067 err
= file_read(root_dir
, u
"\\EFI\\Microsoft\\Boot\\BCD", 0, 100*1024, &bcd
, &len
);
2068 if (err
== EFI_SUCCESS
)
2069 title
= get_bcd_title((uint8_t *) bcd
, len
);
2071 BootEntry
*e
= config_add_entry_loader_auto(config
, device
, root_dir
, NULL
,
2072 u
"auto-windows", 'w', title
?: u
"Windows Boot Manager",
2073 u
"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
2075 if (config
->reboot_for_bitlocker
)
2076 e
->call
= boot_windows_bitlocker
;
2080 static void config_load_type2_entries(
2083 EFI_FILE
*root_dir
) {
2085 _cleanup_(file_closep
) EFI_FILE
*linux_dir
= NULL
;
2086 _cleanup_free_ EFI_FILE_INFO
*f
= NULL
;
2090 /* Adds Boot Loader Type #2 entries (i.e. /EFI/Linux/….efi) */
2096 err
= open_directory(root_dir
, u
"\\EFI\\Linux", &linux_dir
);
2097 if (err
!= EFI_SUCCESS
)
2107 static const char * const sections
[_SECTION_MAX
+ 1] = {
2108 [SECTION_CMDLINE
] = ".cmdline",
2109 [SECTION_OSREL
] = ".osrel",
2113 _cleanup_free_ char16_t
*os_pretty_name
= NULL
, *os_image_id
= NULL
, *os_name
= NULL
, *os_id
= NULL
,
2114 *os_image_version
= NULL
, *os_version
= NULL
, *os_version_id
= NULL
, *os_build_id
= NULL
;
2115 const char16_t
*good_name
, *good_version
, *good_sort_key
;
2116 _cleanup_free_
char *content
= NULL
;
2117 size_t offs
[_SECTION_MAX
] = {}, szs
[_SECTION_MAX
] = {}, pos
= 0;
2118 char *line
, *key
, *value
;
2120 err
= readdir(linux_dir
, &f
, &f_size
);
2121 if (err
!= EFI_SUCCESS
|| !f
)
2124 if (f
->FileName
[0] == '.')
2126 if (FLAGS_SET(f
->Attribute
, EFI_FILE_DIRECTORY
))
2128 if (!endswith_no_case(f
->FileName
, u
".efi"))
2130 if (startswith(f
->FileName
, u
"auto-"))
2133 /* look for .osrel and .cmdline sections in the .efi binary */
2134 err
= pe_file_locate_sections(linux_dir
, f
->FileName
, sections
, offs
, szs
);
2135 if (err
!= EFI_SUCCESS
|| szs
[SECTION_OSREL
] == 0)
2138 err
= file_read(linux_dir
, f
->FileName
, offs
[SECTION_OSREL
], szs
[SECTION_OSREL
], &content
, NULL
);
2139 if (err
!= EFI_SUCCESS
)
2142 /* read properties from the embedded os-release file */
2143 while ((line
= line_get_key_value(content
, "=", &pos
, &key
, &value
)))
2144 if (streq8(key
, "PRETTY_NAME")) {
2145 free(os_pretty_name
);
2146 os_pretty_name
= xstr8_to_16(value
);
2148 } else if (streq8(key
, "IMAGE_ID")) {
2150 os_image_id
= xstr8_to_16(value
);
2152 } else if (streq8(key
, "NAME")) {
2154 os_name
= xstr8_to_16(value
);
2156 } else if (streq8(key
, "ID")) {
2158 os_id
= xstr8_to_16(value
);
2160 } else if (streq8(key
, "IMAGE_VERSION")) {
2161 free(os_image_version
);
2162 os_image_version
= xstr8_to_16(value
);
2164 } else if (streq8(key
, "VERSION")) {
2166 os_version
= xstr8_to_16(value
);
2168 } else if (streq8(key
, "VERSION_ID")) {
2169 free(os_version_id
);
2170 os_version_id
= xstr8_to_16(value
);
2172 } else if (streq8(key
, "BUILD_ID")) {
2174 os_build_id
= xstr8_to_16(value
);
2177 if (!bootspec_pick_name_version_sort_key(
2191 BootEntry
*entry
= xnew(BootEntry
, 1);
2192 *entry
= (BootEntry
) {
2193 .id
= xstrdup16(f
->FileName
),
2194 .type
= LOADER_UNIFIED_LINUX
,
2195 .title
= xstrdup16(good_name
),
2196 .version
= xstrdup16(good_version
),
2198 .loader
= xasprintf("\\EFI\\Linux\\%ls", f
->FileName
),
2199 .sort_key
= xstrdup16(good_sort_key
),
2205 strtolower16(entry
->id
);
2206 config_add_entry(config
, entry
);
2207 boot_entry_parse_tries(entry
, u
"\\EFI\\Linux", f
->FileName
, u
".efi");
2209 if (szs
[SECTION_CMDLINE
] == 0)
2212 content
= mfree(content
);
2214 /* read the embedded cmdline file */
2216 err
= file_read(linux_dir
, f
->FileName
, offs
[SECTION_CMDLINE
], szs
[SECTION_CMDLINE
], &content
, &cmdline_len
);
2217 if (err
== EFI_SUCCESS
) {
2218 entry
->options
= xstrn8_to_16(content
, cmdline_len
);
2219 mangle_stub_cmdline(entry
->options
);
2220 entry
->options_implied
= true;
2225 static void config_load_xbootldr(
2227 EFI_HANDLE
*device
) {
2229 _cleanup_(file_closep
) EFI_FILE
*root_dir
= NULL
;
2230 EFI_HANDLE new_device
= NULL
; /* avoid false maybe-uninitialized warning */
2236 err
= partition_open(MAKE_GUID_PTR(XBOOTLDR
), device
, &new_device
, &root_dir
);
2237 if (err
!= EFI_SUCCESS
)
2240 config_load_type2_entries(config
, new_device
, root_dir
);
2241 config_load_type1_entries(config
, new_device
, root_dir
, NULL
);
2244 static EFI_STATUS
initrd_prepare(
2246 const BootEntry
*entry
,
2247 char16_t
**ret_options
,
2249 size_t *ret_initrd_size
) {
2253 assert(ret_options
);
2255 assert(ret_initrd_size
);
2257 if (entry
->type
!= LOADER_LINUX
|| !entry
->initrd
) {
2258 *ret_options
= NULL
;
2260 *ret_initrd_size
= 0;
2264 /* Note that order of initrds matters. The kernel will only look for microcode updates in the very
2265 * first one it sees. */
2267 /* Add initrd= to options for older kernels that do not support LINUX_INITRD_MEDIA. Should be dropped
2268 * if linux_x86.c is dropped. */
2269 _cleanup_free_ char16_t
*options
= NULL
;
2273 _cleanup_free_
uint8_t *initrd
= NULL
;
2275 STRV_FOREACH(i
, entry
->initrd
) {
2276 _cleanup_free_ char16_t
*o
= options
;
2278 options
= xasprintf("%ls initrd=%ls", o
, *i
);
2280 options
= xasprintf("initrd=%ls", *i
);
2282 _cleanup_(file_closep
) EFI_FILE
*handle
= NULL
;
2283 err
= root
->Open(root
, &handle
, *i
, EFI_FILE_MODE_READ
, 0);
2284 if (err
!= EFI_SUCCESS
)
2287 _cleanup_free_ EFI_FILE_INFO
*info
= NULL
;
2288 err
= get_file_info(handle
, &info
, NULL
);
2289 if (err
!= EFI_SUCCESS
)
2292 if (info
->FileSize
== 0) /* Automatically skip over empty files */
2295 size_t new_size
, read_size
= info
->FileSize
;
2296 if (!ADD_SAFE(&new_size
, size
, read_size
))
2297 return EFI_OUT_OF_RESOURCES
;
2298 initrd
= xrealloc(initrd
, size
, new_size
);
2300 err
= chunked_read(handle
, &read_size
, initrd
+ size
);
2301 if (err
!= EFI_SUCCESS
)
2304 /* Make sure the actual read size is what we expected. */
2305 assert(size
+ read_size
== new_size
);
2309 if (entry
->options
) {
2310 _cleanup_free_ char16_t
*o
= options
;
2311 options
= xasprintf("%ls %ls", o
, entry
->options
);
2314 *ret_options
= TAKE_PTR(options
);
2315 *ret_initrd
= TAKE_PTR(initrd
);
2316 *ret_initrd_size
= size
;
2320 static EFI_STATUS
image_start(
2321 EFI_HANDLE parent_image
,
2322 const BootEntry
*entry
) {
2324 _cleanup_(devicetree_cleanup
) struct devicetree_state dtstate
= {};
2325 _cleanup_(unload_imagep
) EFI_HANDLE image
= NULL
;
2326 _cleanup_free_ EFI_DEVICE_PATH
*path
= NULL
;
2331 /* If this loader entry has a special way to boot, try that first. */
2333 (void) entry
->call();
2335 _cleanup_(file_closep
) EFI_FILE
*image_root
= NULL
;
2336 err
= open_volume(entry
->device
, &image_root
);
2337 if (err
!= EFI_SUCCESS
)
2338 return log_error_status(err
, "Error opening root path: %m");
2340 err
= make_file_device_path(entry
->device
, entry
->loader
, &path
);
2341 if (err
!= EFI_SUCCESS
)
2342 return log_error_status(err
, "Error making file device path: %m");
2344 size_t initrd_size
= 0;
2345 _cleanup_free_
void *initrd
= NULL
;
2346 _cleanup_free_ char16_t
*options_initrd
= NULL
;
2347 err
= initrd_prepare(image_root
, entry
, &options_initrd
, &initrd
, &initrd_size
);
2348 if (err
!= EFI_SUCCESS
)
2349 return log_error_status(err
, "Error preparing initrd: %m");
2351 err
= shim_load_image(parent_image
, path
, &image
);
2352 if (err
!= EFI_SUCCESS
)
2353 return log_error_status(err
, "Error loading %ls: %m", entry
->loader
);
2355 /* DTBs are loaded by the kernel before ExitBootServices, and they can be used to map and assign
2356 * arbitrary memory ranges, so skip them when secure boot is enabled as the DTB here is unverified.
2358 if (entry
->devicetree
&& !secure_boot_enabled()) {
2359 err
= devicetree_install(&dtstate
, image_root
, entry
->devicetree
);
2360 if (err
!= EFI_SUCCESS
)
2361 return log_error_status(err
, "Error loading %ls: %m", entry
->devicetree
);
2364 _cleanup_(cleanup_initrd
) EFI_HANDLE initrd_handle
= NULL
;
2365 err
= initrd_register(initrd
, initrd_size
, &initrd_handle
);
2366 if (err
!= EFI_SUCCESS
)
2367 return log_error_status(err
, "Error registering initrd: %m");
2369 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
;
2370 err
= BS
->HandleProtocol(image
, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL
), (void **) &loaded_image
);
2371 if (err
!= EFI_SUCCESS
)
2372 return log_error_status(err
, "Error getting LoadedImageProtocol handle: %m");
2374 /* If we had to append an initrd= entry to the command line, we have to pass it, and measure it.
2375 * Otherwise, only pass/measure it if it is not implicit anyway (i.e. embedded into the UKI or
2377 _cleanup_free_ char16_t
*options
= xstrdup16(options_initrd
?: entry
->options_implied
? NULL
: entry
->options
);
2379 if (entry
->type
== LOADER_LINUX
&& !is_confidential_vm()) {
2380 const char *extra
= smbios_find_oem_string("io.systemd.boot.kernel-cmdline-extra");
2382 _cleanup_free_ char16_t
*tmp
= TAKE_PTR(options
), *extra16
= xstr8_to_16(extra
);
2383 options
= xasprintf("%ls %ls", tmp
, extra16
);
2388 loaded_image
->LoadOptions
= options
;
2389 loaded_image
->LoadOptionsSize
= strsize16(options
);
2391 /* Try to log any options to the TPM, especially to catch manually edited options */
2392 (void) tpm_log_load_options(options
, NULL
);
2395 efivar_set_time_usec(MAKE_GUID_PTR(LOADER
), u
"LoaderTimeExecUSec", 0);
2396 err
= BS
->StartImage(image
, NULL
, NULL
);
2397 graphics_mode(false);
2398 if (err
== EFI_SUCCESS
)
2401 /* Try calling the kernel compat entry point if one exists. */
2402 if (err
== EFI_UNSUPPORTED
&& entry
->type
== LOADER_LINUX
) {
2403 uint32_t compat_address
;
2405 err
= pe_kernel_info(loaded_image
->ImageBase
, &compat_address
);
2406 if (err
!= EFI_SUCCESS
) {
2407 if (err
!= EFI_UNSUPPORTED
)
2408 return log_error_status(err
, "Error finding kernel compat entry address: %m");
2409 } else if (compat_address
> 0) {
2410 EFI_IMAGE_ENTRY_POINT kernel_entry
=
2411 (EFI_IMAGE_ENTRY_POINT
) ((uint8_t *) loaded_image
->ImageBase
+ compat_address
);
2413 err
= kernel_entry(image
, ST
);
2414 graphics_mode(false);
2415 if (err
== EFI_SUCCESS
)
2418 err
= EFI_UNSUPPORTED
;
2421 return log_error_status(err
, "Failed to execute %ls (%ls): %m", entry
->title_show
, entry
->loader
);
2424 static void config_free(Config
*config
) {
2426 for (size_t i
= 0; i
< config
->n_entries
; i
++)
2427 boot_entry_free(config
->entries
[i
]);
2428 free(config
->entries
);
2429 free(config
->entry_default_config
);
2430 free(config
->entry_default_efivar
);
2431 free(config
->entry_oneshot
);
2432 free(config
->entry_saved
);
2435 static void config_write_entries_to_variable(Config
*config
) {
2436 _cleanup_free_
char *buffer
= NULL
;
2442 for (size_t i
= 0; i
< config
->n_entries
; i
++)
2443 sz
+= strsize16(config
->entries
[i
]->id
);
2445 p
= buffer
= xmalloc(sz
);
2447 for (size_t i
= 0; i
< config
->n_entries
; i
++)
2448 p
= mempcpy(p
, config
->entries
[i
]->id
, strsize16(config
->entries
[i
]->id
));
2450 assert(p
== buffer
+ sz
);
2452 /* Store the full list of discovered entries. */
2453 (void) efivar_set_raw(MAKE_GUID_PTR(LOADER
), u
"LoaderEntries", buffer
, sz
, 0);
2456 static void save_selected_entry(const Config
*config
, const BootEntry
*entry
) {
2459 assert(entry
->loader
|| !entry
->call
);
2461 /* Always export the selected boot entry to the system in a volatile var. */
2462 (void) efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderEntrySelected", entry
->id
, 0);
2464 /* Do not save or delete if this was a oneshot boot. */
2465 if (streq16(config
->entry_oneshot
, entry
->id
))
2468 if (config
->use_saved_entry_efivar
|| (!config
->entry_default_efivar
&& config
->use_saved_entry
)) {
2469 /* Avoid unnecessary NVRAM writes. */
2470 if (streq16(config
->entry_saved
, entry
->id
))
2473 (void) efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryLastBooted", entry
->id
, EFI_VARIABLE_NON_VOLATILE
);
2475 /* Delete the non-volatile var if not needed. */
2476 (void) efivar_unset(MAKE_GUID_PTR(LOADER
), u
"LoaderEntryLastBooted", EFI_VARIABLE_NON_VOLATILE
);
2479 static EFI_STATUS
secure_boot_discover_keys(Config
*config
, EFI_FILE
*root_dir
) {
2481 _cleanup_(file_closep
) EFI_FILE
*keys_basedir
= NULL
;
2483 if (!IN_SET(secure_boot_mode(), SECURE_BOOT_SETUP
, SECURE_BOOT_AUDIT
))
2486 /* the lack of a 'keys' directory is not fatal and is silently ignored */
2487 err
= open_directory(root_dir
, u
"\\loader\\keys", &keys_basedir
);
2488 if (err
== EFI_NOT_FOUND
)
2490 if (err
!= EFI_SUCCESS
)
2494 _cleanup_free_ EFI_FILE_INFO
*dirent
= NULL
;
2495 size_t dirent_size
= 0;
2496 BootEntry
*entry
= NULL
;
2498 err
= readdir(keys_basedir
, &dirent
, &dirent_size
);
2499 if (err
!= EFI_SUCCESS
|| !dirent
)
2502 if (dirent
->FileName
[0] == '.')
2505 if (!FLAGS_SET(dirent
->Attribute
, EFI_FILE_DIRECTORY
))
2508 entry
= xnew(BootEntry
, 1);
2509 *entry
= (BootEntry
) {
2510 .id
= xasprintf("secure-boot-keys-%ls", dirent
->FileName
),
2511 .title
= xasprintf("Enroll Secure Boot keys: %ls", dirent
->FileName
),
2512 .path
= xasprintf("\\loader\\keys\\%ls", dirent
->FileName
),
2513 .type
= LOADER_SECURE_BOOT_KEYS
,
2517 config_add_entry(config
, entry
);
2519 if (IN_SET(config
->secure_boot_enroll
, ENROLL_IF_SAFE
, ENROLL_FORCE
) &&
2520 strcaseeq16(dirent
->FileName
, u
"auto"))
2521 /* If we auto enroll successfully this call does not return.
2522 * If it fails we still want to add other potential entries to the menu. */
2523 secure_boot_enroll_at(root_dir
, entry
->path
, config
->secure_boot_enroll
== ENROLL_FORCE
);
2529 static void export_variables(
2530 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
,
2531 const char16_t
*loaded_image_path
,
2532 uint64_t init_usec
) {
2534 static const uint64_t loader_features
=
2535 EFI_LOADER_FEATURE_CONFIG_TIMEOUT
|
2536 EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT
|
2537 EFI_LOADER_FEATURE_ENTRY_DEFAULT
|
2538 EFI_LOADER_FEATURE_ENTRY_ONESHOT
|
2539 EFI_LOADER_FEATURE_BOOT_COUNTING
|
2540 EFI_LOADER_FEATURE_XBOOTLDR
|
2541 EFI_LOADER_FEATURE_RANDOM_SEED
|
2542 EFI_LOADER_FEATURE_LOAD_DRIVER
|
2543 EFI_LOADER_FEATURE_SORT_KEY
|
2544 EFI_LOADER_FEATURE_SAVED_ENTRY
|
2545 EFI_LOADER_FEATURE_DEVICETREE
|
2546 EFI_LOADER_FEATURE_SECUREBOOT_ENROLL
|
2547 EFI_LOADER_FEATURE_RETAIN_SHIM
|
2548 EFI_LOADER_FEATURE_MENU_DISABLE
|
2551 _cleanup_free_ char16_t
*infostr
= NULL
, *typestr
= NULL
;
2553 assert(loaded_image
);
2555 efivar_set_time_usec(MAKE_GUID_PTR(LOADER
), u
"LoaderTimeInitUSec", init_usec
);
2556 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderInfo", u
"systemd-boot " GIT_VERSION
, 0);
2558 infostr
= xasprintf("%ls %u.%02u", ST
->FirmwareVendor
, ST
->FirmwareRevision
>> 16, ST
->FirmwareRevision
& 0xffff);
2559 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderFirmwareInfo", infostr
, 0);
2561 typestr
= xasprintf("UEFI %u.%02u", ST
->Hdr
.Revision
>> 16, ST
->Hdr
.Revision
& 0xffff);
2562 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderFirmwareType", typestr
, 0);
2564 (void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER
), u
"LoaderFeatures", loader_features
, 0);
2566 /* the filesystem path to this image, to prevent adding ourselves to the menu */
2567 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderImageIdentifier", loaded_image_path
, 0);
2569 /* export the device path this image is started from */
2570 _cleanup_free_ char16_t
*uuid
= disk_get_part_uuid(loaded_image
->DeviceHandle
);
2572 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderDevicePartUUID", uuid
, 0);
2575 static void config_load_all_entries(
2577 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
,
2578 const char16_t
*loaded_image_path
,
2579 EFI_FILE
*root_dir
) {
2582 assert(loaded_image
);
2585 config_load_defaults(config
, root_dir
);
2587 /* Scan /EFI/Linux/ directory */
2588 config_load_type2_entries(config
, loaded_image
->DeviceHandle
, root_dir
);
2590 /* Scan /loader/entries/\*.conf files */
2591 config_load_type1_entries(config
, loaded_image
->DeviceHandle
, root_dir
, loaded_image_path
);
2593 /* Similar, but on any XBOOTLDR partition */
2594 config_load_xbootldr(config
, loaded_image
->DeviceHandle
);
2596 /* Sort entries after version number */
2597 sort_pointer_array((void **) config
->entries
, config
->n_entries
, (compare_pointer_func_t
) boot_entry_compare
);
2599 /* If we find some well-known loaders, add them to the end of the list */
2600 config_add_entry_osx(config
);
2601 config_add_entry_windows(config
, loaded_image
->DeviceHandle
, root_dir
);
2602 config_add_entry_loader_auto(config
, loaded_image
->DeviceHandle
, root_dir
, NULL
,
2603 u
"auto-efi-shell", 's', u
"EFI Shell", u
"\\shell" EFI_MACHINE_TYPE_NAME
".efi");
2604 config_add_entry_loader_auto(config
, loaded_image
->DeviceHandle
, root_dir
, loaded_image_path
,
2605 u
"auto-efi-default", '\0', u
"EFI Default Loader", NULL
);
2607 if (config
->auto_firmware
&& FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI
)) {
2608 BootEntry
*entry
= xnew(BootEntry
, 1);
2609 *entry
= (BootEntry
) {
2610 .id
= xstrdup16(u
"auto-reboot-to-firmware-setup"),
2611 .title
= xstrdup16(u
"Reboot Into Firmware Interface"),
2612 .call
= reboot_into_firmware
,
2616 config_add_entry(config
, entry
);
2619 if (config
->auto_poweroff
) {
2620 BootEntry
*entry
= xnew(BootEntry
, 1);
2621 *entry
= (BootEntry
) {
2622 .id
= xstrdup16(u
"auto-poweroff"),
2623 .title
= xstrdup16(u
"Power Off The System"),
2624 .call
= poweroff_system
,
2628 config_add_entry(config
, entry
);
2631 if (config
->auto_reboot
) {
2632 BootEntry
*entry
= xnew(BootEntry
, 1);
2633 *entry
= (BootEntry
) {
2634 .id
= xstrdup16(u
"auto-reboot"),
2635 .title
= xstrdup16(u
"Reboot The System"),
2636 .call
= reboot_system
,
2640 config_add_entry(config
, entry
);
2643 /* Find secure boot signing keys and autoload them if configured.
2644 * Otherwise, create menu entries so that the user can load them manually.
2645 * If the secure-boot-enroll variable is set to no (the default), we do not
2646 * even search for keys on the ESP */
2647 if (config
->secure_boot_enroll
!= ENROLL_OFF
)
2648 secure_boot_discover_keys(config
, root_dir
);
2650 if (config
->n_entries
== 0)
2653 config_write_entries_to_variable(config
);
2655 generate_boot_entry_titles(config
);
2657 /* Select entry by configured pattern or EFI LoaderDefaultEntry= variable */
2658 config_select_default_entry(config
);
2661 static EFI_STATUS
discover_root_dir(EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
, EFI_FILE
**ret_dir
) {
2662 if (is_direct_boot(loaded_image
->DeviceHandle
))
2663 return vmm_open(&loaded_image
->DeviceHandle
, ret_dir
);
2665 return open_volume(loaded_image
->DeviceHandle
, ret_dir
);
2668 static EFI_STATUS
run(EFI_HANDLE image
) {
2669 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
;
2670 _cleanup_(file_closep
) EFI_FILE
*root_dir
= NULL
;
2671 _cleanup_(config_free
) Config config
= {};
2672 _cleanup_free_ char16_t
*loaded_image_path
= NULL
;
2677 init_usec
= time_usec();
2679 /* Ask Shim to leave its protocol around, so that the stub can use it to validate PEs.
2680 * By default, Shim uninstalls its protocol when calling StartImage(). */
2681 shim_retain_protocol();
2683 err
= BS
->HandleProtocol(image
, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL
), (void **) &loaded_image
);
2684 if (err
!= EFI_SUCCESS
)
2685 return log_error_status(err
, "Error getting a LoadedImageProtocol handle: %m");
2687 (void) device_path_to_str(loaded_image
->FilePath
, &loaded_image_path
);
2689 export_variables(loaded_image
, loaded_image_path
, init_usec
);
2691 err
= discover_root_dir(loaded_image
, &root_dir
);
2692 if (err
!= EFI_SUCCESS
)
2693 return log_error_status(err
, "Unable to open root directory: %m");
2695 (void) load_drivers(image
, loaded_image
, root_dir
);
2697 config_load_all_entries(&config
, loaded_image
, loaded_image_path
, root_dir
);
2699 if (config
.n_entries
== 0)
2700 return log_error_status(
2702 "No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
2704 /* select entry or show menu when key is pressed or timeout is set */
2705 if (config
.force_menu
|| !IN_SET(config
.timeout_sec
, TIMEOUT_MENU_HIDDEN
, TIMEOUT_MENU_DISABLED
))
2707 else if (config
.timeout_sec
!= TIMEOUT_MENU_DISABLED
) {
2710 /* Block up to 100ms to give firmware time to get input working. */
2711 err
= console_key_read(&key
, 100 * 1000);
2712 if (err
== EFI_SUCCESS
) {
2713 /* find matching key in boot entries */
2714 size_t idx
= entry_lookup_key(&config
, config
.idx_default
, KEYCHAR(key
));
2715 if (idx
!= IDX_INVALID
)
2716 config
.idx_default
= idx
;
2725 entry
= config
.entries
[config
.idx_default
];
2727 efivar_set_time_usec(MAKE_GUID_PTR(LOADER
), u
"LoaderTimeMenuUSec", 0);
2728 if (!menu_run(&config
, &entry
, loaded_image_path
))
2732 /* if auto enrollment is activated, we try to load keys for the given entry. */
2733 if (entry
->type
== LOADER_SECURE_BOOT_KEYS
&& config
.secure_boot_enroll
!= ENROLL_OFF
) {
2734 err
= secure_boot_enroll_at(root_dir
, entry
->path
, /*force=*/ true);
2735 if (err
!= EFI_SUCCESS
)
2740 /* Run special entry like "reboot" now. Those that have a loader
2741 * will be handled by image_start() instead. */
2742 if (entry
->call
&& !entry
->loader
) {
2747 (void) boot_entry_bump_counters(entry
);
2748 save_selected_entry(&config
, entry
);
2750 /* Optionally, read a random seed off the ESP and pass it to the OS */
2751 (void) process_random_seed(root_dir
);
2753 err
= image_start(image
, entry
);
2754 if (err
!= EFI_SUCCESS
)
2758 config
.timeout_sec
= 0;
2762 DEFINE_EFI_MAIN_FUNCTION(run
, "systemd-boot", /*wait_for_debugger=*/false);