*/
#include <common.h>
+#include <command.h>
#include <env.h>
+#include <image.h>
+#include <log.h>
#include <malloc.h>
#include <mapmem.h>
#include <lcd.h>
+#include <net.h>
+#include <fdt_support.h>
+#include <linux/libfdt.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <errno.h>
#include "pxe_utils.h"
-#define MAX_TFTP_PATH_LEN 127
+#define MAX_TFTP_PATH_LEN 512
bool is_pxe;
last_slash = strrchr(bootfile, '/');
- if (last_slash == NULL )
+ if (!last_slash)
goto ret;
path_len = (last_slash - bootfile) + 1;
if (bootfile_path_size < path_len) {
printf("bootfile_path too small. (%zd < %zd)\n",
- bootfile_path_size, path_len);
+ bootfile_path_size, path_len);
return -1;
}
return 1;
}
-int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr);
+int (*do_getfile)(struct cmd_tbl *cmdtp, const char *file_path,
+ char *file_addr);
/*
* As in pxelinux, paths to files referenced from files we retrieve are
*
* Returns 1 for success, or < 0 on error.
*/
-static int get_relfile(cmd_tbl_t *cmdtp, const char *file_path,
- unsigned long file_addr)
+static int get_relfile(struct cmd_tbl *cmdtp, const char *file_path,
+ unsigned long file_addr)
{
size_t path_len;
- char relfile[MAX_TFTP_PATH_LEN+1];
+ char relfile[MAX_TFTP_PATH_LEN + 1];
char addr_buf[18];
int err;
path_len += strlen(relfile);
if (path_len > MAX_TFTP_PATH_LEN) {
- printf("Base path too long (%s%s)\n",
- relfile,
- file_path);
+ printf("Base path too long (%s%s)\n", relfile, file_path);
return -ENAMETOOLONG;
}
*
* Returns 1 on success, or < 0 for error.
*/
-int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path,
- unsigned long file_addr)
+int get_pxe_file(struct cmd_tbl *cmdtp, const char *file_path,
+ unsigned long file_addr)
{
unsigned long config_file_size;
char *tftp_filesize;
#define PXELINUX_DIR "pxelinux.cfg/"
-
/*
* Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file
* to do the hard work, the location of the 'pxelinux.cfg' folder is generated
*
* Returns 1 on success or < 0 on error.
*/
-int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file,
- unsigned long pxefile_addr_r)
+int get_pxelinux_path(struct cmd_tbl *cmdtp, const char *file,
+ unsigned long pxefile_addr_r)
{
size_t base_len = strlen(PXELINUX_DIR);
- char path[MAX_TFTP_PATH_LEN+1];
+ char path[MAX_TFTP_PATH_LEN + 1];
if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
printf("path (%s%s) too long, skipping\n",
- PXELINUX_DIR, file);
+ PXELINUX_DIR, file);
return -ENAMETOOLONG;
}
*
* Returns 1 on success or < 0 on error.
*/
-static int get_relfile_envaddr(cmd_tbl_t *cmdtp, const char *file_path, const char *envaddr_name)
+static int get_relfile_envaddr(struct cmd_tbl *cmdtp, const char *file_path,
+ const char *envaddr_name)
{
unsigned long file_addr;
char *envaddr;
if (label->fdtdir)
free(label->fdtdir);
+ if (label->fdtoverlays)
+ free(label->fdtoverlays);
+
free(label);
}
if (label->append) {
char bootargs[CONFIG_SYS_CBSIZE];
- cli_simple_process_macros(label->append, bootargs);
+ cli_simple_process_macros(label->append, bootargs,
+ sizeof(bootargs));
env_set("bootargs", bootargs);
}
return run_command_list(localcmd, strlen(localcmd), 0);
}
+/*
+ * Loads fdt overlays specified in 'fdtoverlays'.
+ */
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+static void label_boot_fdtoverlay(struct cmd_tbl *cmdtp, struct pxe_label *label)
+{
+ char *fdtoverlay = label->fdtoverlays;
+ struct fdt_header *working_fdt;
+ char *fdtoverlay_addr_env;
+ ulong fdtoverlay_addr;
+ ulong fdt_addr;
+ int err;
+
+ /* Get the main fdt and map it */
+ fdt_addr = simple_strtoul(env_get("fdt_addr_r"), NULL, 16);
+ working_fdt = map_sysmem(fdt_addr, 0);
+ err = fdt_check_header(working_fdt);
+ if (err)
+ return;
+
+ /* Get the specific overlay loading address */
+ fdtoverlay_addr_env = env_get("fdtoverlay_addr_r");
+ if (!fdtoverlay_addr_env) {
+ printf("Invalid fdtoverlay_addr_r for loading overlays\n");
+ return;
+ }
+
+ fdtoverlay_addr = simple_strtoul(fdtoverlay_addr_env, NULL, 16);
+
+ /* Cycle over the overlay files and apply them in order */
+ do {
+ struct fdt_header *blob;
+ char *overlayfile;
+ char *end;
+ int len;
+
+ /* Drop leading spaces */
+ while (*fdtoverlay == ' ')
+ ++fdtoverlay;
+
+ /* Copy a single filename if multiple provided */
+ end = strstr(fdtoverlay, " ");
+ if (end) {
+ len = (int)(end - fdtoverlay);
+ overlayfile = malloc(len + 1);
+ strncpy(overlayfile, fdtoverlay, len);
+ overlayfile[len] = '\0';
+ } else
+ overlayfile = fdtoverlay;
+
+ if (!strlen(overlayfile))
+ goto skip_overlay;
+
+ /* Load overlay file */
+ err = get_relfile_envaddr(cmdtp, overlayfile,
+ "fdtoverlay_addr_r");
+ if (err < 0) {
+ printf("Failed loading overlay %s\n", overlayfile);
+ goto skip_overlay;
+ }
+
+ /* Resize main fdt */
+ fdt_shrink_to_minimum(working_fdt, 8192);
+
+ blob = map_sysmem(fdtoverlay_addr, 0);
+ err = fdt_check_header(blob);
+ if (err) {
+ printf("Invalid overlay %s, skipping\n",
+ overlayfile);
+ goto skip_overlay;
+ }
+
+ err = fdt_overlay_apply_verbose(working_fdt, blob);
+ if (err) {
+ printf("Failed to apply overlay %s, skipping\n",
+ overlayfile);
+ goto skip_overlay;
+ }
+
+skip_overlay:
+ if (end)
+ free(overlayfile);
+ } while ((fdtoverlay = strstr(fdtoverlay, " ")));
+}
+#endif
+
/*
* Boot according to the contents of a pxe_label.
*
* If the label specifies an 'append' line, its contents will overwrite that
* of the 'bootargs' environment variable.
*/
-static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label)
+static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
{
char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
char initrd_str[28];
return 0;
}
- if (label->kernel == NULL) {
+ if (!label->kernel) {
printf("No kernel given, skipping %s\n",
- label->name);
+ label->name);
return 1;
}
if (label->initrd) {
if (get_relfile_envaddr(cmdtp, label->initrd, "ramdisk_addr_r") < 0) {
printf("Skipping %s for failure retrieving initrd\n",
- label->name);
+ label->name);
return 1;
}
if (get_relfile_envaddr(cmdtp, label->kernel, "kernel_addr_r") < 0) {
printf("Skipping %s for failure retrieving kernel\n",
- label->name);
+ label->name);
return 1;
}
env_get("gatewayip"), env_get("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';
+ if (IS_ENABLED(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] = "";
strlen(ip_str), strlen(mac_str),
sizeof(bootargs));
return 1;
- } else {
- if (label->append)
- strncpy(bootargs, label->append,
- sizeof(bootargs));
- strcat(bootargs, ip_str);
- strcat(bootargs, mac_str);
-
- cli_simple_process_macros(bootargs, finalbootargs);
- env_set("bootargs", finalbootargs);
- printf("append: %s\n", finalbootargs);
}
+
+ if (label->append)
+ strncpy(bootargs, label->append, sizeof(bootargs));
+
+ strcat(bootargs, ip_str);
+ strcat(bootargs, mac_str);
+
+ cli_simple_process_macros(bootargs, finalbootargs,
+ sizeof(finalbootargs));
+ env_set("bootargs", finalbootargs);
+ printf("append: %s\n", finalbootargs);
}
bootm_argv[1] = env_get("kernel_addr_r");
/*
* fdt usage is optional:
- * It handles the following scenarios. All scenarios are exclusive
+ * It handles the following scenarios.
+ *
+ * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
+ * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
+ * bootm, and adjust argc appropriately.
*
- * 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.
+ * If retrieve fails and no exact fdt blob is specified in pxe file with
+ * "fdt" label, try Scenario 2.
*
* Scenario 2: If there is an fdt_addr specified, pass it along to
* bootm, and adjust argc appropriately.
}
if (fdtfile) {
- int err = get_relfile_envaddr(cmdtp, fdtfile, "fdt_addr_r");
+ 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);
- goto cleanup;
+ bootm_argv[3] = NULL;
+
+ if (label->fdt) {
+ printf("Skipping %s for failure retrieving FDT\n",
+ label->name);
+ goto cleanup;
+ }
}
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+ if (label->fdtoverlays)
+ label_boot_fdtoverlay(cmdtp, label);
+#endif
} else {
bootm_argv[3] = NULL;
}
/* 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
+ else if (IS_ENABLED(CONFIG_CMD_BOOTI))
do_booti(cmdtp, 0, bootm_argc, bootm_argv);
-#elif defined(CONFIG_CMD_BOOTZ)
/* Try booting a Image */
- else
+ else if (IS_ENABLED(CONFIG_CMD_BOOTZ))
do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
-#endif
+ /* Try booting an x86_64 Linux kernel image */
+ else if (IS_ENABLED(CONFIG_CMD_ZBOOT))
+ do_zboot_parent(cmdtp, 0, bootm_argc, bootm_argv, NULL);
+
unmap_sysmem(buf);
cleanup:
T_INCLUDE,
T_FDT,
T_FDTDIR,
+ T_FDTOVERLAYS,
T_ONTIMEOUT,
T_IPAPPEND,
T_BACKGROUND,
{"fdt", T_FDT},
{"devicetreedir", T_FDTDIR},
{"fdtdir", T_FDTDIR},
+ {"fdtoverlays", T_FDTOVERLAYS},
{"ontimeout", T_ONTIMEOUT,},
{"ipappend", T_IPAPPEND,},
{"background", T_BACKGROUND,},
* e is incremented until we find the ending delimiter, or a NUL byte
* is reached. Then, we take e - b to find the length of the token.
*/
- b = e = *p;
+ b = *p;
+ e = *p;
while (*e) {
if ((delim == ' ' && isspace(*e)) || delim == *e)
return 1;
}
-static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
- struct pxe_menu *cfg, int nest_level);
+static int parse_pxefile_top(struct cmd_tbl *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, unsigned long base,
- struct pxe_menu *cfg, int nest_level)
+static int handle_include(struct cmd_tbl *cmdtp, char **c, unsigned long base,
+ struct pxe_menu *cfg, int nest_level)
{
char *include_path;
char *s = *c;
err = parse_sliteral(c, &include_path);
if (err < 0) {
- printf("Expected include path: %.*s\n",
- (int)(*c - s), s);
+ printf("Expected include path: %.*s\n", (int)(*c - s), s);
return err;
}
* 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,
- unsigned long base, int nest_level)
+static int parse_menu(struct cmd_tbl *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, base, cfg,
- nest_level + 1);
+ err = handle_include(cmdtp, c, base, cfg, nest_level + 1);
break;
case T_BACKGROUND:
default:
printf("Ignoring malformed menu command: %.*s\n",
- (int)(*c - s), s);
+ (int)(*c - s), s);
}
if (err < 0)
* Handles parsing a 'menu line' when we're parsing a label.
*/
static int parse_label_menu(char **c, struct pxe_menu *cfg,
- struct pxe_label *label)
+ struct pxe_label *label)
{
struct token t;
char *s;
break;
default:
printf("Ignoring malformed menu command: %.*s\n",
- (int)(*c - s), s);
+ (int)(*c - s), s);
}
eol_or_eof(c);
err = parse_sliteral(c, &label->fdtdir);
break;
+ case T_FDTOVERLAYS:
+ if (!label->fdtoverlays)
+ err = parse_sliteral(c, &label->fdtoverlays);
+ break;
+
case T_LOCALBOOT:
label->localboot = 1;
err = parse_integer(c, &label->localboot_val);
*
* Returns 1 on success, < 0 on error.
*/
-static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
- struct pxe_menu *cfg, int nest_level)
+static int parse_pxefile_top(struct cmd_tbl *cmdtp, char *p, unsigned long base,
+ struct pxe_menu *cfg, int nest_level)
{
struct token t;
char *s, *b, *label_name;
case T_MENU:
cfg->prompt = 1;
err = parse_menu(cmdtp, &p, cfg,
- base + ALIGN(strlen(b) + 1, 4),
- nest_level);
+ base + ALIGN(strlen(b) + 1, 4),
+ nest_level);
break;
case T_TIMEOUT:
case T_INCLUDE:
err = handle_include(cmdtp, &p,
- base + ALIGN(strlen(b), 4), cfg,
- nest_level + 1);
+ base + ALIGN(strlen(b), 4), cfg,
+ nest_level + 1);
break;
case T_PROMPT:
default:
printf("Ignoring unknown command: %.*s\n",
- (int)(p - s), s);
+ (int)(p - s), s);
eol_or_eof(&p);
}
* files it includes). The resulting pxe_menu struct can be free()'d by using
* the destroy_pxe_menu() function.
*/
-struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, unsigned long menucfg)
+struct pxe_menu *parse_pxefile(struct cmd_tbl *cmdtp, unsigned long menucfg)
{
struct pxe_menu *cfg;
char *buf;
* Create a menu and add items for all the labels.
*/
m = menu_create(cfg->title, DIV_ROUND_UP(cfg->timeout, 10),
- cfg->prompt, label_print, NULL, NULL);
+ cfg->prompt, NULL, label_print, NULL, NULL);
if (!m)
return NULL;
if (cfg->default_label &&
(strcmp(label->name, cfg->default_label) == 0))
default_num = label->num;
-
}
/*
/*
* Try to boot any labels we have yet to attempt to boot.
*/
-static void boot_unattempted_labels(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
+static void boot_unattempted_labels(struct cmd_tbl *cmdtp, struct pxe_menu *cfg)
{
struct list_head *pos;
struct pxe_label *label;
* If this function returns, there weren't any labels that successfully
* booted, or the user interrupted the menu selection via ctrl+c.
*/
-void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
+void handle_pxe_menu(struct cmd_tbl *cmdtp, struct pxe_menu *cfg)
{
void *choice;
struct menu *m;
int err;
-#ifdef CONFIG_CMD_BMP
- /* display BMP if available */
- if (cfg->bmp) {
- if (get_relfile(cmdtp, cfg->bmp, load_addr)) {
- run_command("cls", 0);
- bmp_display(load_addr,
- BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
- } else {
- printf("Skipping background bmp %s for failure\n",
- cfg->bmp);
+ if (IS_ENABLED(CONFIG_CMD_BMP)) {
+ /* display BMP if available */
+ if (cfg->bmp) {
+ if (get_relfile(cmdtp, cfg->bmp, image_load_addr)) {
+ if (CONFIG_IS_ENABLED(CMD_CLS))
+ run_command("cls", 0);
+ bmp_display(image_load_addr,
+ BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
+ } else {
+ printf("Skipping background bmp %s for failure\n",
+ cfg->bmp);
+ }
}
}
-#endif
m = pxe_menu_to_menu(cfg);
if (!m)