/*
* Copyright 2010-2011 Calxeda, Inc.
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <malloc.h>
+#include <mapmem.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <errno.h>
#include <linux/list.h>
#include <fs.h>
+#include <asm/io.h>
#include "menu.h"
+#include "cli.h"
#define MAX_TFTP_PATH_LEN 127
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
return 1;
}
+#endif
/*
* Returns the directory the file specified in the bootfile env variable is
static int (*do_getfile)(cmd_tbl_t *cmdtp, const 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};
return 1;
}
+#endif
static char *fs_argv[5];
*
* Returns 1 for success, or < 0 on error.
*/
-static int get_relfile(cmd_tbl_t *cmdtp, const 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));
printf("Retrieving file: %s\n", relfile);
- sprintf(addr_buf, "%p", file_addr);
+ sprintf(addr_buf, "%lx", file_addr);
return do_getfile(cmdtp, relfile, addr_buf);
}
*
* Returns 1 on success, or < 0 for error.
*/
-static int get_pxe_file(cmd_tbl_t *cmdtp, const 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(cmdtp, file_path, 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/"
/*
*
* Returns 1 on success or < 0 on error.
*/
-static int get_pxelinux_path(cmd_tbl_t *cmdtp, const 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];
*
* Returns 1 on success or < 0 on error.
*/
-static int pxe_uuid_path(cmd_tbl_t *cmdtp, void *pxefile_addr_r)
+static int pxe_uuid_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
{
char *uuid_str;
*
* Returns 1 on success or < 0 on error.
*/
-static int pxe_mac_path(cmd_tbl_t *cmdtp, void *pxefile_addr_r)
+static int pxe_mac_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
{
char mac_str[21];
int err;
*
* Returns 1 on success or < 0 on error.
*/
-static int pxe_ipaddr_paths(cmd_tbl_t *cmdtp, 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(cmdtp, ip_addr, pxefile_addr_r);
* Keep trying paths until we successfully get a file we're looking
* for.
*/
- 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) {
+ 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],
- (void *)pxefile_addr_r) > 0) {
+ pxefile_addr_r) > 0) {
printf("Config file found\n");
return 0;
}
return 1;
}
+#endif
/*
* Wrapper to make it easier to store the file at file_path in the location
if (strict_strtoul(envaddr, 16, &file_addr) < 0)
return -EINVAL;
- return get_relfile(cmdtp, file_path, (void *)file_addr);
+ return get_relfile(cmdtp, file_path, file_addr);
}
/*
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);
char initrd_str[22];
char mac_str[29] = "";
char ip_str[68] = "";
- char *bootargs;
int bootm_argc = 3;
int len = 0;
+ ulong kernel_addr;
+ void *buf;
label_print(label);
sprintf(ip_str, " ip=%s:%s:%s:%s",
getenv("ipaddr"), getenv("serverip"),
getenv("gatewayip"), getenv("netmask"));
- len += strlen(ip_str);
}
+#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';
- len += strlen(mac_str);
}
+#endif
- if (label->append)
- len += strlen(label->append);
+ if ((label->ipappend & 0x3) || label->append) {
+ char bootargs[CONFIG_SYS_CBSIZE] = "";
+ char finalbootargs[CONFIG_SYS_CBSIZE];
- if (len) {
- bootargs = malloc(len + 1);
- if (!bootargs)
+ 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;
- bootargs[0] = '\0';
+ }
+
if (label->append)
strcpy(bootargs, label->append);
strcat(bootargs, ip_str);
strcat(bootargs, mac_str);
- setenv("bootargs", bootargs);
- printf("append: %s\n", bootargs);
-
- free(bootargs);
+ cli_simple_process_macros(bootargs, finalbootargs);
+ setenv("bootargs", finalbootargs);
+ printf("append: %s\n", finalbootargs);
}
bootm_argv[1] = getenv("kernel_addr_r");
if (bootm_argv[3])
bootm_argc = 4;
- do_bootm(cmdtp, 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 if do_bootm returns */
- do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
+ /* Try booting a zImage */
+ else
+ do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
#endif
+ unmap_sysmem(buf);
return 1;
}
return 1;
}
-static int parse_pxefile_top(cmd_tbl_t *cmdtp, 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.
* include, nest_level has already been incremented and doesn't need to be
* incremented here.
*/
-static int handle_include(cmd_tbl_t *cmdtp, 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);
return err;
}
- return parse_pxefile_top(cmdtp, 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(cmd_tbl_t *cmdtp, 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;
break;
case T_INCLUDE:
- err = handle_include(cmdtp, c, b + strlen(b) + 1, cfg,
+ err = handle_include(cmdtp, c, base, cfg,
nest_level + 1);
break;
*
* Returns 1 on success, < 0 on error.
*/
-static int parse_pxefile_top(cmd_tbl_t *cmdtp, 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;
switch (t.type) {
case T_MENU:
cfg->prompt = 1;
- err = parse_menu(cmdtp, &p, cfg, b, nest_level);
+ err = parse_menu(cmdtp, &p, cfg,
+ base + ALIGN(strlen(b) + 1, 4),
+ nest_level);
break;
case T_TIMEOUT:
break;
case T_INCLUDE:
- err = handle_include(cmdtp, &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:
* 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(cmd_tbl_t *cmdtp, 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));
INIT_LIST_HEAD(&cfg->labels);
- if (parse_pxefile_top(cmdtp, 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;
}
boot_unattempted_labels(cmdtp, cfg);
}
+#ifdef CONFIG_CMD_NET
/*
* Boots a system using a pxe file
*
return 1;
}
- cfg = parse_pxefile(cmdtp, (char *)(pxefile_addr_r));
+ cfg = parse_pxefile(cmdtp, pxefile_addr_r);
if (cfg == NULL) {
printf("Error parsing config file\n");
destroy_pxe_menu(cfg);
+ copy_filename(net_boot_file_name, "", sizeof(net_boot_file_name));
+
return 0;
}
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;
"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;
is_pxe = false;
- if (strstr(argv[1], "-p")) {
+ if (argc > 1 && strstr(argv[1], "-p")) {
prompt = 1;
argc--;
argv++;
return 1;
}
- if (get_pxe_file(cmdtp, 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(cmdtp, (char *)(pxefile_addr_r));
+ cfg = parse_pxefile(cmdtp, pxefile_addr_r);
if (cfg == NULL) {
printf("Error parsing config file\n");