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