]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/boot.c
sd-boot: introduce and use efivar_unset()
[thirdparty/systemd.git] / src / boot / efi / boot.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "bcd.h"
4 #include "bootspec-fundamental.h"
5 #include "console.h"
6 #include "device-path-util.h"
7 #include "devicetree.h"
8 #include "drivers.h"
9 #include "efivars-fundamental.h"
10 #include "graphics.h"
11 #include "initrd.h"
12 #include "linux.h"
13 #include "measure.h"
14 #include "part-discovery.h"
15 #include "pe.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"
20 #include "sbat.h"
21 #include "secure-boot.h"
22 #include "shim.h"
23 #include "ticks.h"
24 #include "util.h"
25 #include "version.h"
26 #include "vmm.h"
27
28 /* Magic string for recognizing our own binaries */
29 #define SD_MAGIC "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"
30 DECLARE_NOALLOC_SECTION(".sdmagic", SD_MAGIC);
31
32 /* Makes systemd-boot available from \EFI\Linux\ for testing purposes. */
33 DECLARE_NOALLOC_SECTION(
34 ".osrel",
35 "ID=systemd-boot\n"
36 "VERSION=\"" GIT_VERSION "\"\n"
37 "NAME=\"systemd-boot " GIT_VERSION "\"\n");
38
39 DECLARE_SBAT(SBAT_BOOT_SECTION_TEXT);
40
41 typedef enum LoaderType {
42 LOADER_UNDEFINED,
43 LOADER_AUTO,
44 LOADER_EFI,
45 LOADER_LINUX, /* Boot loader spec type #1 entries */
46 LOADER_UNIFIED_LINUX, /* Boot loader spec type #2 entries */
47 LOADER_SECURE_BOOT_KEYS,
48 _LOADER_TYPE_MAX,
49 } LoaderType;
50
51 typedef struct {
52 char16_t *id; /* The unique identifier for this entry (typically the filename of the file defining the entry) */
53 char16_t *title_show; /* The string to actually display (this is made unique before showing) */
54 char16_t *title; /* The raw (human readable) title string of the entry (not necessarily unique) */
55 char16_t *sort_key; /* The string to use as primary sort key, usually ID= from os-release, possibly suffixed */
56 char16_t *version; /* The raw (human readable) version string of the entry */
57 char16_t *machine_id;
58 EFI_HANDLE *device;
59 LoaderType type;
60 char16_t *loader;
61 char16_t *devicetree;
62 char16_t *options;
63 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. */
64 char16_t **initrd;
65 char16_t key;
66 EFI_STATUS (*call)(void);
67 int tries_done;
68 int tries_left;
69 char16_t *path;
70 char16_t *current_name;
71 char16_t *next_name;
72 } ConfigEntry;
73
74 typedef struct {
75 ConfigEntry **entries;
76 size_t n_entries;
77 size_t idx_default;
78 size_t idx_default_efivar;
79 uint32_t timeout_sec; /* Actual timeout used (efi_main() override > efivar > config). */
80 uint32_t timeout_sec_config;
81 uint32_t timeout_sec_efivar;
82 char16_t *entry_default_config;
83 char16_t *entry_default_efivar;
84 char16_t *entry_oneshot;
85 char16_t *entry_saved;
86 bool editor;
87 bool auto_entries;
88 bool auto_firmware;
89 bool reboot_for_bitlocker;
90 secure_boot_enroll secure_boot_enroll;
91 bool force_menu;
92 bool use_saved_entry;
93 bool use_saved_entry_efivar;
94 bool beep;
95 int64_t console_mode;
96 int64_t console_mode_efivar;
97 } Config;
98
99 /* These values have been chosen so that the transitions the user sees could
100 * employ unsigned over-/underflow like this:
101 * efivar unset ↔ force menu ↔ no timeout/skip menu ↔ 1 s ↔ 2 s ↔ … */
102 enum {
103 TIMEOUT_MIN = 1,
104 TIMEOUT_MAX = UINT32_MAX - 2U,
105 TIMEOUT_UNSET = UINT32_MAX - 1U,
106 TIMEOUT_MENU_FORCE = UINT32_MAX,
107 TIMEOUT_MENU_HIDDEN = 0,
108 TIMEOUT_TYPE_MAX = UINT32_MAX,
109 };
110
111 enum {
112 IDX_MAX = INT16_MAX,
113 IDX_INVALID,
114 };
115
116 static void cursor_left(size_t *cursor, size_t *first) {
117 assert(cursor);
118 assert(first);
119
120 if ((*cursor) > 0)
121 (*cursor)--;
122 else if ((*first) > 0)
123 (*first)--;
124 }
125
126 static void cursor_right(size_t *cursor, size_t *first, size_t x_max, size_t len) {
127 assert(cursor);
128 assert(first);
129
130 if ((*cursor)+1 < x_max)
131 (*cursor)++;
132 else if ((*first) + (*cursor) < len)
133 (*first)++;
134 }
135
136 static bool line_edit(char16_t **line_in, size_t x_max, size_t y_pos) {
137 _cleanup_free_ char16_t *line = NULL, *print = NULL;
138 size_t size, len, first = 0, cursor = 0, clear = 0;
139
140 assert(line_in);
141
142 len = strlen16(*line_in);
143 size = len + 1024;
144 line = xnew(char16_t, size);
145 print = xnew(char16_t, x_max + 1);
146 strcpy16(line, strempty(*line_in));
147
148 for (;;) {
149 EFI_STATUS err;
150 uint64_t key;
151 size_t j, cursor_color = EFI_TEXT_ATTR_SWAP(COLOR_EDIT);
152
153 j = MIN(len - first, x_max);
154 memcpy(print, line + first, j * sizeof(char16_t));
155 while (clear > 0 && j < x_max) {
156 clear--;
157 print[j++] = ' ';
158 }
159 print[j] = '\0';
160
161 /* See comment at edit_line() call site for why we start at 1. */
162 print_at(1, y_pos, COLOR_EDIT, print);
163
164 if (!print[cursor])
165 print[cursor] = ' ';
166 print[cursor+1] = '\0';
167 do {
168 print_at(cursor + 1, y_pos, cursor_color, print + cursor);
169 cursor_color = EFI_TEXT_ATTR_SWAP(cursor_color);
170
171 err = console_key_read(&key, 750 * 1000);
172 if (!IN_SET(err, EFI_SUCCESS, EFI_TIMEOUT, EFI_NOT_READY))
173 return false;
174
175 print_at(cursor + 1, y_pos, COLOR_EDIT, print + cursor);
176 } while (err != EFI_SUCCESS);
177
178 switch (key) {
179 case KEYPRESS(0, SCAN_ESC, 0):
180 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'c'):
181 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'g'):
182 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('c')):
183 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('g')):
184 return false;
185
186 case KEYPRESS(0, SCAN_HOME, 0):
187 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'a'):
188 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('a')):
189 /* beginning-of-line */
190 cursor = 0;
191 first = 0;
192 continue;
193
194 case KEYPRESS(0, SCAN_END, 0):
195 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'e'):
196 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('e')):
197 /* end-of-line */
198 cursor = len - first;
199 if (cursor+1 >= x_max) {
200 cursor = x_max-1;
201 first = len - (x_max-1);
202 }
203 continue;
204
205 case KEYPRESS(0, SCAN_DOWN, 0):
206 case KEYPRESS(EFI_ALT_PRESSED, 0, 'f'):
207 case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_RIGHT, 0):
208 /* forward-word */
209 while (line[first + cursor] == ' ')
210 cursor_right(&cursor, &first, x_max, len);
211 while (line[first + cursor] && line[first + cursor] != ' ')
212 cursor_right(&cursor, &first, x_max, len);
213 continue;
214
215 case KEYPRESS(0, SCAN_UP, 0):
216 case KEYPRESS(EFI_ALT_PRESSED, 0, 'b'):
217 case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_LEFT, 0):
218 /* backward-word */
219 if ((first + cursor) > 0 && line[first + cursor-1] == ' ') {
220 cursor_left(&cursor, &first);
221 while ((first + cursor) > 0 && line[first + cursor] == ' ')
222 cursor_left(&cursor, &first);
223 }
224 while ((first + cursor) > 0 && line[first + cursor-1] != ' ')
225 cursor_left(&cursor, &first);
226 continue;
227
228 case KEYPRESS(0, SCAN_RIGHT, 0):
229 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'f'):
230 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('f')):
231 /* forward-char */
232 if (first + cursor == len)
233 continue;
234 cursor_right(&cursor, &first, x_max, len);
235 continue;
236
237 case KEYPRESS(0, SCAN_LEFT, 0):
238 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'b'):
239 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('b')):
240 /* backward-char */
241 cursor_left(&cursor, &first);
242 continue;
243
244 case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_DELETE, 0):
245 case KEYPRESS(EFI_ALT_PRESSED, 0, 'd'):
246 /* kill-word */
247 clear = 0;
248
249 size_t k;
250 for (k = first + cursor; k < len && line[k] == ' '; k++)
251 clear++;
252 for (; k < len && line[k] != ' '; k++)
253 clear++;
254
255 for (size_t i = first + cursor; i + clear < len; i++)
256 line[i] = line[i + clear];
257 len -= clear;
258 line[len] = '\0';
259 continue;
260
261 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'w'):
262 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('w')):
263 case KEYPRESS(EFI_ALT_PRESSED, 0, '\b'):
264 /* backward-kill-word */
265 clear = 0;
266 if ((first + cursor) > 0 && line[first + cursor-1] == ' ') {
267 cursor_left(&cursor, &first);
268 clear++;
269 while ((first + cursor) > 0 && line[first + cursor] == ' ') {
270 cursor_left(&cursor, &first);
271 clear++;
272 }
273 }
274 while ((first + cursor) > 0 && line[first + cursor-1] != ' ') {
275 cursor_left(&cursor, &first);
276 clear++;
277 }
278
279 for (size_t i = first + cursor; i + clear < len; i++)
280 line[i] = line[i + clear];
281 len -= clear;
282 line[len] = '\0';
283 continue;
284
285 case KEYPRESS(0, SCAN_DELETE, 0):
286 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'd'):
287 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('d')):
288 if (len == 0)
289 continue;
290 if (first + cursor == len)
291 continue;
292 for (size_t i = first + cursor; i < len; i++)
293 line[i] = line[i+1];
294 clear = 1;
295 len--;
296 continue;
297
298 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'k'):
299 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('k')):
300 /* kill-line */
301 line[first + cursor] = '\0';
302 clear = len - (first + cursor);
303 len = first + cursor;
304 continue;
305
306 case KEYPRESS(0, 0, '\n'):
307 case KEYPRESS(0, 0, '\r'):
308 case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */
309 case KEYPRESS(0, SCAN_F3, '\r'): /* Teclast X98+ II firmware sends malformed events */
310 if (!streq16(line, *line_in)) {
311 free(*line_in);
312 *line_in = TAKE_PTR(line);
313 }
314 return true;
315
316 case KEYPRESS(0, 0, '\b'):
317 if (len == 0)
318 continue;
319 if (first == 0 && cursor == 0)
320 continue;
321 for (size_t i = first + cursor-1; i < len; i++)
322 line[i] = line[i+1];
323 clear = 1;
324 len--;
325 if (cursor > 0)
326 cursor--;
327 if (cursor > 0 || first == 0)
328 continue;
329 /* show full line if it fits */
330 if (len < x_max) {
331 cursor = first;
332 first = 0;
333 continue;
334 }
335 /* jump left to see what we delete */
336 if (first > 10) {
337 first -= 10;
338 cursor = 10;
339 } else {
340 cursor = first;
341 first = 0;
342 }
343 continue;
344
345 case KEYPRESS(0, 0, ' ') ... KEYPRESS(0, 0, '~'):
346 case KEYPRESS(0, 0, 0x80) ... KEYPRESS(0, 0, 0xffff):
347 if (len+1 == size)
348 continue;
349 for (size_t i = len; i > first + cursor; i--)
350 line[i] = line[i-1];
351 line[first + cursor] = KEYCHAR(key);
352 len++;
353 line[len] = '\0';
354 if (cursor+1 < x_max)
355 cursor++;
356 else if (first + cursor < len)
357 first++;
358 continue;
359 }
360 }
361 }
362
363 static size_t entry_lookup_key(Config *config, size_t start, char16_t key) {
364 assert(config);
365
366 if (key == 0)
367 return IDX_INVALID;
368
369 /* select entry by number key */
370 if (key >= '1' && key <= '9') {
371 size_t i = key - '0';
372 if (i > config->n_entries)
373 i = config->n_entries;
374 return i-1;
375 }
376
377 /* find matching key in config entries */
378 for (size_t i = start; i < config->n_entries; i++)
379 if (config->entries[i]->key == key)
380 return i;
381
382 for (size_t i = 0; i < start; i++)
383 if (config->entries[i]->key == key)
384 return i;
385
386 return IDX_INVALID;
387 }
388
389 static char16_t *update_timeout_efivar(uint32_t *t, bool inc) {
390 assert(t);
391
392 switch (*t) {
393 case TIMEOUT_MAX:
394 *t = inc ? TIMEOUT_MAX : (*t - 1);
395 break;
396 case TIMEOUT_UNSET:
397 *t = inc ? TIMEOUT_MENU_FORCE : TIMEOUT_UNSET;
398 break;
399 case TIMEOUT_MENU_FORCE:
400 *t = inc ? TIMEOUT_MENU_HIDDEN : TIMEOUT_UNSET;
401 break;
402 case TIMEOUT_MENU_HIDDEN:
403 *t = inc ? TIMEOUT_MIN : TIMEOUT_MENU_FORCE;
404 break;
405 default:
406 *t += inc ? 1 : -1;
407 }
408
409 switch (*t) {
410 case TIMEOUT_UNSET:
411 return xstrdup16(u"Menu timeout defined by configuration file.");
412 case TIMEOUT_MENU_FORCE:
413 return xstrdup16(u"Timeout disabled, menu will always be shown.");
414 case TIMEOUT_MENU_HIDDEN:
415 return xstrdup16(u"Menu disabled. Hold down key at bootup to show menu.");
416 default:
417 return xasprintf("Menu timeout set to %u s.", *t);
418 }
419 }
420
421 static bool unicode_supported(void) {
422 static int cache = -1;
423
424 if (cache < 0)
425 /* Basic unicode box drawing support is mandated by the spec, but it does
426 * not hurt to make sure it works. */
427 cache = ST->ConOut->TestString(ST->ConOut, (char16_t *) u"─") == EFI_SUCCESS;
428
429 return cache;
430 }
431
432 static bool ps_continue(void) {
433 const char16_t *sep = unicode_supported() ? u"───" : u"---";
434 printf("\n%ls Press any key to continue, ESC or q to quit. %ls\n\n", sep, sep);
435
436 uint64_t key;
437 return console_key_read(&key, UINT64_MAX) == EFI_SUCCESS &&
438 !IN_SET(key, KEYPRESS(0, SCAN_ESC, 0), KEYPRESS(0, 0, 'q'), KEYPRESS(0, 0, 'Q'));
439 }
440
441 static void print_status(Config *config, char16_t *loaded_image_path) {
442 size_t x_max, y_max;
443 uint32_t screen_width = 0, screen_height = 0;
444 SecureBootMode secure;
445 _cleanup_free_ char16_t *device_part_uuid = NULL;
446
447 assert(config);
448
449 clear_screen(COLOR_NORMAL);
450 console_query_mode(&x_max, &y_max);
451 query_screen_resolution(&screen_width, &screen_height);
452
453 secure = secure_boot_mode();
454 (void) efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", &device_part_uuid);
455
456 printf(" systemd-boot version: " GIT_VERSION "\n");
457 if (loaded_image_path)
458 printf(" loaded image: %ls\n", loaded_image_path);
459 if (device_part_uuid)
460 printf(" loader partition UUID: %ls\n", device_part_uuid);
461 printf(" architecture: " EFI_MACHINE_TYPE_NAME "\n");
462 printf(" UEFI specification: %u.%02u\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
463 printf(" firmware vendor: %ls\n", ST->FirmwareVendor);
464 printf(" firmware version: %u.%02u\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
465 printf(" OS indications: %#" PRIx64 "\n", get_os_indications_supported());
466 printf(" secure boot: %ls (%ls)\n",
467 yes_no(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)),
468 secure_boot_mode_to_string(secure));
469 printf(" shim: %ls\n", yes_no(shim_loaded()));
470 printf(" TPM: %ls\n", yes_no(tpm_present()));
471 printf(" console mode: %i/%" PRIi64 " (%zux%zu @%ux%u)\n",
472 ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1),
473 x_max, y_max, screen_width, screen_height);
474
475 if (!ps_continue())
476 return;
477
478 switch (config->timeout_sec_config) {
479 case TIMEOUT_UNSET:
480 break;
481 case TIMEOUT_MENU_FORCE:
482 printf(" timeout (config): menu-force\n");
483 break;
484 case TIMEOUT_MENU_HIDDEN:
485 printf(" timeout (config): menu-hidden\n");
486 break;
487 default:
488 printf(" timeout (config): %u s\n", config->timeout_sec_config);
489 }
490
491 switch (config->timeout_sec_efivar) {
492 case TIMEOUT_UNSET:
493 break;
494 case TIMEOUT_MENU_FORCE:
495 printf(" timeout (EFI var): menu-force\n");
496 break;
497 case TIMEOUT_MENU_HIDDEN:
498 printf(" timeout (EFI var): menu-hidden\n");
499 break;
500 default:
501 printf(" timeout (EFI var): %u s\n", config->timeout_sec_efivar);
502 }
503
504 if (config->entry_default_config)
505 printf(" default (config): %ls\n", config->entry_default_config);
506 if (config->entry_default_efivar)
507 printf(" default (EFI var): %ls\n", config->entry_default_efivar);
508 if (config->entry_oneshot)
509 printf(" default (one-shot): %ls\n", config->entry_oneshot);
510 if (config->entry_saved)
511 printf(" saved entry: %ls\n", config->entry_saved);
512 printf(" editor: %ls\n", yes_no(config->editor));
513 printf(" auto-entries: %ls\n", yes_no(config->auto_entries));
514 printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware));
515 printf(" beep: %ls\n", yes_no(config->beep));
516 printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
517
518 switch (config->secure_boot_enroll) {
519 case ENROLL_OFF:
520 printf(" secure-boot-enroll: off\n");
521 break;
522 case ENROLL_MANUAL:
523 printf(" secure-boot-enroll: manual\n");
524 break;
525 case ENROLL_IF_SAFE:
526 printf(" secure-boot-enroll: if-safe\n");
527 break;
528 case ENROLL_FORCE:
529 printf(" secure-boot-enroll: force\n");
530 break;
531 default:
532 assert_not_reached();
533 }
534
535 switch (config->console_mode) {
536 case CONSOLE_MODE_AUTO:
537 printf(" console-mode (config): auto\n");
538 break;
539 case CONSOLE_MODE_KEEP:
540 printf(" console-mode (config): keep\n");
541 break;
542 case CONSOLE_MODE_FIRMWARE_MAX:
543 printf(" console-mode (config): max\n");
544 break;
545 default:
546 printf(" console-mode (config): %" PRIi64 "\n", config->console_mode);
547 break;
548 }
549
550 /* EFI var console mode is always a concrete value or unset. */
551 if (config->console_mode_efivar != CONSOLE_MODE_KEEP)
552 printf("console-mode (EFI var): %" PRIi64 "\n", config->console_mode_efivar);
553
554 if (!ps_continue())
555 return;
556
557 for (size_t i = 0; i < config->n_entries; i++) {
558 ConfigEntry *entry = config->entries[i];
559 EFI_DEVICE_PATH *dp = NULL;
560 _cleanup_free_ char16_t *dp_str = NULL;
561
562 if (entry->device &&
563 BS->HandleProtocol(entry->device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp) ==
564 EFI_SUCCESS)
565 (void) device_path_to_str(dp, &dp_str);
566
567 printf(" config entry: %zu/%zu\n", i + 1, config->n_entries);
568 printf(" id: %ls\n", entry->id);
569 if (entry->title)
570 printf(" title: %ls\n", entry->title);
571 if (entry->title_show && !streq16(entry->title, entry->title_show))
572 printf(" title show: %ls\n", entry->title_show);
573 if (entry->sort_key)
574 printf(" sort key: %ls\n", entry->sort_key);
575 if (entry->version)
576 printf(" version: %ls\n", entry->version);
577 if (entry->machine_id)
578 printf(" machine-id: %ls\n", entry->machine_id);
579 if (dp_str)
580 printf(" device: %ls\n", dp_str);
581 if (entry->loader)
582 printf(" loader: %ls\n", entry->loader);
583 STRV_FOREACH(initrd, entry->initrd)
584 printf(" initrd: %ls\n", *initrd);
585 if (entry->devicetree)
586 printf(" devicetree: %ls\n", entry->devicetree);
587 if (entry->options)
588 printf(" options: %ls\n", entry->options);
589 printf(" internal call: %ls\n", yes_no(!!entry->call));
590
591 printf("counting boots: %ls\n", yes_no(entry->tries_left >= 0));
592 if (entry->tries_left >= 0) {
593 printf(" tries: %i left, %i done\n", entry->tries_left, entry->tries_done);
594 printf(" current path: %ls\\%ls\n", entry->path, entry->current_name);
595 printf(" next path: %ls\\%ls\n", entry->path, entry->next_name);
596 }
597
598 if (!ps_continue())
599 return;
600 }
601 }
602
603 static EFI_STATUS reboot_into_firmware(void) {
604 uint64_t osind = 0;
605 EFI_STATUS err;
606
607 if (!FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
608 return log_error_status(EFI_UNSUPPORTED, "Reboot to firmware interface not supported.");
609
610 (void) efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndications", &osind);
611 osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
612
613 err = efivar_set_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndications", osind, EFI_VARIABLE_NON_VOLATILE);
614 if (err != EFI_SUCCESS)
615 return log_error_status(err, "Error setting OsIndications: %m");
616
617 RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
618 assert_not_reached();
619 }
620
621 static bool menu_run(
622 Config *config,
623 ConfigEntry **chosen_entry,
624 char16_t *loaded_image_path) {
625
626 assert(config);
627 assert(chosen_entry);
628
629 EFI_STATUS err;
630 size_t visible_max = 0;
631 size_t idx_highlight = config->idx_default, idx_highlight_prev = 0;
632 size_t idx, idx_first = 0, idx_last = 0;
633 bool new_mode = true, clear = true;
634 bool refresh = true, highlight = false;
635 size_t x_start = 0, y_start = 0, y_status = 0, x_max, y_max;
636 _cleanup_(strv_freep) char16_t **lines = NULL;
637 _cleanup_free_ char16_t *clearline = NULL, *separator = NULL, *status = NULL;
638 uint32_t timeout_efivar_saved = config->timeout_sec_efivar;
639 uint32_t timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
640 bool exit = false, run = true, firmware_setup = false;
641 int64_t console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
642 size_t default_efivar_saved = config->idx_default_efivar;
643
644 graphics_mode(false);
645 ST->ConIn->Reset(ST->ConIn, false);
646 ST->ConOut->EnableCursor(ST->ConOut, false);
647
648 /* draw a single character to make ClearScreen work on some firmware */
649 ST->ConOut->OutputString(ST->ConOut, (char16_t *) u" ");
650
651 err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
652 config->console_mode_efivar : config->console_mode);
653 if (err != EFI_SUCCESS) {
654 clear_screen(COLOR_NORMAL);
655 log_error_status(err, "Error switching console mode: %m");
656 }
657
658 size_t line_width = 0, entry_padding = 3;
659 while (!exit) {
660 uint64_t key;
661
662 if (new_mode) {
663 console_query_mode(&x_max, &y_max);
664
665 /* account for padding+status */
666 visible_max = y_max - 2;
667
668 /* Drawing entries starts at idx_first until idx_last. We want to make
669 * sure that idx_highlight is centered, but not if we are close to the
670 * beginning/end of the entry list. Otherwise we would have a half-empty
671 * screen. */
672 if (config->n_entries <= visible_max || idx_highlight <= visible_max / 2)
673 idx_first = 0;
674 else if (idx_highlight >= config->n_entries - (visible_max / 2))
675 idx_first = config->n_entries - visible_max;
676 else
677 idx_first = idx_highlight - (visible_max / 2);
678 idx_last = idx_first + visible_max - 1;
679
680 /* length of the longest entry */
681 line_width = 0;
682 for (size_t i = 0; i < config->n_entries; i++)
683 line_width = MAX(line_width, strlen16(config->entries[i]->title_show));
684 line_width = MIN(line_width + 2 * entry_padding, x_max);
685
686 /* offsets to center the entries on the screen */
687 x_start = (x_max - (line_width)) / 2;
688 if (config->n_entries < visible_max)
689 y_start = ((visible_max - config->n_entries) / 2) + 1;
690 else
691 y_start = 0;
692
693 /* Put status line after the entry list, but give it some breathing room. */
694 y_status = MIN(y_start + MIN(visible_max, config->n_entries) + 1, y_max - 1);
695
696 lines = strv_free(lines);
697 clearline = mfree(clearline);
698 separator = mfree(separator);
699
700 /* menu entries title lines */
701 lines = xnew(char16_t *, config->n_entries + 1);
702
703 for (size_t i = 0; i < config->n_entries; i++) {
704 size_t j, padding;
705
706 lines[i] = xnew(char16_t, line_width + 1);
707 padding = (line_width - MIN(strlen16(config->entries[i]->title_show), line_width)) / 2;
708
709 for (j = 0; j < padding; j++)
710 lines[i][j] = ' ';
711
712 for (size_t k = 0; config->entries[i]->title_show[k] != '\0' && j < line_width; j++, k++)
713 lines[i][j] = config->entries[i]->title_show[k];
714
715 for (; j < line_width; j++)
716 lines[i][j] = ' ';
717 lines[i][line_width] = '\0';
718 }
719 lines[config->n_entries] = NULL;
720
721 clearline = xnew(char16_t, x_max + 1);
722 separator = xnew(char16_t, x_max + 1);
723 for (size_t i = 0; i < x_max; i++) {
724 clearline[i] = ' ';
725 separator[i] = unicode_supported() ? L'─' : L'-';
726 }
727 clearline[x_max] = 0;
728 separator[x_max] = 0;
729
730 new_mode = false;
731 clear = true;
732 }
733
734 if (clear) {
735 clear_screen(COLOR_NORMAL);
736 clear = false;
737 refresh = true;
738 }
739
740 if (refresh) {
741 for (size_t i = idx_first; i <= idx_last && i < config->n_entries; i++) {
742 print_at(x_start, y_start + i - idx_first,
743 i == idx_highlight ? COLOR_HIGHLIGHT : COLOR_ENTRY,
744 lines[i]);
745 if (i == config->idx_default_efivar)
746 print_at(x_start,
747 y_start + i - idx_first,
748 i == idx_highlight ? COLOR_HIGHLIGHT : COLOR_ENTRY,
749 unicode_supported() ? u" ►" : u"=>");
750 }
751 refresh = false;
752 } else if (highlight) {
753 print_at(x_start, y_start + idx_highlight_prev - idx_first, COLOR_ENTRY, lines[idx_highlight_prev]);
754 print_at(x_start, y_start + idx_highlight - idx_first, COLOR_HIGHLIGHT, lines[idx_highlight]);
755 if (idx_highlight_prev == config->idx_default_efivar)
756 print_at(x_start,
757 y_start + idx_highlight_prev - idx_first,
758 COLOR_ENTRY,
759 unicode_supported() ? u" ►" : u"=>");
760 if (idx_highlight == config->idx_default_efivar)
761 print_at(x_start,
762 y_start + idx_highlight - idx_first,
763 COLOR_HIGHLIGHT,
764 unicode_supported() ? u" ►" : u"=>");
765 highlight = false;
766 }
767
768 if (timeout_remain > 0) {
769 free(status);
770 status = xasprintf("Boot in %u s.", timeout_remain);
771 }
772
773 if (status) {
774 /* If we draw the last char of the last line, the screen will scroll and break our
775 * input. Therefore, draw one less character then we could for the status message.
776 * Note that the same does not apply for the separator line as it will never be drawn
777 * on the last line. */
778 size_t len = strnlen16(status, x_max - 1);
779 size_t x = (x_max - len) / 2;
780 status[len] = '\0';
781 print_at(0, y_status, COLOR_NORMAL, clearline + x_max - x);
782 ST->ConOut->OutputString(ST->ConOut, status);
783 ST->ConOut->OutputString(ST->ConOut, clearline + 1 + x + len);
784
785 len = MIN(MAX(len, line_width) + 2 * entry_padding, x_max);
786 x = (x_max - len) / 2;
787 print_at(x, y_status - 1, COLOR_NORMAL, separator + x_max - len);
788 } else {
789 print_at(0, y_status - 1, COLOR_NORMAL, clearline);
790 print_at(0, y_status, COLOR_NORMAL, clearline + 1); /* See comment above. */
791 }
792
793 /* Beep several times so that the selected entry can be distinguished. */
794 if (config->beep)
795 beep(idx_highlight + 1);
796
797 err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : UINT64_MAX);
798 if (err == EFI_NOT_READY)
799 /* No input device returned a key, try again. This
800 * normally should not happen. */
801 continue;
802 if (err == EFI_TIMEOUT) {
803 assert(timeout_remain > 0);
804 timeout_remain--;
805 if (timeout_remain == 0) {
806 exit = true;
807 break;
808 }
809
810 /* update status */
811 continue;
812 }
813 if (err != EFI_SUCCESS) {
814 exit = true;
815 break;
816 }
817
818 timeout_remain = 0;
819
820 /* clear status after keystroke */
821 status = mfree(status);
822
823 idx_highlight_prev = idx_highlight;
824
825 if (firmware_setup) {
826 firmware_setup = false;
827 if (IN_SET(key, KEYPRESS(0, 0, '\r'), KEYPRESS(0, 0, '\n')))
828 reboot_into_firmware();
829 continue;
830 }
831
832 switch (key) {
833 case KEYPRESS(0, SCAN_UP, 0):
834 case KEYPRESS(0, 0, 'k'):
835 case KEYPRESS(0, 0, 'K'):
836 if (idx_highlight > 0)
837 idx_highlight--;
838 break;
839
840 case KEYPRESS(0, SCAN_DOWN, 0):
841 case KEYPRESS(0, 0, 'j'):
842 case KEYPRESS(0, 0, 'J'):
843 if (idx_highlight < config->n_entries-1)
844 idx_highlight++;
845 break;
846
847 case KEYPRESS(0, SCAN_HOME, 0):
848 case KEYPRESS(EFI_ALT_PRESSED, 0, '<'):
849 if (idx_highlight > 0) {
850 refresh = true;
851 idx_highlight = 0;
852 }
853 break;
854
855 case KEYPRESS(0, SCAN_END, 0):
856 case KEYPRESS(EFI_ALT_PRESSED, 0, '>'):
857 if (idx_highlight < config->n_entries-1) {
858 refresh = true;
859 idx_highlight = config->n_entries-1;
860 }
861 break;
862
863 case KEYPRESS(0, SCAN_PAGE_UP, 0):
864 if (idx_highlight > visible_max)
865 idx_highlight -= visible_max;
866 else
867 idx_highlight = 0;
868 break;
869
870 case KEYPRESS(0, SCAN_PAGE_DOWN, 0):
871 idx_highlight += visible_max;
872 if (idx_highlight > config->n_entries-1)
873 idx_highlight = config->n_entries-1;
874 break;
875
876 case KEYPRESS(0, 0, '\n'):
877 case KEYPRESS(0, 0, '\r'):
878 case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */
879 case KEYPRESS(0, SCAN_F3, '\r'): /* Teclast X98+ II firmware sends malformed events */
880 case KEYPRESS(0, SCAN_RIGHT, 0):
881 exit = true;
882 break;
883
884 case KEYPRESS(0, SCAN_F1, 0):
885 case KEYPRESS(0, 0, 'h'):
886 case KEYPRESS(0, 0, 'H'):
887 case KEYPRESS(0, 0, '?'):
888 /* This must stay below 80 characters! Q/v/Ctrl+l/f deliberately not advertised. */
889 status = xstrdup16(u"(d)efault (t/T)imeout (e)dit (r/R)esolution (p)rint (O)ff re(B)oot (h)elp");
890 break;
891
892 case KEYPRESS(0, 0, 'Q'):
893 exit = true;
894 run = false;
895 break;
896
897 case KEYPRESS(0, 0, 'd'):
898 case KEYPRESS(0, 0, 'D'):
899 if (config->idx_default_efivar != idx_highlight) {
900 free(config->entry_default_efivar);
901 config->entry_default_efivar = xstrdup16(config->entries[idx_highlight]->id);
902 config->idx_default_efivar = idx_highlight;
903 status = xstrdup16(u"Default boot entry selected.");
904 } else {
905 config->entry_default_efivar = mfree(config->entry_default_efivar);
906 config->idx_default_efivar = IDX_INVALID;
907 status = xstrdup16(u"Default boot entry cleared.");
908 }
909 config->use_saved_entry_efivar = false;
910 refresh = true;
911 break;
912
913 case KEYPRESS(0, 0, '-'):
914 case KEYPRESS(0, 0, 'T'):
915 status = update_timeout_efivar(&config->timeout_sec_efivar, false);
916 break;
917
918 case KEYPRESS(0, 0, '+'):
919 case KEYPRESS(0, 0, 't'):
920 status = update_timeout_efivar(&config->timeout_sec_efivar, true);
921 break;
922
923 case KEYPRESS(0, 0, 'e'):
924 case KEYPRESS(0, 0, 'E'):
925 /* only the options of configured entries can be edited */
926 if (!config->editor ||
927 !IN_SET(config->entries[idx_highlight]->type, LOADER_EFI, LOADER_LINUX, LOADER_UNIFIED_LINUX)) {
928 status = xstrdup16(u"Entry does not support editing the command line.");
929 break;
930 }
931
932 /* Unified kernels that are signed as a whole will not accept command line options
933 * when secure boot is enabled unless there is none embedded in the image. Do not try
934 * to pretend we can edit it to only have it be ignored. */
935 if (config->entries[idx_highlight]->type == LOADER_UNIFIED_LINUX &&
936 secure_boot_enabled() &&
937 config->entries[idx_highlight]->options) {
938 status = xstrdup16(u"Entry not editable in SecureBoot mode.");
939 break;
940 }
941
942 /* The edit line may end up on the last line of the screen. And even though we're
943 * not telling the firmware to advance the line, it still does in this one case,
944 * causing a scroll to happen that screws with our beautiful boot loader output.
945 * Since we cannot paint the last character of the edit line, we simply start
946 * at x-offset 1 for symmetry. */
947 print_at(1, y_status, COLOR_EDIT, clearline + 2);
948 exit = line_edit(&config->entries[idx_highlight]->options, x_max - 2, y_status);
949 print_at(1, y_status, COLOR_NORMAL, clearline + 2);
950
951 /* The options string was now edited, hence we have to pass it to the invoked
952 * binary. */
953 config->entries[idx_highlight]->options_implied = false;
954 break;
955
956 case KEYPRESS(0, 0, 'v'):
957 status = xasprintf(
958 "systemd-boot " GIT_VERSION " (" EFI_MACHINE_TYPE_NAME "), "
959 "UEFI Specification %u.%02u, Vendor %ls %u.%02u",
960 ST->Hdr.Revision >> 16,
961 ST->Hdr.Revision & 0xffff,
962 ST->FirmwareVendor,
963 ST->FirmwareRevision >> 16,
964 ST->FirmwareRevision & 0xffff);
965 break;
966
967 case KEYPRESS(0, 0, 'p'):
968 case KEYPRESS(0, 0, 'P'):
969 print_status(config, loaded_image_path);
970 clear = true;
971 break;
972
973 case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'):
974 case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('l')):
975 case 'L': /* only uppercase, do not conflict with lower-case 'l' which picks first Linux entry */
976 clear = true;
977 break;
978
979 case KEYPRESS(0, 0, 'r'):
980 err = console_set_mode(CONSOLE_MODE_NEXT);
981 if (err != EFI_SUCCESS)
982 status = xasprintf_status(err, "Error changing console mode: %m");
983 else {
984 config->console_mode_efivar = ST->ConOut->Mode->Mode;
985 status = xasprintf(
986 "Console mode changed to %" PRIi64 ".",
987 config->console_mode_efivar);
988 }
989 new_mode = true;
990 break;
991
992 case KEYPRESS(0, 0, 'R'):
993 config->console_mode_efivar = CONSOLE_MODE_KEEP;
994 err = console_set_mode(config->console_mode == CONSOLE_MODE_KEEP ?
995 console_mode_initial : config->console_mode);
996 if (err != EFI_SUCCESS)
997 status = xasprintf_status(err, "Error resetting console mode: %m");
998 else
999 status = xasprintf(
1000 "Console mode reset to %s default.",
1001 config->console_mode == CONSOLE_MODE_KEEP ?
1002 "firmware" :
1003 "configuration file");
1004 new_mode = true;
1005 break;
1006
1007 case KEYPRESS(0, 0, 'f'):
1008 case KEYPRESS(0, 0, 'F'):
1009 case KEYPRESS(0, SCAN_F2, 0): /* Most vendors. */
1010 case KEYPRESS(0, SCAN_F10, 0): /* HP and Lenovo. */
1011 case KEYPRESS(0, SCAN_DELETE, 0): /* Same as F2. */
1012 case KEYPRESS(0, SCAN_ESC, 0): /* HP. */
1013 if (FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
1014 firmware_setup = true;
1015 /* Let's make sure the user really wants to do this. */
1016 status = xstrdup16(u"Press Enter to reboot into firmware interface.");
1017 } else
1018 status = xstrdup16(u"Reboot into firmware interface not supported.");
1019 break;
1020
1021 case KEYPRESS(0, 0, 'O'): /* Only uppercase, so that it can't be hit so easily fat-fingered, but still works safely over serial */
1022 RT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1023 break;
1024
1025 case KEYPRESS(0, 0, 'B'): /* ditto */
1026 RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1027 break;
1028
1029 default:
1030 /* jump with a hotkey directly to a matching entry */
1031 idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key));
1032 if (idx == IDX_INVALID)
1033 break;
1034 idx_highlight = idx;
1035 refresh = true;
1036 }
1037
1038 if (idx_highlight > idx_last) {
1039 idx_last = idx_highlight;
1040 idx_first = 1 + idx_highlight - visible_max;
1041 refresh = true;
1042 } else if (idx_highlight < idx_first) {
1043 idx_first = idx_highlight;
1044 idx_last = idx_highlight + visible_max-1;
1045 refresh = true;
1046 }
1047
1048 if (!refresh && idx_highlight != idx_highlight_prev)
1049 highlight = true;
1050 }
1051
1052 *chosen_entry = config->entries[idx_highlight];
1053
1054 /* Update EFI vars after we left the menu to reduce NVRAM writes. */
1055
1056 if (default_efivar_saved != config->idx_default_efivar)
1057 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", config->entry_default_efivar, EFI_VARIABLE_NON_VOLATILE);
1058
1059 if (console_mode_efivar_saved != config->console_mode_efivar) {
1060 if (config->console_mode_efivar == CONSOLE_MODE_KEEP)
1061 efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode", EFI_VARIABLE_NON_VOLATILE);
1062 else
1063 efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode",
1064 config->console_mode_efivar, EFI_VARIABLE_NON_VOLATILE);
1065 }
1066
1067 if (timeout_efivar_saved != config->timeout_sec_efivar) {
1068 switch (config->timeout_sec_efivar) {
1069 case TIMEOUT_UNSET:
1070 efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", EFI_VARIABLE_NON_VOLATILE);
1071 break;
1072 case TIMEOUT_MENU_FORCE:
1073 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-force", EFI_VARIABLE_NON_VOLATILE);
1074 break;
1075 case TIMEOUT_MENU_HIDDEN:
1076 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-hidden", EFI_VARIABLE_NON_VOLATILE);
1077 break;
1078 default:
1079 efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout",
1080 config->timeout_sec_efivar, EFI_VARIABLE_NON_VOLATILE);
1081 }
1082 }
1083
1084 clear_screen(COLOR_NORMAL);
1085 return run;
1086 }
1087
1088 static void config_add_entry(Config *config, ConfigEntry *entry) {
1089 assert(config);
1090 assert(entry);
1091
1092 /* This is just for paranoia. */
1093 assert(config->n_entries < IDX_MAX);
1094
1095 if ((config->n_entries & 15) == 0) {
1096 config->entries = xrealloc(
1097 config->entries,
1098 sizeof(void *) * config->n_entries,
1099 sizeof(void *) * (config->n_entries + 16));
1100 }
1101 config->entries[config->n_entries++] = entry;
1102 }
1103
1104 static void config_entry_free(ConfigEntry *entry) {
1105 if (!entry)
1106 return;
1107
1108 free(entry->id);
1109 free(entry->title_show);
1110 free(entry->title);
1111 free(entry->sort_key);
1112 free(entry->version);
1113 free(entry->machine_id);
1114 free(entry->loader);
1115 free(entry->devicetree);
1116 free(entry->options);
1117 strv_free(entry->initrd);
1118 free(entry->path);
1119 free(entry->current_name);
1120 free(entry->next_name);
1121 free(entry);
1122 }
1123
1124 static void config_entry_freep(ConfigEntry **entry) {
1125 config_entry_free(*entry);
1126 }
1127
1128 static char *line_get_key_value(
1129 char *content,
1130 const char *sep,
1131 size_t *pos,
1132 char **key_ret,
1133 char **value_ret) {
1134
1135 char *line, *value;
1136 size_t linelen;
1137
1138 assert(content);
1139 assert(sep);
1140 assert(pos);
1141 assert(key_ret);
1142 assert(value_ret);
1143
1144 for (;;) {
1145 line = content + *pos;
1146 if (*line == '\0')
1147 return NULL;
1148
1149 linelen = 0;
1150 while (line[linelen] && !strchr8("\n\r", line[linelen]))
1151 linelen++;
1152
1153 /* move pos to next line */
1154 *pos += linelen;
1155 if (content[*pos])
1156 (*pos)++;
1157
1158 /* empty line */
1159 if (linelen == 0)
1160 continue;
1161
1162 /* terminate line */
1163 line[linelen] = '\0';
1164
1165 /* remove leading whitespace */
1166 while (strchr8(" \t", *line)) {
1167 line++;
1168 linelen--;
1169 }
1170
1171 /* remove trailing whitespace */
1172 while (linelen > 0 && strchr8(" \t", line[linelen - 1]))
1173 linelen--;
1174 line[linelen] = '\0';
1175
1176 if (*line == '#')
1177 continue;
1178
1179 /* split key/value */
1180 value = line;
1181 while (*value && !strchr8(sep, *value))
1182 value++;
1183 if (*value == '\0')
1184 continue;
1185 *value = '\0';
1186 value++;
1187 while (*value && strchr8(sep, *value))
1188 value++;
1189
1190 /* unquote */
1191 if (value[0] == '"' && line[linelen - 1] == '"') {
1192 value++;
1193 line[linelen - 1] = '\0';
1194 }
1195
1196 *key_ret = line;
1197 *value_ret = value;
1198 return line;
1199 }
1200 }
1201
1202 static void config_defaults_load_from_file(Config *config, char *content) {
1203 char *line;
1204 size_t pos = 0;
1205 char *key, *value;
1206 EFI_STATUS err;
1207
1208 assert(config);
1209 assert(content);
1210
1211 while ((line = line_get_key_value(content, " \t", &pos, &key, &value))) {
1212 if (streq8(key, "timeout")) {
1213 if (streq8( value, "menu-force"))
1214 config->timeout_sec_config = TIMEOUT_MENU_FORCE;
1215 else if (streq8(value, "menu-hidden"))
1216 config->timeout_sec_config = TIMEOUT_MENU_HIDDEN;
1217 else {
1218 uint64_t u;
1219 if (!parse_number8(value, &u, NULL) || u > TIMEOUT_TYPE_MAX) {
1220 log_error("Error parsing 'timeout' config option: %s", value);
1221 continue;
1222 }
1223 config->timeout_sec_config = u;
1224 }
1225 config->timeout_sec = config->timeout_sec_config;
1226 continue;
1227 }
1228
1229 if (streq8(key, "default")) {
1230 if (value[0] == '@' && !strcaseeq8(value, "@saved")) {
1231 log_error("Unsupported special entry identifier: %s", value);
1232 continue;
1233 }
1234 free(config->entry_default_config);
1235 config->entry_default_config = xstr8_to_16(value);
1236 continue;
1237 }
1238
1239 if (streq8(key, "editor")) {
1240 err = parse_boolean(value, &config->editor);
1241 if (err != EFI_SUCCESS)
1242 log_error("Error parsing 'editor' config option: %s", value);
1243 continue;
1244 }
1245
1246 if (streq8(key, "auto-entries")) {
1247 err = parse_boolean(value, &config->auto_entries);
1248 if (err != EFI_SUCCESS)
1249 log_error("Error parsing 'auto-entries' config option: %s", value);
1250 continue;
1251 }
1252
1253 if (streq8(key, "auto-firmware")) {
1254 err = parse_boolean(value, &config->auto_firmware);
1255 if (err != EFI_SUCCESS)
1256 log_error("Error parsing 'auto-firmware' config option: %s", value);
1257 continue;
1258 }
1259
1260 if (streq8(key, "beep")) {
1261 err = parse_boolean(value, &config->beep);
1262 if (err != EFI_SUCCESS)
1263 log_error("Error parsing 'beep' config option: %s", value);
1264 continue;
1265 }
1266
1267 if (streq8(key, "reboot-for-bitlocker")) {
1268 err = parse_boolean(value, &config->reboot_for_bitlocker);
1269 if (err != EFI_SUCCESS)
1270 log_error("Error parsing 'reboot-for-bitlocker' config option: %s", value);
1271 }
1272
1273 if (streq8(key, "secure-boot-enroll")) {
1274 if (streq8(value, "manual"))
1275 config->secure_boot_enroll = ENROLL_MANUAL;
1276 else if (streq8(value, "force"))
1277 config->secure_boot_enroll = ENROLL_FORCE;
1278 else if (streq8(value, "if-safe"))
1279 config->secure_boot_enroll = ENROLL_IF_SAFE;
1280 else if (streq8(value, "off"))
1281 config->secure_boot_enroll = ENROLL_OFF;
1282 else
1283 log_error("Error parsing 'secure-boot-enroll' config option: %s", value);
1284 continue;
1285 }
1286
1287 if (streq8(key, "console-mode")) {
1288 if (streq8(value, "auto"))
1289 config->console_mode = CONSOLE_MODE_AUTO;
1290 else if (streq8(value, "max"))
1291 config->console_mode = CONSOLE_MODE_FIRMWARE_MAX;
1292 else if (streq8(value, "keep"))
1293 config->console_mode = CONSOLE_MODE_KEEP;
1294 else {
1295 uint64_t u;
1296 if (!parse_number8(value, &u, NULL) || u > CONSOLE_MODE_RANGE_MAX) {
1297 log_error("Error parsing 'console-mode' config option: %s", value);
1298 continue;
1299 }
1300 config->console_mode = u;
1301 }
1302 continue;
1303 }
1304 }
1305 }
1306
1307 static void config_entry_parse_tries(
1308 ConfigEntry *entry,
1309 const char16_t *path,
1310 const char16_t *file,
1311 const char16_t *suffix) {
1312
1313 assert(entry);
1314 assert(path);
1315 assert(file);
1316 assert(suffix);
1317
1318 /*
1319 * Parses a suffix of two counters (one going down, one going up) in the form "+LEFT-DONE" from the end of the
1320 * filename (but before the .efi/.conf suffix), where the "-DONE" part is optional and may be left out (in
1321 * which case that counter as assumed to be zero, i.e. the missing part is synonymous to "-0").
1322 *
1323 * Names we grok, and the series they result in:
1324 *
1325 * foobar+3.efi → foobar+2-1.efi → foobar+1-2.efi → foobar+0-3.efi → STOP!
1326 * foobar+4-0.efi → foobar+3-1.efi → foobar+2-2.efi → foobar+1-3.efi → foobar+0-4.efi → STOP!
1327 */
1328
1329 const char16_t *counter = NULL;
1330 for (;;) {
1331 char16_t *plus = strchr16(counter ?: file, '+');
1332 if (plus) {
1333 /* We want the last "+". */
1334 counter = plus + 1;
1335 continue;
1336 }
1337 if (counter)
1338 break;
1339
1340 /* No boot counter found. */
1341 return;
1342 }
1343
1344 uint64_t tries_left, tries_done = 0;
1345 size_t prefix_len = counter - file;
1346
1347 if (!parse_number16(counter, &tries_left, &counter) || tries_left > INT_MAX)
1348 return;
1349
1350 /* Parse done counter only if present. */
1351 if (*counter == '-' && (!parse_number16(counter + 1, &tries_done, &counter) || tries_done > INT_MAX))
1352 return;
1353
1354 /* Boot counter in the middle of the name? */
1355 if (!streq16(counter, suffix))
1356 return;
1357
1358 entry->tries_left = tries_left;
1359 entry->tries_done = tries_done;
1360 entry->path = xstrdup16(path);
1361 entry->current_name = xstrdup16(file);
1362 entry->next_name = xasprintf(
1363 "%.*ls%" PRIu64 "-%" PRIu64 "%ls",
1364 (int) prefix_len,
1365 file,
1366 LESS_BY(tries_left, 1u),
1367 MIN(tries_done + 1, (uint64_t) INT_MAX),
1368 suffix);
1369 }
1370
1371 static EFI_STATUS config_entry_bump_counters(ConfigEntry *entry) {
1372 _cleanup_free_ char16_t* old_path = NULL, *new_path = NULL;
1373 _cleanup_(file_closep) EFI_FILE *handle = NULL;
1374 _cleanup_free_ EFI_FILE_INFO *file_info = NULL;
1375 size_t file_info_size;
1376 EFI_STATUS err;
1377
1378 assert(entry);
1379
1380 if (entry->tries_left < 0)
1381 return EFI_SUCCESS;
1382
1383 if (!entry->path || !entry->current_name || !entry->next_name)
1384 return EFI_SUCCESS;
1385
1386 _cleanup_(file_closep) EFI_FILE *root = NULL;
1387 err = open_volume(entry->device, &root);
1388 if (err != EFI_SUCCESS)
1389 return log_error_status(err, "Error opening entry root path: %m");
1390
1391 old_path = xasprintf("%ls\\%ls", entry->path, entry->current_name);
1392
1393 err = root->Open(root, &handle, old_path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
1394 if (err != EFI_SUCCESS)
1395 return log_error_status(err, "Error opening boot entry: %m");
1396
1397 err = get_file_info(handle, &file_info, &file_info_size);
1398 if (err != EFI_SUCCESS)
1399 return log_error_status(err, "Error getting boot entry file info: %m");
1400
1401 /* And rename the file */
1402 strcpy16(file_info->FileName, entry->next_name);
1403 err = handle->SetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), file_info_size, file_info);
1404 if (err != EFI_SUCCESS)
1405 return log_error_status(
1406 err, "Failed to rename '%ls' to '%ls', ignoring: %m", old_path, entry->next_name);
1407
1408 /* Flush everything to disk, just in case… */
1409 err = handle->Flush(handle);
1410 if (err != EFI_SUCCESS)
1411 return log_error_status(err, "Error flushing boot entry file info: %m");
1412
1413 /* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on
1414 * success */
1415 new_path = xasprintf("%ls\\%ls", entry->path, entry->next_name);
1416 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderBootCountPath", new_path, 0);
1417
1418 /* If the file we just renamed is the loader path, then let's update that. */
1419 if (streq16(entry->loader, old_path)) {
1420 free(entry->loader);
1421 entry->loader = TAKE_PTR(new_path);
1422 }
1423
1424 return EFI_SUCCESS;
1425 }
1426
1427 static void config_entry_add_type1(
1428 Config *config,
1429 EFI_HANDLE *device,
1430 EFI_FILE *root_dir,
1431 const char16_t *path,
1432 const char16_t *file,
1433 char *content,
1434 const char16_t *loaded_image_path) {
1435
1436 _cleanup_(config_entry_freep) ConfigEntry *entry = NULL;
1437 char *line;
1438 size_t pos = 0, n_initrd = 0;
1439 char *key, *value;
1440 EFI_STATUS err;
1441
1442 assert(config);
1443 assert(device);
1444 assert(root_dir);
1445 assert(path);
1446 assert(file);
1447 assert(content);
1448
1449 entry = xnew(ConfigEntry, 1);
1450 *entry = (ConfigEntry) {
1451 .tries_done = -1,
1452 .tries_left = -1,
1453 };
1454
1455 while ((line = line_get_key_value(content, " \t", &pos, &key, &value))) {
1456 if (streq8(key, "title")) {
1457 free(entry->title);
1458 entry->title = xstr8_to_16(value);
1459 continue;
1460 }
1461
1462 if (streq8(key, "sort-key")) {
1463 free(entry->sort_key);
1464 entry->sort_key = xstr8_to_16(value);
1465 continue;
1466 }
1467
1468 if (streq8(key, "version")) {
1469 free(entry->version);
1470 entry->version = xstr8_to_16(value);
1471 continue;
1472 }
1473
1474 if (streq8(key, "machine-id")) {
1475 free(entry->machine_id);
1476 entry->machine_id = xstr8_to_16(value);
1477 continue;
1478 }
1479
1480 if (streq8(key, "linux")) {
1481 free(entry->loader);
1482 entry->type = LOADER_LINUX;
1483 entry->loader = xstr8_to_path(value);
1484 entry->key = 'l';
1485 continue;
1486 }
1487
1488 if (streq8(key, "efi")) {
1489 entry->type = LOADER_EFI;
1490 free(entry->loader);
1491 entry->loader = xstr8_to_path(value);
1492
1493 /* do not add an entry for ourselves */
1494 if (strcaseeq16(entry->loader, loaded_image_path)) {
1495 entry->type = LOADER_UNDEFINED;
1496 break;
1497 }
1498 continue;
1499 }
1500
1501 if (streq8(key, "architecture")) {
1502 /* do not add an entry for an EFI image of architecture not matching with that of the image */
1503 if (!streq8(value, EFI_MACHINE_TYPE_NAME)) {
1504 entry->type = LOADER_UNDEFINED;
1505 break;
1506 }
1507 continue;
1508 }
1509
1510 if (streq8(key, "devicetree")) {
1511 free(entry->devicetree);
1512 entry->devicetree = xstr8_to_path(value);
1513 continue;
1514 }
1515
1516 if (streq8(key, "initrd")) {
1517 entry->initrd = xrealloc(
1518 entry->initrd,
1519 n_initrd == 0 ? 0 : (n_initrd + 1) * sizeof(uint16_t *),
1520 (n_initrd + 2) * sizeof(uint16_t *));
1521 entry->initrd[n_initrd++] = xstr8_to_path(value);
1522 entry->initrd[n_initrd] = NULL;
1523 continue;
1524 }
1525
1526 if (streq8(key, "options")) {
1527 _cleanup_free_ char16_t *new = NULL;
1528
1529 new = xstr8_to_16(value);
1530 if (entry->options) {
1531 char16_t *s = xasprintf("%ls %ls", entry->options, new);
1532 free(entry->options);
1533 entry->options = s;
1534 } else
1535 entry->options = TAKE_PTR(new);
1536
1537 continue;
1538 }
1539 }
1540
1541 if (entry->type == LOADER_UNDEFINED)
1542 return;
1543
1544 /* check existence */
1545 _cleanup_(file_closep) EFI_FILE *handle = NULL;
1546 err = root_dir->Open(root_dir, &handle, entry->loader, EFI_FILE_MODE_READ, 0ULL);
1547 if (err != EFI_SUCCESS)
1548 return;
1549
1550 entry->device = device;
1551 entry->id = xstrdup16(file);
1552 strtolower16(entry->id);
1553
1554 config_add_entry(config, entry);
1555
1556 config_entry_parse_tries(entry, path, file, u".conf");
1557 TAKE_PTR(entry);
1558 }
1559
1560 static EFI_STATUS efivar_get_timeout(const char16_t *var, uint32_t *ret_value) {
1561 _cleanup_free_ char16_t *value = NULL;
1562 EFI_STATUS err;
1563
1564 assert(var);
1565 assert(ret_value);
1566
1567 err = efivar_get(MAKE_GUID_PTR(LOADER), var, &value);
1568 if (err != EFI_SUCCESS)
1569 return err;
1570
1571 if (streq16(value, u"menu-force")) {
1572 *ret_value = TIMEOUT_MENU_FORCE;
1573 return EFI_SUCCESS;
1574 }
1575 if (streq16(value, u"menu-hidden")) {
1576 *ret_value = TIMEOUT_MENU_HIDDEN;
1577 return EFI_SUCCESS;
1578 }
1579
1580 uint64_t timeout;
1581 if (!parse_number16(value, &timeout, NULL))
1582 return EFI_INVALID_PARAMETER;
1583
1584 *ret_value = MIN(timeout, TIMEOUT_TYPE_MAX);
1585 return EFI_SUCCESS;
1586 }
1587
1588 static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
1589 _cleanup_free_ char *content = NULL;
1590 size_t value = 0; /* avoid false maybe-uninitialized warning */
1591 EFI_STATUS err;
1592
1593 assert(root_dir);
1594
1595 *config = (Config) {
1596 .editor = true,
1597 .auto_entries = true,
1598 .auto_firmware = true,
1599 .reboot_for_bitlocker = false,
1600 .secure_boot_enroll = ENROLL_IF_SAFE,
1601 .idx_default_efivar = IDX_INVALID,
1602 .console_mode = CONSOLE_MODE_KEEP,
1603 .console_mode_efivar = CONSOLE_MODE_KEEP,
1604 .timeout_sec_config = TIMEOUT_UNSET,
1605 .timeout_sec_efivar = TIMEOUT_UNSET,
1606 };
1607
1608 err = file_read(root_dir, u"\\loader\\loader.conf", 0, 0, &content, NULL);
1609 if (err == EFI_SUCCESS)
1610 config_defaults_load_from_file(config, content);
1611
1612 err = efivar_get_timeout(u"LoaderConfigTimeout", &config->timeout_sec_efivar);
1613 if (err == EFI_SUCCESS)
1614 config->timeout_sec = config->timeout_sec_efivar;
1615 else if (err != EFI_NOT_FOUND)
1616 log_error_status(err, "Error reading LoaderConfigTimeout EFI variable: %m");
1617
1618 err = efivar_get_timeout(u"LoaderConfigTimeoutOneShot", &config->timeout_sec);
1619 if (err == EFI_SUCCESS) {
1620 /* Unset variable now, after all it's "one shot". */
1621 (void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeoutOneShot", EFI_VARIABLE_NON_VOLATILE);
1622
1623 config->force_menu = true; /* force the menu when this is set */
1624 } else if (err != EFI_NOT_FOUND)
1625 log_error_status(err, "Error reading LoaderConfigTimeoutOneShot EFI variable: %m");
1626
1627 err = efivar_get_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigConsoleMode", &value);
1628 if (err == EFI_SUCCESS)
1629 config->console_mode_efivar = value;
1630
1631 err = efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", &config->entry_oneshot);
1632 if (err == EFI_SUCCESS)
1633 /* Unset variable now, after all it's "one shot". */
1634 (void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", EFI_VARIABLE_NON_VOLATILE);
1635
1636 (void) efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", &config->entry_default_efivar);
1637
1638 strtolower16(config->entry_default_config);
1639 strtolower16(config->entry_default_efivar);
1640 strtolower16(config->entry_oneshot);
1641 strtolower16(config->entry_saved);
1642
1643 config->use_saved_entry = streq16(config->entry_default_config, u"@saved");
1644 config->use_saved_entry_efivar = streq16(config->entry_default_efivar, u"@saved");
1645 if (config->use_saved_entry || config->use_saved_entry_efivar)
1646 (void) efivar_get(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", &config->entry_saved);
1647 }
1648
1649 static void config_load_entries(
1650 Config *config,
1651 EFI_HANDLE *device,
1652 EFI_FILE *root_dir,
1653 const char16_t *loaded_image_path) {
1654
1655 _cleanup_(file_closep) EFI_FILE *entries_dir = NULL;
1656 _cleanup_free_ EFI_FILE_INFO *f = NULL;
1657 size_t f_size = 0;
1658 EFI_STATUS err;
1659
1660 assert(config);
1661 assert(device);
1662 assert(root_dir);
1663
1664 /* Adds Boot Loader Type #1 entries (i.e. /loader/entries/….conf) */
1665
1666 err = open_directory(root_dir, u"\\loader\\entries", &entries_dir);
1667 if (err != EFI_SUCCESS)
1668 return;
1669
1670 for (;;) {
1671 _cleanup_free_ char *content = NULL;
1672
1673 err = readdir(entries_dir, &f, &f_size);
1674 if (err != EFI_SUCCESS || !f)
1675 break;
1676
1677 if (f->FileName[0] == '.')
1678 continue;
1679 if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY))
1680 continue;
1681
1682 if (!endswith_no_case(f->FileName, u".conf"))
1683 continue;
1684 if (startswith(f->FileName, u"auto-"))
1685 continue;
1686
1687 err = file_read(entries_dir, f->FileName, 0, 0, &content, NULL);
1688 if (err == EFI_SUCCESS)
1689 config_entry_add_type1(config, device, root_dir, u"\\loader\\entries", f->FileName, content, loaded_image_path);
1690 }
1691 }
1692
1693 static int config_entry_compare(const ConfigEntry *a, const ConfigEntry *b) {
1694 int r;
1695
1696 assert(a);
1697 assert(b);
1698
1699 /* Order entries that have no tries left to the end of the list */
1700 r = CMP(a->tries_left == 0, b->tries_left == 0);
1701 if (r != 0)
1702 return r;
1703
1704 /* If there's a sort key defined for *both* entries, then we do new-style ordering, i.e. by
1705 * sort-key/machine-id/version, with a final fallback to id. If there's no sort key for either, we do
1706 * old-style ordering, i.e. by id only. If one has sort key and the other does not, we put new-style
1707 * before old-style. */
1708 r = CMP(!a->sort_key, !b->sort_key);
1709 if (r != 0) /* one is old-style, one new-style */
1710 return r;
1711
1712 if (a->sort_key && b->sort_key) {
1713 r = strcmp16(a->sort_key, b->sort_key);
1714 if (r != 0)
1715 return r;
1716
1717 /* If multiple installations of the same OS are around, group by machine ID */
1718 r = strcmp16(a->machine_id, b->machine_id);
1719 if (r != 0)
1720 return r;
1721
1722 /* If the sort key was defined, then order by version now (downwards, putting the newest first) */
1723 r = -strverscmp_improved(a->version, b->version);
1724 if (r != 0)
1725 return r;
1726 }
1727
1728 /* Now order by ID. The version is likely part of the ID, thus note that this will generatelly put
1729 * the newer versions earlier. Specifying a sort key explicitly is preferable, because it gives an
1730 * explicit sort order. */
1731 r = -strverscmp_improved(a->id, b->id);
1732 if (r != 0)
1733 return r;
1734
1735 if (a->tries_left < 0 || b->tries_left < 0)
1736 return 0;
1737
1738 /* If both items have boot counting, and otherwise are identical, put the entry with more tries left first */
1739 r = -CMP(a->tries_left, b->tries_left);
1740 if (r != 0)
1741 return r;
1742
1743 /* If they have the same number of tries left, then let the one win which was tried fewer times so far */
1744 return CMP(a->tries_done, b->tries_done);
1745 }
1746
1747 static size_t config_entry_find(Config *config, const char16_t *pattern) {
1748 assert(config);
1749
1750 /* We expect pattern and entry IDs to be already case folded. */
1751
1752 if (!pattern)
1753 return IDX_INVALID;
1754
1755 for (size_t i = 0; i < config->n_entries; i++)
1756 if (efi_fnmatch(pattern, config->entries[i]->id))
1757 return i;
1758
1759 return IDX_INVALID;
1760 }
1761
1762 static void config_default_entry_select(Config *config) {
1763 size_t i;
1764
1765 assert(config);
1766
1767 i = config_entry_find(config, config->entry_oneshot);
1768 if (i != IDX_INVALID) {
1769 config->idx_default = i;
1770 return;
1771 }
1772
1773 i = config_entry_find(config, config->use_saved_entry_efivar ? config->entry_saved : config->entry_default_efivar);
1774 if (i != IDX_INVALID) {
1775 config->idx_default = i;
1776 config->idx_default_efivar = i;
1777 return;
1778 }
1779
1780 if (config->use_saved_entry)
1781 /* No need to do the same thing twice. */
1782 i = config->use_saved_entry_efivar ? IDX_INVALID : config_entry_find(config, config->entry_saved);
1783 else
1784 i = config_entry_find(config, config->entry_default_config);
1785 if (i != IDX_INVALID) {
1786 config->idx_default = i;
1787 return;
1788 }
1789
1790 /* select the first suitable entry */
1791 for (i = 0; i < config->n_entries; i++) {
1792 if (config->entries[i]->type == LOADER_AUTO || config->entries[i]->call)
1793 continue;
1794 config->idx_default = i;
1795 return;
1796 }
1797
1798 /* If no configured entry to select from was found, enable the menu. */
1799 config->idx_default = 0;
1800 if (config->timeout_sec == 0)
1801 config->timeout_sec = 10;
1802 }
1803
1804 static bool entries_unique(ConfigEntry **entries, bool *unique, size_t n_entries) {
1805 bool is_unique = true;
1806
1807 assert(entries);
1808 assert(unique);
1809
1810 for (size_t i = 0; i < n_entries; i++)
1811 for (size_t k = i + 1; k < n_entries; k++) {
1812 if (!streq16(entries[i]->title_show, entries[k]->title_show))
1813 continue;
1814
1815 is_unique = unique[i] = unique[k] = false;
1816 }
1817
1818 return is_unique;
1819 }
1820
1821 /* generate a unique title, avoiding non-distinguishable menu entries */
1822 static void config_title_generate(Config *config) {
1823 assert(config);
1824
1825 bool unique[config->n_entries];
1826
1827 /* set title */
1828 for (size_t i = 0; i < config->n_entries; i++) {
1829 assert(!config->entries[i]->title_show);
1830 unique[i] = true;
1831 config->entries[i]->title_show = xstrdup16(config->entries[i]->title ?: config->entries[i]->id);
1832 }
1833
1834 if (entries_unique(config->entries, unique, config->n_entries))
1835 return;
1836
1837 /* add version to non-unique titles */
1838 for (size_t i = 0; i < config->n_entries; i++) {
1839 if (unique[i])
1840 continue;
1841
1842 unique[i] = true;
1843
1844 if (!config->entries[i]->version)
1845 continue;
1846
1847 _cleanup_free_ char16_t *t = config->entries[i]->title_show;
1848 config->entries[i]->title_show = xasprintf("%ls (%ls)", t, config->entries[i]->version);
1849 }
1850
1851 if (entries_unique(config->entries, unique, config->n_entries))
1852 return;
1853
1854 /* add machine-id to non-unique titles */
1855 for (size_t i = 0; i < config->n_entries; i++) {
1856 if (unique[i])
1857 continue;
1858
1859 unique[i] = true;
1860
1861 if (!config->entries[i]->machine_id)
1862 continue;
1863
1864 _cleanup_free_ char16_t *t = config->entries[i]->title_show;
1865 config->entries[i]->title_show = xasprintf("%ls (%.8ls)", t, config->entries[i]->machine_id);
1866 }
1867
1868 if (entries_unique(config->entries, unique, config->n_entries))
1869 return;
1870
1871 /* add file name to non-unique titles */
1872 for (size_t i = 0; i < config->n_entries; i++) {
1873 if (unique[i])
1874 continue;
1875
1876 _cleanup_free_ char16_t *t = config->entries[i]->title_show;
1877 config->entries[i]->title_show = xasprintf("%ls (%ls)", t, config->entries[i]->id);
1878 }
1879 }
1880
1881 static bool is_sd_boot(EFI_FILE *root_dir, const char16_t *loader_path) {
1882 EFI_STATUS err;
1883 static const char * const sections[] = {
1884 ".sdmagic",
1885 NULL
1886 };
1887 size_t offset = 0, size = 0, read;
1888 _cleanup_free_ char *content = NULL;
1889
1890 assert(root_dir);
1891 assert(loader_path);
1892
1893 err = pe_file_locate_sections(root_dir, loader_path, sections, &offset, &size);
1894 if (err != EFI_SUCCESS || size != sizeof(SD_MAGIC))
1895 return false;
1896
1897 err = file_read(root_dir, loader_path, offset, size, &content, &read);
1898 if (err != EFI_SUCCESS || size != read)
1899 return false;
1900
1901 return memcmp(content, SD_MAGIC, sizeof(SD_MAGIC)) == 0;
1902 }
1903
1904 static ConfigEntry *config_entry_add_loader_auto(
1905 Config *config,
1906 EFI_HANDLE *device,
1907 EFI_FILE *root_dir,
1908 const char16_t *loaded_image_path,
1909 const char16_t *id,
1910 char16_t key,
1911 const char16_t *title,
1912 const char16_t *loader) {
1913
1914 assert(config);
1915 assert(device);
1916 assert(root_dir);
1917 assert(id);
1918 assert(title);
1919
1920 if (!config->auto_entries)
1921 return NULL;
1922
1923 if (!loader) {
1924 loader = u"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME ".efi";
1925
1926 /* We are trying to add the default EFI loader here,
1927 * but we do not want to do that if that would be us.
1928 *
1929 * If the default loader is not us, it might be shim. It would
1930 * chainload GRUBX64.EFI in that case, which might be us. */
1931 if (strcaseeq16(loader, loaded_image_path) ||
1932 is_sd_boot(root_dir, loader) ||
1933 is_sd_boot(root_dir, u"\\EFI\\BOOT\\GRUB" EFI_MACHINE_TYPE_NAME u".EFI"))
1934 return NULL;
1935 }
1936
1937 /* check existence */
1938 _cleanup_(file_closep) EFI_FILE *handle = NULL;
1939 EFI_STATUS err = root_dir->Open(root_dir, &handle, (char16_t *) loader, EFI_FILE_MODE_READ, 0ULL);
1940 if (err != EFI_SUCCESS)
1941 return NULL;
1942
1943 ConfigEntry *entry = xnew(ConfigEntry, 1);
1944 *entry = (ConfigEntry) {
1945 .id = xstrdup16(id),
1946 .type = LOADER_AUTO,
1947 .title = xstrdup16(title),
1948 .device = device,
1949 .loader = xstrdup16(loader),
1950 .key = key,
1951 .tries_done = -1,
1952 .tries_left = -1,
1953 };
1954
1955 config_add_entry(config, entry);
1956 return entry;
1957 }
1958
1959 static void config_entry_add_osx(Config *config) {
1960 EFI_STATUS err;
1961 size_t n_handles = 0;
1962 _cleanup_free_ EFI_HANDLE *handles = NULL;
1963
1964 assert(config);
1965
1966 if (!config->auto_entries)
1967 return;
1968
1969 err = BS->LocateHandleBuffer(
1970 ByProtocol, MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), NULL, &n_handles, &handles);
1971 if (err != EFI_SUCCESS)
1972 return;
1973
1974 for (size_t i = 0; i < n_handles; i++) {
1975 _cleanup_(file_closep) EFI_FILE *root = NULL;
1976
1977 if (open_volume(handles[i], &root) != EFI_SUCCESS)
1978 continue;
1979
1980 if (config_entry_add_loader_auto(
1981 config,
1982 handles[i],
1983 root,
1984 NULL,
1985 u"auto-osx",
1986 'a',
1987 u"macOS",
1988 u"\\System\\Library\\CoreServices\\boot.efi"))
1989 break;
1990 }
1991 }
1992
1993 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
1994 static EFI_STATUS boot_windows_bitlocker(void) {
1995 _cleanup_free_ EFI_HANDLE *handles = NULL;
1996 size_t n_handles;
1997 EFI_STATUS err;
1998
1999 // FIXME: Experimental for now. Should be generalized, and become a per-entry option that can be
2000 // enabled independently of BitLocker, and without a BootXXXX entry pre-existing.
2001
2002 /* BitLocker key cannot be sealed without a TPM present. */
2003 if (!tpm_present())
2004 return EFI_NOT_FOUND;
2005
2006 err = BS->LocateHandleBuffer(
2007 ByProtocol, MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL), NULL, &n_handles, &handles);
2008 if (err != EFI_SUCCESS)
2009 return err;
2010
2011 /* Look for BitLocker magic string on all block drives. */
2012 bool found = false;
2013 for (size_t i = 0; i < n_handles; i++) {
2014 EFI_BLOCK_IO_PROTOCOL *block_io;
2015 err = BS->HandleProtocol(handles[i], MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL), (void **) &block_io);
2016 if (err != EFI_SUCCESS || block_io->Media->BlockSize < 512 || block_io->Media->BlockSize > 4096)
2017 continue;
2018
2019 char buf[4096];
2020 err = block_io->ReadBlocks(block_io, block_io->Media->MediaId, 0, sizeof(buf), buf);
2021 if (err != EFI_SUCCESS)
2022 continue;
2023
2024 if (memcmp(buf + 3, "-FVE-FS-", STRLEN("-FVE-FS-")) == 0) {
2025 found = true;
2026 break;
2027 }
2028 }
2029
2030 /* If no BitLocker drive was found, we can just chainload bootmgfw.efi directly. */
2031 if (!found)
2032 return EFI_NOT_FOUND;
2033
2034 _cleanup_free_ uint16_t *boot_order = NULL;
2035 size_t boot_order_size;
2036
2037 /* There can be gaps in Boot#### entries. Instead of iterating over the full
2038 * EFI var list or uint16_t namespace, just look for "Windows Boot Manager" in BootOrder. */
2039 err = efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"BootOrder", (char **) &boot_order, &boot_order_size);
2040 if (err != EFI_SUCCESS || boot_order_size % sizeof(uint16_t) != 0)
2041 return err;
2042
2043 for (size_t i = 0; i < boot_order_size / sizeof(uint16_t); i++) {
2044 _cleanup_free_ char *buf = NULL;
2045 size_t buf_size;
2046
2047 _cleanup_free_ char16_t *name = xasprintf("Boot%04x", boot_order[i]);
2048 err = efivar_get_raw(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), name, &buf, &buf_size);
2049 if (err != EFI_SUCCESS)
2050 continue;
2051
2052 /* Boot#### are EFI_LOAD_OPTION. But we really are only interested
2053 * for the description, which is at this offset. */
2054 size_t offset = sizeof(uint32_t) + sizeof(uint16_t);
2055 if (buf_size < offset + sizeof(char16_t))
2056 continue;
2057
2058 if (streq16((char16_t *) (buf + offset), u"Windows Boot Manager")) {
2059 err = efivar_set_raw(
2060 MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE),
2061 u"BootNext",
2062 boot_order + i,
2063 sizeof(boot_order[i]),
2064 EFI_VARIABLE_NON_VOLATILE);
2065 if (err != EFI_SUCCESS)
2066 return err;
2067 RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
2068 assert_not_reached();
2069 }
2070 }
2071
2072 return EFI_NOT_FOUND;
2073 }
2074 #endif
2075
2076 static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir) {
2077 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
2078 _cleanup_free_ char *bcd = NULL;
2079 char16_t *title = NULL;
2080 EFI_STATUS err;
2081 size_t len;
2082
2083 assert(config);
2084 assert(device);
2085 assert(root_dir);
2086
2087 if (!config->auto_entries)
2088 return;
2089
2090 /* Try to find a better title. */
2091 err = file_read(root_dir, u"\\EFI\\Microsoft\\Boot\\BCD", 0, 100*1024, &bcd, &len);
2092 if (err == EFI_SUCCESS)
2093 title = get_bcd_title((uint8_t *) bcd, len);
2094
2095 ConfigEntry *e = config_entry_add_loader_auto(config, device, root_dir, NULL,
2096 u"auto-windows", 'w', title ?: u"Windows Boot Manager",
2097 u"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
2098
2099 if (config->reboot_for_bitlocker)
2100 e->call = boot_windows_bitlocker;
2101 #endif
2102 }
2103
2104 static void config_entry_add_unified(
2105 Config *config,
2106 EFI_HANDLE *device,
2107 EFI_FILE *root_dir) {
2108
2109 _cleanup_(file_closep) EFI_FILE *linux_dir = NULL;
2110 _cleanup_free_ EFI_FILE_INFO *f = NULL;
2111 size_t f_size = 0;
2112 EFI_STATUS err;
2113
2114 /* Adds Boot Loader Type #2 entries (i.e. /EFI/Linux/….efi) */
2115
2116 assert(config);
2117 assert(device);
2118 assert(root_dir);
2119
2120 err = open_directory(root_dir, u"\\EFI\\Linux", &linux_dir);
2121 if (err != EFI_SUCCESS)
2122 return;
2123
2124 for (;;) {
2125 enum {
2126 SECTION_CMDLINE,
2127 SECTION_OSREL,
2128 _SECTION_MAX,
2129 };
2130
2131 static const char * const sections[_SECTION_MAX + 1] = {
2132 [SECTION_CMDLINE] = ".cmdline",
2133 [SECTION_OSREL] = ".osrel",
2134 NULL,
2135 };
2136
2137 _cleanup_free_ char16_t *os_pretty_name = NULL, *os_image_id = NULL, *os_name = NULL, *os_id = NULL,
2138 *os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL;
2139 const char16_t *good_name, *good_version, *good_sort_key;
2140 _cleanup_free_ char *content = NULL;
2141 size_t offs[_SECTION_MAX] = {}, szs[_SECTION_MAX] = {}, pos = 0;
2142 char *line, *key, *value;
2143
2144 err = readdir(linux_dir, &f, &f_size);
2145 if (err != EFI_SUCCESS || !f)
2146 break;
2147
2148 if (f->FileName[0] == '.')
2149 continue;
2150 if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY))
2151 continue;
2152 if (!endswith_no_case(f->FileName, u".efi"))
2153 continue;
2154 if (startswith(f->FileName, u"auto-"))
2155 continue;
2156
2157 /* look for .osrel and .cmdline sections in the .efi binary */
2158 err = pe_file_locate_sections(linux_dir, f->FileName, sections, offs, szs);
2159 if (err != EFI_SUCCESS || szs[SECTION_OSREL] == 0)
2160 continue;
2161
2162 err = file_read(linux_dir, f->FileName, offs[SECTION_OSREL], szs[SECTION_OSREL], &content, NULL);
2163 if (err != EFI_SUCCESS)
2164 continue;
2165
2166 /* read properties from the embedded os-release file */
2167 while ((line = line_get_key_value(content, "=", &pos, &key, &value))) {
2168 if (streq8(key, "PRETTY_NAME")) {
2169 free(os_pretty_name);
2170 os_pretty_name = xstr8_to_16(value);
2171 continue;
2172 }
2173
2174 if (streq8(key, "IMAGE_ID")) {
2175 free(os_image_id);
2176 os_image_id = xstr8_to_16(value);
2177 continue;
2178 }
2179
2180 if (streq8(key, "NAME")) {
2181 free(os_name);
2182 os_name = xstr8_to_16(value);
2183 continue;
2184 }
2185
2186 if (streq8(key, "ID")) {
2187 free(os_id);
2188 os_id = xstr8_to_16(value);
2189 continue;
2190 }
2191
2192 if (streq8(key, "IMAGE_VERSION")) {
2193 free(os_image_version);
2194 os_image_version = xstr8_to_16(value);
2195 continue;
2196 }
2197
2198 if (streq8(key, "VERSION")) {
2199 free(os_version);
2200 os_version = xstr8_to_16(value);
2201 continue;
2202 }
2203
2204 if (streq8(key, "VERSION_ID")) {
2205 free(os_version_id);
2206 os_version_id = xstr8_to_16(value);
2207 continue;
2208 }
2209
2210 if (streq8(key, "BUILD_ID")) {
2211 free(os_build_id);
2212 os_build_id = xstr8_to_16(value);
2213 continue;
2214 }
2215 }
2216
2217 if (!bootspec_pick_name_version_sort_key(
2218 os_pretty_name,
2219 os_image_id,
2220 os_name,
2221 os_id,
2222 os_image_version,
2223 os_version,
2224 os_version_id,
2225 os_build_id,
2226 &good_name,
2227 &good_version,
2228 &good_sort_key))
2229 continue;
2230
2231 ConfigEntry *entry = xnew(ConfigEntry, 1);
2232 *entry = (ConfigEntry) {
2233 .id = xstrdup16(f->FileName),
2234 .type = LOADER_UNIFIED_LINUX,
2235 .title = xstrdup16(good_name),
2236 .version = xstrdup16(good_version),
2237 .device = device,
2238 .loader = xasprintf("\\EFI\\Linux\\%ls", f->FileName),
2239 .sort_key = xstrdup16(good_sort_key),
2240 .key = 'l',
2241 .tries_done = -1,
2242 .tries_left = -1,
2243 };
2244
2245 strtolower16(entry->id);
2246 config_add_entry(config, entry);
2247 config_entry_parse_tries(entry, u"\\EFI\\Linux", f->FileName, u".efi");
2248
2249 if (szs[SECTION_CMDLINE] == 0)
2250 continue;
2251
2252 content = mfree(content);
2253
2254 /* read the embedded cmdline file */
2255 size_t cmdline_len;
2256 err = file_read(linux_dir, f->FileName, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, &cmdline_len);
2257 if (err == EFI_SUCCESS) {
2258 entry->options = xstrn8_to_16(content, cmdline_len);
2259 mangle_stub_cmdline(entry->options);
2260 entry->options_implied = true;
2261 }
2262 }
2263 }
2264
2265 static void config_load_xbootldr(
2266 Config *config,
2267 EFI_HANDLE *device) {
2268
2269 _cleanup_(file_closep) EFI_FILE *root_dir = NULL;
2270 EFI_HANDLE new_device = NULL; /* avoid false maybe-uninitialized warning */
2271 EFI_STATUS err;
2272
2273 assert(config);
2274 assert(device);
2275
2276 err = partition_open(MAKE_GUID_PTR(XBOOTLDR), device, &new_device, &root_dir);
2277 if (err != EFI_SUCCESS)
2278 return;
2279
2280 config_entry_add_unified(config, new_device, root_dir);
2281 config_load_entries(config, new_device, root_dir, NULL);
2282 }
2283
2284 static EFI_STATUS initrd_prepare(
2285 EFI_FILE *root,
2286 const ConfigEntry *entry,
2287 char16_t **ret_options,
2288 void **ret_initrd,
2289 size_t *ret_initrd_size) {
2290
2291 assert(root);
2292 assert(entry);
2293 assert(ret_options);
2294 assert(ret_initrd);
2295 assert(ret_initrd_size);
2296
2297 if (entry->type != LOADER_LINUX || !entry->initrd) {
2298 ret_options = NULL;
2299 ret_initrd = NULL;
2300 ret_initrd_size = 0;
2301 return EFI_SUCCESS;
2302 }
2303
2304 /* Note that order of initrds matters. The kernel will only look for microcode updates in the very
2305 * first one it sees. */
2306
2307 /* Add initrd= to options for older kernels that do not support LINUX_INITRD_MEDIA. Should be dropped
2308 * if linux_x86.c is dropped. */
2309 _cleanup_free_ char16_t *options = NULL;
2310
2311 EFI_STATUS err;
2312 size_t size = 0;
2313 _cleanup_free_ uint8_t *initrd = NULL;
2314
2315 STRV_FOREACH(i, entry->initrd) {
2316 _cleanup_free_ char16_t *o = options;
2317 if (o)
2318 options = xasprintf("%ls initrd=%ls", o, *i);
2319 else
2320 options = xasprintf("initrd=%ls", *i);
2321
2322 _cleanup_(file_closep) EFI_FILE *handle = NULL;
2323 err = root->Open(root, &handle, *i, EFI_FILE_MODE_READ, 0);
2324 if (err != EFI_SUCCESS)
2325 return err;
2326
2327 _cleanup_free_ EFI_FILE_INFO *info = NULL;
2328 err = get_file_info(handle, &info, NULL);
2329 if (err != EFI_SUCCESS)
2330 return err;
2331
2332 if (info->FileSize == 0) /* Automatically skip over empty files */
2333 continue;
2334
2335 size_t new_size, read_size = info->FileSize;
2336 if (__builtin_add_overflow(size, read_size, &new_size))
2337 return EFI_OUT_OF_RESOURCES;
2338 initrd = xrealloc(initrd, size, new_size);
2339
2340 err = chunked_read(handle, &read_size, initrd + size);
2341 if (err != EFI_SUCCESS)
2342 return err;
2343
2344 /* Make sure the actual read size is what we expected. */
2345 assert(size + read_size == new_size);
2346 size = new_size;
2347 }
2348
2349 if (entry->options) {
2350 _cleanup_free_ char16_t *o = options;
2351 options = xasprintf("%ls %ls", o, entry->options);
2352 }
2353
2354 *ret_options = TAKE_PTR(options);
2355 *ret_initrd = TAKE_PTR(initrd);
2356 *ret_initrd_size = size;
2357 return EFI_SUCCESS;
2358 }
2359
2360 static EFI_STATUS image_start(
2361 EFI_HANDLE parent_image,
2362 const ConfigEntry *entry) {
2363
2364 _cleanup_(devicetree_cleanup) struct devicetree_state dtstate = {};
2365 _cleanup_(unload_imagep) EFI_HANDLE image = NULL;
2366 _cleanup_free_ EFI_DEVICE_PATH *path = NULL;
2367 EFI_STATUS err;
2368
2369 assert(entry);
2370
2371 /* If this loader entry has a special way to boot, try that first. */
2372 if (entry->call)
2373 (void) entry->call();
2374
2375 _cleanup_(file_closep) EFI_FILE *image_root = NULL;
2376 err = open_volume(entry->device, &image_root);
2377 if (err != EFI_SUCCESS)
2378 return log_error_status(err, "Error opening root path: %m");
2379
2380 err = make_file_device_path(entry->device, entry->loader, &path);
2381 if (err != EFI_SUCCESS)
2382 return log_error_status(err, "Error making file device path: %m");
2383
2384 size_t initrd_size = 0;
2385 _cleanup_free_ void *initrd = NULL;
2386 _cleanup_free_ char16_t *options_initrd = NULL;
2387 err = initrd_prepare(image_root, entry, &options_initrd, &initrd, &initrd_size);
2388 if (err != EFI_SUCCESS)
2389 return log_error_status(err, "Error preparing initrd: %m");
2390
2391 err = shim_load_image(parent_image, path, &image);
2392 if (err != EFI_SUCCESS)
2393 return log_error_status(err, "Error loading %ls: %m", entry->loader);
2394
2395 /* DTBs are loaded by the kernel before ExitBootServices, and they can be used to map and assign
2396 * arbitrary memory ranges, so skip it when secure boot is enabled as the DTB here is unverified. */
2397 if (entry->devicetree && !secure_boot_enabled()) {
2398 err = devicetree_install(&dtstate, image_root, entry->devicetree);
2399 if (err != EFI_SUCCESS)
2400 return log_error_status(err, "Error loading %ls: %m", entry->devicetree);
2401 }
2402
2403 _cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
2404 err = initrd_register(initrd, initrd_size, &initrd_handle);
2405 if (err != EFI_SUCCESS)
2406 return log_error_status(err, "Error registering initrd: %m");
2407
2408 EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
2409 err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
2410 if (err != EFI_SUCCESS)
2411 return log_error_status(err, "Error getting LoadedImageProtocol handle: %m");
2412
2413 /* If we had to append an initrd= entry to the command line, we have to pass it, and measure
2414 * it. Otherwise, only pass/measure it if it is not implicit anyway (i.e. embedded into the UKI or
2415 * so). */
2416 char16_t *options = options_initrd ?: entry->options_implied ? NULL : entry->options;
2417 if (options) {
2418 loaded_image->LoadOptions = options;
2419 loaded_image->LoadOptionsSize = strsize16(options);
2420
2421 /* Try to log any options to the TPM, especially to catch manually edited options */
2422 (void) tpm_log_load_options(options, NULL);
2423 }
2424
2425 efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeExecUSec", 0);
2426 err = BS->StartImage(image, NULL, NULL);
2427 graphics_mode(false);
2428 if (err == EFI_SUCCESS)
2429 return EFI_SUCCESS;
2430
2431 /* Try calling the kernel compat entry point if one exists. */
2432 if (err == EFI_UNSUPPORTED && entry->type == LOADER_LINUX) {
2433 uint32_t compat_address;
2434
2435 err = pe_kernel_info(loaded_image->ImageBase, &compat_address);
2436 if (err != EFI_SUCCESS) {
2437 if (err != EFI_UNSUPPORTED)
2438 return log_error_status(err, "Error finding kernel compat entry address: %m");
2439 } else if (compat_address > 0) {
2440 EFI_IMAGE_ENTRY_POINT kernel_entry =
2441 (EFI_IMAGE_ENTRY_POINT) ((uint8_t *) loaded_image->ImageBase + compat_address);
2442
2443 err = kernel_entry(image, ST);
2444 graphics_mode(false);
2445 if (err == EFI_SUCCESS)
2446 return EFI_SUCCESS;
2447 } else
2448 err = EFI_UNSUPPORTED;
2449 }
2450
2451 return log_error_status(err, "Failed to execute %ls (%ls): %m", entry->title_show, entry->loader);
2452 }
2453
2454 static void config_free(Config *config) {
2455 assert(config);
2456 for (size_t i = 0; i < config->n_entries; i++)
2457 config_entry_free(config->entries[i]);
2458 free(config->entries);
2459 free(config->entry_default_config);
2460 free(config->entry_default_efivar);
2461 free(config->entry_oneshot);
2462 free(config->entry_saved);
2463 }
2464
2465 static void config_write_entries_to_variable(Config *config) {
2466 _cleanup_free_ char *buffer = NULL;
2467 size_t sz = 0;
2468 char *p;
2469
2470 assert(config);
2471
2472 for (size_t i = 0; i < config->n_entries; i++)
2473 sz += strsize16(config->entries[i]->id);
2474
2475 p = buffer = xmalloc(sz);
2476
2477 for (size_t i = 0; i < config->n_entries; i++)
2478 p = mempcpy(p, config->entries[i]->id, strsize16(config->entries[i]->id));
2479
2480 assert(p == buffer + sz);
2481
2482 /* Store the full list of discovered entries. */
2483 (void) efivar_set_raw(MAKE_GUID_PTR(LOADER), u"LoaderEntries", buffer, sz, 0);
2484 }
2485
2486 static void save_selected_entry(const Config *config, const ConfigEntry *entry) {
2487 assert(config);
2488 assert(entry);
2489 assert(entry->loader || !entry->call);
2490
2491 /* Always export the selected boot entry to the system in a volatile var. */
2492 (void) efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderEntrySelected", entry->id, 0);
2493
2494 /* Do not save or delete if this was a oneshot boot. */
2495 if (streq16(config->entry_oneshot, entry->id))
2496 return;
2497
2498 if (config->use_saved_entry_efivar || (!config->entry_default_efivar && config->use_saved_entry)) {
2499 /* Avoid unnecessary NVRAM writes. */
2500 if (streq16(config->entry_saved, entry->id))
2501 return;
2502
2503 (void) efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", entry->id, EFI_VARIABLE_NON_VOLATILE);
2504 } else
2505 /* Delete the non-volatile var if not needed. */
2506 (void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", EFI_VARIABLE_NON_VOLATILE);
2507 }
2508
2509 static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir) {
2510 EFI_STATUS err;
2511 _cleanup_(file_closep) EFI_FILE *keys_basedir = NULL;
2512
2513 if (secure_boot_mode() != SECURE_BOOT_SETUP)
2514 return EFI_SUCCESS;
2515
2516 /* the lack of a 'keys' directory is not fatal and is silently ignored */
2517 err = open_directory(root_dir, u"\\loader\\keys", &keys_basedir);
2518 if (err == EFI_NOT_FOUND)
2519 return EFI_SUCCESS;
2520 if (err != EFI_SUCCESS)
2521 return err;
2522
2523 for (;;) {
2524 _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
2525 size_t dirent_size = 0;
2526 ConfigEntry *entry = NULL;
2527
2528 err = readdir(keys_basedir, &dirent, &dirent_size);
2529 if (err != EFI_SUCCESS || !dirent)
2530 return err;
2531
2532 if (dirent->FileName[0] == '.')
2533 continue;
2534
2535 if (!FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
2536 continue;
2537
2538 entry = xnew(ConfigEntry, 1);
2539 *entry = (ConfigEntry) {
2540 .id = xasprintf("secure-boot-keys-%ls", dirent->FileName),
2541 .title = xasprintf("Enroll Secure Boot keys: %ls", dirent->FileName),
2542 .path = xasprintf("\\loader\\keys\\%ls", dirent->FileName),
2543 .type = LOADER_SECURE_BOOT_KEYS,
2544 .tries_done = -1,
2545 .tries_left = -1,
2546 };
2547 config_add_entry(config, entry);
2548
2549 if (IN_SET(config->secure_boot_enroll, ENROLL_IF_SAFE, ENROLL_FORCE) &&
2550 strcaseeq16(dirent->FileName, u"auto"))
2551 /* if we auto enroll successfully this call does not return, if it fails we still
2552 * want to add other potential entries to the menu */
2553 secure_boot_enroll_at(root_dir, entry->path, config->secure_boot_enroll == ENROLL_FORCE);
2554 }
2555
2556 return EFI_SUCCESS;
2557 }
2558
2559 static void export_variables(
2560 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
2561 const char16_t *loaded_image_path,
2562 uint64_t init_usec) {
2563
2564 static const uint64_t loader_features =
2565 EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
2566 EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT |
2567 EFI_LOADER_FEATURE_ENTRY_DEFAULT |
2568 EFI_LOADER_FEATURE_ENTRY_ONESHOT |
2569 EFI_LOADER_FEATURE_BOOT_COUNTING |
2570 EFI_LOADER_FEATURE_XBOOTLDR |
2571 EFI_LOADER_FEATURE_RANDOM_SEED |
2572 EFI_LOADER_FEATURE_LOAD_DRIVER |
2573 EFI_LOADER_FEATURE_SORT_KEY |
2574 EFI_LOADER_FEATURE_SAVED_ENTRY |
2575 EFI_LOADER_FEATURE_DEVICETREE |
2576 EFI_LOADER_FEATURE_SECUREBOOT_ENROLL |
2577 EFI_LOADER_FEATURE_RETAIN_SHIM |
2578 0;
2579
2580 _cleanup_free_ char16_t *infostr = NULL, *typestr = NULL;
2581
2582 assert(loaded_image);
2583
2584 efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeInitUSec", init_usec);
2585 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderInfo", u"systemd-boot " GIT_VERSION, 0);
2586
2587 infostr = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
2588 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", infostr, 0);
2589
2590 typestr = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
2591 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", typestr, 0);
2592
2593 (void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"LoaderFeatures", loader_features, 0);
2594
2595 /* the filesystem path to this image, to prevent adding ourselves to the menu */
2596 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", loaded_image_path, 0);
2597
2598 /* export the device path this image is started from */
2599 _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle);
2600 if (uuid)
2601 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
2602 }
2603
2604 static void config_load_all_entries(
2605 Config *config,
2606 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
2607 const char16_t *loaded_image_path,
2608 EFI_FILE *root_dir) {
2609
2610 assert(config);
2611 assert(loaded_image);
2612 assert(root_dir);
2613
2614 config_load_defaults(config, root_dir);
2615
2616 /* scan /EFI/Linux/ directory */
2617 config_entry_add_unified(config, loaded_image->DeviceHandle, root_dir);
2618
2619 /* scan /loader/entries/\*.conf files */
2620 config_load_entries(config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
2621
2622 /* Similar, but on any XBOOTLDR partition */
2623 config_load_xbootldr(config, loaded_image->DeviceHandle);
2624
2625 /* sort entries after version number */
2626 sort_pointer_array((void **) config->entries, config->n_entries, (compare_pointer_func_t) config_entry_compare);
2627
2628 /* if we find some well-known loaders, add them to the end of the list */
2629 config_entry_add_osx(config);
2630 config_entry_add_windows(config, loaded_image->DeviceHandle, root_dir);
2631 config_entry_add_loader_auto(config, loaded_image->DeviceHandle, root_dir, NULL,
2632 u"auto-efi-shell", 's', u"EFI Shell", u"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
2633 config_entry_add_loader_auto(config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
2634 u"auto-efi-default", '\0', u"EFI Default Loader", NULL);
2635
2636 if (config->auto_firmware && FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
2637 ConfigEntry *entry = xnew(ConfigEntry, 1);
2638 *entry = (ConfigEntry) {
2639 .id = xstrdup16(u"auto-reboot-to-firmware-setup"),
2640 .title = xstrdup16(u"Reboot Into Firmware Interface"),
2641 .call = reboot_into_firmware,
2642 .tries_done = -1,
2643 .tries_left = -1,
2644 };
2645 config_add_entry(config, entry);
2646 }
2647
2648 /* find if secure boot signing keys exist and autoload them if necessary
2649 otherwise creates menu entries so that the user can load them manually
2650 if the secure-boot-enroll variable is set to no (the default), we do not
2651 even search for keys on the ESP */
2652 if (config->secure_boot_enroll != ENROLL_OFF)
2653 secure_boot_discover_keys(config, root_dir);
2654
2655 if (config->n_entries == 0)
2656 return;
2657
2658 config_write_entries_to_variable(config);
2659
2660 config_title_generate(config);
2661
2662 /* select entry by configured pattern or EFI LoaderDefaultEntry= variable */
2663 config_default_entry_select(config);
2664 }
2665
2666 static EFI_STATUS discover_root_dir(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, EFI_FILE **ret_dir) {
2667 if (is_direct_boot(loaded_image->DeviceHandle))
2668 return vmm_open(&loaded_image->DeviceHandle, ret_dir);
2669 else
2670 return open_volume(loaded_image->DeviceHandle, ret_dir);
2671 }
2672
2673 static EFI_STATUS run(EFI_HANDLE image) {
2674 EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
2675 _cleanup_(file_closep) EFI_FILE *root_dir = NULL;
2676 _cleanup_(config_free) Config config = {};
2677 _cleanup_free_ char16_t *loaded_image_path = NULL;
2678 EFI_STATUS err;
2679 uint64_t init_usec;
2680 bool menu = false;
2681
2682 init_usec = time_usec();
2683
2684 /* Ask Shim to leave its protocol around, so that the stub can use it to validate PEs.
2685 * By default, Shim uninstalls its protocol when calling StartImage(). */
2686 shim_retain_protocol();
2687
2688 err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
2689 if (err != EFI_SUCCESS)
2690 return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
2691
2692 (void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
2693
2694 export_variables(loaded_image, loaded_image_path, init_usec);
2695
2696 err = discover_root_dir(loaded_image, &root_dir);
2697 if (err != EFI_SUCCESS)
2698 return log_error_status(err, "Unable to open root directory: %m");
2699
2700 (void) load_drivers(image, loaded_image, root_dir);
2701
2702 config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
2703
2704 if (config.n_entries == 0)
2705 return log_error_status(
2706 EFI_NOT_FOUND,
2707 "No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
2708
2709 /* select entry or show menu when key is pressed or timeout is set */
2710 if (config.force_menu || config.timeout_sec > 0)
2711 menu = true;
2712 else {
2713 uint64_t key;
2714
2715 /* Block up to 100ms to give firmware time to get input working. */
2716 err = console_key_read(&key, 100 * 1000);
2717 if (err == EFI_SUCCESS) {
2718 /* find matching key in config entries */
2719 size_t idx = entry_lookup_key(&config, config.idx_default, KEYCHAR(key));
2720 if (idx != IDX_INVALID)
2721 config.idx_default = idx;
2722 else
2723 menu = true;
2724 }
2725 }
2726
2727 for (;;) {
2728 ConfigEntry *entry;
2729
2730 entry = config.entries[config.idx_default];
2731 if (menu) {
2732 efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeMenuUSec", 0);
2733 if (!menu_run(&config, &entry, loaded_image_path))
2734 return EFI_SUCCESS;
2735 }
2736
2737 /* if auto enrollment is activated, we try to load keys for the given entry. */
2738 if (entry->type == LOADER_SECURE_BOOT_KEYS && config.secure_boot_enroll != ENROLL_OFF) {
2739 err = secure_boot_enroll_at(root_dir, entry->path, /*force=*/ true);
2740 if (err != EFI_SUCCESS)
2741 return err;
2742 continue;
2743 }
2744
2745 /* Run special entry like "reboot" now. Those that have a loader
2746 * will be handled by image_start() instead. */
2747 if (entry->call && !entry->loader) {
2748 entry->call();
2749 continue;
2750 }
2751
2752 (void) config_entry_bump_counters(entry);
2753 save_selected_entry(&config, entry);
2754
2755 /* Optionally, read a random seed off the ESP and pass it to the OS */
2756 (void) process_random_seed(root_dir);
2757
2758 err = image_start(image, entry);
2759 if (err != EFI_SUCCESS)
2760 return err;
2761
2762 menu = true;
2763 config.timeout_sec = 0;
2764 }
2765 }
2766
2767 DEFINE_EFI_MAIN_FUNCTION(run, "systemd-boot", /*wait_for_debugger=*/false);