#define MAX_TFTP_PATH_LEN 127
-
/*
* 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
*/
static int format_mac_pxe(char *outbuf, size_t outbuf_len)
{
- size_t ethaddr_len;
- char *p, *ethaddr;
-
- ethaddr = from_env("ethaddr");
-
- if (!ethaddr)
- return -ENOENT;
+ uchar ethaddr[6];
- 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 (%d < 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;
}
* in. If bootfile isn't defined in the environment, return NULL, which should
* be interpreted as "don't prepend anything to paths".
*/
-static int get_bootfile_path(char *bootfile_path, size_t bootfile_path_size)
+static int get_bootfile_path(const char *file_path, char *bootfile_path,
+ size_t bootfile_path_size)
{
char *bootfile, *last_slash;
- size_t path_len;
+ size_t path_len = 0;
+
+ if (file_path[0] == '/')
+ goto ret;
bootfile = from_env("bootfile");
- if (!bootfile) {
- bootfile_path[0] = '\0';
- return 1;
- }
+ if (!bootfile)
+ goto ret;
last_slash = strrchr(bootfile, '/');
- if (last_slash == NULL) {
- bootfile_path[0] = '\0';
- return 1;
- }
+ if (last_slash == NULL)
+ goto ret;
path_len = (last_slash - bootfile) + 1;
strncpy(bootfile_path, bootfile, path_len);
+ ret:
bootfile_path[path_len] = '\0';
return 1;
}
+static int (*do_getfile)(char *file_path, char *file_addr);
+
+static int do_get_tftp(char *file_path, char *file_addr)
+{
+ char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
+
+ tftp_argv[1] = file_addr;
+ tftp_argv[2] = file_path;
+
+ if (do_tftpb(NULL, 0, 3, tftp_argv))
+ return -ENOENT;
+
+ return 1;
+}
+
+static char *fs_argv[5];
+
+static int do_get_ext2(char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_EXT2
+ fs_argv[0] = "ext2load";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = file_path;
+
+ if (!do_ext2load(NULL, 0, 5, fs_argv))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
+static int do_get_fat(char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_FAT
+ fs_argv[0] = "fatload";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = file_path;
+
+ if (!do_fat_fsload(NULL, 0, 5, fs_argv))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
/*
* As in pxelinux, paths to files referenced from files we retrieve are
* relative to the location of bootfile. get_relfile takes such a path and
size_t path_len;
char relfile[MAX_TFTP_PATH_LEN+1];
char addr_buf[10];
- char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
int err;
- err = get_bootfile_path(relfile, sizeof(relfile));
+ err = get_bootfile_path(file_path, relfile, sizeof(relfile));
if (err < 0)
return err;
sprintf(addr_buf, "%p", file_addr);
- tftp_argv[1] = addr_buf;
- tftp_argv[2] = relfile;
-
- if (do_tftpb(NULL, 0, 3, tftp_argv))
- return -ENOENT;
-
- return 1;
+ return do_getfile(relfile, addr_buf);
}
/*
unsigned long pxefile_addr_r;
int err;
+ do_getfile = do_get_tftp;
+
if (argc != 1)
return CMD_RET_USAGE;
-
pxefile_addr_str = from_env("pxefile_addr_r");
if (!pxefile_addr_str)
*/
struct pxe_label {
char *name;
+ char *menu;
char *kernel;
char *append;
char *initrd;
+ char *fdt;
int attempted;
int localboot;
struct list_head list;
if (label->initrd)
free(label->initrd);
+ if (label->fdt)
+ free(label->fdt);
+
free(label);
}
static void label_print(void *data)
{
struct pxe_label *label = data;
+ const char *c = label->menu ? label->menu : label->kernel;
- printf("Label: %s\n", label->name);
+ printf("%s:\t%s\n", label->name, c);
if (label->kernel)
- printf("\tkernel: %s\n", label->kernel);
+ printf("\t\tkernel: %s\n", label->kernel);
if (label->append)
- printf("\tappend: %s\n", label->append);
+ printf("\t\tappend: %s\n", label->append);
if (label->initrd)
- printf("\tinitrd: %s\n", label->initrd);
+ printf("\t\tinitrd: %s\n", label->initrd);
+
+ if (label->fdt)
+ printf("\tfdt: %s\n", label->fdt);
}
/*
*/
static int label_localboot(struct pxe_label *label)
{
- char *localcmd, *dupcmd;
- int ret;
+ char *localcmd;
localcmd = from_env("localcmd");
if (!localcmd)
return -ENOENT;
- /*
- * dup the command to avoid any issues with the version of it existing
- * in the environment changing during the execution of the command.
- */
- dupcmd = strdup(localcmd);
-
- if (!dupcmd)
- return -ENOMEM;
-
if (label->append)
setenv("bootargs", label->append);
- printf("running: %s\n", dupcmd);
-
- ret = run_command(dupcmd, 0);
-
- free(dupcmd);
+ debug("running: %s\n", localcmd);
- return ret;
+ return run_command_list(localcmd, strlen(localcmd), 0);
}
/*
bootm_argv[1] = getenv("kernel_addr_r");
/*
- * fdt usage is optional. If there is an fdt_addr specified, we will
- * pass it along to bootm, and adjust argc appropriately.
+ * fdt usage is optional:
+ * It handles the following scenarios. All scenarios are exclusive
+ *
+ * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
+ * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
+ * and adjust argc appropriately.
+ *
+ * Scenario 2: If there is an fdt_addr specified, pass it along to
+ * bootm, and adjust argc appropriately.
+ *
+ * Scenario 3: fdt blob is not available.
*/
- bootm_argv[3] = getenv("fdt_addr");
+ 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;
+ }
+ } else
+ bootm_argv[3] = getenv("fdt_addr");
if (bootm_argv[3])
bootm_argc = 4;
T_TIMEOUT,
T_LABEL,
T_KERNEL,
+ T_LINUX,
T_APPEND,
T_INITRD,
T_LOCALBOOT,
T_DEFAULT,
T_PROMPT,
T_INCLUDE,
+ T_FDT,
T_INVALID
};
{"prompt", T_PROMPT},
{"label", T_LABEL},
{"kernel", T_KERNEL},
+ {"linux", T_LINUX},
{"localboot", T_LOCALBOOT},
{"append", T_APPEND},
{"initrd", T_INITRD},
{"include", T_INCLUDE},
+ {"fdt", T_FDT},
{NULL, T_INVALID}
};
if (!cfg->default_label)
return -ENOMEM;
+ break;
+ case T_LABEL:
+ parse_sliteral(c, &label->menu);
break;
default:
printf("Ignoring malformed menu command: %.*s\n",
static int parse_label(char **c, struct pxe_menu *cfg)
{
struct token t;
+ int len;
char *s = *c;
struct pxe_label *label;
int err;
break;
case T_KERNEL:
+ case T_LINUX:
err = parse_sliteral(c, &label->kernel);
break;
case T_APPEND:
err = parse_sliteral(c, &label->append);
+ if (label->initrd)
+ break;
+ s = strstr(label->append, "initrd=");
+ if (!s)
+ break;
+ s += 7;
+ len = (int)(strchr(s, ' ') - s);
+ label->initrd = malloc(len + 1);
+ strncpy(label->initrd, s, len);
+ label->initrd[len] = '\0';
+
break;
case T_INITRD:
- err = parse_sliteral(c, &label->initrd);
+ if (!label->initrd)
+ err = parse_sliteral(c, &label->initrd);
+ break;
+
+ case T_FDT:
+ if (!label->fdt)
+ err = parse_sliteral(c, &label->fdt);
break;
case T_LOCALBOOT:
break;
+ case T_INCLUDE:
+ err = handle_include(&p, b + ALIGN(strlen(b), 4), cfg,
+ nest_level + 1);
+ break;
+
case T_PROMPT:
err = parse_integer(&p, &cfg->prompt);
break;
/*
* 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;
struct pxe_menu *cfg;
char *pxefile_addr_str;
+ do_getfile = do_get_tftp;
+
if (argc == 1) {
pxefile_addr_str = from_env("pxefile_addr_r");
if (!pxefile_addr_str)
"get - try to retrieve a pxe file using tftp\npxe "
"boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
);
+
+/*
+ * 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[])
+{
+ unsigned long pxefile_addr_r;
+ struct pxe_menu *cfg;
+ char *pxefile_addr_str;
+ char *filename;
+ int prompt = 0;
+
+ if (strstr(argv[1], "-p")) {
+ prompt = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ if (argc < 5) {
+ pxefile_addr_str = from_env("pxefile_addr_r");
+ if (!pxefile_addr_str)
+ return 1;
+ } else {
+ pxefile_addr_str = argv[4];
+ }
+
+ if (argc < 6)
+ filename = getenv("bootfile");
+ else {
+ filename = argv[5];
+ setenv("bootfile", filename);
+ }
+
+ if (strstr(argv[3], "ext2"))
+ do_getfile = do_get_ext2;
+ else if (strstr(argv[3], "fat"))
+ do_getfile = do_get_fat;
+ else {
+ printf("Invalid filesystem: %s\n", argv[3]);
+ return 1;
+ }
+ fs_argv[1] = argv[1];
+ fs_argv[2] = argv[2];
+
+ if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
+ printf("Invalid pxefile address: %s\n", pxefile_addr_str);
+ return 1;
+ }
+
+ if (get_pxe_file(filename, (void *)pxefile_addr_r) < 0) {
+ printf("Error reading config file\n");
+ return 1;
+ }
+
+ cfg = parse_pxefile((char *)(pxefile_addr_r));
+
+ if (cfg == NULL) {
+ printf("Error parsing config file\n");
+ return 1;
+ }
+
+ if (prompt)
+ cfg->prompt = 1;
+
+ handle_pxe_menu(cfg);
+
+ destroy_pxe_menu(cfg);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ sysboot, 7, 1, do_sysboot,
+ "command to get and boot from syslinux files",
+ "[-p] <interface> <dev[:part]> <ext2|fat> [addr] [filename]\n"
+ " - load and parse syslinux menu file 'filename' from ext2 or fat\n"
+ " filesystem on 'dev' on 'interface' to address 'addr'"
+);