[From nobody Thu Jun 25 05:55:58 2020
Received: from casper.infradead.org ([2001:8b0:10b:1236::1])
 by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
 id 1jnpzr-0007Cr-F7
 for openwrt-devel@merlin.infradead.org; Tue, 23 Jun 2020 20:58:23 +0000
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version:
 References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:
 Content-Type:Content-ID:Content-Description;
 bh=f9kzsK2pqjPSyjMNIdNPofXlifMXPeh1VW145AcaBm0=; b=pUtHA+k0C5jOfiKwt0Ztftsaq3
 HkmA6PsvygidyHN7uml2aGiEdDYlLxWwf3j2Pjx8wVysMd9PPA+RWgLGKm21zwdABy9NuqCZckJU1
 tbKqalc6wisCKA/hgKOaKKyDE+mprkuHMniGEz8byKuj0laB1r1BLVtGGm8QfD38e8jQRaIvJYMD5
 +dA6IsdPrny/G4tDrm2X4rMui1Sob+Ho76z5qhbM923FD0fvo5oKdAQK+6nPmcfxRRV14hk2VVCc7
 QxMBG3Aih3skZ/2Q8CS3yBsQLLSzkTiOReHyYOg6rtb767ZrQSGtFWmHMgPKvFp04mP32RD6p3A0X
 z/IAIy4Q==;
Received: from polaris.svanheule.net ([2a00:c98:2060:a004:1::200])
 by casper.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
 id 1jnpzn-0005ik-Ll
 for openwrt-devel@lists.openwrt.org; Tue, 23 Jun 2020 20:58:22 +0000
Received: from terra.local.svanheule.net (unknown
 [IPv6:2a02:a03f:5650:d01:497:5396:74c4:9add])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (No client certificate requested)
 (Authenticated sender: sander@svanheule.net)
 by polaris.svanheule.net (Postfix) with ESMTPSA id 4D2D4154ACA;
 Tue, 23 Jun 2020 22:58:14 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net;
 s=mail1707; t=1592945894;
 h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
 to:to:cc:cc:mime-version:mime-version:
 content-transfer-encoding:content-transfer-encoding:
 in-reply-to:in-reply-to:references:references;
 bh=f9kzsK2pqjPSyjMNIdNPofXlifMXPeh1VW145AcaBm0=;
 b=5IxmKXFAJgSylwMkmGWGj+ufo/kw9wCDAofQ3WVPCi2Wdv/905vCApuNBSvuCSnGDvDTuX
 Pl60ys8Hzu3D5c6D7LVFcz5ulkoQ3i6hmQNp/KVIfMzB2Zm1oHAP2KcOxb5GHUy9UCjMaY
 v1tOeExYhkVRQjDrX1X3T5D5m0bVuQSMpY25FRQfCVJFKPLJw0KrSFqWnRadcjBG2CNdgq
 URnMk7vHqUjFtfbGx9yXXbUiX/DuFRU2WiGrJtVvqVWpcBcfZcvy2xVCbNrBbAq56gLlBD
 v7QFtfSeTnUdn3y3jIZ3XHEXolbZeb1BDr59v2I7gcVks+hMi7hXwAdZ1wkhJA==
From: Sander Vanheule &lt;sander@svanheule.net&gt;
To: openwrt-devel@lists.openwrt.org
Cc: Sander Vanheule &lt;sander@svanheule.net&gt;
Subject: [PATCH 1/1] kernel: mtdsplit: support okli loader splitting
Date: Tue, 23 Jun 2020 22:57:55 +0200
Message-Id: &lt;20200623205755.352533-2-sander@svanheule.net&gt;
X-Mailer: git-send-email 2.26.2
In-Reply-To: &lt;20200623205755.352533-1-sander@svanheule.net&gt;
References: &lt;20200623205755.352533-1-sander@svanheule.net&gt;
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 
X-CRM114-CacheID: sfid-20200623_215819_950828_714A18D4 
X-CRM114-Status: GOOD (  19.17  )
X-Spam-Score: -2.1 (--)
X-Spam-Report: SpamAssassin version 3.4.4 on casper.infradead.org summary:
 Content analysis details:   (-2.1 points, 5.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%
 [score: 0.0000]
 -0.0 SPF_PASS               SPF: sender matches SPF record
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
 no trust [2a00:c98:2060:a004:1:0:0:200 listed in]
 [list.dnswl.org]
 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 0.1 DKIM_SIGNED            Message has a DKIM or DK signature, not necessarily
 valid
 -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
 -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from
 envelope-from domain
 -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from
 author's domain

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 &lt;sander@svanheule.net&gt;
---
 .../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-&gt;ih_magic) != IH_MAGIC_OKLI) {
 		pr_debug(&quot;invalid uImage magic: %08x\n&quot;,
@@ -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 &lt; master-&gt;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(&quot;no valid uImage found in \&quot;%s\&quot; at offset %llx\n&quot;,
+				master-&gt;name, (unsigned long long) offset);
+			continue;
+		}
+
+		*uimage_size = sizeof(*buf) + be32_to_cpu(buf-&gt;ih_size);
+
+		if ((offset + *uimage_size) &gt; master-&gt;size) {
+			pr_debug(&quot;uImage exceeds MTD device \&quot;%s\&quot;\n&quot;, master-&gt;name);
+			*uimage_size = 0;
+			continue;
+		}
+		break;
+	}
+
+	vfree(buf);
+
+	if (offset == master-&gt;size) {
+		pr_debug(&quot;no uImage found in \&quot;%s\&quot;\n&quot;, master-&gt;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 *)&amp;magic, sizeof(magic));
+	if (ret)
+		return ret;
+
+	switch (be32_to_cpu(magic)) {
+	case OKLI_MAGIC_ELF:
+	case IH_MAGIC_OKLI:
+		break;
+	default:
+		pr_debug(&quot;invalid partition magic: %08x\n&quot;, be32_to_cpu(magic));
+		return -EINVAL;
+	}
+
+	ret = uimage_okli_find_offset(master, &amp;uimage_size);
+	if (ret &lt; 0)
+		return ret;
+
+	if (uimage_size == 0) {
+		pr_debug(&quot;no uImage found in \&quot;%s\&quot;\n&quot;, master-&gt;name);
+		return -ENODEV;
+	}
+
+	uimage_offset = ret;
+
+	ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size,
+				master-&gt;size, &amp;rootfs_offset, &amp;type);
+	if (ret) {
+		pr_debug(&quot;no rootfs after uImage in \&quot;%s\&quot;\n&quot;, master-&gt;name);
+		return ret;
+	}
+
+	uimage_size = rootfs_offset;
+	rootfs_size = master-&gt;size - rootfs_offset;
+
+	if (rootfs_size == 0) {
+		pr_debug(&quot;no rootfs found in \&quot;%s\&quot;\n&quot;, master-&gt;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


]