uboot/boot/pxe_utils.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2010-2011 Calxeda, Inc.
   4 * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <env.h>
  10#include <image.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <mapmem.h>
  14#include <lcd.h>
  15#include <net.h>
  16#include <fdt_support.h>
  17#include <linux/libfdt.h>
  18#include <linux/string.h>
  19#include <linux/ctype.h>
  20#include <errno.h>
  21#include <linux/list.h>
  22
  23#include <splash.h>
  24#include <asm/io.h>
  25
  26#include "menu.h"
  27#include "cli.h"
  28
  29#include "pxe_utils.h"
  30
  31#define MAX_TFTP_PATH_LEN 512
  32
  33int pxe_get_file_size(ulong *sizep)
  34{
  35        const char *val;
  36
  37        val = from_env("filesize");
  38        if (!val)
  39                return -ENOENT;
  40
  41        if (strict_strtoul(val, 16, sizep) < 0)
  42                return -EINVAL;
  43
  44        return 0;
  45}
  46
  47/**
  48 * format_mac_pxe() - obtain a MAC address in the PXE format
  49 *
  50 * This produces a MAC-address string in the format for the current ethernet
  51 * device:
  52 *
  53 *   01-aa-bb-cc-dd-ee-ff
  54 *
  55 * where aa-ff is the MAC address in hex
  56 *
  57 * @outbuf: Buffer to write string to
  58 * @outbuf_len: length of buffer
  59 * @return 1 if OK, -ENOSPC if buffer is too small, -ENOENT is there is no
  60 *      current ethernet device
  61 */
  62int format_mac_pxe(char *outbuf, size_t outbuf_len)
  63{
  64        uchar ethaddr[6];
  65
  66        if (outbuf_len < 21) {
  67                printf("outbuf is too small (%zd < 21)\n", outbuf_len);
  68                return -ENOSPC;
  69        }
  70
  71        if (!eth_env_get_enetaddr_by_index("eth", eth_get_dev_index(), ethaddr))
  72                return -ENOENT;
  73
  74        sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
  75                ethaddr[0], ethaddr[1], ethaddr[2],
  76                ethaddr[3], ethaddr[4], ethaddr[5]);
  77
  78        return 1;
  79}
  80
  81/**
  82 * get_relfile() - read a file relative to the PXE file
  83 *
  84 * As in pxelinux, paths to files referenced from files we retrieve are
  85 * relative to the location of bootfile. get_relfile takes such a path and
  86 * joins it with the bootfile path to get the full path to the target file. If
  87 * the bootfile path is NULL, we use file_path as is.
  88 *
  89 * @ctx: PXE context
  90 * @file_path: File path to read (relative to the PXE file)
  91 * @file_addr: Address to load file to
  92 * @filesizep: If not NULL, returns the file size in bytes
  93 * Returns 1 for success, or < 0 on error
  94 */
  95static int get_relfile(struct pxe_context *ctx, const char *file_path,
  96                       unsigned long file_addr, ulong *filesizep)
  97{
  98        size_t path_len;
  99        char relfile[MAX_TFTP_PATH_LEN + 1];
 100        char addr_buf[18];
 101        ulong size;
 102        int ret;
 103
 104        if (file_path[0] == '/' && ctx->allow_abs_path)
 105                *relfile = '\0';
 106        else
 107                strncpy(relfile, ctx->bootdir, MAX_TFTP_PATH_LEN);
 108
 109        path_len = strlen(file_path) + strlen(relfile);
 110
 111        if (path_len > MAX_TFTP_PATH_LEN) {
 112                printf("Base path too long (%s%s)\n", relfile, file_path);
 113
 114                return -ENAMETOOLONG;
 115        }
 116
 117        strcat(relfile, file_path);
 118
 119        printf("Retrieving file: %s\n", relfile);
 120
 121        sprintf(addr_buf, "%lx", file_addr);
 122
 123        ret = ctx->getfile(ctx, relfile, addr_buf, &size);
 124        if (ret < 0)
 125                return log_msg_ret("get", ret);
 126        if (filesizep)
 127                *filesizep = size;
 128
 129        return 1;
 130}
 131
 132/**
 133 * get_pxe_file() - read a file
 134 *
 135 * The file is read and nul-terminated
 136 *
 137 * @ctx: PXE context
 138 * @file_path: File path to read (relative to the PXE file)
 139 * @file_addr: Address to load file to
 140 * Returns 1 for success, or < 0 on error
 141 */
 142int get_pxe_file(struct pxe_context *ctx, const char *file_path,
 143                 ulong file_addr)
 144{
 145        ulong size;
 146        int err;
 147        char *buf;
 148
 149        err = get_relfile(ctx, file_path, file_addr, &size);
 150        if (err < 0)
 151                return err;
 152
 153        buf = map_sysmem(file_addr + size, 1);
 154        *buf = '\0';
 155        unmap_sysmem(buf);
 156
 157        return 1;
 158}
 159
 160#define PXELINUX_DIR "pxelinux.cfg/"
 161
 162/**
 163 * get_pxelinux_path() - Get a file in the pxelinux.cfg/ directory
 164 *
 165 * @ctx: PXE context
 166 * @file: Filename to process (relative to pxelinux.cfg/)
 167 * Returns 1 for success, -ENAMETOOLONG if the resulting path is too long.
 168 *      or other value < 0 on other error
 169 */
 170int get_pxelinux_path(struct pxe_context *ctx, const char *file,
 171                      unsigned long pxefile_addr_r)
 172{
 173        size_t base_len = strlen(PXELINUX_DIR);
 174        char path[MAX_TFTP_PATH_LEN + 1];
 175
 176        if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
 177                printf("path (%s%s) too long, skipping\n",
 178                       PXELINUX_DIR, file);
 179                return -ENAMETOOLONG;
 180        }
 181
 182        sprintf(path, PXELINUX_DIR "%s", file);
 183
 184        return get_pxe_file(ctx, path, pxefile_addr_r);
 185}
 186
 187/**
 188 * get_relfile_envaddr() - read a file to an address in an env var
 189 *
 190 * Wrapper to make it easier to store the file at file_path in the location
 191 * specified by envaddr_name. file_path will be joined to the bootfile path,
 192 * if any is specified.
 193 *
 194 * @ctx: PXE context
 195 * @file_path: File path to read (relative to the PXE file)
 196 * @envaddr_name: Name of environment variable which contains the address to
 197 *      load to
 198 * @filesizep: Returns the file size in bytes
 199 * Returns 1 on success, -ENOENT if @envaddr_name does not exist as an
 200 *      environment variable, -EINVAL if its format is not valid hex, or other
 201 *      value < 0 on other error
 202 */
 203static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path,
 204                               const char *envaddr_name, ulong *filesizep)
 205{
 206        unsigned long file_addr;
 207        char *envaddr;
 208
 209        envaddr = from_env(envaddr_name);
 210        if (!envaddr)
 211                return -ENOENT;
 212
 213        if (strict_strtoul(envaddr, 16, &file_addr) < 0)
 214                return -EINVAL;
 215
 216        return get_relfile(ctx, file_path, file_addr, filesizep);
 217}
 218
 219/**
 220 * label_create() - crate a new PXE label
 221 *
 222 * Allocates memory for and initializes a pxe_label. This uses malloc, so the
 223 * result must be free()'d to reclaim the memory.
 224 *
 225 * Returns a pointer to the label, or NULL if out of memory
 226 */
 227static struct pxe_label *label_create(void)
 228{
 229        struct pxe_label *label;
 230
 231        label = malloc(sizeof(struct pxe_label));
 232        if (!label)
 233                return NULL;
 234
 235        memset(label, 0, sizeof(struct pxe_label));
 236
 237        return label;
 238}
 239
 240/**
 241 * label_destroy() - free the memory used by a pxe_label
 242 *
 243 * This frees @label itself as well as memory used by its name,
 244 * kernel, config, append, initrd, fdt, fdtdir and fdtoverlay members, if
 245 * they're non-NULL.
 246 *
 247 * So - be sure to only use dynamically allocated memory for the members of
 248 * the pxe_label struct, unless you want to clean it up first. These are
 249 * currently only created by the pxe file parsing code.
 250 *
 251 * @label: Label to free
 252 */
 253static void label_destroy(struct pxe_label *label)
 254{
 255        free(label->name);
 256        free(label->kernel);
 257        free(label->config);
 258        free(label->append);
 259        free(label->initrd);
 260        free(label->fdt);
 261        free(label->fdtdir);
 262        free(label->fdtoverlays);
 263        free(label);
 264}
 265
 266/**
 267 * label_print() - Print a label and its string members if they're defined
 268 *
 269 * This is passed as a callback to the menu code for displaying each
 270 * menu entry.
 271 *
 272 * @data: Label to print (is cast to struct pxe_label *)
 273 */
 274static void label_print(void *data)
 275{
 276        struct pxe_label *label = data;
 277        const char *c = label->menu ? label->menu : label->name;
 278
 279        printf("%s:\t%s\n", label->num, c);
 280}
 281
 282/**
 283 * label_localboot() - Boot a label that specified 'localboot'
 284 *
 285 * This requires that the 'localcmd' environment variable is defined. Its
 286 * contents will be executed as U-Boot commands.  If the label specified an
 287 * 'append' line, its contents will be used to overwrite the contents of the
 288 * 'bootargs' environment variable prior to running 'localcmd'.
 289 *
 290 * @label: Label to process
 291 * Returns 1 on success or < 0 on error
 292 */
 293static int label_localboot(struct pxe_label *label)
 294{
 295        char *localcmd;
 296
 297        localcmd = from_env("localcmd");
 298        if (!localcmd)
 299                return -ENOENT;
 300
 301        if (label->append) {
 302                char bootargs[CONFIG_SYS_CBSIZE];
 303
 304                cli_simple_process_macros(label->append, bootargs,
 305                                          sizeof(bootargs));
 306                env_set("bootargs", bootargs);
 307        }
 308
 309        debug("running: %s\n", localcmd);
 310
 311        return run_command_list(localcmd, strlen(localcmd), 0);
 312}
 313
 314/**
 315 * label_boot_fdtoverlay() - Loads fdt overlays specified in 'fdtoverlays'
 316 *
 317 * @ctx: PXE context
 318 * @label: Label to process
 319 */
 320#ifdef CONFIG_OF_LIBFDT_OVERLAY
 321static void label_boot_fdtoverlay(struct pxe_context *ctx,
 322                                  struct pxe_label *label)
 323{
 324        char *fdtoverlay = label->fdtoverlays;
 325        struct fdt_header *working_fdt;
 326        char *fdtoverlay_addr_env;
 327        ulong fdtoverlay_addr;
 328        ulong fdt_addr;
 329        int err;
 330
 331        /* Get the main fdt and map it */
 332        fdt_addr = hextoul(env_get("fdt_addr_r"), NULL);
 333        working_fdt = map_sysmem(fdt_addr, 0);
 334        err = fdt_check_header(working_fdt);
 335        if (err)
 336                return;
 337
 338        /* Get the specific overlay loading address */
 339        fdtoverlay_addr_env = env_get("fdtoverlay_addr_r");
 340        if (!fdtoverlay_addr_env) {
 341                printf("Invalid fdtoverlay_addr_r for loading overlays\n");
 342                return;
 343        }
 344
 345        fdtoverlay_addr = hextoul(fdtoverlay_addr_env, NULL);
 346
 347        /* Cycle over the overlay files and apply them in order */
 348        do {
 349                struct fdt_header *blob;
 350                char *overlayfile;
 351                char *end;
 352                int len;
 353
 354                /* Drop leading spaces */
 355                while (*fdtoverlay == ' ')
 356                        ++fdtoverlay;
 357
 358                /* Copy a single filename if multiple provided */
 359                end = strstr(fdtoverlay, " ");
 360                if (end) {
 361                        len = (int)(end - fdtoverlay);
 362                        overlayfile = malloc(len + 1);
 363                        strncpy(overlayfile, fdtoverlay, len);
 364                        overlayfile[len] = '\0';
 365                } else
 366                        overlayfile = fdtoverlay;
 367
 368                if (!strlen(overlayfile))
 369                        goto skip_overlay;
 370
 371                /* Load overlay file */
 372                err = get_relfile_envaddr(ctx, overlayfile, "fdtoverlay_addr_r",
 373                                          NULL);
 374                if (err < 0) {
 375                        printf("Failed loading overlay %s\n", overlayfile);
 376                        goto skip_overlay;
 377                }
 378
 379                /* Resize main fdt */
 380                fdt_shrink_to_minimum(working_fdt, 8192);
 381
 382                blob = map_sysmem(fdtoverlay_addr, 0);
 383                err = fdt_check_header(blob);
 384                if (err) {
 385                        printf("Invalid overlay %s, skipping\n",
 386                               overlayfile);
 387                        goto skip_overlay;
 388                }
 389
 390                err = fdt_overlay_apply_verbose(working_fdt, blob);
 391                if (err) {
 392                        printf("Failed to apply overlay %s, skipping\n",
 393                               overlayfile);
 394                        goto skip_overlay;
 395                }
 396
 397skip_overlay:
 398                if (end)
 399                        free(overlayfile);
 400        } while ((fdtoverlay = strstr(fdtoverlay, " ")));
 401}
 402#endif
 403
 404/**
 405 * label_boot() - Boot according to the contents of a pxe_label
 406 *
 407 * If we can't boot for any reason, we return.  A successful boot never
 408 * returns.
 409 *
 410 * The kernel will be stored in the location given by the 'kernel_addr_r'
 411 * environment variable.
 412 *
 413 * If the label specifies an initrd file, it will be stored in the location
 414 * given by the 'ramdisk_addr_r' environment variable.
 415 *
 416 * If the label specifies an 'append' line, its contents will overwrite that
 417 * of the 'bootargs' environment variable.
 418 *
 419 * @ctx: PXE context
 420 * @label: Label to process
 421 * Returns does not return on success, otherwise returns 0 if a localboot
 422 *      label was processed, or 1 on error
 423 */
 424static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
 425{
 426        char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
 427        char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL };
 428        char *kernel_addr = NULL;
 429        char *initrd_addr_str = NULL;
 430        char initrd_filesize[10];
 431        char initrd_str[28];
 432        char mac_str[29] = "";
 433        char ip_str[68] = "";
 434        char *fit_addr = NULL;
 435        int bootm_argc = 2;
 436        int zboot_argc = 3;
 437        int len = 0;
 438        ulong kernel_addr_r;
 439        void *buf;
 440
 441        label_print(label);
 442
 443        label->attempted = 1;
 444
 445        if (label->localboot) {
 446                if (label->localboot_val >= 0)
 447                        label_localboot(label);
 448                return 0;
 449        }
 450
 451        if (!label->kernel) {
 452                printf("No kernel given, skipping %s\n",
 453                       label->name);
 454                return 1;
 455        }
 456
 457        if (label->initrd) {
 458                ulong size;
 459
 460                if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
 461                                        &size) < 0) {
 462                        printf("Skipping %s for failure retrieving initrd\n",
 463                               label->name);
 464                        return 1;
 465                }
 466
 467                initrd_addr_str = env_get("ramdisk_addr_r");
 468                strcpy(initrd_filesize, simple_xtoa(size));
 469
 470                strncpy(initrd_str, initrd_addr_str, 18);
 471                strcat(initrd_str, ":");
 472                strncat(initrd_str, initrd_filesize, 9);
 473        }
 474
 475        if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r",
 476                                NULL) < 0) {
 477                printf("Skipping %s for failure retrieving kernel\n",
 478                       label->name);
 479                return 1;
 480        }
 481
 482        if (label->ipappend & 0x1) {
 483                sprintf(ip_str, " ip=%s:%s:%s:%s",
 484                        env_get("ipaddr"), env_get("serverip"),
 485                        env_get("gatewayip"), env_get("netmask"));
 486        }
 487
 488        if (IS_ENABLED(CONFIG_CMD_NET)) {
 489                if (label->ipappend & 0x2) {
 490                        int err;
 491
 492                        strcpy(mac_str, " BOOTIF=");
 493                        err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
 494                        if (err < 0)
 495                                mac_str[0] = '\0';
 496                }
 497        }
 498
 499        if ((label->ipappend & 0x3) || label->append) {
 500                char bootargs[CONFIG_SYS_CBSIZE] = "";
 501                char finalbootargs[CONFIG_SYS_CBSIZE];
 502
 503                if (strlen(label->append ?: "") +
 504                    strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) {
 505                        printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n",
 506                               strlen(label->append ?: ""),
 507                               strlen(ip_str), strlen(mac_str),
 508                               sizeof(bootargs));
 509                        return 1;
 510                }
 511
 512                if (label->append)
 513                        strncpy(bootargs, label->append, sizeof(bootargs));
 514
 515                strcat(bootargs, ip_str);
 516                strcat(bootargs, mac_str);
 517
 518                cli_simple_process_macros(bootargs, finalbootargs,
 519                                          sizeof(finalbootargs));
 520                env_set("bootargs", finalbootargs);
 521                printf("append: %s\n", finalbootargs);
 522        }
 523
 524        kernel_addr = env_get("kernel_addr_r");
 525
 526        /* for FIT, append the configuration identifier */
 527        if (label->config) {
 528                int len = strlen(kernel_addr) + strlen(label->config) + 1;
 529
 530                fit_addr = malloc(len);
 531                if (!fit_addr) {
 532                        printf("malloc fail (FIT address)\n");
 533                        return 1;
 534                }
 535                snprintf(fit_addr, len, "%s%s", kernel_addr, label->config);
 536                kernel_addr = fit_addr;
 537        }
 538
 539        /*
 540         * fdt usage is optional:
 541         * It handles the following scenarios.
 542         *
 543         * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
 544         * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
 545         * bootm, and adjust argc appropriately.
 546         *
 547         * If retrieve fails and no exact fdt blob is specified in pxe file with
 548         * "fdt" label, try Scenario 2.
 549         *
 550         * Scenario 2: If there is an fdt_addr specified, pass it along to
 551         * bootm, and adjust argc appropriately.
 552         *
 553         * Scenario 3: fdt blob is not available.
 554         */
 555        bootm_argv[3] = env_get("fdt_addr_r");
 556
 557        /* if fdt label is defined then get fdt from server */
 558        if (bootm_argv[3]) {
 559                char *fdtfile = NULL;
 560                char *fdtfilefree = NULL;
 561
 562                if (label->fdt) {
 563                        fdtfile = label->fdt;
 564                } else if (label->fdtdir) {
 565                        char *f1, *f2, *f3, *f4, *slash;
 566
 567                        f1 = env_get("fdtfile");
 568                        if (f1) {
 569                                f2 = "";
 570                                f3 = "";
 571                                f4 = "";
 572                        } else {
 573                                /*
 574                                 * For complex cases where this code doesn't
 575                                 * generate the correct filename, the board
 576                                 * code should set $fdtfile during early boot,
 577                                 * or the boot scripts should set $fdtfile
 578                                 * before invoking "pxe" or "sysboot".
 579                                 */
 580                                f1 = env_get("soc");
 581                                f2 = "-";
 582                                f3 = env_get("board");
 583                                f4 = ".dtb";
 584                                if (!f1) {
 585                                        f1 = "";
 586                                        f2 = "";
 587                                }
 588                                if (!f3) {
 589                                        f2 = "";
 590                                        f3 = "";
 591                                }
 592                        }
 593
 594                        len = strlen(label->fdtdir);
 595                        if (!len)
 596                                slash = "./";
 597                        else if (label->fdtdir[len - 1] != '/')
 598                                slash = "/";
 599                        else
 600                                slash = "";
 601
 602                        len = strlen(label->fdtdir) + strlen(slash) +
 603                                strlen(f1) + strlen(f2) + strlen(f3) +
 604                                strlen(f4) + 1;
 605                        fdtfilefree = malloc(len);
 606                        if (!fdtfilefree) {
 607                                printf("malloc fail (FDT filename)\n");
 608                                goto cleanup;
 609                        }
 610
 611                        snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
 612                                 label->fdtdir, slash, f1, f2, f3, f4);
 613                        fdtfile = fdtfilefree;
 614                }
 615
 616                if (fdtfile) {
 617                        int err = get_relfile_envaddr(ctx, fdtfile,
 618                                                      "fdt_addr_r", NULL);
 619
 620                        free(fdtfilefree);
 621                        if (err < 0) {
 622                                bootm_argv[3] = NULL;
 623
 624                                if (label->fdt) {
 625                                        printf("Skipping %s for failure retrieving FDT\n",
 626                                               label->name);
 627                                        goto cleanup;
 628                                }
 629                        }
 630
 631#ifdef CONFIG_OF_LIBFDT_OVERLAY
 632                        if (label->fdtoverlays)
 633                                label_boot_fdtoverlay(ctx, label);
 634#endif
 635                } else {
 636                        bootm_argv[3] = NULL;
 637                }
 638        }
 639
 640        bootm_argv[1] = kernel_addr;
 641        zboot_argv[1] = kernel_addr;
 642
 643        if (initrd_addr_str) {
 644                bootm_argv[2] = initrd_str;
 645                bootm_argc = 3;
 646
 647                zboot_argv[3] = initrd_addr_str;
 648                zboot_argv[4] = initrd_filesize;
 649                zboot_argc = 5;
 650        }
 651
 652        if (!bootm_argv[3])
 653                bootm_argv[3] = env_get("fdt_addr");
 654
 655        if (bootm_argv[3]) {
 656                if (!bootm_argv[2])
 657                        bootm_argv[2] = "-";
 658                bootm_argc = 4;
 659        }
 660
 661        kernel_addr_r = genimg_get_kernel_addr(kernel_addr);
 662        buf = map_sysmem(kernel_addr_r, 0);
 663        /* Try bootm for legacy and FIT format image */
 664        if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID)
 665                do_bootm(ctx->cmdtp, 0, bootm_argc, bootm_argv);
 666        /* Try booting an AArch64 Linux kernel image */
 667        else if (IS_ENABLED(CONFIG_CMD_BOOTI))
 668                do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv);
 669        /* Try booting a Image */
 670        else if (IS_ENABLED(CONFIG_CMD_BOOTZ))
 671                do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv);
 672        /* Try booting an x86_64 Linux kernel image */
 673        else if (IS_ENABLED(CONFIG_CMD_ZBOOT))
 674                do_zboot_parent(ctx->cmdtp, 0, zboot_argc, zboot_argv, NULL);
 675
 676        unmap_sysmem(buf);
 677
 678cleanup:
 679        free(fit_addr);
 680
 681        return 1;
 682}
 683
 684/** enum token_type - Tokens for the pxe file parser */
 685enum token_type {
 686        T_EOL,
 687        T_STRING,
 688        T_EOF,
 689        T_MENU,
 690        T_TITLE,
 691        T_TIMEOUT,
 692        T_LABEL,
 693        T_KERNEL,
 694        T_LINUX,
 695        T_APPEND,
 696        T_INITRD,
 697        T_LOCALBOOT,
 698        T_DEFAULT,
 699        T_PROMPT,
 700        T_INCLUDE,
 701        T_FDT,
 702        T_FDTDIR,
 703        T_FDTOVERLAYS,
 704        T_ONTIMEOUT,
 705        T_IPAPPEND,
 706        T_BACKGROUND,
 707        T_INVALID
 708};
 709
 710/** struct token - token - given by a value and a type */
 711struct token {
 712        char *val;
 713        enum token_type type;
 714};
 715
 716/* Keywords recognized */
 717static const struct token keywords[] = {
 718        {"menu", T_MENU},
 719        {"title", T_TITLE},
 720        {"timeout", T_TIMEOUT},
 721        {"default", T_DEFAULT},
 722        {"prompt", T_PROMPT},
 723        {"label", T_LABEL},
 724        {"kernel", T_KERNEL},
 725        {"linux", T_LINUX},
 726        {"localboot", T_LOCALBOOT},
 727        {"append", T_APPEND},
 728        {"initrd", T_INITRD},
 729        {"include", T_INCLUDE},
 730        {"devicetree", T_FDT},
 731        {"fdt", T_FDT},
 732        {"devicetreedir", T_FDTDIR},
 733        {"fdtdir", T_FDTDIR},
 734        {"fdtoverlays", T_FDTOVERLAYS},
 735        {"ontimeout", T_ONTIMEOUT,},
 736        {"ipappend", T_IPAPPEND,},
 737        {"background", T_BACKGROUND,},
 738        {NULL, T_INVALID}
 739};
 740
 741/**
 742 * enum lex_state - lexer state
 743 *
 744 * Since pxe(linux) files don't have a token to identify the start of a
 745 * literal, we have to keep track of when we're in a state where a literal is
 746 * expected vs when we're in a state a keyword is expected.
 747 */
 748enum lex_state {
 749        L_NORMAL = 0,
 750        L_KEYWORD,
 751        L_SLITERAL
 752};
 753
 754/**
 755 * get_string() - retrieves a string from *p and stores it as a token in *t.
 756 *
 757 * This is used for scanning both string literals and keywords.
 758 *
 759 * Characters from *p are copied into t-val until a character equal to
 760 * delim is found, or a NUL byte is reached. If delim has the special value of
 761 * ' ', any whitespace character will be used as a delimiter.
 762 *
 763 * If lower is unequal to 0, uppercase characters will be converted to
 764 * lowercase in the result. This is useful to make keywords case
 765 * insensitive.
 766 *
 767 * The location of *p is updated to point to the first character after the end
 768 * of the token - the ending delimiter.
 769 *
 770 * Memory for t->val is allocated using malloc and must be free()'d to reclaim
 771 * it.
 772 *
 773 * @p: Points to a pointer to the current position in the input being processed.
 774 *      Updated to point at the first character after the current token
 775 * @t: Pointers to a token to fill in
 776 * @delim: Delimiter character to look for, either newline or space
 777 * @lower: true to convert the string to lower case when storing
 778 * Returns the new value of t->val, on success, NULL if out of memory
 779 */
 780static char *get_string(char **p, struct token *t, char delim, int lower)
 781{
 782        char *b, *e;
 783        size_t len, i;
 784
 785        /*
 786         * b and e both start at the beginning of the input stream.
 787         *
 788         * e is incremented until we find the ending delimiter, or a NUL byte
 789         * is reached. Then, we take e - b to find the length of the token.
 790         */
 791        b = *p;
 792        e = *p;
 793        while (*e) {
 794                if ((delim == ' ' && isspace(*e)) || delim == *e)
 795                        break;
 796                e++;
 797        }
 798
 799        len = e - b;
 800
 801        /*
 802         * Allocate memory to hold the string, and copy it in, converting
 803         * characters to lowercase if lower is != 0.
 804         */
 805        t->val = malloc(len + 1);
 806        if (!t->val)
 807                return NULL;
 808
 809        for (i = 0; i < len; i++, b++) {
 810                if (lower)
 811                        t->val[i] = tolower(*b);
 812                else
 813                        t->val[i] = *b;
 814        }
 815
 816        t->val[len] = '\0';
 817
 818        /* Update *p so the caller knows where to continue scanning */
 819        *p = e;
 820        t->type = T_STRING;
 821
 822        return t->val;
 823}
 824
 825/**
 826 * get_keyword() - Populate a keyword token with a type and value
 827 *
 828 * Updates the ->type field based on the keyword string in @val
 829 * @t: Token to populate
 830 */
 831static void get_keyword(struct token *t)
 832{
 833        int i;
 834
 835        for (i = 0; keywords[i].val; i++) {
 836                if (!strcmp(t->val, keywords[i].val)) {
 837                        t->type = keywords[i].type;
 838                        break;
 839                }
 840        }
 841}
 842
 843/**
 844 * get_token() - Get the next token
 845 *
 846 * We have to keep track of which state we're in to know if we're looking to get
 847 * a string literal or a keyword.
 848 *
 849 * @p: Points to a pointer to the current position in the input being processed.
 850 *      Updated to point at the first character after the current token
 851 */
 852static void get_token(char **p, struct token *t, enum lex_state state)
 853{
 854        char *c = *p;
 855
 856        t->type = T_INVALID;
 857
 858        /* eat non EOL whitespace */
 859        while (isblank(*c))
 860                c++;
 861
 862        /*
 863         * eat comments. note that string literals can't begin with #, but
 864         * can contain a # after their first character.
 865         */
 866        if (*c == '#') {
 867                while (*c && *c != '\n')
 868                        c++;
 869        }
 870
 871        if (*c == '\n') {
 872                t->type = T_EOL;
 873                c++;
 874        } else if (*c == '\0') {
 875                t->type = T_EOF;
 876                c++;
 877        } else if (state == L_SLITERAL) {
 878                get_string(&c, t, '\n', 0);
 879        } else if (state == L_KEYWORD) {
 880                /*
 881                 * when we expect a keyword, we first get the next string
 882                 * token delimited by whitespace, and then check if it
 883                 * matches a keyword in our keyword list. if it does, it's
 884                 * converted to a keyword token of the appropriate type, and
 885                 * if not, it remains a string token.
 886                 */
 887                get_string(&c, t, ' ', 1);
 888                get_keyword(t);
 889        }
 890
 891        *p = c;
 892}
 893
 894/**
 895 * eol_or_eof() - Find end of line
 896 *
 897 * Increment *c until we get to the end of the current line, or EOF
 898 *
 899 * @c: Points to a pointer to the current position in the input being processed.
 900 *      Updated to point at the first character after the current token
 901 */
 902static void eol_or_eof(char **c)
 903{
 904        while (**c && **c != '\n')
 905                (*c)++;
 906}
 907
 908/*
 909 * All of these parse_* functions share some common behavior.
 910 *
 911 * They finish with *c pointing after the token they parse, and return 1 on
 912 * success, or < 0 on error.
 913 */
 914
 915/*
 916 * Parse a string literal and store a pointer it at *dst. String literals
 917 * terminate at the end of the line.
 918 */
 919static int parse_sliteral(char **c, char **dst)
 920{
 921        struct token t;
 922        char *s = *c;
 923
 924        get_token(c, &t, L_SLITERAL);
 925
 926        if (t.type != T_STRING) {
 927                printf("Expected string literal: %.*s\n", (int)(*c - s), s);
 928                return -EINVAL;
 929        }
 930
 931        *dst = t.val;
 932
 933        return 1;
 934}
 935
 936/*
 937 * Parse a base 10 (unsigned) integer and store it at *dst.
 938 */
 939static int parse_integer(char **c, int *dst)
 940{
 941        struct token t;
 942        char *s = *c;
 943
 944        get_token(c, &t, L_SLITERAL);
 945        if (t.type != T_STRING) {
 946                printf("Expected string: %.*s\n", (int)(*c - s), s);
 947                return -EINVAL;
 948        }
 949
 950        *dst = simple_strtol(t.val, NULL, 10);
 951
 952        free(t.val);
 953
 954        return 1;
 955}
 956
 957static int parse_pxefile_top(struct pxe_context *ctx, char *p, ulong base,
 958                             struct pxe_menu *cfg, int nest_level);
 959
 960/*
 961 * Parse an include statement, and retrieve and parse the file it mentions.
 962 *
 963 * base should point to a location where it's safe to store the file, and
 964 * nest_level should indicate how many nested includes have occurred. For this
 965 * include, nest_level has already been incremented and doesn't need to be
 966 * incremented here.
 967 */
 968static int handle_include(struct pxe_context *ctx, char **c, unsigned long base,
 969                          struct pxe_menu *cfg, int nest_level)
 970{
 971        char *include_path;
 972        char *s = *c;
 973        int err;
 974        char *buf;
 975        int ret;
 976
 977        err = parse_sliteral(c, &include_path);
 978        if (err < 0) {
 979                printf("Expected include path: %.*s\n", (int)(*c - s), s);
 980                return err;
 981        }
 982
 983        err = get_pxe_file(ctx, include_path, base);
 984        if (err < 0) {
 985                printf("Couldn't retrieve %s\n", include_path);
 986                return err;
 987        }
 988
 989        buf = map_sysmem(base, 0);
 990        ret = parse_pxefile_top(ctx, buf, base, cfg, nest_level);
 991        unmap_sysmem(buf);
 992
 993        return ret;
 994}
 995
 996/*
 997 * Parse lines that begin with 'menu'.
 998 *
 999 * base and nest are provided to handle the 'menu include' case.
1000 *
1001 * base should point to a location where it's safe to store the included file.
1002 *
1003 * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
1004 * a file it includes, 3 when parsing a file included by that file, and so on.
1005 */
1006static int parse_menu(struct pxe_context *ctx, char **c, struct pxe_menu *cfg,
1007                      unsigned long base, int nest_level)
1008{
1009        struct token t;
1010        char *s = *c;
1011        int err = 0;
1012
1013        get_token(c, &t, L_KEYWORD);
1014
1015        switch (t.type) {
1016        case T_TITLE:
1017                err = parse_sliteral(c, &cfg->title);
1018
1019                break;
1020
1021        case T_INCLUDE:
1022                err = handle_include(ctx, c, base, cfg, nest_level + 1);
1023                break;
1024
1025        case T_BACKGROUND:
1026                err = parse_sliteral(c, &cfg->bmp);
1027                break;
1028
1029        default:
1030                printf("Ignoring malformed menu command: %.*s\n",
1031                       (int)(*c - s), s);
1032        }
1033        if (err < 0)
1034                return err;
1035
1036        eol_or_eof(c);
1037
1038        return 1;
1039}
1040
1041/*
1042 * Handles parsing a 'menu line' when we're parsing a label.
1043 */
1044static int parse_label_menu(char **c, struct pxe_menu *cfg,
1045                            struct pxe_label *label)
1046{
1047        struct token t;
1048        char *s;
1049
1050        s = *c;
1051
1052        get_token(c, &t, L_KEYWORD);
1053
1054        switch (t.type) {
1055        case T_DEFAULT:
1056                if (!cfg->default_label)
1057                        cfg->default_label = strdup(label->name);
1058
1059                if (!cfg->default_label)
1060                        return -ENOMEM;
1061
1062                break;
1063        case T_LABEL:
1064                parse_sliteral(c, &label->menu);
1065                break;
1066        default:
1067                printf("Ignoring malformed menu command: %.*s\n",
1068                       (int)(*c - s), s);
1069        }
1070
1071        eol_or_eof(c);
1072
1073        return 0;
1074}
1075
1076/*
1077 * Handles parsing a 'kernel' label.
1078 * expecting "filename" or "<fit_filename>#cfg"
1079 */
1080static int parse_label_kernel(char **c, struct pxe_label *label)
1081{
1082        char *s;
1083        int err;
1084
1085        err = parse_sliteral(c, &label->kernel);
1086        if (err < 0)
1087                return err;
1088
1089        s = strstr(label->kernel, "#");
1090        if (!s)
1091                return 1;
1092
1093        label->config = malloc(strlen(s) + 1);
1094        if (!label->config)
1095                return -ENOMEM;
1096
1097        strcpy(label->config, s);
1098        *s = 0;
1099
1100        return 1;
1101}
1102
1103/*
1104 * Parses a label and adds it to the list of labels for a menu.
1105 *
1106 * A label ends when we either get to the end of a file, or
1107 * get some input we otherwise don't have a handler defined
1108 * for.
1109 *
1110 */
1111static int parse_label(char **c, struct pxe_menu *cfg)
1112{
1113        struct token t;
1114        int len;
1115        char *s = *c;
1116        struct pxe_label *label;
1117        int err;
1118
1119        label = label_create();
1120        if (!label)
1121                return -ENOMEM;
1122
1123        err = parse_sliteral(c, &label->name);
1124        if (err < 0) {
1125                printf("Expected label name: %.*s\n", (int)(*c - s), s);
1126                label_destroy(label);
1127                return -EINVAL;
1128        }
1129
1130        list_add_tail(&label->list, &cfg->labels);
1131
1132        while (1) {
1133                s = *c;
1134                get_token(c, &t, L_KEYWORD);
1135
1136                err = 0;
1137                switch (t.type) {
1138                case T_MENU:
1139                        err = parse_label_menu(c, cfg, label);
1140                        break;
1141
1142                case T_KERNEL:
1143                case T_LINUX:
1144                        err = parse_label_kernel(c, label);
1145                        break;
1146
1147                case T_APPEND:
1148                        err = parse_sliteral(c, &label->append);
1149                        if (label->initrd)
1150                                break;
1151                        s = strstr(label->append, "initrd=");
1152                        if (!s)
1153                                break;
1154                        s += 7;
1155                        len = (int)(strchr(s, ' ') - s);
1156                        label->initrd = malloc(len + 1);
1157                        strncpy(label->initrd, s, len);
1158                        label->initrd[len] = '\0';
1159
1160                        break;
1161
1162                case T_INITRD:
1163                        if (!label->initrd)
1164                                err = parse_sliteral(c, &label->initrd);
1165                        break;
1166
1167                case T_FDT:
1168                        if (!label->fdt)
1169                                err = parse_sliteral(c, &label->fdt);
1170                        break;
1171
1172                case T_FDTDIR:
1173                        if (!label->fdtdir)
1174                                err = parse_sliteral(c, &label->fdtdir);
1175                        break;
1176
1177                case T_FDTOVERLAYS:
1178                        if (!label->fdtoverlays)
1179                                err = parse_sliteral(c, &label->fdtoverlays);
1180                        break;
1181
1182                case T_LOCALBOOT:
1183                        label->localboot = 1;
1184                        err = parse_integer(c, &label->localboot_val);
1185                        break;
1186
1187                case T_IPAPPEND:
1188                        err = parse_integer(c, &label->ipappend);
1189                        break;
1190
1191                case T_EOL:
1192                        break;
1193
1194                default:
1195                        /*
1196                         * put the token back! we don't want it - it's the end
1197                         * of a label and whatever token this is, it's
1198                         * something for the menu level context to handle.
1199                         */
1200                        *c = s;
1201                        return 1;
1202                }
1203
1204                if (err < 0)
1205                        return err;
1206        }
1207}
1208
1209/*
1210 * This 16 comes from the limit pxelinux imposes on nested includes.
1211 *
1212 * There is no reason at all we couldn't do more, but some limit helps prevent
1213 * infinite (until crash occurs) recursion if a file tries to include itself.
1214 */
1215#define MAX_NEST_LEVEL 16
1216
1217/*
1218 * Entry point for parsing a menu file. nest_level indicates how many times
1219 * we've nested in includes.  It will be 1 for the top level menu file.
1220 *
1221 * Returns 1 on success, < 0 on error.
1222 */
1223static int parse_pxefile_top(struct pxe_context *ctx, char *p, unsigned long base,
1224                             struct pxe_menu *cfg, int nest_level)
1225{
1226        struct token t;
1227        char *s, *b, *label_name;
1228        int err;
1229
1230        b = p;
1231
1232        if (nest_level > MAX_NEST_LEVEL) {
1233                printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
1234                return -EMLINK;
1235        }
1236
1237        while (1) {
1238                s = p;
1239
1240                get_token(&p, &t, L_KEYWORD);
1241
1242                err = 0;
1243                switch (t.type) {
1244                case T_MENU:
1245                        cfg->prompt = 1;
1246                        err = parse_menu(ctx, &p, cfg,
1247                                         base + ALIGN(strlen(b) + 1, 4),
1248                                         nest_level);
1249                        break;
1250
1251                case T_TIMEOUT:
1252                        err = parse_integer(&p, &cfg->timeout);
1253                        break;
1254
1255                case T_LABEL:
1256                        err = parse_label(&p, cfg);
1257                        break;
1258
1259                case T_DEFAULT:
1260                case T_ONTIMEOUT:
1261                        err = parse_sliteral(&p, &label_name);
1262
1263                        if (label_name) {
1264                                if (cfg->default_label)
1265                                        free(cfg->default_label);
1266
1267                                cfg->default_label = label_name;
1268                        }
1269
1270                        break;
1271
1272                case T_INCLUDE:
1273                        err = handle_include(ctx, &p,
1274                                             base + ALIGN(strlen(b), 4), cfg,
1275                                             nest_level + 1);
1276                        break;
1277
1278                case T_PROMPT:
1279                        eol_or_eof(&p);
1280                        break;
1281
1282                case T_EOL:
1283                        break;
1284
1285                case T_EOF:
1286                        return 1;
1287
1288                default:
1289                        printf("Ignoring unknown command: %.*s\n",
1290                               (int)(p - s), s);
1291                        eol_or_eof(&p);
1292                }
1293
1294                if (err < 0)
1295                        return err;
1296        }
1297}
1298
1299/*
1300 */
1301void destroy_pxe_menu(struct pxe_menu *cfg)
1302{
1303        struct list_head *pos, *n;
1304        struct pxe_label *label;
1305
1306        free(cfg->title);
1307        free(cfg->default_label);
1308
1309        list_for_each_safe(pos, n, &cfg->labels) {
1310                label = list_entry(pos, struct pxe_label, list);
1311
1312                label_destroy(label);
1313        }
1314
1315        free(cfg);
1316}
1317
1318struct pxe_menu *parse_pxefile(struct pxe_context *ctx, unsigned long menucfg)
1319{
1320        struct pxe_menu *cfg;
1321        char *buf;
1322        int r;
1323
1324        cfg = malloc(sizeof(struct pxe_menu));
1325        if (!cfg)
1326                return NULL;
1327
1328        memset(cfg, 0, sizeof(struct pxe_menu));
1329
1330        INIT_LIST_HEAD(&cfg->labels);
1331
1332        buf = map_sysmem(menucfg, 0);
1333        r = parse_pxefile_top(ctx, buf, menucfg, cfg, 1);
1334        unmap_sysmem(buf);
1335        if (r < 0) {
1336                destroy_pxe_menu(cfg);
1337                return NULL;
1338        }
1339
1340        return cfg;
1341}
1342
1343/*
1344 * Converts a pxe_menu struct into a menu struct for use with U-Boot's generic
1345 * menu code.
1346 */
1347static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
1348{
1349        struct pxe_label *label;
1350        struct list_head *pos;
1351        struct menu *m;
1352        int err;
1353        int i = 1;
1354        char *default_num = NULL;
1355
1356        /*
1357         * Create a menu and add items for all the labels.
1358         */
1359        m = menu_create(cfg->title, DIV_ROUND_UP(cfg->timeout, 10),
1360                        cfg->prompt, NULL, label_print, NULL, NULL);
1361        if (!m)
1362                return NULL;
1363
1364        list_for_each(pos, &cfg->labels) {
1365                label = list_entry(pos, struct pxe_label, list);
1366
1367                sprintf(label->num, "%d", i++);
1368                if (menu_item_add(m, label->num, label) != 1) {
1369                        menu_destroy(m);
1370                        return NULL;
1371                }
1372                if (cfg->default_label &&
1373                    (strcmp(label->name, cfg->default_label) == 0))
1374                        default_num = label->num;
1375        }
1376
1377        /*
1378         * After we've created items for each label in the menu, set the
1379         * menu's default label if one was specified.
1380         */
1381        if (default_num) {
1382                err = menu_default_set(m, default_num);
1383                if (err != 1) {
1384                        if (err != -ENOENT) {
1385                                menu_destroy(m);
1386                                return NULL;
1387                        }
1388
1389                        printf("Missing default: %s\n", cfg->default_label);
1390                }
1391        }
1392
1393        return m;
1394}
1395
1396/*
1397 * Try to boot any labels we have yet to attempt to boot.
1398 */
1399static void boot_unattempted_labels(struct pxe_context *ctx,
1400                                    struct pxe_menu *cfg)
1401{
1402        struct list_head *pos;
1403        struct pxe_label *label;
1404
1405        list_for_each(pos, &cfg->labels) {
1406                label = list_entry(pos, struct pxe_label, list);
1407
1408                if (!label->attempted)
1409                        label_boot(ctx, label);
1410        }
1411}
1412
1413void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
1414{
1415        void *choice;
1416        struct menu *m;
1417        int err;
1418
1419        if (IS_ENABLED(CONFIG_CMD_BMP)) {
1420                /* display BMP if available */
1421                if (cfg->bmp) {
1422                        if (get_relfile(ctx, cfg->bmp, image_load_addr, NULL)) {
1423                                if (CONFIG_IS_ENABLED(CMD_CLS))
1424                                        run_command("cls", 0);
1425                                bmp_display(image_load_addr,
1426                                            BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
1427                        } else {
1428                                printf("Skipping background bmp %s for failure\n",
1429                                       cfg->bmp);
1430                        }
1431                }
1432        }
1433
1434        m = pxe_menu_to_menu(cfg);
1435        if (!m)
1436                return;
1437
1438        err = menu_get_choice(m, &choice);
1439        menu_destroy(m);
1440
1441        /*
1442         * err == 1 means we got a choice back from menu_get_choice.
1443         *
1444         * err == -ENOENT if the menu was setup to select the default but no
1445         * default was set. in that case, we should continue trying to boot
1446         * labels that haven't been attempted yet.
1447         *
1448         * otherwise, the user interrupted or there was some other error and
1449         * we give up.
1450         */
1451
1452        if (err == 1) {
1453                err = label_boot(ctx, choice);
1454                if (!err)
1455                        return;
1456        } else if (err != -ENOENT) {
1457                return;
1458        }
1459
1460        boot_unattempted_labels(ctx, cfg);
1461}
1462
1463int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
1464                  pxe_getfile_func getfile, void *userdata,
1465                  bool allow_abs_path, const char *bootfile)
1466{
1467        const char *last_slash;
1468        size_t path_len = 0;
1469
1470        memset(ctx, '\0', sizeof(*ctx));
1471        ctx->cmdtp = cmdtp;
1472        ctx->getfile = getfile;
1473        ctx->userdata = userdata;
1474        ctx->allow_abs_path = allow_abs_path;
1475
1476        /* figure out the boot directory, if there is one */
1477        if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
1478                return -ENOSPC;
1479        ctx->bootdir = strdup(bootfile ? bootfile : "");
1480        if (!ctx->bootdir)
1481                return -ENOMEM;
1482
1483        if (bootfile) {
1484                last_slash = strrchr(bootfile, '/');
1485                if (last_slash)
1486                        path_len = (last_slash - bootfile) + 1;
1487        }
1488        ctx->bootdir[path_len] = '\0';
1489
1490        return 0;
1491}
1492
1493void pxe_destroy_ctx(struct pxe_context *ctx)
1494{
1495        free(ctx->bootdir);
1496}
1497
1498int pxe_process(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt)
1499{
1500        struct pxe_menu *cfg;
1501
1502        cfg = parse_pxefile(ctx, pxefile_addr_r);
1503        if (!cfg) {
1504                printf("Error parsing config file\n");
1505                return 1;
1506        }
1507
1508        if (prompt)
1509                cfg->prompt = 1;
1510
1511        handle_pxe_menu(ctx, cfg);
1512
1513        destroy_pxe_menu(cfg);
1514
1515        return 0;
1516}
1517