From patchwork Wed Jun 20 13:56:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Maclean X-Patchwork-Id: 932275 X-Patchwork-Delegate: blogic@openwrt.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=monkeh.net Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="P9oJ2i1h"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419mdL6DmQz9s2R for ; Wed, 20 Jun 2018 23:58:30 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Subject:References: In-Reply-To:Message-Id:Date:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=m/8vCu5h2lA7HmseK4kVUxsdXyunBWbXwUXpdXola4U=; b=P9oJ2i1hsgauBg 0njB1YCpDs8oOuunEGPZIfgIGytXuxwI3FhohR/w4MmbJRI0IihM8qpoUpKgv9V7SmpOQ4LNwkMTs BVYY4y6giWNuk5PbIsZD+r7Wu7HmtU9nElrIRnk7YfuV+Zm0DEiW7depdUS1nosTWJPmDz1mhsIN8 l/JZiVH9/lnX8Fj/PrOQQKiDU/G5SxMdFYQlEqJh8s8lJPhEqKJVOWTOpZiz8ybRT5kxfO0vxmmFt xtXZhMDihIK2WuNzuBYZsemcWqEcTT4d929oFFMLCiqKVihFQvxFblHyP0GeIe4F9aZHVbtK8pdAg 3X7DtJHiG7sSHnzlK1WQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fVdcr-0003NS-8m; Wed, 20 Jun 2018 13:58:21 +0000 Received: from monkeh.net ([88.97.98.50] helo=mail.monkeh.net) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fVdbi-0002Rp-It for openwrt-devel@lists.openwrt.org; Wed, 20 Jun 2018 13:57:14 +0000 Received: from terra.home.monkeh.net (unknown [172.16.0.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: monkeh@monkeh.net) by mail.monkeh.net (Postfix) with ESMTPSA id 9082E30A9EF; Wed, 20 Jun 2018 13:56:53 +0000 (UTC) From: Alex Maclean To: openwrt-devel@lists.openwrt.org, mschiffer@universe-factory.net Date: Wed, 20 Jun 2018 14:56:20 +0100 Message-Id: <20180620135622.25543-2-monkeh@monkeh.net> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620135622.25543-1-monkeh@monkeh.net> References: <20180620135622.25543-1-monkeh@monkeh.net> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180620_065710_942504_E7D2EE70 X-CRM114-Status: GOOD ( 16.43 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record Subject: [OpenWrt-Devel] [PATCH 2/4] firmware-utils: tplink-safeloader: add dynamic partitions X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pepe2k@gmail.com, hyniu@o2.pl MIME-Version: 1.0 Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Add support to dynamically split the firmware partition into os-image and file-system partitions. This is done by replacing those entries in the partition table with a single unified firmware partition, which is then split according to actual kernel image size. The factory image will have the file-system partition aligned to a 64K erase block, but the sysupgrade image skips this and aligns only the JFFS2 EOF marker to squeeze out more space. This should prevent further creeping updates to the kernel partition size while maximizing space for the overlay filesystem on smaller devices. Signed-off-by: Alex Maclean --- tools/firmware-utils/src/tplink-safeloader.c | 71 ++++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c index 27c5aa8497..1d011446f5 100644 --- a/tools/firmware-utils/src/tplink-safeloader.c +++ b/tools/firmware-utils/src/tplink-safeloader.c @@ -65,7 +65,7 @@ struct image_partition_entry { /** A flash partition table entry */ struct flash_partition_entry { - const char *name; + char *name; uint32_t base; uint32_t size; }; @@ -77,7 +77,7 @@ struct device_info { const char *support_list; char support_trail; const char *soft_ver; - const struct flash_partition_entry partitions[MAX_PARTITIONS+1]; + struct flash_partition_entry partitions[MAX_PARTITIONS+1]; const char *first_sysupgrade_partition; const char *last_sysupgrade_partition; }; @@ -1135,7 +1135,7 @@ static struct image_partition_entry make_soft_version_from_string(const char *so } /** Generates the support-list partition */ -static struct image_partition_entry make_support_list(const struct device_info *info) { +static struct image_partition_entry make_support_list(struct device_info *info) { size_t len = strlen(info->support_list); struct image_partition_entry entry = alloc_image_partition("support-list", len + 9); @@ -1148,7 +1148,7 @@ static struct image_partition_entry make_support_list(const struct device_info * } /** Creates a new image partition with an arbitrary name from a file */ -static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) { +static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof, struct flash_partition_entry *file_system_partition) { struct stat statbuf; if (stat(filename, &statbuf) < 0) @@ -1157,7 +1157,10 @@ static struct image_partition_entry read_file(const char *part_name, const char size_t len = statbuf.st_size; if (add_jffs2_eof) - len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark); + if (file_system_partition) + len = ALIGN(len + file_system_partition->base, 0x10000) + sizeof(jffs2_eof_mark) - file_system_partition->base; + else + len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark); struct image_partition_entry entry = alloc_image_partition(part_name, len); @@ -1273,7 +1276,7 @@ static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) { 1014-1813 Image partition table (2048 bytes, padded with 0xff) 1814-xxxx Firmware partitions */ -static void * generate_factory_image(const struct device_info *info, const struct image_partition_entry *parts, size_t *len) { +static void * generate_factory_image(struct device_info *info, const struct image_partition_entry *parts, size_t *len) { *len = 0x1814; size_t i; @@ -1306,7 +1309,7 @@ static void * generate_factory_image(const struct device_info *info, const struc should be generalized when TP-LINK starts building its safeloader into hardware with different flash layouts. */ -static void * generate_sysupgrade_image(const struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) { +static void * generate_sysupgrade_image(struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) { size_t i, j; size_t flash_first_partition_index = 0; size_t flash_last_partition_index = 0; @@ -1369,10 +1372,53 @@ static void build_image(const char *output, uint32_t rev, bool add_jffs2_eof, bool sysupgrade, - const struct device_info *info) { + struct device_info *info) { + + size_t i; struct image_partition_entry parts[7] = {}; + struct flash_partition_entry *firmware_partition = NULL; + struct flash_partition_entry *os_image_partition = NULL; + struct flash_partition_entry *file_system_partition = NULL; + size_t firmware_partition_index = 0; + + for (i = 0; info->partitions[i].name; i++) { + if (!strcmp(info->partitions[i].name, "firmware")) + { + firmware_partition = &info->partitions[i]; + firmware_partition_index = i; + } + } + + if (firmware_partition) + { + os_image_partition = &info->partitions[firmware_partition_index]; + file_system_partition = &info->partitions[firmware_partition_index + 1]; + + struct stat kernel; + if (stat(kernel_image, &kernel) < 0) + error(1, errno, "unable to stat file `%s'", kernel_image); + + if (kernel.st_size > firmware_partition->size) + error(1, 0, "kernel overflowed firmware partition\n"); + + for (i = MAX_PARTITIONS-1; i >= firmware_partition_index + 1; i--) + info->partitions[i+1] = info->partitions[i]; + + file_system_partition->name = "file-system"; + file_system_partition->base = firmware_partition->base + kernel.st_size; + + /* Align partition start to erase blocks for factory images only */ + if (!sysupgrade) + file_system_partition->base = ALIGN(firmware_partition->base + kernel.st_size, 0x10000); + + file_system_partition->size = firmware_partition->size - file_system_partition->base; + + os_image_partition->name = "os-image"; + os_image_partition->size = kernel.st_size; + } + parts[0] = make_partition_table(info->partitions); if (info->soft_ver) parts[1] = make_soft_version_from_string(info->soft_ver); @@ -1380,8 +1426,8 @@ static void build_image(const char *output, parts[1] = make_soft_version(rev); parts[2] = make_support_list(info); - parts[3] = read_file("os-image", kernel_image, false); - parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof); + parts[3] = read_file("os-image", kernel_image, false, NULL); + parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof, file_system_partition); /* Some devices need the extra-para partition to accept the firmware */ if (strcasecmp(info->id, "ARCHER-C25-V1") == 0 || @@ -1412,7 +1458,6 @@ static void build_image(const char *output, free(image); - size_t i; for (i = 0; parts[i].name; i++) free_image_partition(parts[i]); } @@ -1442,7 +1487,7 @@ static void usage(const char *argv0) { }; -static const struct device_info *find_board(const char *id) +static struct device_info *find_board(const char *id) { struct device_info *board = NULL; @@ -1772,7 +1817,7 @@ int main(int argc, char *argv[]) { const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL; bool add_jffs2_eof = false, sysupgrade = false; unsigned rev = 0; - const struct device_info *info; + struct device_info *info; set_source_date_epoch(); while (true) {