Explorar o código

firmware-utils: mksercommfw: overhaul image creation

Move the zip compression into a build recipe. Pad the image using the
existing build recipes as well to remove duplicate functionality

Change the code to append header and footer in two steps. Allow to use a
fixed filename as the netgear update image does.

Use a fixed timestamp within the zip archive to make the images
reproducible.

Due to the changes we are now compatible to the gnu89 c standard used by
default on the buildbots and we don't need to force a more recent
standard anymore.

Beside all changes, the footer still looks wrong in compare to the
netgear update image.

Signed-off-by: Mathias Kresin <[email protected]>
Mathias Kresin %!s(int64=6) %!d(string=hai) anos
pai
achega
26a016731d

+ 10 - 0
include/image-commands.mk

@@ -168,6 +168,16 @@ define Build/gzip
 	@mv [email protected] $@
 endef
 
+define Build/zip
+	mkdir [email protected]
+	mv $@ [email protected]/$(1)
+
+	zip -j -X \
+		$(if $(SOURCE_DATE_EPOCH),--mtime="$(SOURCE_DATE_EPOCH)") \
+		$@ [email protected]/$(if $(1),$(1),$@)
+	rm -rf [email protected]
+endef
+
 define Build/jffs2
 	rm -rf $(KDIR_TMP)/$(DEVICE_NAME)/jffs2 && \
 		mkdir -p $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/$$(dirname $(1)) && \

+ 14 - 9
target/linux/ramips/image/mt76x8.mk

@@ -2,17 +2,22 @@
 # MT76x8 Profiles
 #
 
-DEVICE_VARS += SERCOMM_KERNEL_OFFSET SERCOMM_HWID SERCOMM_HWVER SERCOMM_SWVER
+DEVICE_VARS += SERCOMM_HWID SERCOMM_HWVER SERCOMM_SWVER
 
-define Build/mksercommfw
+define Build/sercom-seal
 	$(STAGING_DIR_HOST)/bin/mksercommfw \
-		$@ \
-		$(SERCOMM_KERNEL_OFFSET) \
-		$(SERCOMM_HWID) \
-		$(SERCOMM_HWVER) \
-		$(SERCOMM_SWVER)
+		-i $@ \
+		-b $(SERCOMM_HWID) \
+		-r $(SERCOMM_HWVER) \
+		-v $(SERCOMM_SWVER) \
+		$(1)
 endef
 
+define Build/sercom-footer
+	$(call Build/sercom-seal,-f)
+endef
+
+
 define Device/tplink
   TPLINK_FLASHLAYOUT :=
   TPLINK_HWID :=
@@ -116,14 +121,14 @@ define Device/netgear_r6120
   IMAGE_SIZE := $(ralink_default_fw_size_16M)
   DEVICE_TITLE := Netgear AC1200 R6120
   DEVICE_PACKAGES := kmod-mt76x2 kmod-usb2 kmod-usb-ohci
-  SERCOMM_KERNEL_OFFSET := 0x90000
   SERCOMM_HWID := CGQ
   SERCOMM_HWVER := A001
   SERCOMM_SWVER := 0x0040
   IMAGES += factory.img
   IMAGE/default := append-kernel | pad-to $$$$(BLOCKSIZE)| append-rootfs | pad-rootfs
   IMAGE/sysupgrade.bin := $$(IMAGE/default) | append-metadata | check-size $$$$(IMAGE_SIZE)
-  IMAGE/factory.img := $$(IMAGE/default) | mksercommfw
+  IMAGE/factory.img := pad-extra 576k | $$(IMAGE/default) | \
+	sercom-footer | pad-to 128 | zip R6120.bin | sercom-seal
 endef
 TARGET_DEVICES += netgear_r6120
 

+ 1 - 1
tools/firmware-utils/Makefile

@@ -84,7 +84,7 @@ define Host/Compile
 	$(call cc,mkdhpimg buffalo-lib, -Wall)
 	$(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall --std=c99)
 	$(call cc,dns313-header, -Wall)
