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