kernel: mtdsplit: add support for FIT image
authorJohn Crispin <john@openwrt.org>
Sun, 15 Mar 2015 19:39:27 +0000 (19:39 +0000)
committerJohn Crispin <john@openwrt.org>
Sun, 15 Mar 2015 19:39:27 +0000 (19:39 +0000)
If this option is enabled, the FIT image format will be detected and
split by the mtdsplit code. Detection is based upon the FDT magic, which
will trigger the parsing and detection of the rootfs, ending-up in the
creation of the 2 new partitions.

Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
SVN-Revision: 44792

target/linux/generic/config-3.18
target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c [new file with mode: 0644]

index 3ebffae..295d180 100644 (file)
@@ -2242,6 +2242,7 @@ CONFIG_MTD_ROOTFS_SPLIT=y
 CONFIG_MTD_SPLIT=y
 # CONFIG_MTD_SPLIT_FIRMWARE is not set
 CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
+# CONFIG_MTD_SPLIT_FIT_FW is not set
 # CONFIG_MTD_SPLIT_LZMA_FW is not set
 # CONFIG_MTD_SPLIT_SEAMA_FW is not set
 CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y
index fca6b48..c4e3418 100644 (file)
@@ -30,6 +30,11 @@ config MTD_SPLIT_UIMAGE_FW
        depends on MTD_SPLIT_SUPPORT
        select MTD_SPLIT
 
+config MTD_SPLIT_FIT_FW
+       bool "FIT based firmware partition parser"
+       depends on MTD_SPLIT_SUPPORT
+       select MTD_SPLIT
+
 config MTD_SPLIT_LZMA_FW
        bool "LZMA compressed kernel based firmware partition parser"
        depends on MTD_SPLIT_SUPPORT
index 12661ba..e09476b 100644 (file)
@@ -2,6 +2,7 @@ obj-$(CONFIG_MTD_SPLIT)         += mtdsplit.o
 obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o
 obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o
 obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o
+obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o
 obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o
 obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o
 obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
new file mode 100644 (file)
index 0000000..d1087f6
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/types.h>
+#include <linux/byteorder/generic.h>
+#include <linux/slab.h>
+#include <linux/of_fdt.h>
+
+#include "mtdsplit.h"
+
+struct fdt_header {
+       uint32_t magic;                  /* magic word FDT_MAGIC */
+       uint32_t totalsize;              /* total size of DT block */
+       uint32_t off_dt_struct;          /* offset to structure */
+       uint32_t off_dt_strings;         /* offset to strings */
+       uint32_t off_mem_rsvmap;         /* offset to memory reserve map */
+       uint32_t version;                /* format version */
+       uint32_t last_comp_version;      /* last compatible version */
+
+       /* version 2 fields below */
+       uint32_t boot_cpuid_phys;        /* Which physical CPU id we're
+                                           booting on */
+       /* version 3 fields below */
+       uint32_t size_dt_strings;        /* size of the strings block */
+
+       /* version 17 fields below */
+       uint32_t size_dt_struct;         /* size of the structure block */
+};
+
+static int
+mtdsplit_fit_parse(struct mtd_info *mtd, struct mtd_partition **pparts,
+                  struct mtd_part_parser_data *data)
+{
+       struct fdt_header hdr;
+       size_t hdr_len, retlen;
+       size_t offset;
+       size_t fit_offset, fit_size;
+       size_t rootfs_offset, rootfs_size;
+       struct mtd_partition *parts;
+       int ret;
+
+       hdr_len = sizeof(struct fdt_header);
+
+       /* Parse the MTD device & search for the FIT image location */
+       for(offset = 0; offset < mtd->size; offset += mtd->erasesize) {
+               ret = mtd_read(mtd, 0, hdr_len, &retlen, (void*) &hdr);
+               if (ret) {
+                       pr_err("read error in \"%s\" at offset 0x%llx\n",
+                              mtd->name, (unsigned long long) offset);
+                       return ret;
+               }
+
+               if (retlen != hdr_len) {
+                       pr_err("short read in \"%s\"\n", mtd->name);
+                       return -EIO;
+               }
+
+               /* Check the magic - see if this is a FIT image */
+               if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) {
+                       pr_debug("no valid FIT image found in \"%s\" at offset %llx\n",
+                                mtd->name, (unsigned long long) offset);
+                       continue;
+               }
+
+               /* We found a FIT image. Let's keep going */
+               break;
+       }
+
+       fit_offset = offset;
+       fit_size = be32_to_cpu(hdr.totalsize);
+
+       if (fit_size == 0) {
+               pr_err("FIT image in \"%s\" at offset %llx has null size\n",
+                      mtd->name, (unsigned long long) fit_offset);
+               return -ENODEV;
+       }
+
+       /* Search for the rootfs partition after the FIT image */
+       ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size,
+                                  mtd->size, &rootfs_offset);
+       if (ret) {
+               pr_info("no rootfs found after FIT image in \"%s\"\n",
+                       mtd->name);
+               return ret;
+       }
+
+       rootfs_size = mtd->size - rootfs_offset;
+
+       parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL);
+       if (!parts)
+               return -ENOMEM;
+
+       parts[0].name = KERNEL_PART_NAME;
+       parts[0].offset = fit_offset;
+       parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize;
+
+       parts[1].name = ROOTFS_PART_NAME;
+       parts[1].offset = rootfs_offset;
+       parts[1].size = rootfs_size;
+
+       *pparts = parts;
+       return 2;
+}
+
+static struct mtd_part_parser uimage_parser = {
+       .owner = THIS_MODULE,
+       .name = "fit-fw",
+       .parse_fn = mtdsplit_fit_parse,
+       .type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static int __init mtdsplit_fit_init(void)
+{
+       register_mtd_parser(&uimage_parser);
+
+       return 0;
+}
+
+module_init(mtdsplit_fit_init);