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