X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=common%2Fcmd_pxe.c;h=7e32c95df3217bc575dd39be2a71fd3f6e0deea3;hp=ee75db96853345f503a5b569ff720caf0a49712c;hb=46eeb1405961f091aac2c7ccef593075c1e4d137;hpb=1e362dc3e799fd86722a60f5639e52a67dfc0658 diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index ee75db9685..7e32c95df3 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -1,19 +1,10 @@ /* * Copyright 2010-2011 Calxeda, Inc. + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * SPDX-License-Identifier: GPL-2.0+ */ + #include #include #include @@ -21,17 +12,30 @@ #include #include #include +#include #include "menu.h" +#include "cli.h" #define MAX_TFTP_PATH_LEN 127 +const char *pxe_default_paths[] = { +#ifdef CONFIG_SYS_SOC + "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC, +#endif + "default-" CONFIG_SYS_ARCH, + "default", + NULL +}; + +static bool is_pxe; + /* * Like getenv, but prints an error if envvar isn't defined in the * environment. It always returns what getenv does, so it can be used in * place of getenv without changing error handling otherwise. */ -static char *from_env(char *envvar) +static char *from_env(const char *envvar) { char *ret; @@ -43,6 +47,7 @@ static char *from_env(char *envvar) return ret; } +#ifdef CONFIG_CMD_NET /* * Convert an ethaddr from the environment to the format used by pxelinux * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to @@ -55,40 +60,25 @@ static char *from_env(char *envvar) */ static int format_mac_pxe(char *outbuf, size_t outbuf_len) { - size_t ethaddr_len; - char *p, *ethaddr; + uchar ethaddr[6]; - ethaddr = from_env("ethaddr"); - - if (!ethaddr) - return -ENOENT; - - ethaddr_len = strlen(ethaddr); - - /* - * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at - * the end. - */ - if (outbuf_len < ethaddr_len + 4) { - printf("outbuf is too small (%d < %d)\n", - outbuf_len, ethaddr_len + 4); + if (outbuf_len < 21) { + printf("outbuf is too small (%zd < 21)\n", outbuf_len); return -EINVAL; } - strcpy(outbuf, "01-"); - - for (p = outbuf + 3; *ethaddr; ethaddr++, p++) { - if (*ethaddr == ':') - *p = '-'; - else - *p = tolower(*ethaddr); - } + if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(), + ethaddr)) + return -ENOENT; - *p = '\0'; + sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x", + ethaddr[0], ethaddr[1], ethaddr[2], + ethaddr[3], ethaddr[4], ethaddr[5]); return 1; } +#endif /* * Returns the directory the file specified in the bootfile env variable is @@ -101,7 +91,8 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path, char *bootfile, *last_slash; size_t path_len = 0; - if (file_path[0] == '/') + /* Only syslinux allows absolute paths */ + if (file_path[0] == '/' && !is_pxe) goto ret; bootfile = from_env("bootfile"); @@ -117,7 +108,7 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path, path_len = (last_slash - bootfile) + 1; if (bootfile_path_size < path_len) { - printf("bootfile_path too small. (%d < %d)\n", + printf("bootfile_path too small. (%zd < %zd)\n", bootfile_path_size, path_len); return -1; @@ -131,44 +122,59 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path, return 1; } -static int (*do_getfile)(char *file_path, char *file_addr); +static int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr); -static int do_get_tftp(char *file_path, char *file_addr) +#ifdef CONFIG_CMD_NET +static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr) { char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; tftp_argv[1] = file_addr; - tftp_argv[2] = file_path; + tftp_argv[2] = (void *)file_path; - if (do_tftpb(NULL, 0, 3, tftp_argv)) + if (do_tftpb(cmdtp, 0, 3, tftp_argv)) return -ENOENT; return 1; } +#endif static char *fs_argv[5]; -static int do_get_ext2(char *file_path, char *file_addr) +static int do_get_ext2(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr) { #ifdef CONFIG_CMD_EXT2 fs_argv[0] = "ext2load"; fs_argv[3] = file_addr; - fs_argv[4] = file_path; + fs_argv[4] = (void *)file_path; - if (!do_ext2load(NULL, 0, 5, fs_argv)) + if (!do_ext2load(cmdtp, 0, 5, fs_argv)) return 1; #endif return -ENOENT; } -static int do_get_fat(char *file_path, char *file_addr) +static int do_get_fat(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr) { #ifdef CONFIG_CMD_FAT fs_argv[0] = "fatload"; fs_argv[3] = file_addr; - fs_argv[4] = file_path; + fs_argv[4] = (void *)file_path; - if (!do_fat_fsload(NULL, 0, 5, fs_argv)) + if (!do_fat_fsload(cmdtp, 0, 5, fs_argv)) + return 1; +#endif + return -ENOENT; +} + +static int do_get_any(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr) +{ +#ifdef CONFIG_CMD_FS_GENERIC + fs_argv[0] = "load"; + fs_argv[3] = file_addr; + fs_argv[4] = (void *)file_path; + + if (!do_load(cmdtp, 0, 5, fs_argv, FS_TYPE_ANY)) return 1; #endif return -ENOENT; @@ -182,7 +188,7 @@ static int do_get_fat(char *file_path, char *file_addr) * * Returns 1 for success, or < 0 on error. */ -static int get_relfile(char *file_path, void *file_addr) +static int get_relfile(cmd_tbl_t *cmdtp, const char *file_path, void *file_addr) { size_t path_len; char relfile[MAX_TFTP_PATH_LEN+1]; @@ -211,7 +217,7 @@ static int get_relfile(char *file_path, void *file_addr) sprintf(addr_buf, "%p", file_addr); - return do_getfile(relfile, addr_buf); + return do_getfile(cmdtp, relfile, addr_buf); } /* @@ -221,13 +227,13 @@ static int get_relfile(char *file_path, void *file_addr) * * Returns 1 on success, or < 0 for error. */ -static int get_pxe_file(char *file_path, void *file_addr) +static int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path, void *file_addr) { unsigned long config_file_size; char *tftp_filesize; int err; - err = get_relfile(file_path, file_addr); + err = get_relfile(cmdtp, file_path, file_addr); if (err < 0) return err; @@ -249,6 +255,8 @@ static int get_pxe_file(char *file_path, void *file_addr) return 1; } +#ifdef CONFIG_CMD_NET + #define PXELINUX_DIR "pxelinux.cfg/" /* @@ -258,7 +266,7 @@ static int get_pxe_file(char *file_path, void *file_addr) * * Returns 1 on success or < 0 on error. */ -static int get_pxelinux_path(char *file, void *pxefile_addr_r) +static int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file, void *pxefile_addr_r) { size_t base_len = strlen(PXELINUX_DIR); char path[MAX_TFTP_PATH_LEN+1]; @@ -271,7 +279,7 @@ static int get_pxelinux_path(char *file, void *pxefile_addr_r) sprintf(path, PXELINUX_DIR "%s", file); - return get_pxe_file(path, pxefile_addr_r); + return get_pxe_file(cmdtp, path, pxefile_addr_r); } /* @@ -279,7 +287,7 @@ static int get_pxelinux_path(char *file, void *pxefile_addr_r) * * Returns 1 on success or < 0 on error. */ -static int pxe_uuid_path(void *pxefile_addr_r) +static int pxe_uuid_path(cmd_tbl_t *cmdtp, void *pxefile_addr_r) { char *uuid_str; @@ -288,7 +296,7 @@ static int pxe_uuid_path(void *pxefile_addr_r) if (!uuid_str) return -ENOENT; - return get_pxelinux_path(uuid_str, pxefile_addr_r); + return get_pxelinux_path(cmdtp, uuid_str, pxefile_addr_r); } /* @@ -297,7 +305,7 @@ static int pxe_uuid_path(void *pxefile_addr_r) * * Returns 1 on success or < 0 on error. */ -static int pxe_mac_path(void *pxefile_addr_r) +static int pxe_mac_path(cmd_tbl_t *cmdtp, void *pxefile_addr_r) { char mac_str[21]; int err; @@ -307,7 +315,7 @@ static int pxe_mac_path(void *pxefile_addr_r) if (err < 0) return err; - return get_pxelinux_path(mac_str, pxefile_addr_r); + return get_pxelinux_path(cmdtp, mac_str, pxefile_addr_r); } /* @@ -317,7 +325,7 @@ static int pxe_mac_path(void *pxefile_addr_r) * * Returns 1 on success or < 0 on error. */ -static int pxe_ipaddr_paths(void *pxefile_addr_r) +static int pxe_ipaddr_paths(cmd_tbl_t *cmdtp, void *pxefile_addr_r) { char ip_addr[9]; int mask_pos, err; @@ -325,7 +333,7 @@ static int pxe_ipaddr_paths(void *pxefile_addr_r) sprintf(ip_addr, "%08X", ntohl(NetOurIP)); for (mask_pos = 7; mask_pos >= 0; mask_pos--) { - err = get_pxelinux_path(ip_addr, pxefile_addr_r); + err = get_pxelinux_path(cmdtp, ip_addr, pxefile_addr_r); if (err > 0) return err; @@ -355,7 +363,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *pxefile_addr_str; unsigned long pxefile_addr_r; - int err; + int err, i = 0; do_getfile = do_get_tftp; @@ -376,20 +384,28 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * Keep trying paths until we successfully get a file we're looking * for. */ - if (pxe_uuid_path((void *)pxefile_addr_r) > 0 - || pxe_mac_path((void *)pxefile_addr_r) > 0 - || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 - || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { - + if (pxe_uuid_path(cmdtp, (void *)pxefile_addr_r) > 0 || + pxe_mac_path(cmdtp, (void *)pxefile_addr_r) > 0 || + pxe_ipaddr_paths(cmdtp, (void *)pxefile_addr_r) > 0) { printf("Config file found\n"); return 0; } + while (pxe_default_paths[i]) { + if (get_pxelinux_path(cmdtp, pxe_default_paths[i], + (void *)pxefile_addr_r) > 0) { + printf("Config file found\n"); + return 0; + } + i++; + } + printf("Config file not found\n"); return 1; } +#endif /* * Wrapper to make it easier to store the file at file_path in the location @@ -398,7 +414,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * * Returns 1 on success or < 0 on error. */ -static int get_relfile_envaddr(char *file_path, char *envaddr_name) +static int get_relfile_envaddr(cmd_tbl_t *cmdtp, const char *file_path, const char *envaddr_name) { unsigned long file_addr; char *envaddr; @@ -411,7 +427,7 @@ static int get_relfile_envaddr(char *file_path, char *envaddr_name) if (strict_strtoul(envaddr, 16, &file_addr) < 0) return -EINVAL; - return get_relfile(file_path, (void *)file_addr); + return get_relfile(cmdtp, file_path, (void *)file_addr); } /* @@ -445,14 +461,18 @@ static int get_relfile_envaddr(char *file_path, char *envaddr_name) * list - lets these form a list, which a pxe_menu struct will hold. */ struct pxe_label { + char num[4]; char *name; char *menu; char *kernel; char *append; char *initrd; char *fdt; + char *fdtdir; + int ipappend; int attempted; int localboot; + int localboot_val; struct list_head list; }; @@ -521,6 +541,9 @@ static void label_destroy(struct pxe_label *label) if (label->fdt) free(label->fdt); + if (label->fdtdir) + free(label->fdtdir); + free(label); } @@ -533,21 +556,9 @@ static void label_destroy(struct pxe_label *label) static void label_print(void *data) { struct pxe_label *label = data; - const char *c = label->menu ? label->menu : label->kernel; - - printf("%s:\t%s\n", label->name, c); - - if (label->kernel) - printf("\t\tkernel: %s\n", label->kernel); - - if (label->append) - printf("\t\tappend: %s\n", label->append); + const char *c = label->menu ? label->menu : label->name; - if (label->initrd) - printf("\t\tinitrd: %s\n", label->initrd); - - if (label->fdt) - printf("\tfdt: %s\n", label->fdt); + printf("%s:\t%s\n", label->num, c); } /* @@ -568,8 +579,12 @@ static int label_localboot(struct pxe_label *label) if (!localcmd) return -ENOENT; - if (label->append) - setenv("bootargs", label->append); + if (label->append) { + char bootargs[CONFIG_SYS_CBSIZE]; + + cli_simple_process_macros(label->append, bootargs); + setenv("bootargs", bootargs); + } debug("running: %s\n", localcmd); @@ -591,46 +606,92 @@ static int label_localboot(struct pxe_label *label) * If the label specifies an 'append' line, its contents will overwrite that * of the 'bootargs' environment variable. */ -static void label_boot(struct pxe_label *label) +static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label) { char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; + char initrd_str[22]; + char mac_str[29] = ""; + char ip_str[68] = ""; int bootm_argc = 3; + int len = 0; + ulong kernel_addr; + void *buf; label_print(label); label->attempted = 1; if (label->localboot) { - label_localboot(label); - return; + if (label->localboot_val >= 0) + label_localboot(label); + return 0; } if (label->kernel == NULL) { printf("No kernel given, skipping %s\n", label->name); - return; + return 1; } if (label->initrd) { - if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) { + if (get_relfile_envaddr(cmdtp, label->initrd, "ramdisk_addr_r") < 0) { printf("Skipping %s for failure retrieving initrd\n", label->name); - return; + return 1; } - bootm_argv[2] = getenv("ramdisk_addr_r"); + bootm_argv[2] = initrd_str; + strcpy(bootm_argv[2], getenv("ramdisk_addr_r")); + strcat(bootm_argv[2], ":"); + strcat(bootm_argv[2], getenv("filesize")); } else { bootm_argv[2] = "-"; } - if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) { + if (get_relfile_envaddr(cmdtp, label->kernel, "kernel_addr_r") < 0) { printf("Skipping %s for failure retrieving kernel\n", label->name); - return; + return 1; } - if (label->append) - setenv("bootargs", label->append); + if (label->ipappend & 0x1) { + sprintf(ip_str, " ip=%s:%s:%s:%s", + getenv("ipaddr"), getenv("serverip"), + getenv("gatewayip"), getenv("netmask")); + } + +#ifdef CONFIG_CMD_NET + if (label->ipappend & 0x2) { + int err; + strcpy(mac_str, " BOOTIF="); + err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); + if (err < 0) + mac_str[0] = '\0'; + } +#endif + + if ((label->ipappend & 0x3) || label->append) { + char bootargs[CONFIG_SYS_CBSIZE] = ""; + char finalbootargs[CONFIG_SYS_CBSIZE]; + + if (strlen(label->append ?: "") + + strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) { + printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n", + strlen(label->append ?: ""), + strlen(ip_str), strlen(mac_str), + sizeof(bootargs)); + return 1; + } + + if (label->append) + strcpy(bootargs, label->append); + strcat(bootargs, ip_str); + strcat(bootargs, mac_str); + + cli_simple_process_macros(bootargs, finalbootargs); + setenv("bootargs", finalbootargs); + printf("append: %s\n", finalbootargs); + } bootm_argv[1] = getenv("kernel_addr_r"); @@ -650,19 +711,86 @@ static void label_boot(struct pxe_label *label) bootm_argv[3] = getenv("fdt_addr_r"); /* if fdt label is defined then get fdt from server */ - if (bootm_argv[3] && label->fdt) { - if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) { - printf("Skipping %s for failure retrieving fdt\n", - label->name); - return; + if (bootm_argv[3]) { + char *fdtfile = NULL; + char *fdtfilefree = NULL; + + if (label->fdt) { + fdtfile = label->fdt; + } else if (label->fdtdir) { + char *f1, *f2, *f3, *f4, *slash; + + f1 = getenv("fdtfile"); + if (f1) { + f2 = ""; + f3 = ""; + f4 = ""; + } else { + /* + * For complex cases where this code doesn't + * generate the correct filename, the board + * code should set $fdtfile during early boot, + * or the boot scripts should set $fdtfile + * before invoking "pxe" or "sysboot". + */ + f1 = getenv("soc"); + f2 = "-"; + f3 = getenv("board"); + f4 = ".dtb"; + } + + len = strlen(label->fdtdir); + if (!len) + slash = "./"; + else if (label->fdtdir[len - 1] != '/') + slash = "/"; + else + slash = ""; + + len = strlen(label->fdtdir) + strlen(slash) + + strlen(f1) + strlen(f2) + strlen(f3) + + strlen(f4) + 1; + fdtfilefree = malloc(len); + if (!fdtfilefree) { + printf("malloc fail (FDT filename)\n"); + return 1; + } + + snprintf(fdtfilefree, len, "%s%s%s%s%s%s", + label->fdtdir, slash, f1, f2, f3, f4); + fdtfile = fdtfilefree; } - } else + + if (fdtfile) { + int err = get_relfile_envaddr(cmdtp, fdtfile, "fdt_addr_r"); + free(fdtfilefree); + if (err < 0) { + printf("Skipping %s for failure retrieving fdt\n", + label->name); + return 1; + } + } else { + bootm_argv[3] = NULL; + } + } + + if (!bootm_argv[3]) bootm_argv[3] = getenv("fdt_addr"); if (bootm_argv[3]) bootm_argc = 4; - do_bootm(NULL, 0, bootm_argc, bootm_argv); + kernel_addr = genimg_get_kernel_addr(bootm_argv[1]); + buf = map_sysmem(kernel_addr, 0); + /* Try bootm for legacy and FIT format image */ + if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID) + do_bootm(cmdtp, 0, bootm_argc, bootm_argv); +#ifdef CONFIG_CMD_BOOTZ + /* Try booting a zImage */ + else + do_bootz(cmdtp, 0, bootm_argc, bootm_argv); +#endif + return 1; } /* @@ -685,6 +813,9 @@ enum token_type { T_PROMPT, T_INCLUDE, T_FDT, + T_FDTDIR, + T_ONTIMEOUT, + T_IPAPPEND, T_INVALID }; @@ -712,7 +843,12 @@ static const struct token keywords[] = { {"append", T_APPEND}, {"initrd", T_INITRD}, {"include", T_INCLUDE}, + {"devicetree", T_FDT}, {"fdt", T_FDT}, + {"devicetreedir", T_FDTDIR}, + {"fdtdir", T_FDTDIR}, + {"ontimeout", T_ONTIMEOUT,}, + {"ipappend", T_IPAPPEND,}, {NULL, T_INVALID} }; @@ -903,7 +1039,6 @@ static int parse_integer(char **c, int *dst) { struct token t; char *s = *c; - unsigned long temp; get_token(c, &t, L_SLITERAL); @@ -912,19 +1047,14 @@ static int parse_integer(char **c, int *dst) return -EINVAL; } - if (strict_strtoul(t.val, 10, &temp) < 0) { - printf("Expected unsigned integer: %s\n", t.val); - return -EINVAL; - } - - *dst = (int)temp; + *dst = simple_strtol(t.val, NULL, 10); free(t.val); return 1; } -static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level); +static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, struct pxe_menu *cfg, int nest_level); /* * Parse an include statement, and retrieve and parse the file it mentions. @@ -934,7 +1064,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level); * include, nest_level has already been incremented and doesn't need to be * incremented here. */ -static int handle_include(char **c, char *base, +static int handle_include(cmd_tbl_t *cmdtp, char **c, char *base, struct pxe_menu *cfg, int nest_level) { char *include_path; @@ -949,14 +1079,14 @@ static int handle_include(char **c, char *base, return err; } - err = get_pxe_file(include_path, base); + err = get_pxe_file(cmdtp, include_path, base); if (err < 0) { printf("Couldn't retrieve %s\n", include_path); return err; } - return parse_pxefile_top(base, cfg, nest_level); + return parse_pxefile_top(cmdtp, base, cfg, nest_level); } /* @@ -969,7 +1099,7 @@ static int handle_include(char **c, char *base, * nest_level should be 1 when parsing the top level pxe file, 2 when parsing * a file it includes, 3 when parsing a file included by that file, and so on. */ -static int parse_menu(char **c, struct pxe_menu *cfg, char *b, int nest_level) +static int parse_menu(cmd_tbl_t *cmdtp, char **c, struct pxe_menu *cfg, char *b, int nest_level) { struct token t; char *s = *c; @@ -984,7 +1114,7 @@ static int parse_menu(char **c, struct pxe_menu *cfg, char *b, int nest_level) break; case T_INCLUDE: - err = handle_include(c, b + strlen(b) + 1, cfg, + err = handle_include(cmdtp, c, b + strlen(b) + 1, cfg, nest_level + 1); break; @@ -1016,10 +1146,8 @@ static int parse_label_menu(char **c, struct pxe_menu *cfg, switch (t.type) { case T_DEFAULT: - if (cfg->default_label) - free(cfg->default_label); - - cfg->default_label = strdup(label->name); + if (!cfg->default_label) + cfg->default_label = strdup(label->name); if (!cfg->default_label) return -ENOMEM; @@ -1107,8 +1235,18 @@ static int parse_label(char **c, struct pxe_menu *cfg) err = parse_sliteral(c, &label->fdt); break; + case T_FDTDIR: + if (!label->fdtdir) + err = parse_sliteral(c, &label->fdtdir); + break; + case T_LOCALBOOT: - err = parse_integer(c, &label->localboot); + label->localboot = 1; + err = parse_integer(c, &label->localboot_val); + break; + + case T_IPAPPEND: + err = parse_integer(c, &label->ipappend); break; case T_EOL: @@ -1143,7 +1281,7 @@ static int parse_label(char **c, struct pxe_menu *cfg) * * Returns 1 on success, < 0 on error. */ -static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) +static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, struct pxe_menu *cfg, int nest_level) { struct token t; char *s, *b, *label_name; @@ -1164,7 +1302,8 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) err = 0; switch (t.type) { case T_MENU: - err = parse_menu(&p, cfg, b, nest_level); + cfg->prompt = 1; + err = parse_menu(cmdtp, &p, cfg, b, nest_level); break; case T_TIMEOUT: @@ -1176,6 +1315,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) break; case T_DEFAULT: + case T_ONTIMEOUT: err = parse_sliteral(&p, &label_name); if (label_name) { @@ -1188,12 +1328,12 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) break; case T_INCLUDE: - err = handle_include(&p, b + ALIGN(strlen(b), 4), cfg, + err = handle_include(cmdtp, &p, b + ALIGN(strlen(b), 4), cfg, nest_level + 1); break; case T_PROMPT: - err = parse_integer(&p, &cfg->prompt); + eol_or_eof(&p); break; case T_EOL: @@ -1245,7 +1385,7 @@ static void destroy_pxe_menu(struct pxe_menu *cfg) * files it includes). The resulting pxe_menu struct can be free()'d by using * the destroy_pxe_menu() function. */ -static struct pxe_menu *parse_pxefile(char *menucfg) +static struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, char *menucfg) { struct pxe_menu *cfg; @@ -1258,7 +1398,7 @@ static struct pxe_menu *parse_pxefile(char *menucfg) INIT_LIST_HEAD(&cfg->labels); - if (parse_pxefile_top(menucfg, cfg, 1) < 0) { + if (parse_pxefile_top(cmdtp, menucfg, cfg, 1) < 0) { destroy_pxe_menu(cfg); return NULL; } @@ -1276,11 +1416,14 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) struct list_head *pos; struct menu *m; int err; + int i = 1; + char *default_num = NULL; /* * Create a menu and add items for all the labels. */ - m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print); + m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print, + NULL, NULL); if (!m) return NULL; @@ -1288,18 +1431,23 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) list_for_each(pos, &cfg->labels) { label = list_entry(pos, struct pxe_label, list); - if (menu_item_add(m, label->name, label) != 1) { + sprintf(label->num, "%d", i++); + if (menu_item_add(m, label->num, label) != 1) { menu_destroy(m); return NULL; } + if (cfg->default_label && + (strcmp(label->name, cfg->default_label) == 0)) + default_num = label->num; + } /* * After we've created items for each label in the menu, set the * menu's default label if one was specified. */ - if (cfg->default_label) { - err = menu_default_set(m, cfg->default_label); + if (default_num) { + err = menu_default_set(m, default_num); if (err != 1) { if (err != -ENOENT) { menu_destroy(m); @@ -1316,7 +1464,7 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) /* * Try to boot any labels we have yet to attempt to boot. */ -static void boot_unattempted_labels(struct pxe_menu *cfg) +static void boot_unattempted_labels(cmd_tbl_t *cmdtp, struct pxe_menu *cfg) { struct list_head *pos; struct pxe_label *label; @@ -1325,7 +1473,7 @@ static void boot_unattempted_labels(struct pxe_menu *cfg) label = list_entry(pos, struct pxe_label, list); if (!label->attempted) - label_boot(label); + label_boot(cmdtp, label); } } @@ -1341,7 +1489,7 @@ static void boot_unattempted_labels(struct pxe_menu *cfg) * If this function returns, there weren't any labels that successfully * booted, or the user interrupted the menu selection via ctrl+c. */ -static void handle_pxe_menu(struct pxe_menu *cfg) +static void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg) { void *choice; struct menu *m; @@ -1366,14 +1514,18 @@ static void handle_pxe_menu(struct pxe_menu *cfg) * we give up. */ - if (err == 1) - label_boot(choice); - else if (err != -ENOENT) + if (err == 1) { + err = label_boot(cmdtp, choice); + if (!err) + return; + } else if (err != -ENOENT) { return; + } - boot_unattempted_labels(cfg); + boot_unattempted_labels(cmdtp, cfg); } +#ifdef CONFIG_CMD_NET /* * Boots a system using a pxe file * @@ -1404,17 +1556,19 @@ do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 1; } - cfg = parse_pxefile((char *)(pxefile_addr_r)); + cfg = parse_pxefile(cmdtp, (char *)(pxefile_addr_r)); if (cfg == NULL) { printf("Error parsing config file\n"); return 1; } - handle_pxe_menu(cfg); + handle_pxe_menu(cmdtp, cfg); destroy_pxe_menu(cfg); + copy_filename(BootFile, "", sizeof(BootFile)); + return 0; } @@ -1423,13 +1577,15 @@ static cmd_tbl_t cmd_pxe_sub[] = { U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "") }; -int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { cmd_tbl_t *cp; if (argc < 2) return CMD_RET_USAGE; + is_pxe = true; + /* drop initial "pxe" arg */ argc--; argv++; @@ -1448,13 +1604,14 @@ U_BOOT_CMD( "get - try to retrieve a pxe file using tftp\npxe " "boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n" ); +#endif /* * Boots a system using a local disk syslinux/extlinux file * * Returns 0 on success, 1 on error. */ -int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { unsigned long pxefile_addr_r; struct pxe_menu *cfg; @@ -1462,6 +1619,8 @@ int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) char *filename; int prompt = 0; + is_pxe = false; + if (strstr(argv[1], "-p")) { prompt = 1; argc--; @@ -1490,6 +1649,8 @@ int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) do_getfile = do_get_ext2; else if (strstr(argv[3], "fat")) do_getfile = do_get_fat; + else if (strstr(argv[3], "any")) + do_getfile = do_get_any; else { printf("Invalid filesystem: %s\n", argv[3]); return 1; @@ -1502,12 +1663,12 @@ int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 1; } - if (get_pxe_file(filename, (void *)pxefile_addr_r) < 0) { + if (get_pxe_file(cmdtp, filename, (void *)pxefile_addr_r) < 0) { printf("Error reading config file\n"); return 1; } - cfg = parse_pxefile((char *)(pxefile_addr_r)); + cfg = parse_pxefile(cmdtp, (char *)(pxefile_addr_r)); if (cfg == NULL) { printf("Error parsing config file\n"); @@ -1517,7 +1678,7 @@ int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (prompt) cfg->prompt = 1; - handle_pxe_menu(cfg); + handle_pxe_menu(cmdtp, cfg); destroy_pxe_menu(cfg); @@ -1527,7 +1688,7 @@ int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) U_BOOT_CMD( sysboot, 7, 1, do_sysboot, "command to get and boot from syslinux files", - "[-p] [addr] [filename]\n" - " - load and parse syslinux menu file 'filename' from ext2 or fat\n" - " filesystem on 'dev' on 'interface' to address 'addr'" + "[-p] [addr] [filename]\n" + " - load and parse syslinux menu file 'filename' from ext2, fat\n" + " or any filesystem on 'dev' on 'interface' to address 'addr'" );