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