-	$(call cc,mksercommfw, -Wall --std=gnu99)
+	$(call cc,mksercommfw, -Wall)
 endef
 
 define Host/Install

+ 110 - 271
tools/firmware-utils/src/mksercommfw.c

@@ -5,6 +5,7 @@
 #include <unistd.h>
 #include <byteswap.h>
 #include <endian.h>
+#include <getopt.h>
 
 #if !defined(__BYTE_ORDER)
 #error "Unknown byte order"
@@ -12,14 +13,8 @@
 
 #if __BYTE_ORDER == __BIG_ENDIAN
 #define cpu_to_be32(x)  (x)
-#define be32_to_cpu(x)  (x)
-#define cpu_to_be16(x)  (x)
-#define be16_to_cpu(x)  (x)
 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 #define cpu_to_be32(x)  bswap_32(x)
-#define be32_to_cpu(x)  bswap_32(x)
-#define cpu_to_be16(x)  bswap_16(x)
-#define be16_to_cpu(x)  bswap_16(x)
 #else
 #error "Unsupported endianness"
 #endif
@@ -33,9 +28,6 @@
 #endif
 
 #define ERR(...) {printf(__VA_ARGS__); }
-#define ALIGN(a,b) ((a) + ((b) - ((a) % (b))))
-#define ROOTFS_ALIGN 128
-#define HEADER_SIZE 71
 
 /*
  * Fw Header Layout for Netgear / Sercomm devices (bytes)
@@ -51,14 +43,12 @@
  * magic  : 63-69  ASCII
  * ChkSum : 511    Inverse value of the full image checksum while this location is 0x00
  */
-
 static const char* magic = "sErCoMm"; /* 7 */
-
-/* 7-11: version control/download control ? */
 static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
+static const int header_sz = 512;
+static const int footer_sz = 71;
 
