From 26a016731d1fc1e2bd6b5f8d3af0fdbd631363ff Mon Sep 17 00:00:00 2001 From: Mathias Kresin Date: Sat, 12 Jan 2019 20:18:52 +0100 Subject: [PATCH] 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 --- include/image-commands.mk | 10 + target/linux/ramips/image/mt76x8.mk | 23 +- tools/firmware-utils/Makefile | 2 +- tools/firmware-utils/src/mksercommfw.c | 381 +++++++------------------ 4 files changed, 135 insertions(+), 281 deletions(-) diff --git a/include/image-commands.mk b/include/image-commands.mk index 169c1919e7..70c09ad90c 100644 --- a/include/image-commands.mk +++ b/include/image-commands.mk @@ -168,6 +168,16 @@ define Build/gzip @mv $@.new $@ endef +define Build/zip + mkdir $@.tmp + mv $@ $@.tmp/$(1) + + zip -j -X \ + $(if $(SOURCE_DATE_EPOCH),--mtime="$(SOURCE_DATE_EPOCH)") \ + $@ $@.tmp/$(if $(1),$(1),$@) + rm -rf $@.tmp +endef + define Build/jffs2 rm -rf $(KDIR_TMP)/$(DEVICE_NAME)/jffs2 && \ mkdir -p $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/$$(dirname $(1)) && \ diff --git a/target/linux/ramips/image/mt76x8.mk b/target/linux/ramips/image/mt76x8.mk index 3a2d8e3a5e..be3aeb1093 100644 --- a/target/linux/ramips/image/mt76x8.mk +++ b/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 diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 68782f3802..864a3df15d 100644 --- a/tools/firmware-utils/Makefile +++ b/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 diff --git a/tools/firmware-utils/src/mksercommfw.c b/tools/firmware-utils/src/mksercommfw.c index 23e4dd06b2..f6f1d93f37 100644 --- a/tools/firmware-utils/src/mksercommfw.c +++ b/tools/firmware-utils/src/mksercommfw.c @@ -5,6 +5,7 @@ #include #include #include +#include #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 \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 use hardware id specified with (ASCII)\n" + " -r use hardware revision specified with (ASCII)\n" + " -v set image version to (decimal, hex or octal notation)\n" + " -i 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; } -- 2.30.2