"Das U-Boot" Source Tree
at master 682 lines 16 kB view raw
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);