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