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