backport of: [PATCH] cmd: pxe: add support for FDT overlays
authorRobert Nelson <robertcnelson@gmail.com>
Tue, 14 Feb 2023 22:35:27 +0000 (16:35 -0600)
committerHan Gao <gaohan@iscas.ac.cn>
Fri, 20 Oct 2023 05:38:37 +0000 (13:38 +0800)
Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
cmd/pxe_utils.c
cmd/pxe_utils.h
doc/README.pxe

index a636346bb51ff0a88603133cda331230e40df0db..f91b80bfbcbf36606752361d3a7869514a5888fc 100644 (file)
@@ -9,6 +9,8 @@
 #include <malloc.h>
 #include <mapmem.h>
 #include <lcd.h>
+#include <fdt_support.h>
+#include <linux/libfdt.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <errno.h>
@@ -279,6 +281,9 @@ static void label_destroy(struct pxe_label *label)
        if (label->fdtdir)
                free(label->fdtdir);
 
+       if (label->fdtoverlays)
+               free(label->fdtoverlays);
+
        free(label);
 }
 
@@ -326,6 +331,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.
  *
@@ -520,6 +611,11 @@ static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label)
                                       label->name);
                                goto cleanup;
                        }
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+                       if (label->fdtoverlays)
+                               label_boot_fdtoverlay(cmdtp, label);
+#endif
                } else {
                        bootm_argv[3] = NULL;
                }
@@ -577,6 +673,7 @@ enum token_type {
        T_INCLUDE,
        T_FDT,
        T_FDTDIR,
+       T_FDTOVERLAYS,
        T_ONTIMEOUT,
        T_IPAPPEND,
        T_BACKGROUND,
@@ -611,6 +708,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,},
@@ -1043,6 +1141,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);
index a38ac81a4701beba1542069e4b33f5a960b91f27..ec51e6b8fb78fc769b71c246ae7975ace9862b35 100644 (file)
@@ -43,6 +43,7 @@ struct pxe_label {
        char *initrd;
        char *fdt;
        char *fdtdir;
+       char *fdtoverlays;
        int ipappend;
        int attempted;
        int localboot;
index 42f913c61feba1b61ccbf46e1c51fe0a34d64fe3..b67151ca510e810c823a22bfaaa23e8cb573c5e7 100644 (file)
@@ -89,6 +89,9 @@ pxe boot
      fdt_addr - the location of a fdt blob. 'fdt_addr' will be passed to bootm
      command if it is set and 'fdt_addr_r' is not passed to bootm command.
 
+     fdtoverlay_addr_r - location in RAM at which 'pxe boot' will temporarily store
+     fdt overlay(s) before applying them to the fdt blob stored at 'fdt_addr_r'.
+
 pxe file format
 ===============
 The pxe file format is nearly a subset of the PXELINUX file format; see
@@ -148,6 +151,12 @@ kernel <path>          - if this label is chosen, use tftp to retrieve the kernel
                      It useful for overlay selection in pxe file
                      (see: doc/uImage.FIT/overlay-fdt-boot.txt)
 
+fdtoverlays <path> [...] - if this label is chosen, use tftp to retrieve the DT
+                      overlay(s) at <path>. it will be temporarily stored at the
+                      address indicated in the fdtoverlay_addr_r environment variable,
+                      and then applied in the load order to the fdt blob stored at the
+                      address indicated in the fdt_addr_r environment variable.
+
 append <string>            - use <string> as the kernel command line when booting this
                      label.