Skip to content

Commit

Permalink
firmware-utils: backport sercomm/netgear firmware tool
Browse files Browse the repository at this point in the history
  • Loading branch information
shibajee committed Aug 5, 2020
1 parent b18e3ea commit bc9293f
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 0 deletions.
10 changes: 10 additions & 0 deletions include/image-commands.mk
Expand Up @@ -280,6 +280,16 @@ define Build/tplink-v2-image
rm -rf $@.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

json_quote=$(subst ','\'',$(subst ",\",$(1)))
#")')
metadata_devices=$(if $(1),$(subst "$(space)","$(comma)",$(strip $(foreach v,$(1),"$(call json_quote,$(v))"))))
Expand Down
14 changes: 14 additions & 0 deletions target/linux/ramips/image/Makefile
Expand Up @@ -24,6 +24,7 @@ endef

DEVICE_VARS += DTS IMAGE_SIZE NETGEAR_BOARD_ID NETGEAR_HW_ID
DEVICE_VARS += BUFFALO_TAG_PLATFORM BUFFALO_TAG_VERSION BUFFALO_TAG_MINOR
DEVICE_VARS += SERCOMM_HWNAME SERCOMM_HWID SERCOMM_HWVER SERCOMM_SWVER

loadaddr-y := 0x80000000
loadaddr-$(CONFIG_TARGET_ramips_rt288x) := 0x88000000
Expand Down Expand Up @@ -147,6 +148,19 @@ define Build/mkdlinkfw-factory
mv $@.new $@
endef

define Build/sercom-footer
$(call Build/sercom-seal,-f)
endef

define Build/sercom-seal
$(STAGING_DIR_HOST)/bin/mksercommfw \
-i $@ \
-b $(SERCOMM_HWID) \
-r $(SERCOMM_HWVER) \
-v $(SERCOMM_SWVER) \
$(1)
endef

#
# The real magic happens inside these templates
#
Expand Down
1 change: 1 addition & 0 deletions tools/firmware-utils/Makefile
Expand Up @@ -84,6 +84,7 @@ define Host/Compile
$(call cc,mkdhpimg buffalo-lib, -Wall)
$(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall --std=gnu99)
$(call cc,dns313-header, -Wall)
$(call cc,mksercommfw,-Wall)
endef

define Host/Install
Expand Down
261 changes: 261 additions & 0 deletions tools/firmware-utils/src/mksercommfw.c
@@ -0,0 +1,261 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <byteswap.h>
#include <endian.h>
#include <getopt.h>

#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#endif

#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be32(x) (x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_be32(x) bswap_32(x)
#else
#error "Unsupported endianness"
#endif

/* #define DEBUG 1 */

#ifdef DEBUG
#define DBG(...) {printf(__VA_ARGS__); }
#else
#define DBG(...) {}
#endif

#define ERR(...) {printf(__VA_ARGS__); }

/*
* Fw Header Layout for Netgear / Sercomm devices (bytes)
*
* Size : 512 bytes + zipped image size
*
* Locations:
* magic : 0-6 ASCII
* version: 7-11 fixed
* hwID : 11-44 ASCII
* hwVer : 45-54 ASCII
* swVer : 55-62 uint32_t in BE
* magic : 63-69 ASCII
* ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
*/
static const char* magic = "sErCoMm"; /* 7 */
static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
static const int header_sz = 512;
static const int footer_sz = 71;

static int is_header = 1;

struct file_info {
char* file_name; /* name of the file */
char* file_data; /* data of the file in memory */
u_int32_t file_size; /* length of the file */
};

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 (i = 0; i < len; i++) {
new += data[i];
}

return new;
}

/*
* 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;
}

DBG("Opening file: %s\n", finfo->file_name);

if (!(fp = fopen(finfo->file_name, "rb"))) {
ERR("Error opening file: %s\n", finfo->file_name);
return -1;
}

/* Get filesize */
rewind(fp);
fseek(fp, 0L, SEEK_END);
file_sz = ftell(fp);
rewind(fp);

if (file_sz < 1) {
ERR("Error getting filesize: %s\n", finfo->file_name);
fclose(fp);
return -1;
}

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(finfo->file_size))) {
ERR("Out of memory!\n");
fclose(fp);
return -1;
}

/* 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;
}

DBG("File: read successful\n");
fclose(fp);

return hdr_pos;
}

static int writeFile(struct file_info* finfo) {
FILE* fp;

if (!finfo || !finfo->file_name) {
ERR("Invalid pointer provided!\n");
return -1;
}

DBG("Opening file: %s\n", finfo->file_name);

if (!(fp = fopen(finfo->file_name, "w"))) {
ERR("Error opening file: %s\n", finfo->file_name);
return -1;
}

DBG("Writing file: %s\n", finfo->file_name);

if (fwrite(finfo->file_data, 1, finfo->file_size, fp) != finfo->file_size) {
ERR("Wanted to write, but something went wrong!\n");
fclose(fp);
return -1;
}

fclose(fp);
return 0;
}

static void usage(char* argv[]) {
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[]) {
struct file_info image = { 0 };

char* hwID = NULL;
char* hwVer = NULL;
u_int32_t swVer = 0;
u_int8_t chkSum;
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 (!hwID || !hwVer || !image.file_name) {
usage(argv);
return EXIT_FAILURE;
}

/*
* 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;
}

/* overwrite input file */
if (writeFile(&image))
return EXIT_FAILURE;

return EXIT_SUCCESS;
}

0 comments on commit bc9293f

Please sign in to comment.