"Das U-Boot" Source Tree
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2011-2013 Pali Rohár <pali@kernel.org>
4 */
5
6#include <charset.h>
7#include <cli.h>
8#include <command.h>
9#include <ansi.h>
10#include <efi_config.h>
11#include <efi_variable.h>
12#include <env.h>
13#include <log.h>
14#include <menu.h>
15#include <watchdog.h>
16#include <malloc.h>
17#include <linux/delay.h>
18#include <linux/string.h>
19
20/* maximum bootmenu entries */
21#define MAX_COUNT 99
22
23/* maximal size of bootmenu env
24 * 9 = strlen("bootmenu_")
25 * 2 = strlen(MAX_COUNT)
26 * 1 = NULL term
27 */
28#define MAX_ENV_SIZE (9 + 2 + 1)
29
30enum bootmenu_ret {
31 BOOTMENU_RET_SUCCESS = 0,
32 BOOTMENU_RET_FAIL,
33 BOOTMENU_RET_QUIT,
34 BOOTMENU_RET_UPDATED,
35};
36
37enum boot_type {
38 BOOTMENU_TYPE_NONE = 0,
39 BOOTMENU_TYPE_BOOTMENU,
40 BOOTMENU_TYPE_UEFI_BOOT_OPTION,
41};
42
43struct bootmenu_entry {
44 unsigned short int num; /* unique number 0 .. MAX_COUNT */
45 char key[3]; /* key identifier of number */
46 char *title; /* title of entry */
47 char *command; /* hush command of entry */
48 enum boot_type type; /* boot type of entry */
49 u16 bootorder; /* order for each boot type */
50 struct bootmenu_data *menu; /* this bootmenu */
51 struct bootmenu_entry *next; /* next menu entry (num+1) */
52};
53
54static char *bootmenu_getoption(unsigned short int n)
55{
56 char name[MAX_ENV_SIZE];
57
58 if (n > MAX_COUNT)
59 return NULL;
60
61 sprintf(name, "bootmenu_%d", n);
62 return env_get(name);
63}
64
65static void bootmenu_print_entry(void *data)
66{
67 struct bootmenu_entry *entry = data;
68 int reverse = (entry->menu->active == entry->num);
69
70 /*
71 * Move cursor to line where the entry will be drown (entry->num)
72 * First 3 lines contain bootmenu header + 1 empty line
73 */
74 printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
75
76 if (reverse)
77 puts(ANSI_COLOR_REVERSE);
78
79 printf("%s", entry->title);
80
81 if (reverse)
82 puts(ANSI_COLOR_RESET);
83}
84
85static char *bootmenu_choice_entry(void *data)
86{
87 struct cli_ch_state s_cch, *cch = &s_cch;
88 struct bootmenu_data *menu = data;
89 struct bootmenu_entry *iter;
90 enum bootmenu_key key = BKEY_NONE;
91 int i;
92
93 cli_ch_init(cch);
94
95 while (1) {
96 if (menu->delay >= 0) {
97 /* Autoboot was not stopped */
98 key = bootmenu_autoboot_loop(menu, cch);
99 } else {
100 /* Some key was pressed, so autoboot was stopped */
101 key = bootmenu_loop(menu, cch);
102 }
103
104 switch (key) {
105 case BKEY_UP:
106 menu->last_active = menu->active;
107 if (menu->active > 0)
108 --menu->active;
109 /* no menu key selected, regenerate menu */
110 return NULL;
111 case BKEY_DOWN:
112 menu->last_active = menu->active;
113 if (menu->active < menu->count - 1)
114 ++menu->active;
115 /* no menu key selected, regenerate menu */
116 return NULL;
117 case BKEY_SELECT:
118 iter = menu->first;
119 for (i = 0; i < menu->active; ++i)
120 iter = iter->next;
121 return iter->key;
122 case BKEY_QUIT:
123 /* Quit by choosing the last entry */
124 iter = menu->first;
125 while (iter->next)
126 iter = iter->next;
127 return iter->key;
128 default:
129 break;
130 }
131 }
132
133 /* never happens */
134 debug("bootmenu: this should not happen");
135 return NULL;
136}
137
138static bool bootmenu_need_reprint(void *data)
139{
140 struct bootmenu_data *menu = data;
141 bool need_reprint;
142
143 need_reprint = menu->last_active != menu->active;
144 menu->last_active = menu->active;
145
146 return need_reprint;
147}
148
149static void bootmenu_destroy(struct bootmenu_data *menu)
150{
151 struct bootmenu_entry *iter = menu->first;
152 struct bootmenu_entry *next;
153
154 while (iter) {
155 next = iter->next;
156 free(iter->title);
157 free(iter->command);
158 free(iter);
159 iter = next;
160 }
161 free(menu);
162}
163
164/**
165 * prepare_bootmenu_entry() - generate the bootmenu_xx entries
166 *
167 * This function read the "bootmenu_x" U-Boot environment variable
168 * and generate the bootmenu entries.
169 *
170 * @menu: pointer to the bootmenu structure
171 * @current: pointer to the last bootmenu entry list
172 * @index: pointer to the index of the last bootmenu entry,
173 * the number of bootmenu entry is added by this function
174 * Return: 1 on success, negative value on error
175 */
176static int prepare_bootmenu_entry(struct bootmenu_data *menu,
177 struct bootmenu_entry **current,
178 unsigned short int *index)
179{
180 char *sep;
181 const char *option;
182 unsigned short int i = *index;
183 struct bootmenu_entry *entry = NULL;
184 struct bootmenu_entry *iter = *current;
185
186 while ((option = bootmenu_getoption(i))) {
187
188 /* bootmenu_[num] format is "[title]=[commands]" */
189 sep = strchr(option, '=');
190 if (!sep) {
191 printf("Invalid bootmenu entry: %s\n", option);
192 break;
193 }
194
195 entry = malloc(sizeof(struct bootmenu_entry));
196 if (!entry)
197 return -ENOMEM;
198
199 entry->title = strndup(option, sep - option);
200 if (!entry->title) {
201 free(entry);
202 return -ENOMEM;
203 }
204
205 entry->command = strdup(sep + 1);
206 if (!entry->command) {
207 free(entry->title);
208 free(entry);
209 return -ENOMEM;
210 }
211
212 sprintf(entry->key, "%d", i);
213
214 entry->num = i;
215 entry->menu = menu;
216 entry->type = BOOTMENU_TYPE_BOOTMENU;
217 entry->bootorder = i;
218 entry->next = NULL;
219
220 if (!iter)
221 menu->first = entry;
222 else
223 iter->next = entry;
224
225 iter = entry;
226 ++i;
227
228 if (i == MAX_COUNT - 1)
229 break;
230 }
231
232 *index = i;
233 *current = iter;
234
235 return 1;
236}
237
238#if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) && (IS_ENABLED(CONFIG_CMD_EFICONFIG))
239/**
240 * prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
241 *
242 * This function reads the "BootOrder" UEFI variable
243 * and generate the bootmenu entries in the order of "BootOrder".
244 *
245 * @menu: pointer to the bootmenu structure
246 * @current: pointer to the last bootmenu entry list
247 * @index: pointer to the index of the last bootmenu entry,
248 * the number of uefi entry is added by this function
249 * Return: 1 on success, negative value on error
250 */
251static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu,
252 struct bootmenu_entry **current,
253 unsigned short int *index)
254{
255 u16 *bootorder;
256 efi_status_t ret;
257 unsigned short j;
258 efi_uintn_t num, size;
259 void *load_option;
260 struct efi_load_option lo;
261 u16 varname[] = u"Boot####";
262 unsigned short int i = *index;
263 struct bootmenu_entry *entry = NULL;
264 struct bootmenu_entry *iter = *current;
265
266 bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
267 if (!bootorder)
268 return -ENOENT;
269
270 num = size / sizeof(u16);
271 for (j = 0; j < num; j++) {
272 entry = malloc(sizeof(struct bootmenu_entry));
273 if (!entry)
274 return -ENOMEM;
275
276 efi_create_indexed_name(varname, sizeof(varname),
277 "Boot", bootorder[j]);
278 load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
279 if (!load_option)
280 continue;
281
282 ret = efi_deserialize_load_option(&lo, load_option, &size);
283 if (ret != EFI_SUCCESS) {
284 log_warning("Invalid load option for %ls\n", varname);
285 free(load_option);
286 free(entry);
287 continue;
288 }
289
290 if (lo.attributes & LOAD_OPTION_ACTIVE) {
291 char *buf;
292
293 buf = calloc(1, utf16_utf8_strlen(lo.label) + 1);
294 if (!buf) {
295 free(load_option);
296 free(entry);
297 free(bootorder);
298 return -ENOMEM;
299 }
300 entry->title = buf;
301 utf16_utf8_strncpy(&buf, lo.label, u16_strlen(lo.label));
302 entry->command = strdup("bootefi bootmgr");
303 sprintf(entry->key, "%d", i);
304 entry->num = i;
305 entry->menu = menu;
306 entry->type = BOOTMENU_TYPE_UEFI_BOOT_OPTION;
307 entry->bootorder = bootorder[j];
308 entry->next = NULL;
309
310 if (!iter)
311 menu->first = entry;
312 else
313 iter->next = entry;
314
315 iter = entry;
316 i++;
317 }
318
319 free(load_option);
320
321 if (i == MAX_COUNT - 1)
322 break;
323 }
324
325 free(bootorder);
326 *index = i;
327 *current = iter;
328
329 return 1;
330}
331#endif
332
333/**
334 * bootmenu_create() - create boot menu entries
335 *
336 * @uefi: consider UEFI boot options
337 * @delay: autostart delay in seconds
338 */
339static struct bootmenu_data *bootmenu_create(int uefi, int delay)
340{
341 int ret;
342 unsigned short int i = 0;
343 struct bootmenu_data *menu;
344 struct bootmenu_entry *iter = NULL;
345 struct bootmenu_entry *entry;
346 char *default_str;
347
348 menu = malloc(sizeof(struct bootmenu_data));
349 if (!menu)
350 return NULL;
351
352 menu->delay = delay;
353 menu->active = 0;
354 menu->last_active = -1;
355 menu->first = NULL;
356
357 default_str = env_get("bootmenu_default");
358 if (default_str)
359 menu->active = (int)simple_strtol(default_str, NULL, 10);
360
361 ret = prepare_bootmenu_entry(menu, &iter, &i);
362 if (ret < 0)
363 goto cleanup;
364
365#if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) && (IS_ENABLED(CONFIG_CMD_EFICONFIG))
366 if (uefi && i < MAX_COUNT - 1) {
367 efi_status_t efi_ret;
368
369 /*
370 * UEFI specification requires booting from removal media using
371 * a architecture-specific default image name such as BOOTAA64.EFI.
372 */
373 efi_ret = efi_bootmgr_update_media_device_boot_option();
374 if (efi_ret != EFI_SUCCESS)
375 goto cleanup;
376
377 ret = prepare_uefi_bootorder_entry(menu, &iter, &i);
378 if (ret < 0 && ret != -ENOENT)
379 goto cleanup;
380 }
381#endif
382
383 /* Add Exit entry at the end */
384 if (i <= MAX_COUNT - 1) {
385 entry = malloc(sizeof(struct bootmenu_entry));
386 if (!entry)
387 goto cleanup;
388
389 /* Add Quit entry if exiting bootmenu is disabled */
390 if (!IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE))
391 entry->title = strdup("Exit");
392 else
393 entry->title = strdup("Quit");
394
395 if (!entry->title) {
396 free(entry);
397 goto cleanup;
398 }
399
400 entry->command = strdup("");
401 if (!entry->command) {
402 free(entry->title);
403 free(entry);
404 goto cleanup;
405 }
406
407 sprintf(entry->key, "%d", i);
408
409 entry->num = i;
410 entry->menu = menu;
411 entry->type = BOOTMENU_TYPE_NONE;
412 entry->next = NULL;
413
414 if (!iter)
415 menu->first = entry;
416 else
417 iter->next = entry;
418
419 iter = entry;
420 ++i;
421 }
422
423 menu->count = i;
424
425 if ((menu->active >= menu->count)||(menu->active < 0)) { //ensure active menuitem is inside menu
426 printf("active menuitem (%d) is outside menu (0..%d)\n",menu->active,menu->count-1);
427 menu->active=0;
428 }
429
430 return menu;
431
432cleanup:
433 bootmenu_destroy(menu);
434 return NULL;
435}
436
437static void menu_display_statusline(struct menu *m)
438{
439 struct bootmenu_entry *entry;
440 struct bootmenu_data *menu;
441
442 if (menu_default_choice(m, (void *)&entry) < 0)
443 return;
444
445 menu = entry->menu;
446
447 printf(ANSI_CURSOR_POSITION, 1, 1);
448 puts(ANSI_CLEAR_LINE);
449 printf(ANSI_CURSOR_POSITION, 2, 3);
450 puts("*** U-Boot Boot Menu ***");
451 puts(ANSI_CLEAR_LINE_TO_END);
452 printf(ANSI_CURSOR_POSITION, 3, 1);
453 puts(ANSI_CLEAR_LINE);
454
455 /* First 3 lines are bootmenu header + 2 empty lines between entries */
456 printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
457 puts(ANSI_CLEAR_LINE);
458 printf(ANSI_CURSOR_POSITION, menu->count + 6, 3);
459 puts("Press UP/DOWN to move, ENTER to select, ESC to quit");
460 puts(ANSI_CLEAR_LINE_TO_END);
461 printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
462 puts(ANSI_CLEAR_LINE);
463}
464
465static void handle_uefi_bootnext(void)
466{
467 u16 bootnext;
468 efi_status_t ret;
469 efi_uintn_t size;
470
471 /* Initialize EFI drivers */
472 ret = efi_init_obj_list();
473 if (ret != EFI_SUCCESS) {
474 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
475 ret & ~EFI_ERROR_MASK);
476
477 return;
478 }
479
480 /* If UEFI BootNext variable is set, boot the BootNext load option */
481 size = sizeof(u16);
482 ret = efi_get_variable_int(u"BootNext",
483 &efi_global_variable_guid,
484 NULL, &size, &bootnext, NULL);
485 if (ret == EFI_SUCCESS)
486 /* BootNext does exist here, try to boot */
487 run_command("bootefi bootmgr", 0);
488}
489
490/**
491 * bootmenu_show - display boot menu
492 *
493 * @uefi: generated entries for UEFI boot options
494 * @delay: autoboot delay in seconds
495 */
496static enum bootmenu_ret bootmenu_show(int uefi, int delay)
497{
498 int cmd_ret;
499 int init = 0;
500 void *choice = NULL;
501 char *title = NULL;
502 char *command = NULL;
503 struct menu *menu;
504 struct bootmenu_entry *iter;
505 int ret = BOOTMENU_RET_SUCCESS;
506 struct bootmenu_data *bootmenu;
507 efi_status_t efi_ret = EFI_SUCCESS;
508 char *option, *sep;
509
510 if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) && uefi)
511 handle_uefi_bootnext();
512
513 /* If delay is 0 do not create menu, just run first entry */
514 if (delay == 0) {
515 option = bootmenu_getoption(0);
516 if (!option) {
517 puts("bootmenu option 0 was not found\n");
518 return BOOTMENU_RET_FAIL;
519 }
520 sep = strchr(option, '=');
521 if (!sep) {
522 puts("bootmenu option 0 is invalid\n");
523 return BOOTMENU_RET_FAIL;
524 }
525 cmd_ret = run_command(sep + 1, 0);
526 return (cmd_ret == CMD_RET_SUCCESS ? BOOTMENU_RET_SUCCESS : BOOTMENU_RET_FAIL);
527 }
528
529 bootmenu = bootmenu_create(uefi, delay);
530 if (!bootmenu)
531 return BOOTMENU_RET_FAIL;
532
533 menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline,
534 bootmenu_print_entry, bootmenu_choice_entry,
535 bootmenu_need_reprint, bootmenu);
536 if (!menu) {
537 bootmenu_destroy(bootmenu);
538 return BOOTMENU_RET_FAIL;
539 }
540
541 for (iter = bootmenu->first; iter; iter = iter->next) {
542 if (menu_item_add(menu, iter->key, iter) != 1)
543 goto cleanup;
544 }
545
546 /* Default menu entry is always first */
547 menu_default_set(menu, "0");
548
549 puts(ANSI_CURSOR_HIDE);
550 puts(ANSI_CLEAR_CONSOLE);
551 printf(ANSI_CURSOR_POSITION, 1, 1);
552
553 init = 1;
554
555 if (menu_get_choice(menu, &choice) == 1) {
556 iter = choice;
557 title = strdup(iter->title);
558 command = strdup(iter->command);
559
560 /* last entry exits bootmenu */
561 if (iter->num == iter->menu->count - 1) {
562 ret = BOOTMENU_RET_QUIT;
563 goto cleanup;
564 }
565 } else {
566 goto cleanup;
567 }
568
569 /*
570 * If the selected entry is UEFI BOOT####, set the BootNext variable.
571 * Then uefi bootmgr is invoked by the preset command in iter->command.
572 */
573 if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) {
574 if (iter->type == BOOTMENU_TYPE_UEFI_BOOT_OPTION) {
575 /*
576 * UEFI specification requires BootNext variable needs non-volatile
577 * attribute, but this BootNext is only used inside of U-Boot and
578 * removed by efi bootmgr once BootNext is processed.
579 * So this BootNext can be volatile.
580 */
581 efi_ret = efi_set_variable_int(u"BootNext", &efi_global_variable_guid,
582 EFI_VARIABLE_BOOTSERVICE_ACCESS |
583 EFI_VARIABLE_RUNTIME_ACCESS,
584 sizeof(u16), &iter->bootorder, false);
585 if (efi_ret != EFI_SUCCESS)
586 goto cleanup;
587 }
588 }
589
590cleanup:
591 menu_destroy(menu);
592 bootmenu_destroy(bootmenu);
593
594 if (init) {
595 puts(ANSI_CURSOR_SHOW);
596 puts(ANSI_CLEAR_CONSOLE);
597 printf(ANSI_CURSOR_POSITION, 1, 1);
598 }
599
600 if (title && command) {
601 debug("Starting entry '%s'\n", title);
602 free(title);
603 if (efi_ret == EFI_SUCCESS)
604 cmd_ret = run_command(command, 0);
605 free(command);
606 }
607
608#ifdef CFG_POSTBOOTMENU
609 run_command(CFG_POSTBOOTMENU, 0);
610#endif
611
612 if (efi_ret != EFI_SUCCESS || cmd_ret != CMD_RET_SUCCESS)
613 ret = BOOTMENU_RET_FAIL;
614
615 return ret;
616}
617
618#ifdef CONFIG_AUTOBOOT_MENU_SHOW
619int menu_show(int bootdelay)
620{
621 int ret;
622
623 while (1) {
624 ret = bootmenu_show(1, bootdelay);
625 bootdelay = -1;
626 if (ret == BOOTMENU_RET_UPDATED)
627 continue;
628
629 if (IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE)) {
630 if (ret == BOOTMENU_RET_QUIT) {
631 /* default boot process */
632 if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR))
633 run_command("bootefi bootmgr", 0);
634
635 run_command("run bootcmd", 0);
636 }
637 } else {
638 break;
639 }
640 }
641
642 return -1; /* -1 - abort boot and run monitor code */
643}
644#endif
645
646int do_bootmenu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
647{
648 char *delay_str = NULL;
649 int delay = 10;
650 int uefi = 0;
651
652#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
653 delay = CONFIG_BOOTDELAY;
654#endif
655
656 if (argc >= 2) {
657 if (!strcmp("-e", argv[1])) {
658 uefi = 1;
659 --argc;
660 ++argv;
661 }
662 }
663 if (argc >= 2)
664 delay_str = argv[1];
665
666 if (!delay_str)
667 delay_str = env_get("bootmenu_delay");
668
669 if (delay_str)
670 delay = (int)simple_strtol(delay_str, NULL, 10);
671
672 bootmenu_show(uefi, delay);
673 return 0;
674}
675
676U_BOOT_CMD(
677 bootmenu, 2, 1, do_bootmenu,
678 "ANSI terminal bootmenu",
679 "[-e] [delay]\n"
680 "-e - show UEFI entries\n"
681 "delay - show ANSI terminal bootmenu with autoboot delay"
682);