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