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