[OpenWrt-Devel,2/4] firmware-utils: tplink-safeloader: add dynamic partitions
diff mbox series

Message ID 20180620135622.25543-2-monkeh@monkeh.net
State Accepted
Delegated to: John Crispin
Headers show
Series
  • [OpenWrt-Devel,1/4] firmware-utils: mktplinkfw: add rootfs offset for combined images
Related show

Commit Message

Alex Maclean June 20, 2018, 1:56 p.m. UTC
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 <monkeh@monkeh.net>
---
 tools/firmware-utils/src/tplink-safeloader.c | 71 ++++++++++++++++----
 1 file changed, 58 insertions(+), 13 deletions(-)

Patch
diff mbox series

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) {