From d1f4e5ba7facdfa12de537a676b0d9e7270f25d2 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Thu, 2 Aug 2007 19:05:28 +0000
Subject: [PATCH] add firmware generation tool for ZyXEL boards

SVN-Revision: 8318
---
 tools/firmware-utils/Makefile      |   1 +
 tools/firmware-utils/src/mkzynfw.c | 998 +++++++++++++++++++++++++++++
 tools/firmware-utils/src/zynos.h   | 213 ++++++
 3 files changed, 1212 insertions(+)
 create mode 100755 tools/firmware-utils/src/mkzynfw.c
 create mode 100755 tools/firmware-utils/src/zynos.h

diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
index e8c5f00cea..24cf88eecd 100644
--- a/tools/firmware-utils/Makefile
+++ b/tools/firmware-utils/Makefile
@@ -29,6 +29,7 @@ define Build/Compile
 	$(call cc,srec2bin)
 	$(call cc,mkmylofw)
 	$(call cc,mkcsysimg)
+	$(call cc,mkzynfw)
 endef
 
 define Build/Install
diff --git a/tools/firmware-utils/src/mkzynfw.c b/tools/firmware-utils/src/mkzynfw.c
new file mode 100755
index 0000000000..8fb3dadb58
--- /dev/null
+++ b/tools/firmware-utils/src/mkzynfw.c
@@ -0,0 +1,998 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2007 OpenWrt.org
+ *  Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
+ *
+ *  This code was based on the information of the ZyXEL's firmware 
+ *  image format written by Kolja Waschk, can be found at: 
+ *  http://www.ixo.de/info/zyxel_uclinux
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the
+ *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#include "zynos.h"
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE16_TO_HOST(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#  define HOST_TO_BE16(x)	bswap_16(x)
+#  define HOST_TO_BE32(x)	bswap_32(x)
+#  define BE16_TO_HOST(x)	bswap_16(x)
+#  define BE32_TO_HOST(x)	bswap_32(x)
+#else
+#  define HOST_TO_BE16(x)	(x)
+#  define HOST_TO_BE32(x)	(x)
+#  define BE16_TO_HOST(x)	(x)
+#  define BE32_TO_HOST(x)	(x)
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE16_TO_HOST(x)	bswap_16(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#endif
+
+#define ALIGN(x,y)	(((x)+((y)-1)) & ~((y)-1))
+
+#define MAX_NUM_BLOCKS	8
+#define MAX_ARG_COUNT	32
+#define MAX_ARG_LEN	1024
+#define FILE_BUF_LEN	(16*1024)
+
+
+struct csum_state{
+	int		odd;
+	uint32_t	sum;
+	uint32_t	tmp;
+};
+
+struct fw_block {
+	uint32_t	align;		/* alignment of this block */
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+	char		*mmap_name;	/* name in the MMAP table */
+	int		type;		/* block type */
+	uint32_t	padlen;
+	uint8_t		padc;
+};
+
+#define BLOCK_TYPE_BOOTEXT	0
+#define BLOCK_TYPE_RAW		1
+
+struct fw_mmap {
+	uint32_t	addr;
+	uint32_t	size;
+	uint32_t	user_addr;
+	uint32_t	user_size;
+};
+#define MMAP_DATA_SIZE	1024
+#define MMAP_ALIGN	16
+
+struct board_info {
+	char *name;		/* model name */
+	char *desc;		/* description */
+	uint16_t model;		/* model id */
+	uint32_t flash_base;	/* flash base address */
+	uint32_t flash_size;	/* board flash size */
+	uint32_t code_start;	/* code start address */
+	uint32_t fw_offs;	/* offset of the firmware within the flash */
+};
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname = NULL;
+int verblevel = 0;
+
+struct board_info *board = NULL;
+
+struct fw_block blocks[MAX_NUM_BLOCKS];
+struct fw_block *bootext_block = NULL;
+int num_blocks = 0;
+
+#define ADM5120_FLASH_BASE	0xBFC00000
+#define ADM5120_CODE_START	0x80008000
+
+/* TODO: check values for AR7 */
+#define AR7_FLASH_BASE		0xB0000000
+#define AR7_CODE_START		0x94008000
+
+#define BOARD(n, d, m, fb, fs, cs, fo) { \
+	.name = (n), .desc=(d), .model = (m), \
+	.flash_base = (fb), .flash_size = (fs)<<20, \
+	.code_start = (cs), .fw_offs = (fo) \
+	}
+
+#define ADMBOARD1(n, d, m, fs) BOARD(n, d, m, \
+	ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000)
+
+#define ADMBOARD2(n, d, m, fs) BOARD(n, d, m, \
+	ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000)
+
+#define AR7BOARD1(n, d, m, fs) BOARD(n, d, m, \
+	AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000)
+
+static struct board_info boards[] = {
+	/* 
+	 * Infineon/ADMtek ADM5120 based boards 
+	 */
+	ADMBOARD2("ES-2024A",	"ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4),
+	ADMBOARD2("ES-2024PWR",	"ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4),
+	ADMBOARD2("ES-2108",	"ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4),
+	ADMBOARD2("ES-2108-F",	"ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4),
+	ADMBOARD2("ES-2108-G",	"ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4),
+	ADMBOARD2("ES-2108-LC",	"ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4),
+	ADMBOARD2("ES-2108PWR",	"ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4),
+	ADMBOARD1("HS-100",	"ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2),
+	ADMBOARD1("HS-100W",	"ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2),
+	ADMBOARD1("P-334",	"ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2),
+	ADMBOARD1("P-334U",	"ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4),
+	ADMBOARD1("P-334W",	"ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2),
+	ADMBOARD1("P-334WH",	"ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4),
+	ADMBOARD1("P-334WHD",	"ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4),
+	ADMBOARD1("P-334WT",	"ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4),
+	ADMBOARD1("P-335",	"ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4),
+	ADMBOARD1("P-335Plus",	"ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4),
+	ADMBOARD1("P-335U",	"ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4),
+	ADMBOARD1("P-335WT",	"ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4),
+#if 0
+	/* 
+	 * Texas Instruments AR7 based boards
+	 */
+	AR7BOARD1("P-660H-61",  "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2),
+	AR7BOARD1("P-660H-63",  "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2),
+	AR7BOARD1("P-660H-D1",  "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2),
+	AR7BOARD1("P-660H-D3",  "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2),
+	AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2),
+	AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2),
+	AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2),
+	AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2),
+	AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2),
+	AR7BOARD1("P-660R-61",  "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2),
+	AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2),
+	AR7BOARD1("P-660R-63",  "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2),
+	AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2),
+	AR7BOARD1("P-660R-67",  "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2),
+	AR7BOARD1("P-660R-D1",  "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2),
+	AR7BOARD1("P-660R-D3",  "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2),
+#endif
+	{.name = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ", %s\n", progname, ## __VA_ARGS__ \
+		, strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+	fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+	if (verblevel < lev) \
+		break;\
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL		-1
+#define ERR_INVALID_IMAGE	-2
+
+/*
+ * Helper routines
+ */
+void
+usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+	);
+	for (board = boards; board->name != NULL; board++){
+		fprintf(stream,
+"                    %-12s= %s\n",
+		 board->name, board->desc);
+	};
+	fprintf(stream,
+"  -b <file>[:<align>]\n"
+"                  add boot extension block to the image\n"
+"  -r <file>[:<align>]\n"
+"                  add raw block to the image\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+	
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+		return -1;
+	}
+	
+	*val = t & 0xFFFF;
+	return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+		return -1;
+	}
+	
+	*val = t & 0xFF;
+	return 0;
+}
+
+int
+str2sig(char *arg, uint32_t *sig)
+{
+	if (strlen(arg) != 4)
+		return -1;
+
+	*sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
+	
+	return 0;
+}
+
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+	int res = 0;
+	size_t argl;
+	char *tok;
+	char **ap = &buf;
+	int i;
+
+	memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+	if ((arg == NULL)) {
+		/* no arguments */
+		return 0;
+	}
+
+	argl = strlen(arg);
+	if (argl == 0) {
+		/* no arguments */
+		return 0;
+	}
+
+	if (argl >= MAX_ARG_LEN) {
+		/* argument is too long */
+		argl = MAX_ARG_LEN-1;
+	}
+
+	memcpy(buf, arg, argl);
+	buf[argl] = '\0';
+
+	for (i = 0; i < MAX_ARG_COUNT; i++) {
+		tok = strsep(ap, ":");
+		if (tok == NULL) {
+			break;
+		}
+#if 0
+		else if (tok[0] == '\0') {
+			break;
+		}
+#endif
+		argv[i] = tok;
+		res++;
+	}
+
+	return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+	if (arg == NULL || *arg != '-')
+		return 0;
+
+	ERR("option -%c requires an argument\n", c);
+	return -1;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+	int ret = 1;
+	if (arg != NULL) {
+		if (*arg) ret = 0;
+	};
+	return ret;
+}
+
+
+void
+csum_init(struct csum_state *css)
+{
+	css->odd = 0;
+	css->sum = 0;
+	css->tmp = 0;
+}
+
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	if (len == 0)
+		return;
+
+	if (css->odd) {
+		css->sum += (css->tmp << 8) + p[0];
+		if (css->sum > 0xFFFF) {
+			css->sum += 1;
+			css->sum &= 0xFFFF;
+		}
+		css->odd = 0;
+		len--;
+		p++;
+	}
+
+	for ( ; len > 1; len -= 2, p +=2 ) {
+		css->sum  += (p[0] << 8) + p[1];
+		if (css->sum > 0xFFFF) {
+			css->sum += 1;
+			css->sum &= 0xFFFF;
+		}
+	}
+
+	if (len == 1){
+		css->tmp = p[0];
+		css->odd = 1;
+	}
+}
+
+
+uint16_t
+csum_get(struct csum_state *css)
+{
+	char pad = 0;
+
+	csum_update(&pad, 1, css);
+	return css->sum;
+}
+
+uint16_t
+csum_buf(uint8_t *p, uint32_t len)
+{
+	struct csum_state css;
+
+	csum_init(&css);
+	csum_update(p, len, &css);
+	return csum_get(&css);
+
+}
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+		struct csum_state *css)
+{
+	errno = 0;
+
+	fwrite(data, len, 1, outfile);
+	if (errno) {
+		ERR("unable to write output file");
+		return -1;
+	}
+
+	if (css) {
+		csum_update(data, len, css);
+	}
+
+	return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+		 struct csum_state *css)
+{
+	uint8_t buf[512];
+	size_t buflen = sizeof(buf);
+
+	memset(buf, padc, buflen);
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		if (write_out_data(outfile, buf, buflen, css))
+			return -1;
+			
+		len -= buflen;
+	}
+
+	return 0;
+}
+
+
+int
+write_out_data_align(FILE *outfile, uint8_t *data, size_t len, size_t align,
+		struct csum_state *css)
+{
+	size_t padlen;
+	int res;
+
+	res = write_out_data(outfile, data, len, css);
+	if (res)
+		return res;
+
+	padlen = ALIGN(len,align) - len;
+	res = write_out_padding(outfile, padlen, 0xFF, css);
+
+	return res;
+}
+
+
+int
+write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
+{
+	struct zyn_rombin_hdr t;
+
+	errno = 0;
+	if (fseek(outfile, 0, SEEK_SET) != 0) {
+		ERRS("fseek failed on output file");
+		return -1;
+	}
+
+	/* setup temporary header fields */
+	memset(&t,0, sizeof(t));
+	t.addr = HOST_TO_BE32(hdr->addr);
+	memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN);
+	t.type = hdr->type;
+	t.flags = hdr->flags;
+	t.osize = HOST_TO_BE32(hdr->osize);
+	t.csize = HOST_TO_BE32(hdr->csize);
+	t.ocsum = HOST_TO_BE16(hdr->ocsum);
+	t.ccsum = HOST_TO_BE16(hdr->ccsum);
+	t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr);
+
+	return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL);
+}
+
+
+int
+write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
+{
+	struct zyn_mmt_hdr *mh;
+	uint8_t buf[MMAP_DATA_SIZE];
+	uint32_t user_size;
+	char *data;
+	int res;
+
+	memset(buf,0,sizeof(buf));
+
+	mh = (struct zyn_mmt_hdr *)buf;
+
+	/* TODO: needs to recreate the memory map too? */
+	mh->count=0;
+	
+	/* Build user data section */
+	data = buf+sizeof(*mh);
+	data += sprintf(data,"Model 1 %d", BE16_TO_HOST(board->model));
+	*data++ = '\0';
+	/* TODO: make hardware version configurable? */
+	data += sprintf(data,"HwVerRange 2 %d %d", 0, 0);
+	*data++ = '\0';
+
+	user_size = (uint8_t *)data - buf;
+	mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh));
+	mh->user_end= HOST_TO_BE32(mmap->addr+user_size);
+	mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size));
+
+	res = write_out_data(outfile, buf, sizeof(buf), css);
+	
+	return res;
+}
+
+
+int
+block_stat_file(struct fw_block *block)
+{
+	struct stat st;
+	int res;
+
+	if (block->file_name == NULL)
+		return 0;
+
+	res = stat(block->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", block->file_name);
+		return res;
+	}
+
+	block->file_size = st.st_size;
+	return 0;
+}
+
+
+int
+write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
+{
+	char buf[FILE_BUF_LEN];
+	size_t buflen = sizeof(buf);
+	FILE *f;
+	int res;
+
+	DBG(2, "writing out file, name=%s, len=%d",
+		name, len);
+
+	errno = 0;
+	f = fopen(name,"r");
+	if (errno) {
+		ERRS("unable to open file: %s", name);
+		return -1;
+	}
+
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		/* read data from source file */
+		errno = 0;
+		fread(buf, buflen, 1, f);
+		if (errno != 0) {
+			ERRS("unable to read from file: %s",name);
+			res = -1;
+			break;
+		}
+
+		res = write_out_data(outfile, buf, buflen, css);
+		if (res)
+			break;
+
+		len -= buflen;
+	}
+
+	fclose(f);
+	return res;
+}
+
+
+int
+write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
+{
+	int res;
+	
+	if (block == NULL)
+		return 0;
+
+	if (block->file_name == NULL)
+		return 0;
+
+	if (block->file_size == 0)
+		return 0;
+
+	res = write_out_file(outfile, block->file_name, 
+			block->file_size, css);
+	return res;
+}
+
+
+int
+write_out_image(FILE *outfile)
+{
+	struct fw_block *block;
+	struct fw_mmap mmap;
+	struct zyn_rombin_hdr hdr;
+	struct csum_state css;
+	int i, res;
+	uint32_t offset;
+	uint32_t padlen;
+
+	/* setup header fields */
+	hdr.addr = board->code_start;
+	hdr.type = OBJECT_TYPE_BOOTEXT;
+	hdr.flags = ROMBIN_FLAG_40;
+
+	res = write_out_header(outfile, &hdr);
+	if (res)
+		return res;
+
+	offset = sizeof(hdr);
+
+	csum_init(&css);
+	res = write_out_block(outfile, bootext_block, &css);
+	if (res)
+		return res;
+
+	offset += bootext_block->file_size;
+
+	padlen = ALIGN(offset,MMAP_ALIGN) - offset;
+	res = write_out_padding(outfile, padlen, 0xFF, &css);
+	if (res)
+		return res;
+
+	offset += padlen;
+
+	mmap.addr = board->flash_base + board->fw_offs + offset;
+	hdr.mmap_addr = mmap.addr;
+	res = write_out_mmap(outfile, &mmap, &css);
+	if (res)
+		return res;
+
+	offset += MMAP_DATA_SIZE;
+	hdr.osize = offset - sizeof(hdr);
+	hdr.ocsum = csum_get(&css);
+
+	for (i=0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		if (block->type == BLOCK_TYPE_BOOTEXT)
+			continue;
+
+		padlen = ALIGN(offset,block->align) - offset;
+		res = write_out_padding(outfile, padlen, 0xFF, NULL);
+		if (res)
+			return res;
+		offset += padlen;
+
+		res = write_out_block(outfile, block, NULL);
+		if (res)
+			return res;
+		offset += block->file_size;
+	}
+
+	res = write_out_header(outfile, &hdr);
+
+	return res;
+}
+
+
+struct board_info *
+find_board(char *name)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->name != NULL; board++){
+		if (strcmp(name, board->name) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+	DBG(1,"parsing board option: -%c %s", ch, arg);
+
+	if (board != NULL) {
+		ERR("only one board option allowed");
+		return -1;
+	}
+
+	if (required_arg(ch, arg))
+		return -1;
+
+	board = find_board(arg);
+	if (board == NULL){
+		ERR("invalid/unknown board specified: %s", arg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int
+parse_opt_ofname(char ch, char *arg)
+{
+
+	if (ofname != NULL) {
+		ERR("only one output file allowed");
+		return -1;
+	}
+
+	if (required_arg(ch, arg)) 
+		return -1;
+
+	ofname = arg;
+
+	return 0;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	char *p;
+	struct fw_block *block;
+	int i;
+
+	if ( num_blocks > MAX_NUM_BLOCKS ) {
+		ERR("too many blocks specified");
+		return -1;
+	}
+
+	block = &blocks[num_blocks++];
+	
+	/* setup default field values */
+	block->padc = 0xFF;
+
+	switch(ch) {
+	case 'b':
+		if (bootext_block) {
+			ERR("only one boot extension block allowed");
+			break;
+		}
+		block->type = BLOCK_TYPE_BOOTEXT;
+		bootext_block = block;
+		break;
+	case 'r':
+		block->type = BLOCK_TYPE_RAW;
+		break;
+	}
+
+	argc = parse_arg(arg, buf, argv);
+
+	i = 0;
+	p = argv[i++];
+	if (is_empty_arg(p)) {
+		ERR("no file specified in %s", arg);
+		return -1;
+	} else {
+		block->file_name = strdup(p);
+		if (block->file_name == NULL) {
+			ERR("not enough memory");
+			return -1;
+		}
+	}
+
+	if(block->type == BLOCK_TYPE_BOOTEXT)
+		return 0;
+
+	p = argv[i++];
+	if (!is_empty_arg(p)) {
+		if (str2u32(p, &block->align) != 0) {
+			ERR("invalid block align in %s", arg);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int
+calc_block_offsets(int type, uint32_t *offset)
+{
+	struct fw_block *block;
+	uint32_t next_offs;
+	uint32_t avail;
+	int i, res;
+
+	DBG(1,"calculating block offsets, starting with %lu",
+		*offset);
+
+	res = 0;
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		if (block->type != type)
+			continue;
+
+		next_offs = ALIGN(*offset, block->align);
+		avail = board->flash_size - board->fw_offs - next_offs;
+		if (next_offs + block->file_size > avail) {
+			ERR("file %s is too big, offset = %u, size=%u,"
+				" align = %u", block->file_name, 
+				(unsigned)next_offs, 
+				(unsigned)block->file_size, 
+				(unsigned)block->align);
+			res = -1;
+			break;
+		}
+
+		block->padlen = next_offs - *offset;
+		*offset += block->file_size;
+	}
+	
+	return res;
+}
+
+int
+process_blocks(void)
+{
+	struct fw_block *block;
+	uint32_t offset;
+	int i;
+	int res;
+
+	/* collecting file stats */
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+		res = block_stat_file(block);
+		if (res)
+			return res;
+	}
+
+	offset = board->fw_offs + bootext_block->file_size;
+	res = calc_block_offsets(BLOCK_TYPE_RAW, &offset);
+
+	return res;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	int optinvalid = 0;   /* flag for invalid option */
+	int c;
+	int res = EXIT_FAILURE;
+
+	FILE *outfile;
+	
+	progname=basename(argv[0]);
+
+	opterr = 0;  /* could not print standard getopt error messages */
+	while ( 1 ) {
+		optinvalid = 0;
+		
+		c = getopt(argc, argv, "b:B:ho:r:v");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'b':
+		case 'r':
+			optinvalid = parse_opt_block(c,optarg);
+			break;
+		case 'B':
+			optinvalid = parse_opt_board(c,optarg);
+			break;
+		case 'o':
+			optinvalid = parse_opt_ofname(c,optarg);
+			break;
+		case 'v':
+			verblevel++;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			optinvalid = 1;
+			break;
+		}
+		if (optinvalid != 0 ) {
+			ERR("invalid option: -%c", optopt);
+			goto out;
+		}
+	}
+
+	if (board == NULL) {
+		ERR("no board specified");
+		goto out;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto out;
+	}
+
+	if (optind < argc) {
+		ERR("invalid option: %s", argv[optind]);
+		goto out;
+	}
+	
+
+	if (process_blocks() != 0) {
+		goto out;
+	}
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	if (write_out_image(outfile) != 0)
+		goto out_flush;
+
+	DBG(1,"Image file %s completed.", ofname);
+
+	res = EXIT_SUCCESS;
+
+out_flush:
+	fflush(outfile);
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+out:
+	return res;
+}
diff --git a/tools/firmware-utils/src/zynos.h b/tools/firmware-utils/src/zynos.h
new file mode 100755
index 0000000000..ef6c91ef39
--- /dev/null
+++ b/tools/firmware-utils/src/zynos.h
@@ -0,0 +1,213 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2007 OpenWrt.org
+ *  Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
+ *
+ *  This code was based on the information of the ZyXEL's firmware 
+ *  image format written by Kolja Waschk, can be found at: 
+ *  http://www.ixo.de/info/zyxel_uclinux
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the
+ *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _ZYNOS_H
+#define _ZYNOS_H
+
+
+#define BOOTBASE_NAME_LEN	32
+#define BOOTBASE_MAC_LEN	6
+#define BOOTBASE_FEAT_LEN	22
+
+struct zyn_bootbase_info {
+	char		vendor[BOOTBASE_NAME_LEN]; /* Vendor name */
+	char		model[BOOTBASE_NAME_LEN]; /* Model name */
+	uint32_t	bootext_addr;	/* absolute address of the Boot Extension */
+	uint32_t	res0;
+	uint16_t	model_id;	/* model id */
+	uint8_t		feat_other[BOOTBASE_FEAT_LEN]; /* other feature bits */
+	uint8_t		feat_main;	/* main feature bits */
+	uint8_t		res1;		/* unknown/unused */
+	uint8_t		mac[BOOTBASE_MAC_LEN]; /* mac address */
+	uint8_t		country;	/* default country code */
+	uint8_t		dbgflag;	/* debug flag */
+} __attribute__((packed));
+
+#define ROMBIN_SIG_LEN	3
+#define ROMBIN_VER_LEN	15
+
+struct zyn_rombin_hdr {
+	uint32_t	addr;		/* load address of the object */
+	uint16_t	res0;		/* unknown/unused */
+	char		sig[ROMBIN_SIG_LEN];	/* magic, must be "SIG" */
+	uint8_t		type;		/* type of the object */
+	uint32_t	osize;		/* size of the uncompressed data */
+	uint32_t	csize;		/* size of the compressed data */
+	uint8_t		flags;		/* various flags */
+	uint8_t		res1;		/* unknown/unused */
+	uint16_t	ocsum;		/* csum of the uncompressed data */
+	uint16_t	ccsum;		/* csum of the compressed data */
+	char		ver[ROMBIN_VER_LEN];
+	uint32_t	mmap_addr;	/* address of the Memory Map Table*/
+	uint32_t	res2;		/* unknown/unused*/
+	uint8_t		res3;		/* unknown/unused*/
+} __attribute__((packed));
+
+#define ROMBIN_SIGNATURE	"SIG"
+
+/* Rombin flag bits */
+#define ROMBIN_FLAG_01		0x01
+#define ROMBIN_FLAG_02		0x02
+#define ROMBIN_FLAG_04		0x04
+#define ROMBIN_FLAG_08		0x08
+#define ROMBIN_FLAG_10		0x10
+#define ROMBIN_FLAG_20		0x20
+#define ROMBIN_FLAG_40		0x40
+#define ROMBIN_FLAG_COMPRESSED	0x80	/* the binary is compressed */
+
+/* Object types */
+#define OBJECT_TYPE_ROMIMG	0x01
+#define OBJECT_TYPE_ROMBOOT	0x02
+#define OBJECT_TYPE_BOOTEXT	0x03
+#define OBJECT_TYPE_ROMBIN	0x04
+#define OBJECT_TYPE_ROMDIR	0x05
+#define OBJECT_TYPE_6		0x06
+#define OBJECT_TYPE_ROMMAP	0x07
+#define OBJECT_TYPE_RAM		0x80
+#define OBJECT_TYPE_RAMCODE	0x81
+#define OBJECT_TYPE_RAMBOOT	0x82
+
+/*
+ * Memory Map Table header
+ */
+struct zyn_mmt_hdr {
+	uint16_t	count;
+	uint32_t	user_start;
+	uint32_t	user_end;
+	uint16_t	csum;
+	uint8_t		res[12];
+} __attribute__((packed));
+
+#define OBJECT_NAME_LEN		8
+
+struct zyn_mmt_item {
+	uint8_t		type;	/* type of the object */
+	uint8_t		name[OBJECT_NAME_LEN]; /* name of the object */
+	uint8_t		res0;	/* unused/unknown */
+	uint32_t	addr;
+	uint32_t	size;	/* size of the object */
+	uint8_t		res1[3]; /* unused/unknown */
+	uint8_t		type2;
+} __attribute__((packed));
+
+/*
+ * Board IDs (in big-endian format)
+ */
+#define MID(x)	(((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8)
+
+/* 
+ * Infineon/ADMtek ADM5120 based models 
+ */
+#define ZYNOS_MODEL_ES_2024A		MID(  221)
+#define ZYNOS_MODEL_ES_2024PWR		MID( 4097)
+#define ZYNOS_MODEL_ES_2108		MID(61952)
+#define ZYNOS_MODEL_ES_2108_F		MID(44801)
+#define ZYNOS_MODEL_ES_2108_G		MID(62208)
+#define ZYNOS_MODEL_ES_2108_LC		MID(64512)
+#define ZYNOS_MODEL_ES_2108PWR		MID(62464)
+#define ZYNOS_MODEL_HS_100		MID(61855)
+#define ZYNOS_MODEL_HS_100W		ZYNOS_MODEL_HS_100
+#define ZYNOS_MODEL_P_334		MID(62879)
+#define ZYNOS_MODEL_P_334U		MID(56735)
+#define ZYNOS_MODEL_P_334W		MID(62367)
+#define ZYNOS_MODEL_P_334WH		MID(57344)
+#define ZYNOS_MODEL_P_334WHD		MID(57600)
+#define ZYNOS_MODEL_P_334WT		MID(61343)
+#define ZYNOS_MODEL_P_335		MID(60831)
+#define ZYNOS_MODEL_P_335PLUS		MID( 9472)
+#define ZYNOS_MODEL_P_335U		MID(56479)
+#define ZYNOS_MODEL_P_335WT		ZYNOS_MODEL_P_335
+
+/* 
+ * Texas Instruments AR7 based models 
+ */
+#define ZYNOS_MODEL_P_2602H_61C		MID( 3229)
+#define ZYNOS_MODEL_P_2602H_63C		MID( 3485)
+#define ZYNOS_MODEL_P_2602H_D1A		/* n.a. */
+#define ZYNOS_MODEL_P_2602H_D3A		/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_61C	/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_63		/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_63C	ZYNOS_MODEL_P_2602H_63C
+#define ZYNOS_MODEL_P_2602HW_D1A	/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_D3A	/* n.a. */
+#define ZYNOS_MODEL_P_2602HWL_61	MID( 1181)
+#define ZYNOS_MODEL_P_2602HWL_61C	ZYNOS_MODEL_P_2602H_61C
+#define ZYNOS_MODEL_P_2602HWL_63C	ZYNOS_MODEL_P_2602H_63C
+#define ZYNOS_MODEL_P_2602HWL_D1A	MID( 6301)
+#define ZYNOS_MODEL_P_2602HWL_D3A	MID( 7581)
+#define ZYNOS_MODEL_P_2602HWNLI_D7A	MID( 6813)
+
+#define ZYNOS_MODEL_P_2602R_61		MID( 2205)
+#define ZYNOS_MODEL_P_2602R_63		MID( 3997)
+#define ZYNOS_MODEL_P_2602R_D1A		/* n.a. */
+#define ZYNOS_MODEL_P_2602R_D3A		/* n.a. */
+#define ZYNOS_MODEL_P_2602RL_D1A	MID( 6045)
+#define ZYNOS_MODEL_P_2602RL_D3A	MID( 7069)
+
+#define ZYNOS_MODEL_P_660H_61		MID(19346)
+#define ZYNOS_MODEL_P_660H_63		MID(22162)
+#define ZYNOS_MODEL_P_660H_67		/* n.a. */
+#define ZYNOS_MODEL_P_660H_D1		MID( 7066)
+#define ZYNOS_MODEL_P_660H_D3		MID(13210)
+
+#define ZYNOS_MODEL_P_660HW_61		ZYNOS_MODEL_P_660H_61
+#define ZYNOS_MODEL_P_660HW_63		ZYNOS_MODEL_P_660H_63
+#define ZYNOS_MODEL_P_660HW_67		ZYNOS_MODEL_P_660HW_63
+#define ZYNOS_MODEL_P_660HW_D1		MID( 9114)
+#define ZYNOS_MODEL_P_660HW_D3		MID(12698)
+
+#define ZYNOS_MODEL_P_660R_61		MID(20882)
+#define ZYNOS_MODEL_P_660R_61C		MID( 1178)
+#define ZYNOS_MODEL_P_660R_63		MID(21138)
+#define ZYNOS_MODEL_P_660R_63C		MID(  922)
+#define ZYNOS_MODEL_P_660R_67		ZYNOS_MODEL_P_660R_63
+#define ZYNOS_MODEL_P_660R_67C		/* n.a. */
+#define ZYNOS_MODEL_P_660R_D1		MID( 7322)
+#define ZYNOS_MODEL_P_660R_D3		MID(10138)
+
+#define ZYNOS_MODEL_P_661H_61		MID(19346)
+#define ZYNOS_MODEL_P_661H_63		MID( 1946)
+#define ZYNOS_MODEL_P_661H_D1		MID(10650)
+#define ZYNOS_MODEL_P_661H_D3		MID(12442)
+
+#define ZYNOS_MODEL_P_661HW_61		ZYNOS_MODEL_P_661H_61
+#define ZYNOS_MODEL_P_661HW_63		ZYNOS_MODEL_P_661H_63
+#define ZYNOS_MODEL_P_661HW_D1		MID(10906)
+#define ZYNOS_MODEL_P_661HW_D3		MID(14746)
+
+#define ZYNOS_MODEL_P_662H_61		MID(22418)
+#define ZYNOS_MODEL_P_662H_63		/* n.a. */
+#define ZYNOS_MODEL_P_662H_67		/* n.a. */
+#define ZYNOS_MODEL_P_662H_D1		/* n.a. */
+#define ZYNOS_MODEL_P_662H_D3		/* n.a. */
+
+#define ZYNOS_MODEL_P_662HW_61		/* n.a. */
+#define ZYNOS_MODEL_P_662HW_63		MID(22674)
+#define ZYNOS_MODEL_P_662HW_67		/* n.a. */
+#define ZYNOS_MODEL_P_662HW_D1		MID(10394)
+#define ZYNOS_MODEL_P_662HW_D3		MID(12954)
+
+#endif /* _ZYNOS_H */
-- 
GitLab