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