[PATCH 8/8] kernel: mtdsplit_uimage: replace "edimax,uimage" parser

Bjørn Mork bjorn at mork.no
Wed Nov 25 06:45:11 EST 2020


The "edimax,uimage" format places the uimage header at an offset
and has an additional magic where the header normally would be.
Extend the generic parser with two device tree properties and
use this instead.

Signed-off-by: Bjørn Mork <bjorn at mork.no>
---
 .../drivers/mtd/mtdsplit/mtdsplit_uimage.c    | 159 ++++++------------
 .../dts/mt7620a_edimax_br-6478ac-v2.dts       |   4 +-
 .../ramips/dts/mt7620a_edimax_ew-7478apc.dts  |   4 +-
 .../linux/ramips/dts/mt7621_edimax_re23s.dts  |   4 +-
 .../ramips/dts/rt3050_edimax_3g-6200n.dts     |   4 +-
 .../ramips/dts/rt3050_edimax_3g-6200nl.dts    |   4 +-
 .../ramips/dts/rt3662_edimax_br-6475nd.dts    |   4 +-
 7 files changed, 70 insertions(+), 113 deletions(-)

diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
index 20aae10a0a2a..d2f0c7cea809 100644
--- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
@@ -22,12 +22,6 @@
 
 #include "mtdsplit.h"
 
-/*
- * uimage_header itself is only 64B, but it may be prepended with another data.
- * Currently the biggest size is for Fon(Foxconn) devices: 64B + 32B
- */
-#define MAX_HEADER_LEN		96
-
 #define IH_MAGIC	0x27051956	/* Image Magic Number		*/
 #define IH_NMLEN		32	/* Image Name Length		*/
 
