[PATCH 1/1] kernel: mtdsplit: support okli loader splitting

Sander Vanheule sander at svanheule.net
Sat Jun 27 07:04:42 EDT 2020


okli images always have the following structure:
* ELF kernel loader
* kernel uImage
* rootfs

Because the kernel loader is limited in size, the uImage can start
within the same erase block. The current version of the the uImage
splitter doesn't handle uImages not starting at an erase block
boundary, requiring fixed partition splits. A fixed rootfs/kernel split
may require future tuning if the kernel size changes. A fixed
loader/firmware split enabled the current uImage splitter, but would
require sysupgrade files without a loader, complicating build
directives.

This patch implements a basic partition scan, assuming the order listed
above. If the ELF loader is present at the start of the firmware
partition, it is included in the kernel partition. If not, then the
dynamic kernel partition only comprises the uImage. This is done for
backwards compatibility with other devices that use an openwrt,okli
compatible firmware partition with a separate loader partition.

Signed-off-by: Sander Vanheule <sander at svanheule.net>
---
 .../drivers/mtd/mtdsplit/mtdsplit_uimage.c    | 124 +++++++++++++++++-
 1 file changed, 118 insertions(+), 6 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 525ad8218b..5476ed3508 100644
--- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
@@ -411,12 +411,13 @@ static struct mtd_part_parser uimage_fonfxc_parser = {
  * OKLI (OpenWrt Kernel Loader Image)
  **************************************************/
 
-#define IH_MAGIC_OKLI	0x4f4b4c49
+#define IH_MAGIC_OKLI    0x4f4b4c49
+#define OKLI_MAGIC_ELF   0x7f454c46
+#define OKLI_NUM_PARTS   2
+#define OKLI_SEARCH_STEP 0x1000
 
-static ssize_t uimage_verify_okli(u_char *buf, size_t len, int *extralen)
+static int uimage_verify_okli(struct uimage_header *header)
 {
-	struct uimage_header *header = (struct uimage_header *)buf;
-
 	/* default sanity checks */
 	if (be32_to_cpu(header->ih_magic) != IH_MAGIC_OKLI) {
 		pr_debug("invalid uImage magic: %08x\n",
@@ -439,13 +440,124 @@ static ssize_t uimage_verify_okli(u_char *buf, size_t len, int *extralen)
 	return 0;
 }
 
+static ssize_t
+uimage_okli_find_offset(struct mtd_info *master,
+			size_t *uimage_size)
+{
+	struct uimage_header *buf;
+	size_t buf_len = sizeof(struct uimage_header);
+	size_t offset;
+	int ret;
+
+	buf = vmalloc(buf_len);
+	if (!buf)
+		return -ENOMEM;
+
+	/* use default okli step size to search for uImage */
+	for (offset = 0; offset < master->size; offset += OKLI_SEARCH_STEP) {
+		*uimage_size = 0;
+
+		ret = read_uimage_header(master, offset, (u_char *)buf, buf_len);
+		if (ret)
+			continue;
+
+		ret = uimage_verify_okli(buf);
+		if (ret) {
+			pr_debug("no valid uImage found in \"%s\" at offset %llx\n",
+				master->name, (unsigned long long) offset);
+			continue;
+		}
+
+		*uimage_size = sizeof(*buf) + be32_to_cpu(buf->ih_size);
+
+		if ((offset + *uimage_size) > master->size) {
+			pr_debug("uImage exceeds MTD device \"%s\"\n", master->name);
+			*uimage_size = 0;
+			continue;
+		}
+		break;
+	}
+
+	vfree(buf);
+
+	if (offset == master->size) {
+		pr_debug("no uImage found in \"%s\"\n", master->name);
+		return -ENODEV;
+	}
+
+	return offset;
+}
+
 static int
 mtdsplit_uimage_parse_okli(struct mtd_info *master,
 			      const struct mtd_partition **pparts,
 			      struct mtd_part_parser_data *data)
 {
-	return __mtdsplit_parse_uimage(master, pparts, data,
-				      uimage_verify_okli);
+	struct mtd_partition *parts;
+	size_t uimage_offset;
+	size_t uimage_size = 0;
+	size_t rootfs_offset;
+	size_t rootfs_size = 0;
+	int ret;
+	enum mtdsplit_part_type type;
+
+	uint32_t magic;
+	ret = read_uimage_header(master, 0, (u_char *)&magic, sizeof(magic));
+	if (ret)
+		return ret;
+
+	switch (be32_to_cpu(magic)) {
+	case OKLI_MAGIC_ELF:
+	case IH_MAGIC_OKLI:
+		break;
+	default:
+		pr_debug("invalid partition magic: %08x\n", be32_to_cpu(magic));
+		return -EINVAL;
+	}
+
+	ret = uimage_okli_find_offset(master, &uimage_size);
+	if (ret < 0)
+		return ret;
+
+	if (uimage_size == 0) {
+		pr_debug("no uImage found in \"%s\"\n", master->name);
+		return -ENODEV;
+	}
+
+	uimage_offset = ret;
+
+	ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size,
+				master->size, &rootfs_offset, &type);
+	if (ret) {
+		pr_debug("no rootfs after uImage in \"%s\"\n", master->name);
+		return ret;
+	}
+
+	uimage_size = rootfs_offset;
+	rootfs_size = master->size - rootfs_offset;
+
+	if (rootfs_size == 0) {
+		pr_debug("no rootfs found in \"%s\"\n", master->name);
+		return -ENODEV;
+	}
+
+	parts = kzalloc(OKLI_NUM_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = uimage_size;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[1].name = UBI_PART_NAME;
+	else
+		parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return OKLI_NUM_PARTS;
 }
 
 static const struct of_device_id mtdsplit_uimage_okli_of_match_table[] = {
-- 
2.26.2




More information about the openwrt-devel mailing list