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