X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=inline;f=common%2Fcmd_pxe.c;h=080b3760de0074d2468a838a12ce850ac510b059;hb=434afa809e91bbf67e003df8daf0e2f39c48ce59;hp=2dbd49cbd6641352786a24110e0d3646f66f7dfc;hpb=5644369450635fa5c2967bee55b1ac41f6e988d0;p=u-boot
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
index 2dbd49cbd6..080b3760de 100644
--- a/common/cmd_pxe.c
+++ b/common/cmd_pxe.c
@@ -1,37 +1,43 @@
/*
* 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
+#include
#include
#include
#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 +49,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 +62,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 +93,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 +110,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 +124,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,11 +190,12 @@ 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,
+ unsigned long file_addr)
{
size_t path_len;
char relfile[MAX_TFTP_PATH_LEN+1];
- char addr_buf[10];
+ char addr_buf[18];
int err;
err = get_bootfile_path(file_path, relfile, sizeof(relfile));
@@ -209,9 +218,9 @@ static int get_relfile(char *file_path, void *file_addr)
printf("Retrieving file: %s\n", relfile);
- sprintf(addr_buf, "%p", file_addr);
+ sprintf(addr_buf, "%lx", file_addr);
- return do_getfile(relfile, addr_buf);
+ return do_getfile(cmdtp, relfile, addr_buf);
}
/*
@@ -221,13 +230,15 @@ 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,
+ unsigned long file_addr)
{
unsigned long config_file_size;
char *tftp_filesize;
int err;
+ char *buf;
- err = get_relfile(file_path, file_addr);
+ err = get_relfile(cmdtp, file_path, file_addr);
if (err < 0)
return err;
@@ -244,11 +255,15 @@ static int get_pxe_file(char *file_path, void *file_addr)
if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
return -EINVAL;
- *(char *)(file_addr + config_file_size) = '\0';
+ buf = map_sysmem(file_addr + config_file_size, 1);
+ *buf = '\0';
+ unmap_sysmem(buf);
return 1;
}
+#ifdef CONFIG_CMD_NET
+
#define PXELINUX_DIR "pxelinux.cfg/"
/*
@@ -258,7 +273,8 @@ 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,
+ unsigned long pxefile_addr_r)
{
size_t base_len = strlen(PXELINUX_DIR);
char path[MAX_TFTP_PATH_LEN+1];
@@ -271,7 +287,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 +295,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, unsigned long pxefile_addr_r)
{
char *uuid_str;
@@ -288,7 +304,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 +313,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, unsigned long pxefile_addr_r)
{
char mac_str[21];
int err;
@@ -307,7 +323,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,15 +333,15 @@ 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, unsigned long pxefile_addr_r)
{
char ip_addr[9];
int mask_pos, err;
- sprintf(ip_addr, "%08X", ntohl(NetOurIP));
+ sprintf(ip_addr, "%08X", ntohl(net_ip.s_addr));
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 +371,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 +392,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, pxefile_addr_r) > 0 ||
+ pxe_mac_path(cmdtp, pxefile_addr_r) > 0 ||
+ pxe_ipaddr_paths(cmdtp, 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],
+ 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 +422,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 +435,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, file_addr);
}
/*
@@ -445,14 +469,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 +549,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 +564,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);
+ const char *c = label->menu ? label->menu : label->name;
- if (label->kernel)
- printf("\t\tkernel: %s\n", label->kernel);
-
- if (label->append)
- printf("\t\tappend: %s\n", label->append);
-
- 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 +587,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 +614,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 +719,91 @@ 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;
+ }
+
+ 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;
}
- } else
+ }
+
+ 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_BOOTI
+ /* Try booting an AArch64 Linux kernel image */
+ else
+ do_booti(cmdtp, 0, bootm_argc, bootm_argv);
+#elif defined(CONFIG_CMD_BOOTZ)
+ /* Try booting a Image */
+ else
+ do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
+#endif
+ unmap_sysmem(buf);
+ return 1;
}
/*
@@ -685,6 +826,9 @@ enum token_type {
T_PROMPT,
T_INCLUDE,
T_FDT,
+ T_FDTDIR,
+ T_ONTIMEOUT,
+ T_IPAPPEND,
T_INVALID
};
@@ -712,7 +856,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 +1052,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 +1060,15 @@ 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, unsigned long base,
+ struct pxe_menu *cfg, int nest_level);
/*
* Parse an include statement, and retrieve and parse the file it mentions.
@@ -934,12 +1078,14 @@ 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, unsigned long base,
struct pxe_menu *cfg, int nest_level)
{
char *include_path;
char *s = *c;
int err;
+ char *buf;
+ int ret;
err = parse_sliteral(c, &include_path);
@@ -949,27 +1095,32 @@ 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);
+ buf = map_sysmem(base, 0);
+ ret = parse_pxefile_top(cmdtp, buf, base, cfg, nest_level);
+ unmap_sysmem(buf);
+
+ return ret;
}
/*
* Parse lines that begin with 'menu'.
*
- * b and nest are provided to handle the 'menu include' case.
+ * base and nest are provided to handle the 'menu include' case.
*
- * b should be the address where the file currently being parsed is stored.
+ * base should point to a location where it's safe to store the included file.
*
* 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,
+ unsigned long base, int nest_level)
{
struct token t;
char *s = *c;
@@ -984,7 +1135,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, base, cfg,
nest_level + 1);
break;
@@ -1016,10 +1167,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 +1256,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 +1302,8 @@ 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, unsigned long base,
+ struct pxe_menu *cfg, int nest_level)
{
struct token t;
char *s, *b, *label_name;
@@ -1164,7 +1324,10 @@ 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,
+ base + ALIGN(strlen(b) + 1, 4),
+ nest_level);
break;
case T_TIMEOUT:
@@ -1176,6 +1339,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 +1352,13 @@ 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,
- nest_level + 1);
+ err = handle_include(cmdtp, &p,
+ base + 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,9 +1410,11 @@ 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, unsigned long menucfg)
{
struct pxe_menu *cfg;
+ char *buf;
+ int r;
cfg = malloc(sizeof(struct pxe_menu));
@@ -1258,7 +1425,11 @@ static struct pxe_menu *parse_pxefile(char *menucfg)
INIT_LIST_HEAD(&cfg->labels);
- if (parse_pxefile_top(menucfg, cfg, 1) < 0) {
+ buf = map_sysmem(menucfg, 0);
+ r = parse_pxefile_top(cmdtp, buf, menucfg, cfg, 1);
+ unmap_sysmem(buf);
+
+ if (r < 0) {
destroy_pxe_menu(cfg);
return NULL;
}
@@ -1276,6 +1447,8 @@ 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.
@@ -1289,18 +1462,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);
@@ -1317,7 +1495,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;
@@ -1326,7 +1504,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);
}
}
@@ -1342,7 +1520,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;
@@ -1367,14 +1545,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
*
@@ -1405,17 +1587,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, 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(net_boot_file_name, "", sizeof(net_boot_file_name));
+
return 0;
}
@@ -1424,13 +1608,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++;
@@ -1449,13 +1635,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;
@@ -1463,7 +1650,9 @@ int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
char *filename;
int prompt = 0;
- if (strstr(argv[1], "-p")) {
+ is_pxe = false;
+
+ if (argc > 1 && strstr(argv[1], "-p")) {
prompt = 1;
argc--;
argv++;
@@ -1491,6 +1680,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;
@@ -1503,12 +1694,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, pxefile_addr_r) < 0) {
printf("Error reading config file\n");
return 1;
}
- cfg = parse_pxefile((char *)(pxefile_addr_r));
+ cfg = parse_pxefile(cmdtp, pxefile_addr_r);
if (cfg == NULL) {
printf("Error parsing config file\n");
@@ -1518,7 +1709,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);
@@ -1528,7 +1719,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'"
);