uboot/cmd/efidebug.c
<<
>>
Prefs
   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_dt_fixup.h>
  12#include <efi_load_initrd.h>
  13#include <efi_loader.h>
  14#include <efi_rng.h>
  15#include <efi_variable.h>
  16#include <exports.h>
  17#include <hexdump.h>
  18#include <log.h>
  19#include <malloc.h>
  20#include <mapmem.h>
  21#include <part.h>
  22#include <search.h>
  23#include <linux/ctype.h>
  24#include <linux/err.h>
  25
  26#define BS systab.boottime
  27#define RT systab.runtime
  28
  29#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
  30/**
  31 * do_efi_capsule_update() - process a capsule update
  32 *
  33 * @cmdtp:      Command table
  34 * @flag:       Command flag
  35 * @argc:       Number of arguments
  36 * @argv:       Argument array
  37 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
  38 *
  39 * Implement efidebug "capsule update" sub-command.
  40 * process a capsule update.
  41 *
  42 *     efidebug capsule update [-v] <capsule address>
  43 */
  44static int do_efi_capsule_update(struct cmd_tbl *cmdtp, int flag,
  45                                 int argc, char * const argv[])
  46{
  47        struct efi_capsule_header *capsule;
  48        int verbose = 0;
  49        char *endp;
  50        efi_status_t ret;
  51
  52        if (argc != 2 && argc != 3)
  53                return CMD_RET_USAGE;
  54
  55        if (argc == 3) {
  56                if (strcmp(argv[1], "-v"))
  57                        return CMD_RET_USAGE;
  58
  59                verbose = 1;
  60                argc--;
  61                argv++;
  62        }
  63
  64        capsule = (typeof(capsule))hextoul(argv[1], &endp);
  65        if (endp == argv[1]) {
  66                printf("Invalid address: %s", argv[1]);
  67                return CMD_RET_FAILURE;
  68        }
  69
  70        if (verbose) {
  71                printf("Capsule guid: %pUl\n", &capsule->capsule_guid);
  72                printf("Capsule flags: 0x%x\n", capsule->flags);
  73                printf("Capsule header size: 0x%x\n", capsule->header_size);
  74                printf("Capsule image size: 0x%x\n",
  75                       capsule->capsule_image_size);
  76        }
  77
  78        ret = EFI_CALL(RT->update_capsule(&capsule, 1, 0));
  79        if (ret) {
  80                printf("Cannot handle a capsule at %p", capsule);
  81                return CMD_RET_FAILURE;
  82        }
  83
  84        return CMD_RET_SUCCESS;
  85}
  86
  87static int do_efi_capsule_on_disk_update(struct cmd_tbl *cmdtp, int flag,
  88                                         int argc, char * const argv[])
  89{
  90        efi_status_t ret;
  91
  92        ret = efi_launch_capsules();
  93
  94        return ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
  95}
  96
  97/**
  98 * do_efi_capsule_show() - show capsule information
  99 *
 100 * @cmdtp:      Command table
 101 * @flag:       Command flag
 102 * @argc:       Number of arguments
 103 * @argv:       Argument array
 104 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 105 *
 106 * Implement efidebug "capsule show" sub-command.
 107 * show capsule information.
 108 *
 109 *     efidebug capsule show <capsule address>
 110 */
 111static int do_efi_capsule_show(struct cmd_tbl *cmdtp, int flag,
 112                               int argc, char * const argv[])
 113{
 114        struct efi_capsule_header *capsule;
 115        char *endp;
 116
 117        if (argc != 2)
 118                return CMD_RET_USAGE;
 119
 120        capsule = (typeof(capsule))hextoul(argv[1], &endp);
 121        if (endp == argv[1]) {
 122                printf("Invalid address: %s", argv[1]);
 123                return CMD_RET_FAILURE;
 124        }
 125
 126        printf("Capsule guid: %pUl\n", &capsule->capsule_guid);
 127        printf("Capsule flags: 0x%x\n", capsule->flags);
 128        printf("Capsule header size: 0x%x\n", capsule->header_size);
 129        printf("Capsule image size: 0x%x\n",
 130               capsule->capsule_image_size);
 131
 132        return CMD_RET_SUCCESS;
 133}
 134
 135#ifdef CONFIG_EFI_ESRT
 136
 137#define EFI_ESRT_FW_TYPE_NUM 4
 138char *efi_fw_type_str[EFI_ESRT_FW_TYPE_NUM] = {"unknown", "system FW", "device FW",
 139         "UEFI driver"};
 140
 141#define EFI_ESRT_UPDATE_STATUS_NUM 9
 142char *efi_update_status_str[EFI_ESRT_UPDATE_STATUS_NUM] = {"success", "unsuccessful",
 143        "insufficient resources", "incorrect version", "invalid format",
 144        "auth error", "power event (AC)", "power event (batt)",
 145        "unsatisfied dependencies"};
 146
 147#define EFI_FW_TYPE_STR_GET(idx) (\
 148EFI_ESRT_FW_TYPE_NUM > (idx) ? efi_fw_type_str[(idx)] : "error"\
 149)
 150
 151#define EFI_FW_STATUS_STR_GET(idx) (\
 152EFI_ESRT_UPDATE_STATUS_NUM  > (idx) ? efi_update_status_str[(idx)] : "error"\
 153)
 154
 155/**
 156 * do_efi_capsule_esrt() - manage UEFI capsules
 157 *
 158 * @cmdtp:      Command table
 159 * @flag:       Command flag
 160 * @argc:       Number of arguments
 161 * @argv:       Argument array
 162 * Return:      CMD_RET_SUCCESS on success,
 163 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
 164 *
 165 * Implement efidebug "capsule esrt" sub-command.
 166 * The prints the current ESRT table.
 167 *
 168 *     efidebug capsule esrt
 169 */
 170static int do_efi_capsule_esrt(struct cmd_tbl *cmdtp, int flag,
 171                               int argc, char * const argv[])
 172{
 173        struct efi_system_resource_table *esrt = NULL;
 174
 175        if (argc != 1)
 176                return CMD_RET_USAGE;
 177
 178        for (int idx = 0; idx < systab.nr_tables; idx++)
 179                if (!guidcmp(&efi_esrt_guid, &systab.tables[idx].guid))
 180                        esrt = (struct efi_system_resource_table *)systab.tables[idx].table;
 181
 182        if (!esrt) {
 183                log_info("ESRT: table not present\n");
 184                return CMD_RET_SUCCESS;
 185        }
 186
 187        printf("========================================\n");
 188        printf("ESRT: fw_resource_count=%d\n", esrt->fw_resource_count);
 189        printf("ESRT: fw_resource_count_max=%d\n", esrt->fw_resource_count_max);
 190        printf("ESRT: fw_resource_version=%lld\n", esrt->fw_resource_version);
 191
 192        for (int idx = 0; idx < esrt->fw_resource_count; idx++) {
 193                printf("[entry %d]==============================\n", idx);
 194                printf("ESRT: fw_class=%pUL\n", &esrt->entries[idx].fw_class);
 195                printf("ESRT: fw_type=%s\n", EFI_FW_TYPE_STR_GET(esrt->entries[idx].fw_type));
 196                printf("ESRT: fw_version=%d\n", esrt->entries[idx].fw_version);
 197                printf("ESRT: lowest_supported_fw_version=%d\n",
 198                       esrt->entries[idx].lowest_supported_fw_version);
 199                printf("ESRT: capsule_flags=%d\n",
 200                       esrt->entries[idx].capsule_flags);
 201                printf("ESRT: last_attempt_version=%d\n",
 202                       esrt->entries[idx].last_attempt_version);
 203                printf("ESRT: last_attempt_status=%s\n",
 204                       EFI_FW_STATUS_STR_GET(esrt->entries[idx].last_attempt_status));
 205        }
 206        printf("========================================\n");
 207
 208        return CMD_RET_SUCCESS;
 209}
 210#endif /*  CONFIG_EFI_ESRT */
 211/**
 212 * do_efi_capsule_res() - show a capsule update result
 213 *
 214 * @cmdtp:      Command table
 215 * @flag:       Command flag
 216 * @argc:       Number of arguments
 217 * @argv:       Argument array
 218 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 219 *
 220 * Implement efidebug "capsule result" sub-command.
 221 * show a capsule update result.
 222 * If result number is not specified, CapsuleLast will be shown.
 223 *
 224 *     efidebug capsule result [<capsule result number>]
 225 */
 226static int do_efi_capsule_res(struct cmd_tbl *cmdtp, int flag,
 227                              int argc, char * const argv[])
 228{
 229        int capsule_id;
 230        char *endp;
 231        u16 var_name16[12];
 232        efi_guid_t guid;
 233        struct efi_capsule_result_variable_header *result = NULL;
 234        efi_uintn_t size;
 235        efi_status_t ret;
 236
 237        if (argc != 1 && argc != 2)
 238                return CMD_RET_USAGE;
 239
 240        guid = efi_guid_capsule_report;
 241        if (argc == 1) {
 242                size = sizeof(var_name16);
 243                ret = efi_get_variable_int(L"CapsuleLast", &guid, NULL,
 244                                           &size, var_name16, NULL);
 245
 246                if (ret != EFI_SUCCESS) {
 247                        if (ret == EFI_NOT_FOUND)
 248                                printf("CapsuleLast doesn't exist\n");
 249                        else
 250                                printf("Failed to get CapsuleLast\n");
 251
 252                        return CMD_RET_FAILURE;
 253                }
 254                printf("CapsuleLast is %ls\n", var_name16);
 255        } else {
 256                argc--;
 257                argv++;
 258
 259                capsule_id = hextoul(argv[0], &endp);
 260                if (capsule_id < 0 || capsule_id > 0xffff)
 261                        return CMD_RET_USAGE;
 262
 263                efi_create_indexed_name(var_name16, sizeof(var_name16),
 264                                        "Capsule", capsule_id);
 265        }
 266
 267        size = 0;
 268        ret = efi_get_variable_int(var_name16, &guid, NULL, &size, NULL, NULL);
 269        if (ret == EFI_BUFFER_TOO_SMALL) {
 270                result = malloc(size);
 271                if (!result)
 272                        return CMD_RET_FAILURE;
 273                ret = efi_get_variable_int(var_name16, &guid, NULL, &size,
 274                                           result, NULL);
 275        }
 276        if (ret != EFI_SUCCESS) {
 277                free(result);
 278                printf("Failed to get %ls\n", var_name16);
 279
 280                return CMD_RET_FAILURE;
 281        }
 282
 283        printf("Result total size: 0x%x\n", result->variable_total_size);
 284        printf("Capsule guid: %pUl\n", &result->capsule_guid);
 285        printf("Time processed: %04d-%02d-%02d %02d:%02d:%02d\n",
 286               result->capsule_processed.year, result->capsule_processed.month,
 287               result->capsule_processed.day, result->capsule_processed.hour,
 288               result->capsule_processed.minute,
 289               result->capsule_processed.second);
 290        printf("Capsule status: 0x%lx\n", result->capsule_status);
 291
 292        free(result);
 293
 294        return CMD_RET_SUCCESS;
 295}
 296
 297static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
 298        U_BOOT_CMD_MKENT(update, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_update,
 299                         "", ""),
 300        U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show,
 301                         "", ""),
 302#ifdef CONFIG_EFI_ESRT
 303        U_BOOT_CMD_MKENT(esrt, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_esrt,
 304                         "", ""),
 305#endif
 306        U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update,
 307                         "", ""),
 308        U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
 309                         "", ""),
 310};
 311
 312/**
 313 * do_efi_capsule() - manage UEFI capsules
 314 *
 315 * @cmdtp:      Command table
 316 * @flag:       Command flag
 317 * @argc:       Number of arguments
 318 * @argv:       Argument array
 319 * Return:      CMD_RET_SUCCESS on success,
 320 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
 321 *
 322 * Implement efidebug "capsule" sub-command.
 323 */
 324static int do_efi_capsule(struct cmd_tbl *cmdtp, int flag,
 325                          int argc, char * const argv[])
 326{
 327        struct cmd_tbl *cp;
 328
 329        if (argc < 2)
 330                return CMD_RET_USAGE;
 331
 332        argc--; argv++;
 333
 334        cp = find_cmd_tbl(argv[0], cmd_efidebug_capsule_sub,
 335                          ARRAY_SIZE(cmd_efidebug_capsule_sub));
 336        if (!cp)
 337                return CMD_RET_USAGE;
 338
 339        return cp->cmd(cmdtp, flag, argc, argv);
 340}
 341#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
 342
 343/**
 344 * efi_get_device_path_text() - get device path text
 345 *
 346 * Return the text representation of the device path of a handle.
 347 *
 348 * @handle:     handle of UEFI device
 349 * Return:
 350 * Pointer to the device path text or NULL.
 351 * The caller is responsible for calling FreePool().
 352 */
 353static u16 *efi_get_device_path_text(efi_handle_t handle)
 354{
 355        struct efi_handler *handler;
 356        efi_status_t ret;
 357
 358        ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
 359        if (ret == EFI_SUCCESS && handler->protocol_interface) {
 360                struct efi_device_path *dp = handler->protocol_interface;
 361
 362                return efi_dp_str(dp);
 363        } else {
 364                return NULL;
 365        }
 366}
 367
 368#define EFI_HANDLE_WIDTH ((int)sizeof(efi_handle_t) * 2)
 369
 370static const char spc[] = "                ";
 371static const char sep[] = "================";
 372
 373/**
 374 * do_efi_show_devices() - show UEFI devices
 375 *
 376 * @cmdtp:      Command table
 377 * @flag:       Command flag
 378 * @argc:       Number of arguments
 379 * @argv:       Argument array
 380 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 381 *
 382 * Implement efidebug "devices" sub-command.
 383 * Show all UEFI devices and their information.
 384 */
 385static int do_efi_show_devices(struct cmd_tbl *cmdtp, int flag,
 386                               int argc, char *const argv[])
 387{
 388        efi_handle_t *handles;
 389        efi_uintn_t num, i;
 390        u16 *dev_path_text;
 391        efi_status_t ret;
 392
 393        ret = EFI_CALL(efi_locate_handle_buffer(ALL_HANDLES, NULL, NULL,
 394                                                &num, &handles));
 395        if (ret != EFI_SUCCESS)
 396                return CMD_RET_FAILURE;
 397
 398        if (!num)
 399                return CMD_RET_SUCCESS;
 400
 401        printf("Device%.*s Device Path\n", EFI_HANDLE_WIDTH - 6, spc);
 402        printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
 403        for (i = 0; i < num; i++) {
 404                dev_path_text = efi_get_device_path_text(handles[i]);
 405                if (dev_path_text) {
 406                        printf("%p %ls\n", handles[i], dev_path_text);
 407                        efi_free_pool(dev_path_text);
 408                }
 409        }
 410
 411        efi_free_pool(handles);
 412
 413        return CMD_RET_SUCCESS;
 414}
 415
 416/**
 417 * efi_get_driver_handle_info() - get information of UEFI driver
 418 *
 419 * @handle:             Handle of UEFI device
 420 * @driver_name:        Driver name
 421 * @image_path:         Pointer to text of device path
 422 * Return:              0 on success, -1 on failure
 423 *
 424 * Currently return no useful information as all UEFI drivers are
 425 * built-in..
 426 */
 427static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name,
 428                                      u16 **image_path)
 429{
 430        struct efi_handler *handler;
 431        struct efi_loaded_image *image;
 432        efi_status_t ret;
 433
 434        /*
 435         * driver name
 436         * TODO: support EFI_COMPONENT_NAME2_PROTOCOL
 437         */
 438        *driver_name = NULL;
 439
 440        /* image name */
 441        ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
 442        if (ret != EFI_SUCCESS) {
 443                *image_path = NULL;
 444                return 0;
 445        }
 446
 447        image = handler->protocol_interface;
 448        *image_path = efi_dp_str(image->file_path);
 449
 450        return 0;
 451}
 452
 453/**
 454 * do_efi_show_drivers() - show UEFI drivers
 455 *
 456 * @cmdtp:      Command table
 457 * @flag:       Command flag
 458 * @argc:       Number of arguments
 459 * @argv:       Argument array
 460 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 461 *
 462 * Implement efidebug "drivers" sub-command.
 463 * Show all UEFI drivers and their information.
 464 */
 465static int do_efi_show_drivers(struct cmd_tbl *cmdtp, int flag,
 466                               int argc, char *const argv[])
 467{
 468        efi_handle_t *handles;
 469        efi_uintn_t num, i;
 470        u16 *driver_name, *image_path_text;
 471        efi_status_t ret;
 472
 473        ret = EFI_CALL(efi_locate_handle_buffer(
 474                                BY_PROTOCOL, &efi_guid_driver_binding_protocol,
 475                                NULL, &num, &handles));
 476        if (ret != EFI_SUCCESS)
 477                return CMD_RET_FAILURE;
 478
 479        if (!num)
 480                return CMD_RET_SUCCESS;
 481
 482        printf("Driver%.*s Name                 Image Path\n",
 483               EFI_HANDLE_WIDTH - 6, spc);
 484        printf("%.*s ==================== ====================\n",
 485               EFI_HANDLE_WIDTH, sep);
 486        for (i = 0; i < num; i++) {
 487                if (!efi_get_driver_handle_info(handles[i], &driver_name,
 488                                                &image_path_text)) {
 489                        if (image_path_text)
 490                                printf("%p %-20ls %ls\n", handles[i],
 491                                       driver_name, image_path_text);
 492                        else
 493                                printf("%p %-20ls <built-in>\n",
 494                                       handles[i], driver_name);
 495                        efi_free_pool(driver_name);
 496                        efi_free_pool(image_path_text);
 497                }
 498        }
 499
 500        efi_free_pool(handles);
 501
 502        return CMD_RET_SUCCESS;
 503}
 504
 505static const struct {
 506        const char *text;
 507        const efi_guid_t guid;
 508} guid_list[] = {
 509        {
 510                "Device Path",
 511                EFI_DEVICE_PATH_PROTOCOL_GUID,
 512        },
 513        {
 514                "Device Path To Text",
 515                EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID,
 516        },
 517        {
 518                "Device Path Utilities",
 519                EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID,
 520        },
 521        {
 522                "Unicode Collation 2",
 523                EFI_UNICODE_COLLATION_PROTOCOL2_GUID,
 524        },
 525        {
 526                "Driver Binding",
 527                EFI_DRIVER_BINDING_PROTOCOL_GUID,
 528        },
 529        {
 530                "Simple Text Input",
 531                EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID,
 532        },
 533        {
 534                "Simple Text Input Ex",
 535                EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID,
 536        },
 537        {
 538                "Simple Text Output",
 539                EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID,
 540        },
 541        {
 542                "Block IO",
 543                EFI_BLOCK_IO_PROTOCOL_GUID,
 544        },
 545        {
 546                "Simple File System",
 547                EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID,
 548        },
 549        {
 550                "Loaded Image",
 551                EFI_LOADED_IMAGE_PROTOCOL_GUID,
 552        },
 553        {
 554                "Graphics Output",
 555                EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID,
 556        },
 557        {
 558                "HII String",
 559                EFI_HII_STRING_PROTOCOL_GUID,
 560        },
 561        {
 562                "HII Database",
 563                EFI_HII_DATABASE_PROTOCOL_GUID,
 564        },
 565        {
 566                "HII Config Routing",
 567                EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID,
 568        },
 569        {
 570                "Load File2",
 571                EFI_LOAD_FILE2_PROTOCOL_GUID,
 572        },
 573        {
 574                "Random Number Generator",
 575                EFI_RNG_PROTOCOL_GUID,
 576        },
 577        {
 578                "Simple Network",
 579                EFI_SIMPLE_NETWORK_PROTOCOL_GUID,
 580        },
 581        {
 582                "PXE Base Code",
 583                EFI_PXE_BASE_CODE_PROTOCOL_GUID,
 584        },
 585        {
 586                "Device-Tree Fixup",
 587                EFI_DT_FIXUP_PROTOCOL_GUID,
 588        },
 589        {
 590                "System Partition",
 591                PARTITION_SYSTEM_GUID
 592        },
 593        {
 594                "Firmware Management",
 595                EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID
 596        },
 597        /* Configuration table GUIDs */
 598        {
 599                "ACPI table",
 600                EFI_ACPI_TABLE_GUID,
 601        },
 602        {
 603                "EFI System Resource Table",
 604                EFI_SYSTEM_RESOURCE_TABLE_GUID,
 605        },
 606        {
 607                "device tree",
 608                EFI_FDT_GUID,
 609        },
 610        {
 611                "SMBIOS table",
 612                SMBIOS_TABLE_GUID,
 613        },
 614        {
 615                "Runtime properties",
 616                EFI_RT_PROPERTIES_TABLE_GUID,
 617        },
 618        {
 619                "TCG2 Final Events Table",
 620                EFI_TCG2_FINAL_EVENTS_TABLE_GUID,
 621        },
 622};
 623
 624/**
 625 * get_guid_text - get string of GUID
 626 *
 627 * Return description of GUID.
 628 *
 629 * @guid:       GUID
 630 * Return:      description of GUID or NULL
 631 */
 632static const char *get_guid_text(const void *guid)
 633{
 634        int i;
 635
 636        for (i = 0; i < ARRAY_SIZE(guid_list); i++) {
 637                /*
 638                 * As guidcmp uses memcmp() we can safely accept unaligned
 639                 * GUIDs.
 640                 */
 641                if (!guidcmp(&guid_list[i].guid, guid))
 642                        return guid_list[i].text;
 643        }
 644
 645        return NULL;
 646}
 647
 648/**
 649 * do_efi_show_handles() - show UEFI handles
 650 *
 651 * @cmdtp:      Command table
 652 * @flag:       Command flag
 653 * @argc:       Number of arguments
 654 * @argv:       Argument array
 655 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 656 *
 657 * Implement efidebug "dh" sub-command.
 658 * Show all UEFI handles and their information, currently all protocols
 659 * added to handle.
 660 */
 661static int do_efi_show_handles(struct cmd_tbl *cmdtp, int flag,
 662                               int argc, char *const argv[])
 663{
 664        efi_handle_t *handles;
 665        efi_guid_t **guid;
 666        efi_uintn_t num, count, i, j;
 667        const char *guid_text;
 668        efi_status_t ret;
 669
 670        ret = EFI_CALL(efi_locate_handle_buffer(ALL_HANDLES, NULL, NULL,
 671                                                &num, &handles));
 672        if (ret != EFI_SUCCESS)
 673                return CMD_RET_FAILURE;
 674
 675        if (!num)
 676                return CMD_RET_SUCCESS;
 677
 678        printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
 679        printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
 680        for (i = 0; i < num; i++) {
 681                printf("%p", handles[i]);
 682                ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid,
 683                                                        &count));
 684                if (ret || !count) {
 685                        putc('\n');
 686                        continue;
 687                }
 688
 689                for (j = 0; j < count; j++) {
 690                        if (j)
 691                                printf(", ");
 692                        else
 693                                putc(' ');
 694
 695                        guid_text = get_guid_text(guid[j]);
 696                        if (guid_text)
 697                                puts(guid_text);
 698                        else
 699                                printf("%pUl", guid[j]);
 700                }
 701                putc('\n');
 702        }
 703
 704        efi_free_pool(handles);
 705
 706        return CMD_RET_SUCCESS;
 707}
 708
 709/**
 710 * do_efi_show_images() - show UEFI images
 711 *
 712 * @cmdtp:      Command table
 713 * @flag:       Command flag
 714 * @argc:       Number of arguments
 715 * @argv:       Argument array
 716 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 717 *
 718 * Implement efidebug "images" sub-command.
 719 * Show all UEFI loaded images and their information.
 720 */
 721static int do_efi_show_images(struct cmd_tbl *cmdtp, int flag,
 722                              int argc, char *const argv[])
 723{
 724        efi_print_image_infos(NULL);
 725
 726        return CMD_RET_SUCCESS;
 727}
 728
 729static const char * const efi_mem_type_string[] = {
 730        [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
 731        [EFI_LOADER_CODE] = "LOADER CODE",
 732        [EFI_LOADER_DATA] = "LOADER DATA",
 733        [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
 734        [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
 735        [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
 736        [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
 737        [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
 738        [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
 739        [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
 740        [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
 741        [EFI_MMAP_IO] = "IO",
 742        [EFI_MMAP_IO_PORT] = "IO PORT",
 743        [EFI_PAL_CODE] = "PAL",
 744        [EFI_PERSISTENT_MEMORY_TYPE] = "PERSISTENT",
 745};
 746
 747static const struct efi_mem_attrs {
 748        const u64 bit;
 749        const char *text;
 750} efi_mem_attrs[] = {
 751        {EFI_MEMORY_UC, "UC"},
 752        {EFI_MEMORY_UC, "UC"},
 753        {EFI_MEMORY_WC, "WC"},
 754        {EFI_MEMORY_WT, "WT"},
 755        {EFI_MEMORY_WB, "WB"},
 756        {EFI_MEMORY_UCE, "UCE"},
 757        {EFI_MEMORY_WP, "WP"},
 758        {EFI_MEMORY_RP, "RP"},
 759        {EFI_MEMORY_XP, "WP"},
 760        {EFI_MEMORY_NV, "NV"},
 761        {EFI_MEMORY_MORE_RELIABLE, "REL"},
 762        {EFI_MEMORY_RO, "RO"},
 763        {EFI_MEMORY_SP, "SP"},
 764        {EFI_MEMORY_RUNTIME, "RT"},
 765};
 766
 767/**
 768 * print_memory_attributes() - print memory map attributes
 769 *
 770 * @attributes: Attribute value
 771 *
 772 * Print memory map attributes
 773 */
 774static void print_memory_attributes(u64 attributes)
 775{
 776        int sep, i;
 777
 778        for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
 779                if (attributes & efi_mem_attrs[i].bit) {
 780                        if (sep) {
 781                                putc('|');
 782                        } else {
 783                                putc(' ');
 784                                sep = 1;
 785                        }
 786                        puts(efi_mem_attrs[i].text);
 787                }
 788}
 789
 790#define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
 791
 792/**
 793 * do_efi_show_memmap() - show UEFI memory map
 794 *
 795 * @cmdtp:      Command table
 796 * @flag:       Command flag
 797 * @argc:       Number of arguments
 798 * @argv:       Argument array
 799 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 800 *
 801 * Implement efidebug "memmap" sub-command.
 802 * Show UEFI memory map.
 803 */
 804static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag,
 805                              int argc, char *const argv[])
 806{
 807        struct efi_mem_desc *memmap = NULL, *map;
 808        efi_uintn_t map_size = 0;
 809        const char *type;
 810        int i;
 811        efi_status_t ret;
 812
 813        ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
 814        if (ret == EFI_BUFFER_TOO_SMALL) {
 815                map_size += sizeof(struct efi_mem_desc); /* for my own */
 816                ret = efi_allocate_pool(EFI_LOADER_DATA, map_size,
 817                                        (void *)&memmap);
 818                if (ret != EFI_SUCCESS)
 819                        return CMD_RET_FAILURE;
 820                ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
 821        }
 822        if (ret != EFI_SUCCESS) {
 823                efi_free_pool(memmap);
 824                return CMD_RET_FAILURE;
 825        }
 826
 827        printf("Type             Start%.*s End%.*s Attributes\n",
 828               EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
 829        printf("================ %.*s %.*s ==========\n",
 830               EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
 831        /*
 832         * Coverity check: dereferencing null pointer "map."
 833         * This is a false positive as memmap will always be
 834         * populated by allocate_pool() above.
 835         */
 836        for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
 837                if (map->type < ARRAY_SIZE(efi_mem_type_string))
 838                        type = efi_mem_type_string[map->type];
 839                else
 840                        type = "(unknown)";
 841
 842                printf("%-16s %.*llx-%.*llx", type,
 843                       EFI_PHYS_ADDR_WIDTH,
 844                       (u64)map_to_sysmem((void *)(uintptr_t)
 845                                          map->physical_start),
 846                       EFI_PHYS_ADDR_WIDTH,
 847                       (u64)map_to_sysmem((void *)(uintptr_t)
 848                                          (map->physical_start +
 849                                           map->num_pages * EFI_PAGE_SIZE)));
 850
 851                print_memory_attributes(map->attribute);
 852                putc('\n');
 853        }
 854
 855        efi_free_pool(memmap);
 856
 857        return CMD_RET_SUCCESS;
 858}
 859
 860/**
 861 * do_efi_show_tables() - show UEFI configuration tables
 862 *
 863 * @cmdtp:      Command table
 864 * @flag:       Command flag
 865 * @argc:       Number of arguments
 866 * @argv:       Argument array
 867 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
 868 *
 869 * Implement efidebug "tables" sub-command.
 870 * Show UEFI configuration tables.
 871 */
 872static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
 873                              int argc, char *const argv[])
 874{
 875        efi_uintn_t i;
 876        const char *guid_str;
 877
 878        for (i = 0; i < systab.nr_tables; ++i) {
 879                guid_str = get_guid_text(&systab.tables[i].guid);
 880                if (!guid_str)
 881                        guid_str = "";
 882                printf("%pUl %s\n", &systab.tables[i].guid, guid_str);
 883        }
 884
 885        return CMD_RET_SUCCESS;
 886}
 887
 888/**
 889 * create_initrd_dp() - Create a special device for our Boot### option
 890 *
 891 * @dev:        Device
 892 * @part:       Disk partition
 893 * @file:       Filename
 894 * Return:      Pointer to the device path or ERR_PTR
 895 *
 896 */
 897static
 898struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
 899                                         const char *file)
 900
 901{
 902        struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL;
 903        struct efi_device_path *initrd_dp = NULL;
 904        efi_status_t ret;
 905        const struct efi_initrd_dp id_dp = {
 906                .vendor = {
 907                        {
 908                        DEVICE_PATH_TYPE_MEDIA_DEVICE,
 909                        DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
 910                        sizeof(id_dp.vendor),
 911                        },
 912                        EFI_INITRD_MEDIA_GUID,
 913                },
 914                .end = {
 915                        DEVICE_PATH_TYPE_END,
 916                        DEVICE_PATH_SUB_TYPE_END,
 917                        sizeof(id_dp.end),
 918                }
 919        };
 920
 921        ret = efi_dp_from_name(dev, part, file, &tmp_dp, &tmp_fp);
 922        if (ret != EFI_SUCCESS) {
 923                printf("Cannot create device path for \"%s %s\"\n", part, file);
 924                goto out;
 925        }
 926
 927        initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp,
 928                                  tmp_fp);
 929
 930out:
 931        efi_free_pool(tmp_dp);
 932        efi_free_pool(tmp_fp);
 933        return initrd_dp;
 934}
 935
 936/**
 937 * do_efi_boot_add() - set UEFI load option
 938 *
 939 * @cmdtp:      Command table
 940 * @flag:       Command flag
 941 * @argc:       Number of arguments
 942 * @argv:       Argument array
 943 * Return:      CMD_RET_SUCCESS on success,
 944 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
 945 *
 946 * Implement efidebug "boot add" sub-command. Create or change UEFI load option.
 947 *
 948 * efidebug boot add -b <id> <label> <interface> <devnum>[:<part>] <file>
 949 *                   -i <file> <interface2> <devnum2>[:<part>] <initrd>
 950 *                   -s '<options>'
 951 */
 952static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
 953                           int argc, char *const argv[])
 954{
 955        int id;
 956        char *endp;
 957        u16 var_name16[9];
 958        efi_guid_t guid;
 959        size_t label_len, label_len16;
 960        u16 *label;
 961        struct efi_device_path *device_path = NULL, *file_path = NULL;
 962        struct efi_device_path *final_fp = NULL;
 963        struct efi_device_path *initrd_dp = NULL;
 964        struct efi_load_option lo;
 965        void *data = NULL;
 966        efi_uintn_t size;
 967        efi_uintn_t fp_size = 0;
 968        efi_status_t ret;
 969        int r = CMD_RET_SUCCESS;
 970
 971        guid = efi_global_variable_guid;
 972
 973        /* attributes */
 974        lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
 975        lo.optional_data = NULL;
 976        lo.label = NULL;
 977
 978        argc--;
 979        argv++; /* 'add' */
 980        for (; argc > 0; argc--, argv++) {
 981                if (!strcmp(argv[0], "-b")) {
 982                        if (argc <  5 || lo.label) {
 983                                r = CMD_RET_USAGE;
 984                                goto out;
 985                        }
 986                        id = (int)hextoul(argv[1], &endp);
 987                        if (*endp != '\0' || id > 0xffff)
 988                                return CMD_RET_USAGE;
 989
 990                        efi_create_indexed_name(var_name16, sizeof(var_name16),
 991                                                "Boot", id);
 992
 993                        /* label */
 994                        label_len = strlen(argv[2]);
 995                        label_len16 = utf8_utf16_strnlen(argv[2], label_len);
 996                        label = malloc((label_len16 + 1) * sizeof(u16));
 997                        if (!label)
 998                                return CMD_RET_FAILURE;
 999                        lo.label = label; /* label will be changed below */
1000                        utf8_utf16_strncpy(&label, argv[2], label_len);
1001
1002                        /* file path */
1003                        ret = efi_dp_from_name(argv[3], argv[4], argv[5],
1004                                               &device_path, &file_path);
1005                        if (ret != EFI_SUCCESS) {
1006                                printf("Cannot create device path for \"%s %s\"\n",
1007                                       argv[3], argv[4]);
1008                                r = CMD_RET_FAILURE;
1009                                goto out;
1010                        }
1011                        fp_size += efi_dp_size(file_path) +
1012                                sizeof(struct efi_device_path);
1013                        argc -= 5;
1014                        argv += 5;
1015                } else if (!strcmp(argv[0], "-i")) {
1016                        if (argc < 3 || initrd_dp) {
1017                                r = CMD_RET_USAGE;
1018                                goto out;
1019                        }
1020
1021                        initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3]);
1022                        if (!initrd_dp) {
1023                                printf("Cannot add an initrd\n");
1024                                r = CMD_RET_FAILURE;
1025                                goto out;
1026                        }
1027                        argc -= 3;
1028                        argv += 3;
1029                        fp_size += efi_dp_size(initrd_dp) +
1030                                sizeof(struct efi_device_path);
1031                } else if (!strcmp(argv[0], "-s")) {
1032                        if (argc < 1 || lo.optional_data) {
1033                                r = CMD_RET_USAGE;
1034                                goto out;
1035                        }
1036                        lo.optional_data = (const u8 *)argv[1];
1037                        argc -= 1;
1038                        argv += 1;
1039                } else {
1040                        r = CMD_RET_USAGE;
1041                        goto out;
1042                }
1043        }
1044
1045        if (!file_path) {
1046                printf("Missing binary\n");
1047                r = CMD_RET_USAGE;
1048                goto out;
1049        }
1050
1051        final_fp = efi_dp_concat(file_path, initrd_dp);
1052        if (!final_fp) {
1053                printf("Cannot create final device path\n");
1054                r = CMD_RET_FAILURE;
1055                goto out;
1056        }
1057
1058        lo.file_path = final_fp;
1059        lo.file_path_length = fp_size;
1060
1061        size = efi_serialize_load_option(&lo, (u8 **)&data);
1062        if (!size) {
1063                r = CMD_RET_FAILURE;
1064                goto out;
1065        }
1066
1067        ret = efi_set_variable_int(var_name16, &guid,
1068                                   EFI_VARIABLE_NON_VOLATILE |
1069                                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
1070                                   EFI_VARIABLE_RUNTIME_ACCESS,
1071                                   size, data, false);
1072        if (ret != EFI_SUCCESS) {
1073                printf("Cannot set %ls\n", var_name16);
1074                r = CMD_RET_FAILURE;
1075        }
1076
1077out:
1078        free(data);
1079        efi_free_pool(final_fp);
1080        efi_free_pool(initrd_dp);
1081        efi_free_pool(device_path);
1082        efi_free_pool(file_path);
1083        free(lo.label);
1084
1085        return r;
1086}
1087
1088/**
1089 * do_efi_boot_rm() - delete UEFI load options
1090 *
1091 * @cmdtp:      Command table
1092 * @flag:       Command flag
1093 * @argc:       Number of arguments
1094 * @argv:       Argument array
1095 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1096 *
1097 * Implement efidebug "boot rm" sub-command.
1098 * Delete UEFI load options.
1099 *
1100 *     efidebug boot rm <id> ...
1101 */
1102static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag,
1103                          int argc, char *const argv[])
1104{
1105        efi_guid_t guid;
1106        int id, i;
1107        char *endp;
1108        u16 var_name16[9];
1109        efi_status_t ret;
1110
1111        if (argc == 1)
1112                return CMD_RET_USAGE;
1113
1114        guid = efi_global_variable_guid;
1115        for (i = 1; i < argc; i++, argv++) {
1116                id = (int)hextoul(argv[1], &endp);
1117                if (*endp != '\0' || id > 0xffff)
1118                        return CMD_RET_FAILURE;
1119
1120                efi_create_indexed_name(var_name16, sizeof(var_name16),
1121                                        "Boot", id);
1122                ret = efi_set_variable_int(var_name16, &guid, 0, 0, NULL,
1123                                           false);
1124                if (ret) {
1125                        printf("Cannot remove %ls\n", var_name16);
1126                        return CMD_RET_FAILURE;
1127                }
1128        }
1129
1130        return CMD_RET_SUCCESS;
1131}
1132
1133/**
1134 * show_efi_boot_opt_data() - dump UEFI load option
1135 *
1136 * @varname16:  variable name
1137 * @data:       value of UEFI load option variable
1138 * @size:       size of the boot option
1139 *
1140 * Decode the value of UEFI load option variable and print information.
1141 */
1142static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size)
1143{
1144        struct efi_device_path *initrd_path = NULL;
1145        struct efi_load_option lo;
1146        u16 *dp_str;
1147        efi_status_t ret;
1148        efi_uintn_t initrd_dp_size;
1149        const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
1150
1151        ret = efi_deserialize_load_option(&lo, data, size);
1152        if (ret != EFI_SUCCESS) {
1153                printf("%ls: invalid load option\n", varname16);
1154                return;
1155        }
1156
1157        printf("%ls:\nattributes: %c%c%c (0x%08x)\n",
1158               varname16,
1159               /* ACTIVE */
1160               lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
1161               /* FORCE RECONNECT */
1162               lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
1163               /* HIDDEN */
1164               lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
1165               lo.attributes);
1166        printf("  label: %ls\n", lo.label);
1167
1168        dp_str = efi_dp_str(lo.file_path);
1169        printf("  file_path: %ls\n", dp_str);
1170        efi_free_pool(dp_str);
1171
1172        initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, lf2_initrd_guid);
1173        if (initrd_path) {
1174                dp_str = efi_dp_str(initrd_path);
1175                printf("  initrd_path: %ls\n", dp_str);
1176                efi_free_pool(dp_str);
1177                efi_free_pool(initrd_path);
1178        }
1179
1180        printf("  data:\n");
1181        print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
1182                       lo.optional_data, *size, true);
1183}
1184
1185/**
1186 * show_efi_boot_opt() - dump UEFI load option
1187 *
1188 * @varname16:  variable name
1189 *
1190 * Dump information defined by UEFI load option.
1191 */
1192static void show_efi_boot_opt(u16 *varname16)
1193{
1194        void *data;
1195        efi_uintn_t size;
1196        efi_status_t ret;
1197
1198        size = 0;
1199        ret = EFI_CALL(efi_get_variable(varname16, &efi_global_variable_guid,
1200                                        NULL, &size, NULL));
1201        if (ret == EFI_BUFFER_TOO_SMALL) {
1202                data = malloc(size);
1203                if (!data) {
1204                        printf("ERROR: Out of memory\n");
1205                        return;
1206                }
1207                ret = EFI_CALL(efi_get_variable(varname16,
1208                                                &efi_global_variable_guid,
1209                                                NULL, &size, data));
1210                if (ret == EFI_SUCCESS)
1211                        show_efi_boot_opt_data(varname16, data, &size);
1212                free(data);
1213        }
1214}
1215
1216static int u16_tohex(u16 c)
1217{
1218        if (c >= '0' && c <= '9')
1219                return c - '0';
1220        if (c >= 'A' && c <= 'F')
1221                return c - 'A' + 10;
1222
1223        /* not hexadecimal */
1224        return -1;
1225}
1226
1227/**
1228 * show_efi_boot_dump() - dump all UEFI load options
1229 *
1230 * @cmdtp:      Command table
1231 * @flag:       Command flag
1232 * @argc:       Number of arguments
1233 * @argv:       Argument array
1234 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1235 *
1236 * Implement efidebug "boot dump" sub-command.
1237 * Dump information of all UEFI load options defined.
1238 *
1239 *     efidebug boot dump
1240 */
1241static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag,
1242                            int argc, char *const argv[])
1243{
1244        u16 *var_name16, *p;
1245        efi_uintn_t buf_size, size;
1246        efi_guid_t guid;
1247        int id, i, digit;
1248        efi_status_t ret;
1249
1250        if (argc > 1)
1251                return CMD_RET_USAGE;
1252
1253        buf_size = 128;
1254        var_name16 = malloc(buf_size);
1255        if (!var_name16)
1256                return CMD_RET_FAILURE;
1257
1258        var_name16[0] = 0;
1259        for (;;) {
1260                size = buf_size;
1261                ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
1262                                                          &guid));
1263                if (ret == EFI_NOT_FOUND)
1264                        break;
1265                if (ret == EFI_BUFFER_TOO_SMALL) {
1266                        buf_size = size;
1267                        p = realloc(var_name16, buf_size);
1268                        if (!p) {
1269                                free(var_name16);
1270                                return CMD_RET_FAILURE;
1271                        }
1272                        var_name16 = p;
1273                        ret = EFI_CALL(efi_get_next_variable_name(&size,
1274                                                                  var_name16,
1275                                                                  &guid));
1276                }
1277                if (ret != EFI_SUCCESS) {
1278                        free(var_name16);
1279                        return CMD_RET_FAILURE;
1280                }
1281
1282                if (memcmp(var_name16, L"Boot", 8))
1283                        continue;
1284
1285                for (id = 0, i = 0; i < 4; i++) {
1286                        digit = u16_tohex(var_name16[4 + i]);
1287                        if (digit < 0)
1288                                break;
1289                        id = (id << 4) + digit;
1290                }
1291                if (i == 4 && !var_name16[8])
1292                        show_efi_boot_opt(var_name16);
1293        }
1294
1295        free(var_name16);
1296
1297        return CMD_RET_SUCCESS;
1298}
1299
1300/**
1301 * show_efi_boot_order() - show order of UEFI load options
1302 *
1303 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1304 *
1305 * Show order of UEFI load options defined by BootOrder variable.
1306 */
1307static int show_efi_boot_order(void)
1308{
1309        u16 *bootorder;
1310        efi_uintn_t size;
1311        int num, i;
1312        u16 var_name16[9];
1313        void *data;
1314        struct efi_load_option lo;
1315        efi_status_t ret;
1316
1317        size = 0;
1318        ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1319                                        NULL, &size, NULL));
1320        if (ret != EFI_BUFFER_TOO_SMALL) {
1321                if (ret == EFI_NOT_FOUND) {
1322                        printf("BootOrder not defined\n");
1323                        return CMD_RET_SUCCESS;
1324                } else {
1325                        return CMD_RET_FAILURE;
1326                }
1327        }
1328        bootorder = malloc(size);
1329        if (!bootorder) {
1330                printf("ERROR: Out of memory\n");
1331                return CMD_RET_FAILURE;
1332        }
1333        ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1334                                        NULL, &size, bootorder));
1335        if (ret != EFI_SUCCESS) {
1336                ret = CMD_RET_FAILURE;
1337                goto out;
1338        }
1339
1340        num = size / sizeof(u16);
1341        for (i = 0; i < num; i++) {
1342                efi_create_indexed_name(var_name16, sizeof(var_name16),
1343                                        "Boot", bootorder[i]);
1344
1345                size = 0;
1346                ret = EFI_CALL(efi_get_variable(var_name16,
1347                                                &efi_global_variable_guid, NULL,
1348                                                &size, NULL));
1349                if (ret != EFI_BUFFER_TOO_SMALL) {
1350                        printf("%2d: %ls: (not defined)\n", i + 1, var_name16);
1351                        continue;
1352                }
1353
1354                data = malloc(size);
1355                if (!data) {
1356                        ret = CMD_RET_FAILURE;
1357                        goto out;
1358                }
1359                ret = EFI_CALL(efi_get_variable(var_name16,
1360                                                &efi_global_variable_guid, NULL,
1361                                                &size, data));
1362                if (ret != EFI_SUCCESS) {
1363                        free(data);
1364                        ret = CMD_RET_FAILURE;
1365                        goto out;
1366                }
1367
1368                ret = efi_deserialize_load_option(&lo, data, &size);
1369                if (ret != EFI_SUCCESS) {
1370                        printf("%ls: invalid load option\n", var_name16);
1371                        ret = CMD_RET_FAILURE;
1372                        goto out;
1373                }
1374
1375                printf("%2d: %ls: %ls\n", i + 1, var_name16, lo.label);
1376
1377                free(data);
1378        }
1379out:
1380        free(bootorder);
1381
1382        return ret;
1383}
1384
1385/**
1386 * do_efi_boot_next() - manage UEFI BootNext variable
1387 *
1388 * @cmdtp:      Command table
1389 * @flag:       Command flag
1390 * @argc:       Number of arguments
1391 * @argv:       Argument array
1392 * Return:      CMD_RET_SUCCESS on success,
1393 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1394 *
1395 * Implement efidebug "boot next" sub-command.
1396 * Set BootNext variable.
1397 *
1398 *     efidebug boot next <id>
1399 */
1400static int do_efi_boot_next(struct cmd_tbl *cmdtp, int flag,
1401                            int argc, char *const argv[])
1402{
1403        u16 bootnext;
1404        efi_uintn_t size;
1405        char *endp;
1406        efi_guid_t guid;
1407        efi_status_t ret;
1408        int r = CMD_RET_SUCCESS;
1409
1410        if (argc != 2)
1411                return CMD_RET_USAGE;
1412
1413        bootnext = (u16)hextoul(argv[1], &endp);
1414        if (*endp) {
1415                printf("invalid value: %s\n", argv[1]);
1416                r = CMD_RET_FAILURE;
1417                goto out;
1418        }
1419
1420        guid = efi_global_variable_guid;
1421        size = sizeof(u16);
1422        ret = efi_set_variable_int(L"BootNext", &guid,
1423                                        EFI_VARIABLE_NON_VOLATILE |
1424                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
1425                                        EFI_VARIABLE_RUNTIME_ACCESS,
1426                                        size, &bootnext, false);
1427        if (ret != EFI_SUCCESS) {
1428                printf("Cannot set BootNext\n");
1429                r = CMD_RET_FAILURE;
1430        }
1431out:
1432        return r;
1433}
1434
1435/**
1436 * do_efi_boot_order() - manage UEFI BootOrder variable
1437 *
1438 * @cmdtp:      Command table
1439 * @flag:       Command flag
1440 * @argc:       Number of arguments
1441 * @argv:       Argument array
1442 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1443 *
1444 * Implement efidebug "boot order" sub-command.
1445 * Show order of UEFI load options, or change it in BootOrder variable.
1446 *
1447 *     efidebug boot order [<id> ...]
1448 */
1449static int do_efi_boot_order(struct cmd_tbl *cmdtp, int flag,
1450                             int argc, char *const argv[])
1451{
1452        u16 *bootorder = NULL;
1453        efi_uintn_t size;
1454        int id, i;
1455        char *endp;
1456        efi_guid_t guid;
1457        efi_status_t ret;
1458        int r = CMD_RET_SUCCESS;
1459
1460        if (argc == 1)
1461                return show_efi_boot_order();
1462
1463        argc--;
1464        argv++;
1465
1466        size = argc * sizeof(u16);
1467        bootorder = malloc(size);
1468        if (!bootorder)
1469                return CMD_RET_FAILURE;
1470
1471        for (i = 0; i < argc; i++) {
1472                id = (int)hextoul(argv[i], &endp);
1473                if (*endp != '\0' || id > 0xffff) {
1474                        printf("invalid value: %s\n", argv[i]);
1475                        r = CMD_RET_FAILURE;
1476                        goto out;
1477                }
1478
1479                bootorder[i] = (u16)id;
1480        }
1481
1482        guid = efi_global_variable_guid;
1483        ret = efi_set_variable_int(L"BootOrder", &guid,
1484                                        EFI_VARIABLE_NON_VOLATILE |
1485                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
1486                                        EFI_VARIABLE_RUNTIME_ACCESS,
1487                                        size, bootorder, true);
1488        if (ret != EFI_SUCCESS) {
1489                printf("Cannot set BootOrder\n");
1490                r = CMD_RET_FAILURE;
1491        }
1492out:
1493        free(bootorder);
1494
1495        return r;
1496}
1497
1498static struct cmd_tbl cmd_efidebug_boot_sub[] = {
1499        U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
1500        U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
1501        U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
1502        U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
1503        U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
1504                         "", ""),
1505};
1506
1507/**
1508 * do_efi_boot_opt() - manage UEFI load options
1509 *
1510 * @cmdtp:      Command table
1511 * @flag:       Command flag
1512 * @argc:       Number of arguments
1513 * @argv:       Argument array
1514 * Return:      CMD_RET_SUCCESS on success,
1515 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1516 *
1517 * Implement efidebug "boot" sub-command.
1518 */
1519static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag,
1520                           int argc, char *const argv[])
1521{
1522        struct cmd_tbl *cp;
1523
1524        if (argc < 2)
1525                return CMD_RET_USAGE;
1526
1527        argc--; argv++;
1528
1529        cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
1530                          ARRAY_SIZE(cmd_efidebug_boot_sub));
1531        if (!cp)
1532                return CMD_RET_USAGE;
1533
1534        return cp->cmd(cmdtp, flag, argc, argv);
1535}
1536
1537/**
1538 * do_efi_test_bootmgr() - run simple bootmgr for test
1539 *
1540 * @cmdtp:      Command table
1541 * @flag:       Command flag
1542 * @argc:       Number of arguments
1543 * @argv:       Argument array
1544 * Return:      CMD_RET_SUCCESS on success,
1545 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1546 *
1547 * Implement efidebug "test bootmgr" sub-command.
1548 * Run simple bootmgr for test.
1549 *
1550 *     efidebug test bootmgr
1551 */
1552static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
1553                                              int argc, char * const argv[])
1554{
1555        efi_handle_t image;
1556        efi_uintn_t exit_data_size = 0;
1557        u16 *exit_data = NULL;
1558        efi_status_t ret;
1559        void *load_options = NULL;
1560
1561        ret = efi_bootmgr_load(&image, &load_options);
1562        printf("efi_bootmgr_load() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1563
1564        /* We call efi_start_image() even if error for test purpose. */
1565        ret = EFI_CALL(efi_start_image(image, &exit_data_size, &exit_data));
1566        printf("efi_start_image() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1567        if (ret && exit_data)
1568                efi_free_pool(exit_data);
1569
1570        efi_restore_gd();
1571
1572        free(load_options);
1573        return CMD_RET_SUCCESS;
1574}
1575
1576static struct cmd_tbl cmd_efidebug_test_sub[] = {
1577#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1578        U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr,
1579                         "", ""),
1580#endif
1581};
1582
1583/**
1584 * do_efi_test() - manage UEFI load options
1585 *
1586 * @cmdtp:      Command table
1587 * @flag:       Command flag
1588 * @argc:       Number of arguments
1589 * @argv:       Argument array
1590 * Return:      CMD_RET_SUCCESS on success,
1591 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1592 *
1593 * Implement efidebug "test" sub-command.
1594 */
1595static int do_efi_test(struct cmd_tbl *cmdtp, int flag,
1596                       int argc, char * const argv[])
1597{
1598        struct cmd_tbl *cp;
1599
1600        if (argc < 2)
1601                return CMD_RET_USAGE;
1602
1603        argc--; argv++;
1604
1605        cp = find_cmd_tbl(argv[0], cmd_efidebug_test_sub,
1606                          ARRAY_SIZE(cmd_efidebug_test_sub));
1607        if (!cp)
1608                return CMD_RET_USAGE;
1609
1610        return cp->cmd(cmdtp, flag, argc, argv);
1611}
1612
1613/**
1614 * do_efi_query_info() - QueryVariableInfo EFI service
1615 *
1616 * @cmdtp:      Command table
1617 * @flag:       Command flag
1618 * @argc:       Number of arguments
1619 * @argv:       Argument array
1620 * Return:      CMD_RET_SUCCESS on success,
1621 *              CMD_RET_USAGE or CMD_RET_FAILURE on failure
1622 *
1623 * Implement efidebug "test" sub-command.
1624 */
1625
1626static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag,
1627                             int argc, char * const argv[])
1628{
1629        efi_status_t ret;
1630        u32 attr = 0;
1631        u64 max_variable_storage_size;
1632        u64 remain_variable_storage_size;
1633        u64 max_variable_size;
1634        int i;
1635
1636        for (i = 1; i < argc; i++) {
1637                if (!strcmp(argv[i], "-bs"))
1638                        attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
1639                else if (!strcmp(argv[i], "-rt"))
1640                        attr |= EFI_VARIABLE_RUNTIME_ACCESS;
1641                else if (!strcmp(argv[i], "-nv"))
1642                        attr |= EFI_VARIABLE_NON_VOLATILE;
1643                else if (!strcmp(argv[i], "-at"))
1644                        attr |=
1645                                EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1646        }
1647
1648        ret = EFI_CALL(efi_query_variable_info(attr,
1649                                               &max_variable_storage_size,
1650                                               &remain_variable_storage_size,
1651                                               &max_variable_size));
1652        if (ret != EFI_SUCCESS) {
1653                printf("Error: Cannot query UEFI variables, r = %lu\n",
1654                       ret & ~EFI_ERROR_MASK);
1655                return CMD_RET_FAILURE;
1656        }
1657
1658        printf("Max storage size %llu\n", max_variable_storage_size);
1659        printf("Remaining storage size %llu\n", remain_variable_storage_size);
1660        printf("Max variable size %llu\n", max_variable_size);
1661
1662        return CMD_RET_SUCCESS;
1663}
1664
1665static struct cmd_tbl cmd_efidebug_sub[] = {
1666        U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
1667#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1668        U_BOOT_CMD_MKENT(capsule, CONFIG_SYS_MAXARGS, 1, do_efi_capsule,
1669                         "", ""),
1670#endif
1671        U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
1672                         "", ""),
1673        U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
1674                         "", ""),
1675        U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
1676                         "", ""),
1677        U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
1678                         "", ""),
1679        U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
1680                         "", ""),
1681        U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables,
1682                         "", ""),
1683        U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_efi_test,
1684                         "", ""),
1685        U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info,
1686                         "", ""),
1687};
1688
1689/**
1690 * do_efidebug() - display and configure UEFI environment
1691 *
1692 * @cmdtp:      Command table
1693 * @flag:       Command flag
1694 * @argc:       Number of arguments
1695 * @argv:       Argument array
1696 * Return:      CMD_RET_SUCCESS on success,
1697 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1698 *
1699 * Implement efidebug command which allows us to display and
1700 * configure UEFI environment.
1701 */
1702static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
1703                       int argc, char *const argv[])
1704{
1705        struct cmd_tbl *cp;
1706        efi_status_t r;
1707
1708        if (argc < 2)
1709                return CMD_RET_USAGE;
1710
1711        argc--; argv++;
1712
1713        /* Initialize UEFI drivers */
1714        r = efi_init_obj_list();
1715        if (r != EFI_SUCCESS) {
1716                printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1717                       r & ~EFI_ERROR_MASK);
1718                return CMD_RET_FAILURE;
1719        }
1720
1721        cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1722                          ARRAY_SIZE(cmd_efidebug_sub));
1723        if (!cp)
1724                return CMD_RET_USAGE;
1725
1726        return cp->cmd(cmdtp, flag, argc, argv);
1727}
1728
1729#ifdef CONFIG_SYS_LONGHELP
1730static char efidebug_help_text[] =
1731        "  - UEFI Shell-like interface to configure UEFI environment\n"
1732        "\n"
1733        "efidebug boot add "
1734        "-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
1735        "-i <interface> <devnum>[:<part>] <initrd file path> "
1736        "-s '<optional data>'\n"
1737        "  - set UEFI BootXXXX variable\n"
1738        "    <load options> will be passed to UEFI application\n"
1739        "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1740        "  - delete UEFI BootXXXX variables\n"
1741        "efidebug boot dump\n"
1742        "  - dump all UEFI BootXXXX variables\n"
1743        "efidebug boot next <bootid>\n"
1744        "  - set UEFI BootNext variable\n"
1745        "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1746        "  - set/show UEFI boot order\n"
1747        "\n"
1748#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1749        "efidebug capsule update [-v] <capsule address>\n"
1750        "  - process a capsule\n"
1751        "efidebug capsule disk-update\n"
1752        "  - update a capsule from disk\n"
1753        "efidebug capsule show <capsule address>\n"
1754        "  - show capsule information\n"
1755        "efidebug capsule result [<capsule result var>]\n"
1756        "  - show a capsule update result\n"
1757#ifdef CONFIG_EFI_ESRT
1758        "efidebug capsule esrt\n"
1759        "  - print the ESRT\n"
1760#endif
1761        "\n"
1762#endif
1763        "efidebug devices\n"
1764        "  - show UEFI devices\n"
1765        "efidebug drivers\n"
1766        "  - show UEFI drivers\n"
1767        "efidebug dh\n"
1768        "  - show UEFI handles\n"
1769        "efidebug images\n"
1770        "  - show loaded images\n"
1771        "efidebug memmap\n"
1772        "  - show UEFI memory map\n"
1773        "efidebug tables\n"
1774        "  - show UEFI configuration tables\n"
1775#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1776        "efidebug test bootmgr\n"
1777        "  - run simple bootmgr for test\n"
1778#endif
1779        "efidebug query [-nv][-bs][-rt][-at]\n"
1780        "  - show size of UEFI variables store\n";
1781#endif
1782
1783U_BOOT_CMD(
1784        efidebug, CONFIG_SYS_MAXARGS, 0, do_efidebug,
1785        "Configure UEFI environment",
1786        efidebug_help_text
1787);
1788