diff options
Diffstat (limited to 'tools/firmware-utils/src')
-rw-r--r-- | tools/firmware-utils/src/mkdapimg2.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/tools/firmware-utils/src/mkdapimg2.c b/tools/firmware-utils/src/mkdapimg2.c new file mode 100644 index 0000000000..aef003c280 --- /dev/null +++ b/tools/firmware-utils/src/mkdapimg2.c @@ -0,0 +1,204 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License, + * version 2 as published by the Free Software Foundation. + * + * (C) Nicolò Veronese <nicveronese@gmail.com> + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <libgen.h> +#include <stdarg.h> +#include <getopt.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> // htonl + +// Usage: mkdapimg2 -s signature [-v version] [-r region] +// [-k uImage block size] -i <input> -o <output> +// +// NOTE: The kernel block size is used to know the offset of the rootfs +// in the image file. +// +// The system writes in the uImage partition until the end of uImage +// is reached, after that, the system jumps to the offset specified with the -k +// parameter and begin writing at the beginning of the rootfs MTD partition. +// +// If the -k parameter is the size of the original uImage partition, the system +// continue writing in the rootfs partition starting from the last block +// that has been wrote. (This is useful if the new kernel size is +// different from the original one) +// +// Example: +// ------------------------------------------ +// Creating 7 MTD partitions on "ath-nor0": +// 0x000000000000-0x000000010000 : "u-boot" +// 0x000000010000-0x000000020000 : "ART" +// 0x000000020000-0x000000030000 : "MP" +// 0x000000030000-0x000000040000 : "config" +// 0x000000040000-0x000000120000 : "uImage" +// 0x000000120000-0x000000800000 : "rootfs" +// 0x000000040000-0x000000800000 : "firmware" +// ------------------------------------------ +// +// 0x000000120000-0x000000040000 = 0xE0000 -> 917504 +// +// e.g.: mkdapimg2 -s HONEYBEE-FIRMWARE-DAP-1330 -v 1.00.21 -r Default +// -k 917504 -i sysupgarde.bin -o factory.bin +// +// +// The img_hdr_struct was taken from the D-Link SDK: +// DAP-1330_OSS-firmware_1.00b21/DAP-1330_OSS-firmware_1.00b21/uboot/uboot.patch + +#define MAX_SIGN_LEN 32 +#define MAX_FW_VER_LEN 16 +#define MAX_REG_LEN 8 + +struct img_hdr_struct { + uint32_t hdr_len; + uint32_t checksum; + uint32_t total_size; + uint32_t kernel_size; + char signature[MAX_SIGN_LEN]; + char fw_ver[MAX_FW_VER_LEN]; + char fw_reg[MAX_REG_LEN]; +} imghdr ; + +char *progname; + +void +perrexit(int code, char *msg) +{ + fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno)); + exit(code); +} + +void +usage() +{ + fprintf(stderr, "usage: %s -s signature [-v version] [-r region] [-k uImage part size] -i <input> -o <output>\n", progname); + exit(1); +} + +int +main(int ac, char *av[]) +{ + char signature[MAX_SIGN_LEN]; + char version[MAX_FW_VER_LEN]; + char region[MAX_REG_LEN]; + int kernel = 0; + + FILE *ifile, *ofile; + int c; + + uint32_t cksum; + uint32_t bcnt; + + progname = basename(av[0]); + + memset(signature, 0, sizeof(signature)); + memset(version, 0, sizeof(version)); + memset(region, 0, sizeof(region)); + + while ( 1 ) { + char *ptr; + int c; + + c = getopt(ac, av, "s:v:r:k:i:o:"); + if (c == -1) + break; + + switch (c) { + case 's': + if (strlen(optarg) > MAX_SIGN_LEN + 1) { + fprintf(stderr, "%s: signature exceeds %d chars\n", + progname, MAX_SIGN_LEN); + exit(1); + } + strcpy(signature, optarg); + break; + case 'v': + if (strlen(optarg) > MAX_FW_VER_LEN + 1) { + fprintf(stderr, "%s: version exceeds %d chars\n", + progname, MAX_FW_VER_LEN); + exit(1); + } + strcpy(version, optarg); + break; + case 'r': + if (strlen(optarg) > MAX_REG_LEN + 1) { + fprintf(stderr, "%s: region exceeds %d chars\n", + progname, MAX_REG_LEN); + exit(1); + } + strcpy(region, optarg); + break; + case 'k': + kernel = strtoul(optarg, &ptr, 0); + if(ptr[0] == 'k'){ + kernel *= 1000; + } + break; + case 'i': + if ((ifile = fopen(optarg, "r")) == NULL) + perrexit(1, optarg); + break; + case 'o': + if ((ofile = fopen(optarg, "w")) == NULL) + perrexit(1, optarg); + break; + default: + usage(); + } + } + + if (signature[0] == 0 || ifile == NULL || ofile == NULL) { + usage(); + exit(1); + } + + for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++) + cksum += c & 0xff; + + if (fseek(ifile, 0, SEEK_SET) < 0) + perrexit(2, "fseek on input"); + + // Fill in the header + memset(&imghdr, 0, sizeof(imghdr)); + imghdr.hdr_len = sizeof(imghdr); + imghdr.checksum = htonl(cksum); + imghdr.total_size = htonl(bcnt); + imghdr.kernel_size = htonl(kernel); + + strncpy(imghdr.signature, signature, MAX_SIGN_LEN); + strncpy(imghdr.fw_ver, version, MAX_FW_VER_LEN); + strncpy(imghdr.fw_reg, region, MAX_REG_LEN); + + if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0) + perrexit(2, "fwrite header on output"); + + while ((c = fgetc(ifile)) != EOF) { + if (fputc(c, ofile) == EOF) + perrexit(2, "fputc on output"); + } + + if (ferror(ifile)) + perrexit(2, "fgetc on input"); + + fclose(ofile); + fclose(ifile); + + fprintf(stderr, "imgHdr.hdr_len = %lu\n", sizeof(imghdr)); + fprintf(stderr, "imgHdr.checksum = 0x%08x\n", cksum); + fprintf(stderr, "imgHdr.total_size = 0x%08x\n", bcnt); + fprintf(stderr, "imgHdr.kernel_size = 0x%08x\n", kernel); + fprintf(stderr, "imgHdr.header = %s\n", signature); + fprintf(stderr, "imgHdr.fw_ver = %s\n", version); + fprintf(stderr, "imgHdr.fw_reg = %s\n", region); + + return 0; +} |