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