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