1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * UEFI Shell-like command 4 * 5 * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited 6 */ 7 8 #include <charset.h> 9 #include <common.h> 10 #include <command.h> 11 #include <efi_loader.h> 12 #include <environment.h> 13 #include <exports.h> 14 #include <malloc.h> 15 #include <search.h> 16 #include <linux/ctype.h> 17 18 #define BS systab.boottime 19 #define RT systab.runtime 20 21 /** 22 * efi_get_device_handle_info() - get information of UEFI device 23 * 24 * @handle: Handle of UEFI device 25 * @dev_path_text: Pointer to text of device path 26 * Return: 0 on success, -1 on failure 27 * 28 * Currently return a formatted text of device path. 29 */ 30 static int efi_get_device_handle_info(efi_handle_t handle, u16 **dev_path_text) 31 { 32 struct efi_device_path *dp; 33 efi_status_t ret; 34 35 ret = EFI_CALL(BS->open_protocol(handle, &efi_guid_device_path, 36 (void **)&dp, NULL /* FIXME */, NULL, 37 EFI_OPEN_PROTOCOL_GET_PROTOCOL)); 38 if (ret == EFI_SUCCESS) { 39 *dev_path_text = efi_dp_str(dp); 40 return 0; 41 } else { 42 return -1; 43 } 44 } 45 46 #define EFI_HANDLE_WIDTH ((int)sizeof(efi_handle_t) * 2) 47 48 static const char spc[] = " "; 49 static const char sep[] = "================"; 50 51 /** 52 * do_efi_show_devices() - show UEFI devices 53 * 54 * @cmdtp: Command table 55 * @flag: Command flag 56 * @argc: Number of arguments 57 * @argv: Argument array 58 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 59 * 60 * Implement efidebug "devices" sub-command. 61 * Show all UEFI devices and their information. 62 */ 63 static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag, 64 int argc, char * const argv[]) 65 { 66 efi_handle_t *handles; 67 efi_uintn_t num, i; 68 u16 *dev_path_text; 69 efi_status_t ret; 70 71 ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL, 72 &num, &handles)); 73 if (ret != EFI_SUCCESS) 74 return CMD_RET_FAILURE; 75 76 if (!num) 77 return CMD_RET_SUCCESS; 78 79 printf("Device%.*s Device Path\n", EFI_HANDLE_WIDTH - 6, spc); 80 printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep); 81 for (i = 0; i < num; i++) { 82 if (!efi_get_device_handle_info(handles[i], &dev_path_text)) { 83 printf("%p %ls\n", handles[i], dev_path_text); 84 efi_free_pool(dev_path_text); 85 } 86 } 87 88 EFI_CALL(BS->free_pool(handles)); 89 90 return CMD_RET_SUCCESS; 91 } 92 93 /** 94 * efi_get_driver_handle_info() - get information of UEFI driver 95 * 96 * @handle: Handle of UEFI device 97 * @driver_name: Driver name 98 * @image_path: Pointer to text of device path 99 * Return: 0 on success, -1 on failure 100 * 101 * Currently return no useful information as all UEFI drivers are 102 * built-in.. 103 */ 104 static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name, 105 u16 **image_path) 106 { 107 struct efi_handler *handler; 108 struct efi_loaded_image *image; 109 efi_status_t ret; 110 111 /* 112 * driver name 113 * TODO: support EFI_COMPONENT_NAME2_PROTOCOL 114 */ 115 *driver_name = NULL; 116 117 /* image name */ 118 ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler); 119 if (ret != EFI_SUCCESS) { 120 *image_path = NULL; 121 return 0; 122 } 123 124 image = handler->protocol_interface; 125 *image_path = efi_dp_str(image->file_path); 126 127 return 0; 128 } 129 130 /** 131 * do_efi_show_drivers() - show UEFI drivers 132 * 133 * @cmdtp: Command table 134 * @flag: Command flag 135 * @argc: Number of arguments 136 * @argv: Argument array 137 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 138 * 139 * Implement efidebug "drivers" sub-command. 140 * Show all UEFI drivers and their information. 141 */ 142 static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag, 143 int argc, char * const argv[]) 144 { 145 efi_handle_t *handles; 146 efi_uintn_t num, i; 147 u16 *driver_name, *image_path_text; 148 efi_status_t ret; 149 150 ret = EFI_CALL(BS->locate_handle_buffer( 151 BY_PROTOCOL, &efi_guid_driver_binding_protocol, 152 NULL, &num, &handles)); 153 if (ret != EFI_SUCCESS) 154 return CMD_RET_FAILURE; 155 156 if (!num) 157 return CMD_RET_SUCCESS; 158 159 printf("Driver%.*s Name Image Path\n", 160 EFI_HANDLE_WIDTH - 6, spc); 161 printf("%.*s ==================== ====================\n", 162 EFI_HANDLE_WIDTH, sep); 163 for (i = 0; i < num; i++) { 164 if (!efi_get_driver_handle_info(handles[i], &driver_name, 165 &image_path_text)) { 166 if (image_path_text) 167 printf("%p %-20ls %ls\n", handles[i], 168 driver_name, image_path_text); 169 else 170 printf("%p %-20ls <built-in>\n", 171 handles[i], driver_name); 172 EFI_CALL(BS->free_pool(driver_name)); 173 EFI_CALL(BS->free_pool(image_path_text)); 174 } 175 } 176 177 EFI_CALL(BS->free_pool(handles)); 178 179 return CMD_RET_SUCCESS; 180 } 181 182 static const struct { 183 const char *text; 184 const efi_guid_t guid; 185 } guid_list[] = { 186 { 187 "Device Path", 188 DEVICE_PATH_GUID, 189 }, 190 { 191 "Device Path To Text", 192 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, 193 }, 194 { 195 "Device Path Utilities", 196 EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID, 197 }, 198 { 199 "Unicode Collation 2", 200 EFI_UNICODE_COLLATION_PROTOCOL2_GUID, 201 }, 202 { 203 "Driver Binding", 204 EFI_DRIVER_BINDING_PROTOCOL_GUID, 205 }, 206 { 207 "Simple Text Input", 208 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, 209 }, 210 { 211 "Simple Text Input Ex", 212 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, 213 }, 214 { 215 "Simple Text Output", 216 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, 217 }, 218 { 219 "Block IO", 220 BLOCK_IO_GUID, 221 }, 222 { 223 "Simple File System", 224 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, 225 }, 226 { 227 "Loaded Image", 228 LOADED_IMAGE_PROTOCOL_GUID, 229 }, 230 { 231 "GOP", 232 EFI_GOP_GUID, 233 }, 234 }; 235 236 /** 237 * get_guid_text - get string of protocol guid 238 * @guid: Protocol guid 239 * Return: String 240 * 241 * Return string for display to represent the protocol. 242 */ 243 static const char *get_guid_text(const efi_guid_t *guid) 244 { 245 int i; 246 247 for (i = 0; i < ARRAY_SIZE(guid_list); i++) 248 if (!guidcmp(&guid_list[i].guid, guid)) 249 break; 250 251 if (i != ARRAY_SIZE(guid_list)) 252 return guid_list[i].text; 253 else 254 return NULL; 255 } 256 257 /** 258 * do_efi_show_handles() - show UEFI handles 259 * 260 * @cmdtp: Command table 261 * @flag: Command flag 262 * @argc: Number of arguments 263 * @argv: Argument array 264 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 265 * 266 * Implement efidebug "dh" sub-command. 267 * Show all UEFI handles and their information, currently all protocols 268 * added to handle. 269 */ 270 static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag, 271 int argc, char * const argv[]) 272 { 273 efi_handle_t *handles; 274 efi_guid_t **guid; 275 efi_uintn_t num, count, i, j; 276 const char *guid_text; 277 efi_status_t ret; 278 279 ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL, 280 &num, &handles)); 281 if (ret != EFI_SUCCESS) 282 return CMD_RET_FAILURE; 283 284 if (!num) 285 return CMD_RET_SUCCESS; 286 287 printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc); 288 printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep); 289 for (i = 0; i < num; i++) { 290 printf("%p", handles[i]); 291 ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid, 292 &count)); 293 if (ret || !count) { 294 putc('\n'); 295 continue; 296 } 297 298 for (j = 0; j < count; j++) { 299 if (j) 300 printf(", "); 301 else 302 putc(' '); 303 304 guid_text = get_guid_text(guid[j]); 305 if (guid_text) 306 puts(guid_text); 307 else 308 printf("%pUl", guid[j]); 309 } 310 putc('\n'); 311 } 312 313 EFI_CALL(BS->free_pool(handles)); 314 315 return CMD_RET_SUCCESS; 316 } 317 318 /** 319 * do_efi_show_images() - show UEFI images 320 * 321 * @cmdtp: Command table 322 * @flag: Command flag 323 * @argc: Number of arguments 324 * @argv: Argument array 325 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 326 * 327 * Implement efidebug "images" sub-command. 328 * Show all UEFI loaded images and their information. 329 */ 330 static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag, 331 int argc, char * const argv[]) 332 { 333 efi_print_image_infos(NULL); 334 335 return CMD_RET_SUCCESS; 336 } 337 338 static const char * const efi_mem_type_string[] = { 339 [EFI_RESERVED_MEMORY_TYPE] = "RESERVED", 340 [EFI_LOADER_CODE] = "LOADER CODE", 341 [EFI_LOADER_DATA] = "LOADER DATA", 342 [EFI_BOOT_SERVICES_CODE] = "BOOT CODE", 343 [EFI_BOOT_SERVICES_DATA] = "BOOT DATA", 344 [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE", 345 [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA", 346 [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL", 347 [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM", 348 [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM", 349 [EFI_ACPI_MEMORY_NVS] = "ACPI NVS", 350 [EFI_MMAP_IO] = "IO", 351 [EFI_MMAP_IO_PORT] = "IO PORT", 352 [EFI_PAL_CODE] = "PAL", 353 }; 354 355 static const struct efi_mem_attrs { 356 const u64 bit; 357 const char *text; 358 } efi_mem_attrs[] = { 359 {EFI_MEMORY_UC, "UC"}, 360 {EFI_MEMORY_UC, "UC"}, 361 {EFI_MEMORY_WC, "WC"}, 362 {EFI_MEMORY_WT, "WT"}, 363 {EFI_MEMORY_WB, "WB"}, 364 {EFI_MEMORY_UCE, "UCE"}, 365 {EFI_MEMORY_WP, "WP"}, 366 {EFI_MEMORY_RP, "RP"}, 367 {EFI_MEMORY_XP, "WP"}, 368 {EFI_MEMORY_NV, "NV"}, 369 {EFI_MEMORY_MORE_RELIABLE, "REL"}, 370 {EFI_MEMORY_RO, "RO"}, 371 {EFI_MEMORY_RUNTIME, "RT"}, 372 }; 373 374 /** 375 * print_memory_attributes() - print memory map attributes 376 * @attributes: Attribute value 377 * 378 * Print memory map attributes 379 */ 380 static void print_memory_attributes(u64 attributes) 381 { 382 int sep, i; 383 384 for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++) 385 if (attributes & efi_mem_attrs[i].bit) { 386 if (sep) { 387 putc('|'); 388 } else { 389 putc(' '); 390 sep = 1; 391 } 392 puts(efi_mem_attrs[i].text); 393 } 394 } 395 396 #define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2) 397 398 /** 399 * do_efi_show_memmap() - show UEFI memory map 400 * 401 * @cmdtp: Command table 402 * @flag: Command flag 403 * @argc: Number of arguments 404 * @argv: Argument array 405 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 406 * 407 * Implement efidebug "memmap" sub-command. 408 * Show UEFI memory map. 409 */ 410 static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag, 411 int argc, char * const argv[]) 412 { 413 struct efi_mem_desc *memmap = NULL, *map; 414 efi_uintn_t map_size = 0; 415 const char *type; 416 int i; 417 efi_status_t ret; 418 419 ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, NULL, NULL, NULL)); 420 if (ret == EFI_BUFFER_TOO_SMALL) { 421 map_size += sizeof(struct efi_mem_desc); /* for my own */ 422 ret = EFI_CALL(BS->allocate_pool(EFI_LOADER_DATA, 423 map_size, (void *)&memmap)); 424 if (ret != EFI_SUCCESS) 425 return CMD_RET_FAILURE; 426 ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, 427 NULL, NULL, NULL)); 428 } 429 if (ret != EFI_SUCCESS) { 430 EFI_CALL(BS->free_pool(memmap)); 431 return CMD_RET_FAILURE; 432 } 433 434 printf("Type Start%.*s End%.*s Attributes\n", 435 EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc); 436 printf("================ %.*s %.*s ==========\n", 437 EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep); 438 for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) { 439 if (map->type < EFI_MAX_MEMORY_TYPE) 440 type = efi_mem_type_string[map->type]; 441 else 442 type = "(unknown)"; 443 444 printf("%-16s %.*llx-%.*llx", type, 445 EFI_PHYS_ADDR_WIDTH, 446 map->physical_start, 447 EFI_PHYS_ADDR_WIDTH, 448 map->physical_start + map->num_pages * EFI_PAGE_SIZE); 449 450 print_memory_attributes(map->attribute); 451 putc('\n'); 452 } 453 454 EFI_CALL(BS->free_pool(memmap)); 455 456 return CMD_RET_SUCCESS; 457 } 458 459 /** 460 * do_efi_boot_add() - set UEFI load option 461 * 462 * @cmdtp: Command table 463 * @flag: Command flag 464 * @argc: Number of arguments 465 * @argv: Argument array 466 * Return: CMD_RET_SUCCESS on success, 467 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure 468 * 469 * Implement efidebug "boot add" sub-command. 470 * Create or change UEFI load option. 471 * - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options> 472 */ 473 static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, 474 int argc, char * const argv[]) 475 { 476 int id; 477 char *endp; 478 char var_name[9]; 479 u16 var_name16[9], *p; 480 efi_guid_t guid; 481 size_t label_len, label_len16; 482 u16 *label; 483 struct efi_device_path *device_path = NULL, *file_path = NULL; 484 struct efi_load_option lo; 485 void *data = NULL; 486 efi_uintn_t size; 487 int ret; 488 489 if (argc < 6 || argc > 7) 490 return CMD_RET_USAGE; 491 492 id = (int)simple_strtoul(argv[1], &endp, 16); 493 if (*endp != '\0' || id > 0xffff) 494 return CMD_RET_USAGE; 495 496 sprintf(var_name, "Boot%04X", id); 497 p = var_name16; 498 utf8_utf16_strncpy(&p, var_name, 9); 499 500 guid = efi_global_variable_guid; 501 502 /* attributes */ 503 lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */ 504 505 /* label */ 506 label_len = strlen(argv[2]); 507 label_len16 = utf8_utf16_strnlen(argv[2], label_len); 508 label = malloc((label_len16 + 1) * sizeof(u16)); 509 if (!label) 510 return CMD_RET_FAILURE; 511 lo.label = label; /* label will be changed below */ 512 utf8_utf16_strncpy(&label, argv[2], label_len); 513 514 /* file path */ 515 ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path, 516 &file_path); 517 if (ret != EFI_SUCCESS) { 518 printf("Cannot create device path for \"%s %s\"\n", 519 argv[3], argv[4]); 520 ret = CMD_RET_FAILURE; 521 goto out; 522 } 523 lo.file_path = file_path; 524 lo.file_path_length = efi_dp_size(file_path) 525 + sizeof(struct efi_device_path); /* for END */ 526 527 /* optional data */ 528 lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]); 529 530 size = efi_serialize_load_option(&lo, (u8 **)&data); 531 if (!size) { 532 ret = CMD_RET_FAILURE; 533 goto out; 534 } 535 536 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 537 EFI_VARIABLE_BOOTSERVICE_ACCESS | 538 EFI_VARIABLE_RUNTIME_ACCESS, 539 size, data)); 540 ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); 541 out: 542 free(data); 543 efi_free_pool(device_path); 544 efi_free_pool(file_path); 545 free(lo.label); 546 547 return ret; 548 } 549 550 /** 551 * do_efi_boot_rm() - delete UEFI load options 552 * 553 * @cmdtp: Command table 554 * @flag: Command flag 555 * @argc: Number of arguments 556 * @argv: Argument array 557 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 558 * 559 * Implement efidebug "boot rm" sub-command. 560 * Delete UEFI load options. 561 * - boot rm <id> ... 562 */ 563 static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag, 564 int argc, char * const argv[]) 565 { 566 efi_guid_t guid; 567 int id, i; 568 char *endp; 569 char var_name[9]; 570 u16 var_name16[9]; 571 efi_status_t ret; 572 573 if (argc == 1) 574 return CMD_RET_USAGE; 575 576 guid = efi_global_variable_guid; 577 for (i = 1; i < argc; i++, argv++) { 578 id = (int)simple_strtoul(argv[1], &endp, 16); 579 if (*endp != '\0' || id > 0xffff) 580 return CMD_RET_FAILURE; 581 582 sprintf(var_name, "Boot%04X", id); 583 utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9); 584 585 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL)); 586 if (ret) { 587 printf("cannot remove Boot%04X", id); 588 return CMD_RET_FAILURE; 589 } 590 } 591 592 return CMD_RET_SUCCESS; 593 } 594 595 /** 596 * show_efi_boot_opt_data() - dump UEFI load option 597 * 598 * @id: Load option number 599 * @data: Value of UEFI load option variable 600 * 601 * Decode the value of UEFI load option variable and print information. 602 */ 603 static void show_efi_boot_opt_data(int id, void *data) 604 { 605 struct efi_load_option lo; 606 char *label, *p; 607 size_t label_len16, label_len; 608 u16 *dp_str; 609 610 efi_deserialize_load_option(&lo, data); 611 612 label_len16 = u16_strlen(lo.label); 613 label_len = utf16_utf8_strnlen(lo.label, label_len16); 614 label = malloc(label_len + 1); 615 if (!label) 616 return; 617 p = label; 618 utf16_utf8_strncpy(&p, lo.label, label_len16); 619 620 printf("Boot%04X:\n", id); 621 printf("\tattributes: %c%c%c (0x%08x)\n", 622 /* ACTIVE */ 623 lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-', 624 /* FORCE RECONNECT */ 625 lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-', 626 /* HIDDEN */ 627 lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-', 628 lo.attributes); 629 printf("\tlabel: %s\n", label); 630 631 dp_str = efi_dp_str(lo.file_path); 632 printf("\tfile_path: %ls\n", dp_str); 633 efi_free_pool(dp_str); 634 635 printf("\tdata: %s\n", lo.optional_data); 636 637 free(label); 638 } 639 640 /** 641 * show_efi_boot_opt() - dump UEFI load option 642 * 643 * @id: Load option number 644 * 645 * Dump information defined by UEFI load option. 646 */ 647 static void show_efi_boot_opt(int id) 648 { 649 char var_name[9]; 650 u16 var_name16[9], *p; 651 efi_guid_t guid; 652 void *data = NULL; 653 efi_uintn_t size; 654 int ret; 655 656 sprintf(var_name, "Boot%04X", id); 657 p = var_name16; 658 utf8_utf16_strncpy(&p, var_name, 9); 659 guid = efi_global_variable_guid; 660 661 size = 0; 662 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL)); 663 if (ret == (int)EFI_BUFFER_TOO_SMALL) { 664 data = malloc(size); 665 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, 666 data)); 667 } 668 if (ret == EFI_SUCCESS) 669 show_efi_boot_opt_data(id, data); 670 else if (ret == EFI_NOT_FOUND) 671 printf("Boot%04X: not found\n", id); 672 673 free(data); 674 } 675 676 /** 677 * show_efi_boot_dump() - dump all UEFI load options 678 * 679 * @cmdtp: Command table 680 * @flag: Command flag 681 * @argc: Number of arguments 682 * @argv: Argument array 683 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 684 * 685 * Implement efidebug "boot dump" sub-command. 686 * Dump information of all UEFI load options defined. 687 * - boot dump 688 */ 689 static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag, 690 int argc, char * const argv[]) 691 { 692 char regex[256]; 693 char * const regexlist[] = {regex}; 694 char *variables = NULL, *boot, *value; 695 int len; 696 int id; 697 698 if (argc > 1) 699 return CMD_RET_USAGE; 700 701 snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+"); 702 703 /* TODO: use GetNextVariableName? */ 704 len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, 705 &variables, 0, 1, regexlist); 706 707 if (!len) 708 return CMD_RET_SUCCESS; 709 710 if (len < 0) 711 return CMD_RET_FAILURE; 712 713 boot = variables; 714 while (*boot) { 715 value = strstr(boot, "Boot") + 4; 716 id = (int)simple_strtoul(value, NULL, 16); 717 show_efi_boot_opt(id); 718 boot = strchr(boot, '\n'); 719 if (!*boot) 720 break; 721 boot++; 722 } 723 free(variables); 724 725 return CMD_RET_SUCCESS; 726 } 727 728 /** 729 * show_efi_boot_order() - show order of UEFI load options 730 * 731 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 732 * 733 * Show order of UEFI load options defined by BootOrder variable. 734 */ 735 static int show_efi_boot_order(void) 736 { 737 efi_guid_t guid; 738 u16 *bootorder = NULL; 739 efi_uintn_t size; 740 int num, i; 741 char var_name[9]; 742 u16 var_name16[9], *p16; 743 void *data; 744 struct efi_load_option lo; 745 char *label, *p; 746 size_t label_len16, label_len; 747 efi_status_t ret; 748 749 guid = efi_global_variable_guid; 750 size = 0; 751 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size, 752 NULL)); 753 if (ret == EFI_BUFFER_TOO_SMALL) { 754 bootorder = malloc(size); 755 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, 756 &size, bootorder)); 757 } 758 if (ret == EFI_NOT_FOUND) { 759 printf("BootOrder not defined\n"); 760 ret = CMD_RET_SUCCESS; 761 goto out; 762 } else if (ret != EFI_SUCCESS) { 763 ret = CMD_RET_FAILURE; 764 goto out; 765 } 766 767 num = size / sizeof(u16); 768 for (i = 0; i < num; i++) { 769 sprintf(var_name, "Boot%04X", bootorder[i]); 770 p16 = var_name16; 771 utf8_utf16_strncpy(&p16, var_name, 9); 772 773 size = 0; 774 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, 775 NULL)); 776 if (ret != EFI_BUFFER_TOO_SMALL) { 777 printf("%2d: Boot%04X: (not defined)\n", 778 i + 1, bootorder[i]); 779 continue; 780 } 781 782 data = malloc(size); 783 if (!data) { 784 ret = CMD_RET_FAILURE; 785 goto out; 786 } 787 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, 788 data)); 789 if (ret != EFI_SUCCESS) { 790 free(data); 791 ret = CMD_RET_FAILURE; 792 goto out; 793 } 794 795 efi_deserialize_load_option(&lo, data); 796 797 label_len16 = u16_strlen(lo.label); 798 label_len = utf16_utf8_strnlen(lo.label, label_len16); 799 label = malloc(label_len + 1); 800 if (!label) { 801 free(data); 802 ret = CMD_RET_FAILURE; 803 goto out; 804 } 805 p = label; 806 utf16_utf8_strncpy(&p, lo.label, label_len16); 807 printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label); 808 free(label); 809 810 free(data); 811 } 812 out: 813 free(bootorder); 814 815 return ret; 816 } 817 818 /** 819 * do_efi_boot_next() - manage UEFI BootNext variable 820 * 821 * @cmdtp: Command table 822 * @flag: Command flag 823 * @argc: Number of arguments 824 * @argv: Argument array 825 * Return: CMD_RET_SUCCESS on success, 826 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure 827 * 828 * Implement efidebug "boot next" sub-command. 829 * Set BootNext variable. 830 * - boot next <id> 831 */ 832 static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag, 833 int argc, char * const argv[]) 834 { 835 u16 bootnext; 836 efi_uintn_t size; 837 char *endp; 838 efi_guid_t guid; 839 efi_status_t ret; 840 841 if (argc != 2) 842 return CMD_RET_USAGE; 843 844 bootnext = (u16)simple_strtoul(argv[1], &endp, 16); 845 if (*endp != '\0' || bootnext > 0xffff) { 846 printf("invalid value: %s\n", argv[1]); 847 ret = CMD_RET_FAILURE; 848 goto out; 849 } 850 851 guid = efi_global_variable_guid; 852 size = sizeof(u16); 853 ret = EFI_CALL(RT->set_variable(L"BootNext", &guid, 854 EFI_VARIABLE_BOOTSERVICE_ACCESS | 855 EFI_VARIABLE_RUNTIME_ACCESS, 856 size, &bootnext)); 857 ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); 858 out: 859 return ret; 860 } 861 862 /** 863 * do_efi_boot_order() - manage UEFI BootOrder variable 864 * 865 * @cmdtp: Command table 866 * @flag: Command flag 867 * @argc: Number of arguments 868 * @argv: Argument array 869 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure 870 * 871 * Implement efidebug "boot order" sub-command. 872 * Show order of UEFI load options, or change it in BootOrder variable. 873 * - boot order [<id> ...] 874 */ 875 static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag, 876 int argc, char * const argv[]) 877 { 878 u16 *bootorder = NULL; 879 efi_uintn_t size; 880 int id, i; 881 char *endp; 882 efi_guid_t guid; 883 efi_status_t ret; 884 885 if (argc == 1) 886 return show_efi_boot_order(); 887 888 argc--; 889 argv++; 890 891 size = argc * sizeof(u16); 892 bootorder = malloc(size); 893 if (!bootorder) 894 return CMD_RET_FAILURE; 895 896 for (i = 0; i < argc; i++) { 897 id = (int)simple_strtoul(argv[i], &endp, 16); 898 if (*endp != '\0' || id > 0xffff) { 899 printf("invalid value: %s\n", argv[i]); 900 ret = CMD_RET_FAILURE; 901 goto out; 902 } 903 904 bootorder[i] = (u16)id; 905 } 906 907 guid = efi_global_variable_guid; 908 ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid, 909 EFI_VARIABLE_BOOTSERVICE_ACCESS | 910 EFI_VARIABLE_RUNTIME_ACCESS, 911 size, bootorder)); 912 ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); 913 out: 914 free(bootorder); 915 916 return ret; 917 } 918 919 static cmd_tbl_t cmd_efidebug_boot_sub[] = { 920 U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""), 921 U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""), 922 U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""), 923 U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""), 924 U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order, 925 "", ""), 926 }; 927 928 /** 929 * do_efi_boot_opt() - manage UEFI load options 930 * 931 * @cmdtp: Command table 932 * @flag: Command flag 933 * @argc: Number of arguments 934 * @argv: Argument array 935 * Return: CMD_RET_SUCCESS on success, 936 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure 937 * 938 * Implement efidebug "boot" sub-command. 939 * See above for details of sub-commands. 940 */ 941 static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag, 942 int argc, char * const argv[]) 943 { 944 cmd_tbl_t *cp; 945 946 if (argc < 2) 947 return CMD_RET_USAGE; 948 949 argc--; argv++; 950 951 cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub, 952 ARRAY_SIZE(cmd_efidebug_boot_sub)); 953 if (!cp) 954 return CMD_RET_USAGE; 955 956 return cp->cmd(cmdtp, flag, argc, argv); 957 } 958 959 static cmd_tbl_t cmd_efidebug_sub[] = { 960 U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), 961 U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices, 962 "", ""), 963 U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers, 964 "", ""), 965 U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles, 966 "", ""), 967 U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images, 968 "", ""), 969 U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap, 970 "", ""), 971 }; 972 973 /** 974 * do_efidebug() - display and configure UEFI environment 975 * 976 * @cmdtp: Command table 977 * @flag: Command flag 978 * @argc: Number of arguments 979 * @argv: Argument array 980 * Return: CMD_RET_SUCCESS on success, 981 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure 982 * 983 * Implement efidebug command which allows us to display and 984 * configure UEFI environment. 985 * See above for details of sub-commands. 986 */ 987 static int do_efidebug(cmd_tbl_t *cmdtp, int flag, 988 int argc, char * const argv[]) 989 { 990 cmd_tbl_t *cp; 991 efi_status_t r; 992 993 if (argc < 2) 994 return CMD_RET_USAGE; 995 996 argc--; argv++; 997 998 /* Initialize UEFI drivers */ 999 r = efi_init_obj_list(); 1000 if (r != EFI_SUCCESS) { 1001 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", 1002 r & ~EFI_ERROR_MASK); 1003 return CMD_RET_FAILURE; 1004 } 1005 1006 cp = find_cmd_tbl(argv[0], cmd_efidebug_sub, 1007 ARRAY_SIZE(cmd_efidebug_sub)); 1008 if (!cp) 1009 return CMD_RET_USAGE; 1010 1011 return cp->cmd(cmdtp, flag, argc, argv); 1012 } 1013 1014 #ifdef CONFIG_SYS_LONGHELP 1015 static char efidebug_help_text[] = 1016 " - UEFI Shell-like interface to configure UEFI environment\n" 1017 "\n" 1018 "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n" 1019 " - set UEFI BootXXXX variable\n" 1020 " <load options> will be passed to UEFI application\n" 1021 "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n" 1022 " - delete UEFI BootXXXX variables\n" 1023 "efidebug boot dump\n" 1024 " - dump all UEFI BootXXXX variables\n" 1025 "efidebug boot next <bootid>\n" 1026 " - set UEFI BootNext variable\n" 1027 "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n" 1028 " - set/show UEFI boot order\n" 1029 "\n" 1030 "efidebug devices\n" 1031 " - show uefi devices\n" 1032 "efidebug drivers\n" 1033 " - show uefi drivers\n" 1034 "efidebug dh\n" 1035 " - show uefi handles\n" 1036 "efidebug images\n" 1037 " - show loaded images\n" 1038 "efidebug memmap\n" 1039 " - show uefi memory map\n"; 1040 #endif 1041 1042 U_BOOT_CMD( 1043 efidebug, 10, 0, do_efidebug, 1044 "Configure UEFI environment", 1045 efidebug_help_text 1046 ); 1047