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