-
-/* 512 onwards -> ZIP containing rootfs with the same Header */
+static int is_header = 1;
 
 struct file_info {
 	char* file_name; /* name of the file */
@@ -68,23 +58,32 @@ struct file_info {
 
 static u_int8_t getCheckSum(char* data, int len) {
 	u_int8_t new = 0;
+	int i;
 
 	if (!data) {
 		ERR("Invalid pointer provided!\n");
 		return 0;
 	}
 
-	for (int i = 0; i < len; i++) {
+	for (i = 0; i < len; i++) {
 		new += data[i];
 	}
 
 	return new;
 }
 
-static int bufferFile(struct file_info* finfo) {
-	int fs = 0;
+/*
+ * read file into buffer
+ * add space for header/footer
+ */
+static int copyToOutputBuf(struct file_info* finfo) {
 	FILE* fp = NULL;
 
+	int file_sz = 0;
+	int extra_sz;
+	int hdr_pos;
+	int img_pos;
+
 	if (!finfo || !finfo->file_name) {
 		ERR("Invalid pointer provided!\n");
 		return -1;
@@ -100,25 +99,39 @@ static int bufferFile(struct file_info* finfo) {
 	/* Get filesize */
 	rewind(fp);
 	fseek(fp, 0L, SEEK_END);
-	fs = ftell(fp);
+	file_sz = ftell(fp);
 	rewind(fp);
 
-	if (fs < 0) {
+	if (file_sz < 1) {
 		ERR("Error getting filesize: %s\n", finfo->file_name);
 		fclose(fp);
 		return -1;
 	}
 
-	DBG("Filesize: %i\n", fs);
-	finfo->file_size = fs;
+	if (is_header) {
+		extra_sz = header_sz;
+		hdr_pos = 0;
+		img_pos = header_sz;
+	} else {
+		extra_sz = footer_sz;
+		hdr_pos = file_sz;
+		img_pos = 0;
+	}
+
+	DBG("Filesize: %i\n", file_sz);
+	finfo->file_size = file_sz + extra_sz;
 
-	if (!(finfo->file_data = malloc(fs))) {
+	if (!(finfo->file_data = malloc(finfo->file_size))) {
 		ERR("Out of memory!\n");
 		fclose(fp);
 		return -1;
 	}
 
-	if (fread(finfo->file_data, 1, fs, fp) != fs) {
+	/* init header/footer bytes */
+	memset(finfo->file_data + hdr_pos, 0, extra_sz);
+
+	/* read file and take care of leading header if exists */
+	if (fread(finfo->file_data + img_pos, 1, file_sz, fp) != file_sz) {
 		ERR("Error reading file %s\n", finfo->file_name);
 		fclose(fp);
 		return -1;
@@ -127,7 +140,7 @@ static int bufferFile(struct file_info* finfo) {
 	DBG("File: read successful\n");
 	fclose(fp);
 
-	return 0;
+	return hdr_pos;
 }
 
 static int writeFile(struct file_info* finfo) {
@@ -157,266 +170,92 @@ static int writeFile(struct file_info* finfo) {
 	return 0;
 }
 
-static void fi_clean(struct file_info* finfo) {
-	if (!finfo)
-		return;
-
-	if (finfo->file_name) {
-		finfo->file_name = NULL;
-	}
-
-	if (finfo->file_data) {
-		free(finfo->file_data);
-		finfo->file_data = NULL;
-	}
-
-	finfo->file_size = 0;
-}
-
 static void usage(char* argv[]) {
-    printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
-           "All are positional arguments ...	\n"
-           "	sysupgradefile:     File with the kernel uimage at 0\n"
-           "	kernel_offset:      Offset where the kernel is located (decimal, hex or octal notation)\n"
-           "	HWID:               Hardware ID, ASCII\n"
-           "	HWVER:              Hardware Version, ASCII\n"
-           "	SWID:               Software Version (decimal, hex or octal notation)\n"
-           "	\n"
-           , argv[0]);
+	printf("Usage: %s [OPTIONS...]\n"
+	       "\n"
+	       "Options:\n"
+	       "  -f            add sercom footer (if absent, header)\n"
+	       "  -b <hwid>     use hardware id specified with <hwid> (ASCII)\n"
+	       "  -r <hwrev>    use hardware revision specified with <hwrev> (ASCII)\n"
+	       "  -v <version>  set image version to <version> (decimal, hex or octal notation)\n"
+	       "  -i <file>     input file\n"
+	       , argv[0]);
 }
 
 int main(int argc, char* argv[]) {
-	int ret = 1;
-	int rootfsname_sz;
-	int zipfsname_sz;
-	int zipcmd_sz;
-	u_int32_t kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
-	u_int32_t swVer = 0;
-	struct file_info sysupgrade = { 0 };
-	struct file_info header = { 0 };
-	struct file_info rootfs = { 0 };
-	struct file_info zippedfs = { 0 };
 	struct file_info image = { 0 };
+
 	char* hwID = NULL;
 	char* hwVer = NULL;
-	char* rootfsname = NULL;
-	char* zipfsname = NULL;
-	char* zipcmd = NULL;
+	u_int32_t swVer = 0;
 	u_int8_t chkSum;
-
-	if (argc == 2) {
-		struct file_info myfile = { argv[1], 0, 0 };
-
-		if (bufferFile(&myfile))
-			return 1;
-
-		chkSum = getCheckSum(myfile.file_data, myfile.file_size);
-		printf("Checksum for File: 0x%hhX\n", chkSum);
-
-		return 0;
+	int hdr_offset;
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "b:i:r:v:f");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'b':
+			hwID = optarg;
+			break;
+		case 'f':
+			is_header = 0;
+			break;
+		case 'i':
+			image.file_name = optarg;
+			break;
+		case 'r':
+			hwVer = optarg;
+			break;
+		case 'v':
+			swVer = (u_int32_t) strtol(optarg, NULL, 0);
+			swVer = cpu_to_be32(swVer);
+			break;
+		default:
+			usage(argv);
+			return EXIT_FAILURE;
+		}
 	}
 
-	if (argc != 6) {
-		usage(argv);
-		return 1;
+	if (!hwID || !hwVer || !image.file_name) {
+			usage(argv);
+			return EXIT_FAILURE;
 	}
 
-	printf("Building fw image for sercomm devices ..\n");
-
-	/* process args */
-	hwID = argv[3];
-	hwVer = argv[4];
-
-	sysupgrade.file_name = argv[1];
-	image.file_name = argv[1];
-	kernel_offset = (u_int32_t) strtol(argv[2], NULL, 0);
-	swVer = (u_int32_t) strtol(argv[5], NULL, 0);
-	swVer = cpu_to_be32(swVer);
-
-	/* Check if files actually exist */
-	if (access(sysupgrade.file_name, (F_OK | R_OK))) {
-		/* Error */
-		ERR("File not found: %s\n", sysupgrade.file_name);
-		goto cleanup;
+	/*
+	 * copy input to buffer, add extra space for header/footer and return
+	 * header position
+	 */
+	hdr_offset = copyToOutputBuf(&image);
+	if (hdr_offset < 0)
+		return EXIT_FAILURE;
+
+	DBG("Filling header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
+
+	strncpy(image.file_data + hdr_offset + 0, magic, 7);
+	memcpy(image.file_data + hdr_offset + 7, version, sizeof(version));
+	strncpy(image.file_data + hdr_offset + 11, hwID, 34);
+	strncpy(image.file_data + hdr_offset + 45, hwVer, 10);
+	memcpy(image.file_data + hdr_offset + 55, &swVer, sizeof(swVer));
+	strncpy(image.file_data + hdr_offset + 63, magic, 7);
+
+	/* calculate checksum and invert checksum */
+	if (is_header) {
+		chkSum = getCheckSum(image.file_data, image.file_size);
+		chkSum = (chkSum ^ 0xFF) + 1;
+		DBG("Checksum for Image: %hhX\n", chkSum);
+
+		/* write checksum to header */
+		image.file_data[511] = (char) chkSum;
 	}
 
-	/* Calculate amount of required memory (incl. 0-term) */
-	rootfsname_sz = strlen(sysupgrade.file_name) + 7 + 1;
-	zipfsname_sz = strlen(sysupgrade.file_name) + 7 + 4 + 1;
-
-	/* Allocate required memory */
-	if (!(rootfsname = (char*) malloc(rootfsname_sz)) || !(zipfsname =
-			(char*) malloc(zipfsname_sz))) {
-		/* Error */
-		ERR("Out of memory!\n");
-		goto cleanup;
-	}
-
-	/* Create filenames */
-	if (snprintf(rootfsname, rootfsname_sz, "%s.rootfs", sysupgrade.file_name)
-			>= rootfsname_sz
-			|| snprintf(zipfsname, zipfsname_sz, "%s.rootfs.zip",
-					sysupgrade.file_name) >= zipfsname_sz) {
-		/* Error */
-		ERR("Buffer too small!\n");
-		goto cleanup;
-	}
-
-	/* Buffer all files */
-	if (bufferFile(&sysupgrade)) {
-		/* Error */
-		goto cleanup;
-	}
-
-	DBG("Building header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
-
-	/* Construct the firmware header/magic */
-	header.file_name = NULL;
-	header.file_size = HEADER_SIZE;
-
-	if (!(header.file_data = (char*) calloc(1, HEADER_SIZE))) {
-		/* Error */
-		ERR("Out of memory!\n");
-		goto cleanup;
-	}
-
-	strncpy(header.file_data + 0, magic, 7);
-	memcpy(header.file_data + 7, version, sizeof(version));
-	strncpy(header.file_data + 11, hwID, 34);
-	strncpy(header.file_data + 45, hwVer, 10);
-	memcpy(header.file_data + 55, &swVer, sizeof(swVer));
-	strncpy(header.file_data + 63, magic, 7);
-
-	DBG("Creating rootfs ..\n");
-
-	/* Construct a rootfs */
-	rootfs.file_name = rootfsname;
-	rootfs.file_size = ALIGN(
-			sysupgrade.file_size + kernel_offset + header.file_size,
-			ROOTFS_ALIGN);
-
-	if (!(rootfs.file_data = calloc(1, rootfs.file_size))) {
-		/* Error */
-		ERR("Out of memory!\n");
-		goto cleanup;
-	}
-
-	/* copy Owrt image to kernel location */
-	memcpy(rootfs.file_data + kernel_offset, sysupgrade.file_data,
-			sysupgrade.file_size);
-
-	/* Append header after the owrt image.  The updater searches for it */
-	memcpy(rootfs.file_data + kernel_offset + sysupgrade.file_size,
-			header.file_data, header.file_size);
-
-	/* Write to file */
-	if (writeFile(&rootfs)) {
-		/* Error */
-		goto cleanup;
-	}
-
-	/* Construct a zip */
-	DBG("Preparing to zip ..\n");
-
-	/* now that we got the rootfs, repeat the whole thing again(sorta):
-	 * 1. zip the rootfs */
-	zipcmd_sz = 3 + 1 + strlen(zipfsname) + 1 + strlen(rootfs.file_name) + 1;
-
-	if (!(zipcmd = malloc(zipcmd_sz))) {
-		/* Error */
-		ERR("Out of memory!\n");
-		goto cleanup;
-	}
-
-	if (snprintf(zipcmd, zipcmd_sz, "%s %s %s", "zip", zipfsname,
-			rootfs.file_name) >= zipcmd_sz) {
-		/* Error */
-		ERR("Buffer too small!\n");
-		goto cleanup;
-	}
-
-	if (system(zipcmd)) {
-		/* Error */
-		ERR("Error creating a zip file!\n");
-		goto cleanup;
-	}
-
-	/* and load zipped fs */
-	zippedfs.file_name = zipfsname;
-
-	if (bufferFile(&zippedfs)) {
-		/* Error */
-		goto cleanup;
-	}
-
-	DBG("Creating Image.\n");
-
-	/* 2. create new file 512 + rootfs size */
-	image.file_size = zippedfs.file_size + 512;
-	if (!(image.file_data = malloc(zippedfs.file_size + 512))) {
-		/* Error */
-		ERR("Out of memory!\n");
-		goto cleanup;
-	}
-
-	/* 3. add header to file */
-	memcpy(image.file_data, header.file_data, header.file_size);
-
-	/* 4. clear remaining space */
-	if (header.file_size < 512)
-		memset(image.file_data + header.file_size, 0, 512 - header.file_size);
-
-	/* 5. copy zipfile at loc 512 */
-	memcpy(image.file_data + 512, zippedfs.file_data, zippedfs.file_size);
-
-	/* 6. do a checksum run, and compute checksum */
-	chkSum = getCheckSum(image.file_data, image.file_size);
-
-	DBG("Checksum for Image: %hhX\n", chkSum);
-
-	/* 7. write the checksum inverted into byte 511 to bring it to 0 on verification */
-	chkSum = (chkSum ^ 0xFF) + 1;
-	image.file_data[511] = (char) chkSum;
-
-	chkSum = getCheckSum(image.file_data, image.file_size);
-	DBG("Checksum for after fix: %hhX\n", chkSum);
-
-	if (chkSum != 0) {
-		ERR("Invalid checksum!\n")
-		goto cleanup;
-	}
-
-	/* 8. pray that the updater will accept the file */
-	if (writeFile(&image)) {
-		/* Error */
-		goto cleanup;
-	}
-
-	/* All seems OK */
-	ret = 0;
-
-	cleanup:
-
-	if (rootfs.file_name && !access(rootfs.file_name, F_OK | W_OK))
-		remove(rootfs.file_name);
-
-	if (zippedfs.file_name && !access(zippedfs.file_name, F_OK | W_OK))
-		remove(zippedfs.file_name);
-
-	fi_clean(&sysupgrade);
-	fi_clean(&header);
-	fi_clean(&rootfs);
-	fi_clean(&zippedfs);
-	fi_clean(&image);
-
-	if (rootfsname)
-		free(rootfsname);
-
-	if (zipfsname)
-		free(zipfsname);
-
-	if (zipcmd)
-		free(zipcmd);
+	/* overwrite input file */
+	if (writeFile(&image))
+		return EXIT_FAILURE;
 
-	return ret;
+	return EXIT_SUCCESS;
 }