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        efi_status_t ret;
1147
1148        ret = efi_deserialize_load_option(&lo, data, size);
1149        if (ret != EFI_SUCCESS) {
1150                printf("%ls: invalid load option\n", varname16);
1151                return;
1152        }
1153
1154        printf("%ls:\nattributes: %c%c%c (0x%08x)\n",
1155               varname16,
1156               /* ACTIVE */
1157               lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
1158               /* FORCE RECONNECT */
1159               lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
1160               /* HIDDEN */
1161               lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
1162               lo.attributes);
1163        printf("  label: %ls\n", lo.label);
1164
1165        printf("  file_path: %pD\n", lo.file_path);
1166
1167        initrd_path = efi_dp_from_lo(&lo, &efi_lf2_initrd_guid);
1168        if (initrd_path) {
1169                printf("  initrd_path: %pD\n", initrd_path);
1170                efi_free_pool(initrd_path);
1171        }
1172
1173        printf("  data:\n");
1174        print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
1175                       lo.optional_data, *size, true);
1176}
1177
1178/**
1179 * show_efi_boot_opt() - dump UEFI load option
1180 *
1181 * @varname16:  variable name
1182 *
1183 * Dump information defined by UEFI load option.
1184 */
1185static void show_efi_boot_opt(u16 *varname16)
1186{
1187        void *data;
1188        efi_uintn_t size;
1189        efi_status_t ret;
1190
1191        size = 0;
1192        ret = EFI_CALL(efi_get_variable(varname16, &efi_global_variable_guid,
1193                                        NULL, &size, NULL));
1194        if (ret == EFI_BUFFER_TOO_SMALL) {
1195                data = malloc(size);
1196                if (!data) {
1197                        printf("ERROR: Out of memory\n");
1198                        return;
1199                }
1200                ret = EFI_CALL(efi_get_variable(varname16,
1201                                                &efi_global_variable_guid,
1202                                                NULL, &size, data));
1203                if (ret == EFI_SUCCESS)
1204                        show_efi_boot_opt_data(varname16, data, &size);
1205                free(data);
1206        }
1207}
1208
1209static int u16_tohex(u16 c)
1210{
1211        if (c >= '0' && c <= '9')
1212                return c - '0';
1213        if (c >= 'A' && c <= 'F')
1214                return c - 'A' + 10;
1215
1216        /* not hexadecimal */
1217        return -1;
1218}
1219
1220/**
1221 * show_efi_boot_dump() - dump all UEFI load options
1222 *
1223 * @cmdtp:      Command table
1224 * @flag:       Command flag
1225 * @argc:       Number of arguments
1226 * @argv:       Argument array
1227 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1228 *
1229 * Implement efidebug "boot dump" sub-command.
1230 * Dump information of all UEFI load options defined.
1231 *
1232 *     efidebug boot dump
1233 */
1234static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag,
1235                            int argc, char *const argv[])
1236{
1237        u16 *var_name16, *p;
1238        efi_uintn_t buf_size, size;
1239        efi_guid_t guid;
1240        int id, i, digit;
1241        efi_status_t ret;
1242
1243        if (argc > 1)
1244                return CMD_RET_USAGE;
1245
1246        buf_size = 128;
1247        var_name16 = malloc(buf_size);
1248        if (!var_name16)
1249                return CMD_RET_FAILURE;
1250
1251        var_name16[0] = 0;
1252        for (;;) {
1253                size = buf_size;
1254                ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
1255                                                          &guid));
1256                if (ret == EFI_NOT_FOUND)
1257                        break;
1258                if (ret == EFI_BUFFER_TOO_SMALL) {
1259                        buf_size = size;
1260                        p = realloc(var_name16, buf_size);
1261                        if (!p) {
1262                                free(var_name16);
1263                                return CMD_RET_FAILURE;
1264                        }
1265                        var_name16 = p;
1266                        ret = EFI_CALL(efi_get_next_variable_name(&size,
1267                                                                  var_name16,
1268                                                                  &guid));
1269                }
1270                if (ret != EFI_SUCCESS) {
1271                        free(var_name16);
1272                        return CMD_RET_FAILURE;
1273                }
1274
1275                if (memcmp(var_name16, L"Boot", 8))
1276                        continue;
1277
1278                for (id = 0, i = 0; i < 4; i++) {
1279                        digit = u16_tohex(var_name16[4 + i]);
1280                        if (digit < 0)
1281                                break;
1282                        id = (id << 4) + digit;
1283                }
1284                if (i == 4 && !var_name16[8])
1285                        show_efi_boot_opt(var_name16);
1286        }
1287
1288        free(var_name16);
1289
1290        return CMD_RET_SUCCESS;
1291}
1292
1293/**
1294 * show_efi_boot_order() - show order of UEFI load options
1295 *
1296 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1297 *
1298 * Show order of UEFI load options defined by BootOrder variable.
1299 */
1300static int show_efi_boot_order(void)
1301{
1302        u16 *bootorder;
1303        efi_uintn_t size;
1304        int num, i;
1305        u16 var_name16[9];
1306        void *data;
1307        struct efi_load_option lo;
1308        efi_status_t ret;
1309
1310        size = 0;
1311        ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1312                                        NULL, &size, NULL));
1313        if (ret != EFI_BUFFER_TOO_SMALL) {
1314                if (ret == EFI_NOT_FOUND) {
1315                        printf("BootOrder not defined\n");
1316                        return CMD_RET_SUCCESS;
1317                } else {
1318                        return CMD_RET_FAILURE;
1319                }
1320        }
1321        bootorder = malloc(size);
1322        if (!bootorder) {
1323                printf("ERROR: Out of memory\n");
1324                return CMD_RET_FAILURE;
1325        }
1326        ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1327                                        NULL, &size, bootorder));
1328        if (ret != EFI_SUCCESS) {
1329                ret = CMD_RET_FAILURE;
1330                goto out;
1331        }
1332
1333        num = size / sizeof(u16);
1334        for (i = 0; i < num; i++) {
1335                efi_create_indexed_name(var_name16, sizeof(var_name16),
1336                                        "Boot", bootorder[i]);
1337
1338                size = 0;
1339                ret = EFI_CALL(efi_get_variable(var_name16,
1340                                                &efi_global_variable_guid, NULL,
1341                                                &size, NULL));
1342                if (ret != EFI_BUFFER_TOO_SMALL) {
1343                        printf("%2d: %ls: (not defined)\n", i + 1, var_name16);
1344                        continue;
1345                }
1346
1347                data = malloc(size);
1348                if (!data) {
1349                        ret = CMD_RET_FAILURE;
1350                        goto out;
1351                }
1352                ret = EFI_CALL(efi_get_variable(var_name16,
1353                                                &efi_global_variable_guid, NULL,
1354                                                &size, data));
1355                if (ret != EFI_SUCCESS) {
1356                        free(data);
1357                        ret = CMD_RET_FAILURE;
1358                        goto out;
1359                }
1360
1361                ret = efi_deserialize_load_option(&lo, data, &size);
1362                if (ret != EFI_SUCCESS) {
1363                        printf("%ls: invalid load option\n", var_name16);
1364                        ret = CMD_RET_FAILURE;
1365                        goto out;
1366                }
1367
1368                printf("%2d: %ls: %ls\n", i + 1, var_name16, lo.label);
1369
1370                free(data);
1371        }
1372out:
1373        free(bootorder);
1374
1375        return ret;
1376}
1377
1378/**
1379 * do_efi_boot_next() - manage UEFI BootNext variable
1380 *
1381 * @cmdtp:      Command table
1382 * @flag:       Command flag
1383 * @argc:       Number of arguments
1384 * @argv:       Argument array
1385 * Return:      CMD_RET_SUCCESS on success,
1386 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1387 *
1388 * Implement efidebug "boot next" sub-command.
1389 * Set BootNext variable.
1390 *
1391 *     efidebug boot next <id>
1392 */
1393static int do_efi_boot_next(struct cmd_tbl *cmdtp, int flag,
1394                            int argc, char *const argv[])
1395{
1396        u16 bootnext;
1397        efi_uintn_t size;
1398        char *endp;
1399        efi_guid_t guid;
1400        efi_status_t ret;
1401        int r = CMD_RET_SUCCESS;
1402
1403        if (argc != 2)
1404                return CMD_RET_USAGE;
1405
1406        bootnext = (u16)hextoul(argv[1], &endp);
1407        if (*endp) {
1408                printf("invalid value: %s\n", argv[1]);
1409                r = CMD_RET_FAILURE;
1410                goto out;
1411        }
1412
1413        guid = efi_global_variable_guid;
1414        size = sizeof(u16);
1415        ret = efi_set_variable_int(L"BootNext", &guid,
1416                                        EFI_VARIABLE_NON_VOLATILE |
1417                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
1418                                        EFI_VARIABLE_RUNTIME_ACCESS,
1419                                        size, &bootnext, false);
1420        if (ret != EFI_SUCCESS) {
1421                printf("Cannot set BootNext\n");
1422                r = CMD_RET_FAILURE;
1423        }
1424out:
1425        return r;
1426}
1427
1428/**
1429 * do_efi_boot_order() - manage UEFI BootOrder variable
1430 *
1431 * @cmdtp:      Command table
1432 * @flag:       Command flag
1433 * @argc:       Number of arguments
1434 * @argv:       Argument array
1435 * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1436 *
1437 * Implement efidebug "boot order" sub-command.
1438 * Show order of UEFI load options, or change it in BootOrder variable.
1439 *
1440 *     efidebug boot order [<id> ...]
1441 */
1442static int do_efi_boot_order(struct cmd_tbl *cmdtp, int flag,
1443                             int argc, char *const argv[])
1444{
1445        u16 *bootorder = NULL;
1446        efi_uintn_t size;
1447        int id, i;
1448        char *endp;
1449        efi_guid_t guid;
1450        efi_status_t ret;
1451        int r = CMD_RET_SUCCESS;
1452
1453        if (argc == 1)
1454                return show_efi_boot_order();
1455
1456        argc--;
1457        argv++;
1458
1459        size = argc * sizeof(u16);
1460        bootorder = malloc(size);
1461        if (!bootorder)
1462                return CMD_RET_FAILURE;
1463
1464        for (i = 0; i < argc; i++) {
1465                id = (int)hextoul(argv[i], &endp);
1466                if (*endp != '\0' || id > 0xffff) {
1467                        printf("invalid value: %s\n", argv[i]);
1468                        r = CMD_RET_FAILURE;
1469                        goto out;
1470                }
1471
1472                bootorder[i] = (u16)id;
1473        }
1474
1475        guid = efi_global_variable_guid;
1476        ret = efi_set_variable_int(L"BootOrder", &guid,
1477                                        EFI_VARIABLE_NON_VOLATILE |
1478                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
1479                                        EFI_VARIABLE_RUNTIME_ACCESS,
1480                                        size, bootorder, true);
1481        if (ret != EFI_SUCCESS) {
1482                printf("Cannot set BootOrder\n");
1483                r = CMD_RET_FAILURE;
1484        }
1485out:
1486        free(bootorder);
1487
1488        return r;
1489}
1490
1491static struct cmd_tbl cmd_efidebug_boot_sub[] = {
1492        U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
1493        U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
1494        U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
1495        U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
1496        U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
1497                         "", ""),
1498};
1499
1500/**
1501 * do_efi_boot_opt() - manage UEFI load options
1502 *
1503 * @cmdtp:      Command table
1504 * @flag:       Command flag
1505 * @argc:       Number of arguments
1506 * @argv:       Argument array
1507 * Return:      CMD_RET_SUCCESS on success,
1508 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1509 *
1510 * Implement efidebug "boot" sub-command.
1511 */
1512static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag,
1513                           int argc, char *const argv[])
1514{
1515        struct cmd_tbl *cp;
1516
1517        if (argc < 2)
1518                return CMD_RET_USAGE;
1519
1520        argc--; argv++;
1521
1522        cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
1523                          ARRAY_SIZE(cmd_efidebug_boot_sub));
1524        if (!cp)
1525                return CMD_RET_USAGE;
1526
1527        return cp->cmd(cmdtp, flag, argc, argv);
1528}
1529
1530/**
1531 * do_efi_test_bootmgr() - run simple bootmgr for test
1532 *
1533 * @cmdtp:      Command table
1534 * @flag:       Command flag
1535 * @argc:       Number of arguments
1536 * @argv:       Argument array
1537 * Return:      CMD_RET_SUCCESS on success,
1538 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1539 *
1540 * Implement efidebug "test bootmgr" sub-command.
1541 * Run simple bootmgr for test.
1542 *
1543 *     efidebug test bootmgr
1544 */
1545static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
1546                                              int argc, char * const argv[])
1547{
1548        efi_handle_t image;
1549        efi_uintn_t exit_data_size = 0;
1550        u16 *exit_data = NULL;
1551        efi_status_t ret;
1552        void *load_options = NULL;
1553
1554        ret = efi_bootmgr_load(&image, &load_options);
1555        printf("efi_bootmgr_load() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1556
1557        /* We call efi_start_image() even if error for test purpose. */
1558        ret = EFI_CALL(efi_start_image(image, &exit_data_size, &exit_data));
1559        printf("efi_start_image() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1560        if (ret && exit_data)
1561                efi_free_pool(exit_data);
1562
1563        efi_restore_gd();
1564
1565        free(load_options);
1566        return CMD_RET_SUCCESS;
1567}
1568
1569static struct cmd_tbl cmd_efidebug_test_sub[] = {
1570#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1571        U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr,
1572                         "", ""),
1573#endif
1574};
1575
1576/**
1577 * do_efi_test() - manage UEFI load options
1578 *
1579 * @cmdtp:      Command table
1580 * @flag:       Command flag
1581 * @argc:       Number of arguments
1582 * @argv:       Argument array
1583 * Return:      CMD_RET_SUCCESS on success,
1584 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1585 *
1586 * Implement efidebug "test" sub-command.
1587 */
1588static int do_efi_test(struct cmd_tbl *cmdtp, int flag,
1589                       int argc, char * const argv[])
1590{
1591        struct cmd_tbl *cp;
1592
1593        if (argc < 2)
1594                return CMD_RET_USAGE;
1595
1596        argc--; argv++;
1597
1598        cp = find_cmd_tbl(argv[0], cmd_efidebug_test_sub,
1599                          ARRAY_SIZE(cmd_efidebug_test_sub));
1600        if (!cp)
1601                return CMD_RET_USAGE;
1602
1603        return cp->cmd(cmdtp, flag, argc, argv);
1604}
1605
1606/**
1607 * do_efi_query_info() - QueryVariableInfo EFI service
1608 *
1609 * @cmdtp:      Command table
1610 * @flag:       Command flag
1611 * @argc:       Number of arguments
1612 * @argv:       Argument array
1613 * Return:      CMD_RET_SUCCESS on success,
1614 *              CMD_RET_USAGE or CMD_RET_FAILURE on failure
1615 *
1616 * Implement efidebug "test" sub-command.
1617 */
1618
1619static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag,
1620                             int argc, char * const argv[])
1621{
1622        efi_status_t ret;
1623        u32 attr = 0;
1624        u64 max_variable_storage_size;
1625        u64 remain_variable_storage_size;
1626        u64 max_variable_size;
1627        int i;
1628
1629        for (i = 1; i < argc; i++) {
1630                if (!strcmp(argv[i], "-bs"))
1631                        attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
1632                else if (!strcmp(argv[i], "-rt"))
1633                        attr |= EFI_VARIABLE_RUNTIME_ACCESS;
1634                else if (!strcmp(argv[i], "-nv"))
1635                        attr |= EFI_VARIABLE_NON_VOLATILE;
1636                else if (!strcmp(argv[i], "-at"))
1637                        attr |=
1638                                EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1639        }
1640
1641        ret = EFI_CALL(efi_query_variable_info(attr,
1642                                               &max_variable_storage_size,
1643                                               &remain_variable_storage_size,
1644                                               &max_variable_size));
1645        if (ret != EFI_SUCCESS) {
1646                printf("Error: Cannot query UEFI variables, r = %lu\n",
1647                       ret & ~EFI_ERROR_MASK);
1648                return CMD_RET_FAILURE;
1649        }
1650
1651        printf("Max storage size %llu\n", max_variable_storage_size);
1652        printf("Remaining storage size %llu\n", remain_variable_storage_size);
1653        printf("Max variable size %llu\n", max_variable_size);
1654
1655        return CMD_RET_SUCCESS;
1656}
1657
1658static struct cmd_tbl cmd_efidebug_sub[] = {
1659        U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
1660#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1661        U_BOOT_CMD_MKENT(capsule, CONFIG_SYS_MAXARGS, 1, do_efi_capsule,
1662                         "", ""),
1663#endif
1664        U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
1665                         "", ""),
1666        U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
1667                         "", ""),
1668        U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
1669                         "", ""),
1670        U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
1671                         "", ""),
1672        U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
1673                         "", ""),
1674        U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables,
1675                         "", ""),
1676        U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_efi_test,
1677                         "", ""),
1678        U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info,
1679                         "", ""),
1680};
1681
1682/**
1683 * do_efidebug() - display and configure UEFI environment
1684 *
1685 * @cmdtp:      Command table
1686 * @flag:       Command flag
1687 * @argc:       Number of arguments
1688 * @argv:       Argument array
1689 * Return:      CMD_RET_SUCCESS on success,
1690 *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1691 *
1692 * Implement efidebug command which allows us to display and
1693 * configure UEFI environment.
1694 */
1695static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
1696                       int argc, char *const argv[])
1697{
1698        struct cmd_tbl *cp;
1699        efi_status_t r;
1700
1701        if (argc < 2)
1702                return CMD_RET_USAGE;
1703
1704        argc--; argv++;
1705
1706        /* Initialize UEFI drivers */
1707        r = efi_init_obj_list();
1708        if (r != EFI_SUCCESS) {
1709                printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1710                       r & ~EFI_ERROR_MASK);
1711                return CMD_RET_FAILURE;
1712        }
1713
1714        cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1715                          ARRAY_SIZE(cmd_efidebug_sub));
1716        if (!cp)
1717                return CMD_RET_USAGE;
1718
1719        return cp->cmd(cmdtp, flag, argc, argv);
1720}
1721
1722#ifdef CONFIG_SYS_LONGHELP
1723static char efidebug_help_text[] =
1724        "  - UEFI Shell-like interface to configure UEFI environment\n"
1725        "\n"
1726        "efidebug boot add "
1727        "-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
1728        "-i <interface> <devnum>[:<part>] <initrd file path> "
1729        "-s '<optional data>'\n"
1730        "  - set UEFI BootXXXX variable\n"
1731        "    <load options> will be passed to UEFI application\n"
1732        "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1733        "  - delete UEFI BootXXXX variables\n"
1734        "efidebug boot dump\n"
1735        "  - dump all UEFI BootXXXX variables\n"
1736        "efidebug boot next <bootid>\n"
1737        "  - set UEFI BootNext variable\n"
1738        "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1739        "  - set/show UEFI boot order\n"
1740        "\n"
1741#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1742        "efidebug capsule update [-v] <capsule address>\n"
1743        "  - process a capsule\n"
1744        "efidebug capsule disk-update\n"
1745        "  - update a capsule from disk\n"
1746        "efidebug capsule show <capsule address>\n"
1747        "  - show capsule information\n"
1748        "efidebug capsule result [<capsule result var>]\n"
1749        "  - show a capsule update result\n"
1750#ifdef CONFIG_EFI_ESRT
1751        "efidebug capsule esrt\n"
1752        "  - print the ESRT\n"
1753#endif
1754        "\n"
1755#endif
1756        "efidebug devices\n"
1757        "  - show UEFI devices\n"
1758        "efidebug drivers\n"
1759        "  - show UEFI drivers\n"
1760        "efidebug dh\n"
1761        "  - show UEFI handles\n"
1762        "efidebug images\n"
1763        "  - show loaded images\n"
1764        "efidebug memmap\n"
1765        "  - show UEFI memory map\n"
1766        "efidebug tables\n"
1767        "  - show UEFI configuration tables\n"
1768#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1769        "efidebug test bootmgr\n"
1770        "  - run simple bootmgr for test\n"
1771#endif
1772        "efidebug query [-nv][-bs][-rt][-at]\n"
1773        "  - show size of UEFI variables store\n";
1774#endif
1775
1776U_BOOT_CMD(
1777        efidebug, CONFIG_SYS_MAXARGS, 0, do_efidebug,
1778        "Configure UEFI environment",
1779        efidebug_help_text
1780);
1781