blob: 2f8714c4c09ca8e7e58aa1452988652d9af75abb [file] [log] [blame]
Jason Hobbsafc8cd92011-06-29 11:25:18 -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
29static char *from_env(char *envvar)
30{
31 char *ret;
32
33 ret = getenv(envvar);
34
35 if (!ret)
36 printf("missing environment variable: %s\n", envvar);
37
38 return ret;
39}
40
41/*
42 * Returns the ethaddr environment variable formated with -'s instead of :'s
43 */
44static void format_mac_pxecfg(char **outbuf)
45{
46 char *p, *ethaddr;
47
48 *outbuf = NULL;
49
50 ethaddr = from_env("ethaddr");
51
52 if (!ethaddr)
John Rigbya7dbc122011-07-13 23:05:19 -060053 ethaddr = from_env("usbethaddr");
54
55 if (!ethaddr)
Jason Hobbsafc8cd92011-06-29 11:25:18 -050056 return;
57
Loïc Minier8ed2c442011-08-17 15:32:55 +020058 /* "01-" MAC type prefix, dash-separated MAC address, zero */
59 *outbuf = malloc(3 + strlen(ethaddr) + 1);
Jason Hobbsafc8cd92011-06-29 11:25:18 -050060
61 if (*outbuf == NULL)
62 return;
63
Loïc Minier8ed2c442011-08-17 15:32:55 +020064 /* MAC type 1; ideally should be read from the DHCP/BOOTP reply packet,
65 * but in practice always 1 for Ethernet */
66 sprintf(*outbuf, "01-%s", ethaddr);
67
Loïc Minier01915ec2011-08-17 22:57:11 +020068 /* convert colons to dashes and lower case the MAC address */
Loïc Minier8ed2c442011-08-17 15:32:55 +020069 for (p = *outbuf + 3; *p; p++) {
Jason Hobbsafc8cd92011-06-29 11:25:18 -050070 if (*p == ':')
71 *p = '-';
Loïc Minier01915ec2011-08-17 22:57:11 +020072 else
73 *p = tolower(*p);
Jason Hobbsafc8cd92011-06-29 11:25:18 -050074 }
75}
76
77/*
78 * Returns the directory the file specified in the bootfile env variable is
79 * in.
80 */
81static char *get_bootfile_path(void)
82{
83 char *bootfile, *bootfile_path, *last_slash;
84 size_t path_len;
85
86 bootfile = from_env("bootfile");
87
88 if (!bootfile)
89 return NULL;
90
91 last_slash = strrchr(bootfile, '/');
92
93 if (last_slash == NULL)
94 return NULL;
95
96 path_len = (last_slash - bootfile) + 1;
97
98 bootfile_path = malloc(path_len + 1);
99
100 if (bootfile_path == NULL) {
101 printf("out of memory\n");
102 return NULL;
103 }
104
105 strncpy(bootfile_path, bootfile, path_len);
106
107 bootfile_path[path_len] = '\0';
108
109 return bootfile_path;
110}
111
112/*
113 * As in pxelinux, paths to files in pxecfg files are relative to the location
114 * of bootfile. get_relfile takes a path from a pxecfg file and joins it with
115 * the bootfile path to get the full path to the target file.
116 */
117static int get_relfile(char *file_path, void *file_addr)
118{
119 char *bootfile_path;
120 size_t path_len;
121 char relfile[MAX_TFTP_PATH_LEN+1];
122 char addr_buf[10];
123 char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
124
125 bootfile_path = get_bootfile_path();
126
127 path_len = strlen(file_path);
128
129 if (bootfile_path)
130 path_len += strlen(bootfile_path);
131
132 if (path_len > MAX_TFTP_PATH_LEN) {
133 printf("Base path too long (%s%s)\n",
134 bootfile_path ? bootfile_path : "",
135 file_path);
136
137 if (bootfile_path)
138 free(bootfile_path);
139
140 return -ENAMETOOLONG;
141 }
142
143 sprintf(relfile, "%s%s",
144 bootfile_path ? bootfile_path : "",
145 file_path);
146
147 if (bootfile_path)
148 free(bootfile_path);
149
150 printf("Retreiving file: %s\n", relfile);
151
152 sprintf(addr_buf, "%p", file_addr);
153
154 tftp_argv[1] = addr_buf;
155 tftp_argv[2] = relfile;
156
157 if (do_tftpb(NULL, 0, 3, tftp_argv)) {
158 printf("File not found\n");
159 return -ENOENT;
160 }
161
162 return 1;
163}
164
165static int get_pxecfg_file(char *file_path, void *file_addr)
166{
167 unsigned long config_file_size;
168 int err;
169
170 err = get_relfile(file_path, file_addr);
171
172 if (err < 0)
173 return err;
174
175 config_file_size = simple_strtoul(getenv("filesize"), NULL, 16);
176 *(char *)(file_addr + config_file_size) = '\0';
177
178 return 1;
179}
180
181static int get_pxelinux_path(char *file, void *pxecfg_addr)
182{
183 size_t base_len = strlen("pxelinux.cfg/");
184 char path[MAX_TFTP_PATH_LEN+1];
185
186 if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
187 printf("path too long, skipping\n");
188 return -ENAMETOOLONG;
189 }
190
191 sprintf(path, "pxelinux.cfg/%s", file);
192
193 return get_pxecfg_file(path, pxecfg_addr);
194}
195
196static int pxecfg_uuid_path(void *pxecfg_addr)
197{
198 char *uuid_str;
199
200 uuid_str = from_env("pxeuuid");
201
202 if (!uuid_str)
203 return -ENOENT;
204
205 return get_pxelinux_path(uuid_str, pxecfg_addr);
206}
207
208static int pxecfg_mac_path(void *pxecfg_addr)
209{
210 char *mac_str = NULL;
211
212 format_mac_pxecfg(&mac_str);
213
214 if (!mac_str)
215 return -ENOENT;
216
217 return get_pxelinux_path(mac_str, pxecfg_addr);
218}
219
220static int pxecfg_ipaddr_paths(void *pxecfg_addr)
221{
222 char ip_addr[9];
223 int mask_pos, err;
224
225 sprintf(ip_addr, "%08X", ntohl(NetOurIP));
226
227 for (mask_pos = 7; mask_pos >= 0; mask_pos--) {
228 err = get_pxelinux_path(ip_addr, pxecfg_addr);
229
230 if (err > 0)
231 return err;
232
233 ip_addr[mask_pos] = '\0';
234 }
235
236 return -ENOENT;
237}
238
239/*
240 * Follows pxelinux's rules to download a pxecfg file from a tftp server. The
241 * file is stored at the location given by the pxecfg_addr environment
242 * variable, which must be set.
243 *
244 * UUID comes from pxeuuid env variable, if defined
245 * MAC addr comes from ethaddr env variable, if defined
246 * IP
247 *
248 * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
249 */
250static int get_pxecfg(int argc, char * const argv[])
251{
252 char *pxecfg_ram;
253 void *pxecfg_addr;
254
255 pxecfg_ram = from_env("pxecfg_ram");
256
257 if (!pxecfg_ram)
258 return 1;
259
260 pxecfg_addr = (void *)simple_strtoul(pxecfg_ram, NULL, 16);
261
262 if (pxecfg_uuid_path(pxecfg_addr) > 0
263 || pxecfg_mac_path(pxecfg_addr) > 0
264 || pxecfg_ipaddr_paths(pxecfg_addr) > 0
265 || get_pxelinux_path("default", pxecfg_addr) > 0) {
266
267 printf("Config file found\n");
268
269 return 1;
270 }
271
272 printf("Config file not found\n");
273
274 return 0;
275}
276
277static int get_relfile_envaddr(char *file_path, char *envaddr_name)
278{
279 void *file_addr;
280 char *envaddr;
281
282 envaddr = from_env(envaddr_name);
283
284 if (!envaddr)
285 return -ENOENT;
286
287 file_addr = (void *)simple_strtoul(envaddr, NULL, 16);
288
289 return get_relfile(file_path, file_addr);
290}
291
292struct pxecfg_label {
293 char *name;
294 char *kernel;
295 char *append;
296 char *initrd;
297 int attempted;
298 int localboot;
299 struct list_head list;
300};
301
302struct pxecfg {
303 char *title;
304 char *default_label;
305 int timeout;
306 int prompt;
307 struct list_head labels;
308};
309
310struct pxecfg_label *label_create(void)
311{
312 struct pxecfg_label *label;
313
314 label = malloc(sizeof *label);
315
316 if (!label)
317 return NULL;
318
319 label->name = NULL;
320 label->kernel = NULL;
321 label->append = NULL;
322 label->initrd = NULL;
323 label->localboot = 0;
324 label->attempted = 0;
325
326 return label;
327}
328
329static void label_destroy(struct pxecfg_label *label)
330{
331 if (label->name)
332 free(label->name);
333
334 if (label->kernel)
335 free(label->kernel);
336
337 if (label->append)
338 free(label->append);
339
340 if (label->initrd)
341 free(label->initrd);
342
343 free(label);
344}
345
346static void label_print(void *data)
347{
348 struct pxecfg_label *label = data;
349
350 printf("Label: %s\n", label->name);
351
352 if (label->kernel)
353 printf("\tkernel: %s\n", label->kernel);
354
355 if (label->append)
356 printf("\tappend: %s\n", label->append);
357
358 if (label->initrd)
359 printf("\tinitrd: %s\n", label->initrd);
360}
361
362static int label_localboot(struct pxecfg_label *label)
363{
364 char *localcmd, *dupcmd;
365 int ret;
366
367 localcmd = from_env("localcmd");
368
369 if (!localcmd)
370 return -ENOENT;
371
372 /*
373 * dup the command to avoid any issues with the version of it existing
374 * in the environment changing during the execution of the command.
375 */
376 dupcmd = strdup(localcmd);
377
378 if (!dupcmd) {
379 printf("out of memory\n");
380 return -ENOMEM;
381 }
382
383 if (label->append)
384 setenv("bootargs", label->append);
385
386 printf("running: %s\n", dupcmd);
387
388 ret = run_command2(dupcmd, 0);
389
390 free(dupcmd);
391
392 return ret;
393}
394
395/*
396 * Do what it takes to boot a chosen label.
397 *
398 * Retreive the kernel and initrd, and prepare bootargs.
399 */
400static void label_boot(struct pxecfg_label *label)
401{
402 char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
403
404 label_print(label);
405
406 label->attempted = 1;
407
408 if (label->localboot) {
409 label_localboot(label);
410 return;
411 }
412
413 if (label->kernel == NULL) {
414 printf("No kernel given, skipping label\n");
415 return;
416 }
417
418 if (label->initrd) {
419 if (get_relfile_envaddr(label->initrd, "initrd_ram") < 0) {
420 printf("Skipping label\n");
421 return;
422 }
423
424 bootm_argv[2] = getenv("initrd_ram");
425 } else {
426 bootm_argv[2] = "-";
427 }
428
429 if (get_relfile_envaddr(label->kernel, "kernel_ram") < 0) {
430 printf("Skipping label\n");
431 return;
432 }
433
434 if (label->append)
435 setenv("bootargs", label->append);
436
437 bootm_argv[1] = getenv("kernel_ram");
438
439 /*
440 * fdt usage is optional - if unset, this stays NULL.
441 */
442 bootm_argv[3] = getenv("fdtaddr");
443
Ricardo Salveti de Araujo2f84e8e2011-07-11 01:37:45 -0300444 if (bootm_argv[3])
445 do_bootm(NULL, 0, 4, bootm_argv);
446 else
447 do_bootm(NULL, 0, 3, bootm_argv);
Jason Hobbsafc8cd92011-06-29 11:25:18 -0500448}
449
450enum token_type {
451 T_EOL,
452 T_STRING,
453 T_EOF,
454 T_MENU,
455 T_TITLE,
456 T_TIMEOUT,
457 T_LABEL,
458 T_KERNEL,
459 T_APPEND,
460 T_INITRD,
461 T_LOCALBOOT,
462 T_DEFAULT,
463 T_PROMPT,
464 T_INCLUDE,
465 T_INVALID
466};
467
468struct token {
469 char *val;
470 enum token_type type;
471};
472
473enum lex_state {
474 L_NORMAL = 0,
475 L_KEYWORD,
476 L_SLITERAL
477};
478
479static const struct token keywords[] = {
480 {"menu", T_MENU},
481 {"title", T_TITLE},
482 {"timeout", T_TIMEOUT},
483 {"default", T_DEFAULT},
484 {"prompt", T_PROMPT},
485 {"label", T_LABEL},
486 {"kernel", T_KERNEL},
487 {"localboot", T_LOCALBOOT},
488 {"append", T_APPEND},
489 {"initrd", T_INITRD},
490 {"include", T_INCLUDE},
491 {NULL, T_INVALID}
492};
493
494static char *get_string(char **p, struct token *t, char delim, int lower)
495{
496 char *b, *e;
497 size_t len, i;
498
499 b = e = *p;
500
501 while (*e) {
502 if ((delim == ' ' && isspace(*e)) || delim == *e)
503 break;
504 e++;
505 }
506
507 len = e - b;
508
509 t->val = malloc(len + 1);
510 if (!t->val) {
511 printf("out of memory\n");
512 return NULL;
513 }
514
515 for (i = 0; i < len; i++, b++) {
516 if (lower)
517 t->val[i] = tolower(*b);
518 else
519 t->val[i] = *b;
520 }
521
522 t->val[len] = '\0';
523
524 *p = e;
525
526 t->type = T_STRING;
527
528 return t->val;
529}
530
531static void get_keyword(struct token *t)
532{
533 int i;
534
535 for (i = 0; keywords[i].val; i++) {
536 if (!strcmp(t->val, keywords[i].val)) {
537 t->type = keywords[i].type;
538 break;
539 }
540 }
541}
542
543static void get_token(char **p, struct token *t, enum lex_state state)
544{
545 char *c = *p;
546
547 t->type = T_INVALID;
548
549 /* eat non EOL whitespace */
550 while (*c == ' ' || *c == '\t')
551 c++;
552
553 /* eat comments */
554 if (*c == '#') {
555 while (*c && *c != '\n')
556 c++;
557 }
558
559 if (*c == '\n') {
560 t->type = T_EOL;
561 c++;
562 } else if (*c == '\0') {
563 t->type = T_EOF;
564 c++;
565 } else if (state == L_SLITERAL) {
566 get_string(&c, t, '\n', 0);
567 } else if (state == L_KEYWORD) {
568 get_string(&c, t, ' ', 1);
569 get_keyword(t);
570 }
571
572 *p = c;
573}
574
575static void eol_or_eof(char **c)
576{
577 while (**c && **c != '\n')
578 (*c)++;
579}
580
581static int parse_sliteral(char **c, char **dst)
582{
583 struct token t;
584 char *s = *c;
585
586 get_token(c, &t, L_SLITERAL);
587
588 if (t.type != T_STRING) {
589 printf("Expected string literal: %.*s\n", (int)(*c - s), s);
590 return -EINVAL;
591 }
592
593 *dst = t.val;
594
595 return 1;
596}
597
598static int parse_integer(char **c, int *dst)
599{
600 struct token t;
601 char *s = *c;
602
603 get_token(c, &t, L_SLITERAL);
604
605 if (t.type != T_STRING) {
606 printf("Expected string: %.*s\n", (int)(*c - s), s);
607 return -EINVAL;
608 }
609
610 *dst = (int)simple_strtoul(t.val, NULL, 10);
611
612 free(t.val);
613
614 return 1;
615}
616
617static int parse_pxecfg_top(char *p, struct pxecfg *cfg, int nest_level);
618
619static int handle_include(char **c, char *base,
620 struct pxecfg *cfg, int nest_level)
621{
622 char *include_path;
623 int err;
624
625 err = parse_sliteral(c, &include_path);
626
627 if (err < 0) {
628 printf("Expected include path\n");
629 return err;
630 }
631
632 err = get_pxecfg_file(include_path, base);
633
634 if (err < 0) {
635 printf("Couldn't get %s\n", include_path);
636 return err;
637 }
638
639 return parse_pxecfg_top(base, cfg, nest_level);
640}
641
642static int parse_menu(char **c, struct pxecfg *cfg, char *b, int nest_level)
643{
644 struct token t;
645 char *s = *c;
646 int err;
647
648 get_token(c, &t, L_KEYWORD);
649
650 switch (t.type) {
651 case T_TITLE:
652 err = parse_sliteral(c, &cfg->title);
653
654 break;
655
656 case T_INCLUDE:
657 err = handle_include(c, b + strlen(b) + 1, cfg,
658 nest_level + 1);
659 break;
660
661 default:
662 printf("Ignoring malformed menu command: %.*s\n",
663 (int)(*c - s), s);
664 }
665
666 if (err < 0)
667 return err;
668
669 eol_or_eof(c);
670
671 return 1;
672}
673
674static int parse_label_menu(char **c, struct pxecfg *cfg,
675 struct pxecfg_label *label)
676{
677 struct token t;
678 char *s;
679
680 s = *c;
681
682 get_token(c, &t, L_KEYWORD);
683
684 switch (t.type) {
685 case T_DEFAULT:
686 if (cfg->default_label)
687 free(cfg->default_label);
688
689 cfg->default_label = strdup(label->name);
690
691 if (!cfg->default_label)
692 return -ENOMEM;
693
694 break;
695 default:
696 printf("Ignoring malformed menu command: %.*s\n",
697 (int)(*c - s), s);
698 }
699
700 eol_or_eof(c);
701
702 return 0;
703}
704
705static int parse_label(char **c, struct pxecfg *cfg)
706{
707 struct token t;
708 char *s;
709 struct pxecfg_label *label;
710 int err;
711
712 label = label_create();
713 if (!label)
714 return -ENOMEM;
715
716 err = parse_sliteral(c, &label->name);
717 if (err < 0) {
718 printf("Expected label name\n");
719 label_destroy(label);
720 return -EINVAL;
721 }
722
723 list_add_tail(&label->list, &cfg->labels);
724
725 while (1) {
726 s = *c;
727 get_token(c, &t, L_KEYWORD);
728
729 err = 0;
730 switch (t.type) {
731 case T_MENU:
732 err = parse_label_menu(c, cfg, label);
733 break;
734
735 case T_KERNEL:
736 err = parse_sliteral(c, &label->kernel);
737 break;
738
739 case T_APPEND:
740 err = parse_sliteral(c, &label->append);
741 break;
742
743 case T_INITRD:
744 err = parse_sliteral(c, &label->initrd);
745 break;
746
747 case T_LOCALBOOT:
748 err = parse_integer(c, &label->localboot);
749 break;
750
751 case T_EOL:
752 break;
753
754 /*
755 * A label ends when we either get to the end of a file, or
756 * get some input we otherwise don't have a handler defined
757 * for.
758 */
759 default:
760 /* put it back */
761 *c = s;
762 return 1;
763 }
764
765 if (err < 0)
766 return err;
767 }
768}
769
770#define MAX_NEST_LEVEL 16
771
772static int parse_pxecfg_top(char *p, struct pxecfg *cfg, int nest_level)
773{
774 struct token t;
775 char *s, *b, *label_name;
776 int err;
777
778 b = p;
779
780 if (nest_level > MAX_NEST_LEVEL) {
781 printf("Maximum nesting exceeded\n");
782 return -EMLINK;
783 }
784
785 while (1) {
786 s = p;
787
788 get_token(&p, &t, L_KEYWORD);
789
790 err = 0;
791 switch (t.type) {
792 case T_MENU:
793 err = parse_menu(&p, cfg, b, nest_level);
794 break;
795
796 case T_TIMEOUT:
797 err = parse_integer(&p, &cfg->timeout);
798 break;
799
800 case T_LABEL:
801 err = parse_label(&p, cfg);
802 break;
803
804 case T_DEFAULT:
805 err = parse_sliteral(&p, &label_name);
806
807 if (label_name) {
808 if (cfg->default_label)
809 free(cfg->default_label);
810
811 cfg->default_label = label_name;
812 }
813
814 break;
815
816 case T_PROMPT:
817 err = parse_integer(&p, &cfg->prompt);
818 break;
819
820 case T_EOL:
821 break;
822
823 case T_EOF:
824 return 1;
825
826 default:
827 printf("Ignoring unknown command: %.*s\n",
828 (int)(p - s), s);
829 eol_or_eof(&p);
830 }
831
832 if (err < 0)
833 return err;
834 }
835}
836
837static void destroy_pxecfg(struct pxecfg *cfg)
838{
839 struct list_head *pos, *n;
840 struct pxecfg_label *label;
841
842 if (cfg->title)
843 free(cfg->title);
844
845 if (cfg->default_label)
846 free(cfg->default_label);
847
848 list_for_each_safe(pos, n, &cfg->labels) {
849 label = list_entry(pos, struct pxecfg_label, list);
850
851 label_destroy(label);
852 }
853
854 free(cfg);
855}
856
857static struct pxecfg *parse_pxecfg(char *menucfg)
858{
859 struct pxecfg *cfg;
860
861 cfg = malloc(sizeof(*cfg));
862
863 if (!cfg) {
864 printf("Out of memory\n");
865 return NULL;
866 }
867
868 cfg->timeout = 0;
869 cfg->prompt = 0;
870 cfg->default_label = NULL;
871 cfg->title = NULL;
872
873 INIT_LIST_HEAD(&cfg->labels);
874
875 if (parse_pxecfg_top(menucfg, cfg, 1) < 0) {
876 destroy_pxecfg(cfg);
877 return NULL;
878 }
879
880 return cfg;
881}
882
883static struct menu *pxecfg_to_menu(struct pxecfg *cfg)
884{
885 struct pxecfg_label *label;
886 struct list_head *pos;
887 struct menu *m;
888 int err;
889
890 m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print);
891
892 if (!m)
893 return NULL;
894
895 list_for_each(pos, &cfg->labels) {
896 label = list_entry(pos, struct pxecfg_label, list);
897
898 if (menu_item_add(m, label->name, label) != 1) {
899 menu_destroy(m);
900 return NULL;
901 }
902 }
903
904 if (cfg->default_label) {
905 err = menu_default_set(m, cfg->default_label);
906 if (err != 1) {
907 if (err != -ENOENT) {
908 menu_destroy(m);
909 return NULL;
910 }
911
912 printf("Missing default: %s\n", cfg->default_label);
913 }
914 }
915
916 return m;
917}
918
919static void boot_unattempted_labels(struct pxecfg *cfg)
920{
921 struct list_head *pos;
922 struct pxecfg_label *label;
923
924 list_for_each(pos, &cfg->labels) {
925 label = list_entry(pos, struct pxecfg_label, list);
926
927 if (!label->attempted)
928 label_boot(label);
929 }
930}
931
932static void handle_pxecfg(struct pxecfg *cfg)
933{
934 void *choice;
935 struct menu *m;
936
937 m = pxecfg_to_menu(cfg);
938 if (!m)
939 return;
940
941 if (menu_get_choice(m, &choice) == 1)
942 label_boot(choice);
943
944 menu_destroy(m);
945
946 boot_unattempted_labels(cfg);
947}
948
949static int boot_pxecfg(int argc, char * const argv[])
950{
951 unsigned long pxecfg_addr;
952 struct pxecfg *cfg;
953 char *pxecfg_ram;
954
955 if (argc == 2) {
956 pxecfg_ram = from_env("pxecfg_ram");
957 if (!pxecfg_ram)
958 return 1;
959
960 pxecfg_addr = simple_strtoul(pxecfg_ram, NULL, 16);
961 } else if (argc == 3) {
962 pxecfg_addr = simple_strtoul(argv[2], NULL, 16);
963 } else {
964 printf("Invalid number of arguments\n");
965 return 1;
966 }
967
968 cfg = parse_pxecfg((char *)(pxecfg_addr));
969
970 if (cfg == NULL) {
971 printf("Error parsing config file\n");
972 return 1;
973 }
974
975 handle_pxecfg(cfg);
976
977 destroy_pxecfg(cfg);
978
979 return 0;
980}
981
982int do_pxecfg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
983{
984 if (argc < 2) {
985 printf("pxecfg requires at least one argument\n");
986 return EINVAL;
987 }
988
989 if (!strcmp(argv[1], "get"))
990 return get_pxecfg(argc, argv);
991
992 if (!strcmp(argv[1], "boot"))
993 return boot_pxecfg(argc, argv);
994
995 printf("Invalid pxecfg command: %s\n", argv[1]);
996
997 return EINVAL;
998}
999
1000U_BOOT_CMD(
1001 pxecfg, 2, 1, do_pxecfg,
1002 "commands to get and boot from pxecfg files",
1003 "get - try to retrieve a pxecfg file using tftp\npxecfg "
1004 "boot [pxecfg_addr] - boot from the pxecfg file at pxecfg_addr\n"
1005);