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