@@ -76,30 +70,59 @@ read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf,
 }
 
 static void uimage_parse_dt(struct mtd_info *master, int *extralen,
-			    u32 *ih_magic, u32 *ih_type)
+			    u32 *ih_magic, u32 *ih_type,
+			    u32 *ih_start, u32 *extra_magic)
 {
 	struct device_node *np = mtd_get_of_node(master);
 
 	if (!np)
 		return;
 	if (!of_property_read_u32(np, "extralen", extralen))
-		pr_debug("got extralen=%d from device-tree\n", *extralen);
+		pr_debug("got extralen=%u from device-tree\n", *extralen);
 	if (!of_property_read_u32(np, "ih-magic", ih_magic))
 		pr_debug("got ih-magic=%08x from device-tree\n", *ih_magic);
 	if (!of_property_read_u32(np, "ih-type", ih_type))
 		pr_debug("got ih-type=%08x from device-tree\n", *ih_type);
+	if (!of_property_read_u32(np, "ih-start", ih_start))
+		pr_debug("got ih-start=%u from device-tree\n", *ih_start);
+	if (!of_property_read_u32(np, "extra-magic", extra_magic))
+		pr_debug("got extra-magic=%08x from device-tree\n", *extra_magic);
+}
+
+static ssize_t uimage_verify_default(u_char *buf, u32 ih_magic, u32 ih_type)
+{
+	struct uimage_header *header = (struct uimage_header *)buf;
+
+	/* default sanity checks */
+	if (be32_to_cpu(header->ih_magic) != ih_magic) {
+		pr_debug("invalid uImage magic: %08x != %08x\n",
+			 be32_to_cpu(header->ih_magic), ih_magic);
+		return -EINVAL;
+	}
+
+	if (header->ih_os != IH_OS_LINUX) {
+		pr_debug("invalid uImage OS: %08x != %08x\n",
+			 be32_to_cpu(header->ih_os), IH_OS_LINUX);
+		return -EINVAL;
+	}
+
+	if (header->ih_type != ih_type) {
+		pr_debug("invalid uImage type: %08x != %08x\n",
+			 be32_to_cpu(header->ih_type), ih_type);
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 /**
  * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts
  *
- * @find_header: function to call for a block of data that will return offset
- *      and tail padding length of a valid uImage header if found
  */
-static int __mtdsplit_parse_uimage(struct mtd_info *master,
-		   const struct mtd_partition **pparts,
-		   struct mtd_part_parser_data *data,
-		   ssize_t (*find_header)(u_char *buf, size_t len, u32 ih_magic, u32 ih_type))
+static int
+__mtdsplit_parse_uimage(struct mtd_info *master,
+			const struct mtd_partition **pparts,
+			struct mtd_part_parser_data *data)
 {
 	struct mtd_partition *parts;
 	u_char *buf;
@@ -109,11 +132,14 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master,
 	size_t uimage_size = 0;
 	size_t rootfs_offset;
 	size_t rootfs_size = 0;
+	size_t buflen;
 	int uimage_part, rf_part;
 	int ret;
 	int extralen = 0;
 	u32 ih_magic = IH_MAGIC;
 	u32 ih_type = IH_TYPE_KERNEL;
+	u32 ih_start = 0;
+	u32 extra_magic = 0;
 	enum mtdsplit_part_type type;
 
 	nr_parts = 2;
@@ -121,34 +147,38 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master,
 	if (!parts)
 		return -ENOMEM;
 
-	buf = vmalloc(MAX_HEADER_LEN);
+	uimage_parse_dt(master, &extralen, &ih_magic, &ih_type, &ih_start, &extra_magic);
+	buflen = sizeof(struct uimage_header) + ih_start;
+	buf = vmalloc(buflen);
 	if (!buf) {
 		ret = -ENOMEM;
 		goto err_free_parts;
 	}
 
-	uimage_parse_dt(master, &extralen, &ih_magic, &ih_type);
-
 	/* find uImage on erase block boundaries */
 	for (offset = 0; offset < master->size; offset += master->erasesize) {
 		struct uimage_header *header;
 
 		uimage_size = 0;
 
-		ret = read_uimage_header(master, offset, buf, MAX_HEADER_LEN);
+		ret = read_uimage_header(master, offset, buf, buflen);
 		if (ret)
 			continue;
 
-		ret = find_header(buf, MAX_HEADER_LEN, ih_magic, ih_type);
+		/* verify optional extra magic before uimage header */
+		if (ih_start && extra_magic && (be32_to_cpu(*(u32 *)buf) != extra_magic))
+			continue;
+
+		ret = uimage_verify_default(buf + ih_start, ih_magic, ih_type);
 		if (ret < 0) {
 			pr_debug("no valid uImage found in \"%s\" at offset %llx\n",
 				 master->name, (unsigned long long) offset);
 			continue;
 		}
-		header = (struct uimage_header *)(buf + ret);
+		header = (struct uimage_header *)(buf + ih_start);
 
 		uimage_size = sizeof(*header) +
-				be32_to_cpu(header->ih_size) + ret + extralen;
+				be32_to_cpu(header->ih_size) + ih_start + extralen;
 
 		if ((offset + uimage_size) > master->size) {
 			pr_debug("uImage exceeds MTD device \"%s\"\n",
@@ -227,41 +257,6 @@ err_free_parts:
 	return ret;
 }
 
-static ssize_t uimage_verify_default(u_char *buf, size_t len, u32 ih_magic, u32 ih_type)
-{
-	struct uimage_header *header = (struct uimage_header *)buf;
-
-	/* default sanity checks */
-	if (be32_to_cpu(header->ih_magic) != ih_magic) {
-		pr_debug("invalid uImage magic: %08x != %08x\n",
-			 be32_to_cpu(header->ih_magic), ih_magic);
-		return -EINVAL;
-	}
-
-	if (header->ih_os != IH_OS_LINUX) {
-		pr_debug("invalid uImage OS: %08x != %08x\n",
-			 be32_to_cpu(header->ih_os), IH_OS_LINUX);
-		return -EINVAL;
-	}
-
-	if (header->ih_type != ih_type) {
-		pr_debug("invalid uImage type: %08x != %08x\n",
-			 be32_to_cpu(header->ih_type), ih_type);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-mtdsplit_uimage_parse_generic(struct mtd_info *master,
-			      const struct mtd_partition **pparts,
-			      struct mtd_part_parser_data *data)
-{
-	return __mtdsplit_parse_uimage(master, pparts, data,
-				      uimage_verify_default);
-}
-
 static const struct of_device_id mtdsplit_uimage_of_match_table[] = {
 	{ .compatible = "denx,uimage" },
 	{},
@@ -271,59 +266,10 @@ static struct mtd_part_parser uimage_generic_parser = {
 	.owner = THIS_MODULE,
 	.name = "uimage-fw",
 	.of_match_table = mtdsplit_uimage_of_match_table,
-	.parse_fn = mtdsplit_uimage_parse_generic,
+	.parse_fn = __mtdsplit_parse_uimage,
 	.type = MTD_PARSER_TYPE_FIRMWARE,
 };
 
-/**************************************************
- * Edimax
- **************************************************/
-
-#define FW_EDIMAX_OFFSET	20
-#define FW_MAGIC_EDIMAX		0x43535953
-
-static ssize_t uimage_find_edimax(u_char *buf, size_t len, u32 ih_magic, u32 ih_type)
-{
-	u32 *magic;
-
-	if (len < FW_EDIMAX_OFFSET + sizeof(struct uimage_header)) {
-		pr_err("Buffer too small for checking Edimax header\n");
-		return -ENOSPC;
-	}
-
-	magic = (u32 *)buf;
-	if (be32_to_cpu(*magic) != FW_MAGIC_EDIMAX)
-		return -EINVAL;
-
-	if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len, ih_magic, ih_type))
-		return FW_EDIMAX_OFFSET;
-
-	return -EINVAL;
-}
-
-static int
-mtdsplit_uimage_parse_edimax(struct mtd_info *master,
-			      const struct mtd_partition **pparts,
-			      struct mtd_part_parser_data *data)
-{
-	return __mtdsplit_parse_uimage(master, pparts, data,
-				       uimage_find_edimax);
-}
-
-static const struct of_device_id mtdsplit_uimage_edimax_of_match_table[] = {
-	{ .compatible = "edimax,uimage" },
-	{},
-};
-
-static struct mtd_part_parser uimage_edimax_parser = {
-	.owner = THIS_MODULE,
-	.name = "edimax-fw",
-	.of_match_table = mtdsplit_uimage_edimax_of_match_table,
-	.parse_fn = mtdsplit_uimage_parse_edimax,
-	.type = MTD_PARSER_TYPE_FIRMWARE,
-};
-
-
 /**************************************************
  * Init
  **************************************************/
@@ -331,7 +277,6 @@ static struct mtd_part_parser uimage_edimax_parser = {
 static int __init mtdsplit_uimage_init(void)
 {
 	register_mtd_parser(&uimage_generic_parser);
-	register_mtd_parser(&uimage_edimax_parser);
 
 	return 0;
 }
diff --git a/target/linux/ramips/dts/mt7620a_edimax_br-6478ac-v2.dts b/target/linux/ramips/dts/mt7620a_edimax_br-6478ac-v2.dts
index 0b991611b223..f91a8dd9a243 100644
--- a/target/linux/ramips/dts/mt7620a_edimax_br-6478ac-v2.dts
+++ b/target/linux/ramips/dts/mt7620a_edimax_br-6478ac-v2.dts
@@ -116,7 +116,9 @@
 			};
 
 			partition at 70000 {
-				compatible = "edimax,uimage";
+				compatible = "denx,uimage";
+				ih-start = <20>;
+				extra-magic = <0x43535953>;
 				label = "firmware";
 				reg = <0x00070000 0x00790000>;
 			};
diff --git a/target/linux/ramips/dts/mt7620a_edimax_ew-7478apc.dts b/target/linux/ramips/dts/mt7620a_edimax_ew-7478apc.dts
index 1e1b2830f02b..05675d1bfee9 100644
--- a/target/linux/ramips/dts/mt7620a_edimax_ew-7478apc.dts
+++ b/target/linux/ramips/dts/mt7620a_edimax_ew-7478apc.dts
@@ -102,7 +102,9 @@
 			};
 
 			partition at 70000 {
-				compatible = "edimax,uimage";
+				compatible = "denx,uimage";
+				ih-start = <20>;
+				extra-magic = <0x43535953>;
 				label = "firmware";
 				reg = <0x00070000 0x00790000>;
 			};
diff --git a/target/linux/ramips/dts/mt7621_edimax_re23s.dts b/target/linux/ramips/dts/mt7621_edimax_re23s.dts
index cf44746e8f61..f6166bcdedd6 100644
--- a/target/linux/ramips/dts/mt7621_edimax_re23s.dts
+++ b/target/linux/ramips/dts/mt7621_edimax_re23s.dts
@@ -97,7 +97,9 @@
 			};
 
 			partition at 70000 {
-				compatible = "edimax,uimage";
+				compatible = "denx,uimage";
+				ih-start = <20>;
+				extra-magic = <0x43535953>;
 				label = "firmware";
 				reg = <0x70000 0xf50000>;
 			};
diff --git a/target/linux/ramips/dts/rt3050_edimax_3g-6200n.dts b/target/linux/ramips/dts/rt3050_edimax_3g-6200n.dts
index a185e5d5bb8d..e902603f904d 100644
--- a/target/linux/ramips/dts/rt3050_edimax_3g-6200n.dts
+++ b/target/linux/ramips/dts/rt3050_edimax_3g-6200n.dts
@@ -50,7 +50,9 @@
 			};
 
 			partition at 50000 {
-				compatible = "edimax,uimage";
+				compatible = "denx,uimage";
+				ih-start = <20>;
+				extra-magic = <0x43535953>;
 				label = "firmware";
 				reg = <0x50000 0x390000>;
 			};
diff --git a/target/linux/ramips/dts/rt3050_edimax_3g-6200nl.dts b/target/linux/ramips/dts/rt3050_edimax_3g-6200nl.dts
index 41768078f5fc..03572a30ca70 100644
--- a/target/linux/ramips/dts/rt3050_edimax_3g-6200nl.dts
+++ b/target/linux/ramips/dts/rt3050_edimax_3g-6200nl.dts
@@ -50,7 +50,9 @@
 			};
 
 			partition at 50000 {
-				compatible = "edimax,uimage";
+				compatible = "denx,uimage";
+				ih-start = <20>;
+				extra-magic = <0x43535953>;
 				label = "firmware";
 				reg = <0x50000 0x390000>;
 			};
diff --git a/target/linux/ramips/dts/rt3662_edimax_br-6475nd.dts b/target/linux/ramips/dts/rt3662_edimax_br-6475nd.dts
index c0e3193818d0..a9c6548cc0a8 100644
--- a/target/linux/ramips/dts/rt3662_edimax_br-6475nd.dts
+++ b/target/linux/ramips/dts/rt3662_edimax_br-6475nd.dts
@@ -86,7 +86,9 @@
 			};
 
 			partition at 70000 {
-				compatible = "edimax,uimage";
+				compatible = "denx,uimage";
+				ih-start = <20>;
+				extra-magic = <0x43535953>;
 				reg = <0x00070000 0x00790000>;
 				label = "firmware";
 			};
-- 
2.20.1




More information about the openwrt-devel mailing list