|
@@ -13,6 +13,8 @@
|
|
|
#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>
|
|
@@ -284,6 +286,9 @@ static void label_destroy(struct pxe_label *label)
|
|
|
if (label->fdtdir)
|
|
|
free(label->fdtdir);
|
|
|
|
|
|
+ if (label->fdtoverlays)
|
|
|
+ free(label->fdtoverlays);
|
|
|
+
|
|
|
free(label);
|
|
|
}
|
|
|
|
|
@@ -332,6 +337,92 @@ static int label_localboot(struct pxe_label *label)
|
|
|
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.
|
|
|
*
|
|
@@ -534,6 +625,11 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
|
|
|
goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
|
|
+ if (label->fdtoverlays)
|
|
|
+ label_boot_fdtoverlay(cmdtp, label);
|
|
|
+#endif
|
|
|
} else {
|
|
|
bootm_argv[3] = NULL;
|
|
|
}
|
|
@@ -591,6 +687,7 @@ enum token_type {
|
|
|
T_INCLUDE,
|
|
|
T_FDT,
|
|
|
T_FDTDIR,
|
|
|
+ T_FDTOVERLAYS,
|
|
|
T_ONTIMEOUT,
|
|
|
T_IPAPPEND,
|
|
|
T_BACKGROUND,
|
|
@@ -625,6 +722,7 @@ static const struct token keywords[] = {
|
|
|
{"fdt", T_FDT},
|
|
|
{"devicetreedir", T_FDTDIR},
|
|
|
{"fdtdir", T_FDTDIR},
|
|
|
+ {"fdtoverlays", T_FDTOVERLAYS},
|
|
|
{"ontimeout", T_ONTIMEOUT,},
|
|
|
{"ipappend", T_IPAPPEND,},
|
|
|
{"background", T_BACKGROUND,},
|
|
@@ -1057,6 +1155,11 @@ static int parse_label(char **c, struct pxe_menu *cfg)
|
|
|
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);
|