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