From d673a23639860e21ef87c4c455018c4b6245868a Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Wed, 3 Nov 2021 14:32:11 +0100
Subject: [PATCH] tools: add realtek image building code

Signed-off-by: John Crispin <john@phrozen.org>
---
 tools/Makefile              |   1 +
 tools/rtk-tools/Makefile    |  50 ++++
 tools/rtk-tools/src/apmib.h |  77 +++++++
 tools/rtk-tools/src/cvimg.c | 443 ++++++++++++++++++++++++++++++++++++
 tools/rtk-tools/src/mgbin.c | 429 ++++++++++++++++++++++++++++++++++
 5 files changed, 1000 insertions(+)
 create mode 100644 tools/rtk-tools/Makefile
 create mode 100644 tools/rtk-tools/src/apmib.h
 create mode 100644 tools/rtk-tools/src/cvimg.c
 create mode 100644 tools/rtk-tools/src/mgbin.c

diff --git a/tools/Makefile b/tools/Makefile
index ae3cc5dfd6..a2d49967e7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -36,6 +36,7 @@ tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
 tools-$(CONFIG_USES_MINOR) += kernel2minor
 tools-$(CONFIG_USE_SPARSE) += sparse
 tools-$(CONFIG_USE_LLVM_BUILD) += llvm-bpf
+tools-$(CONFIG_TARGET_rtkmipsel) += rtk-tools
 
 # builddir dependencies
 $(curdir)/autoconf/compile := $(curdir)/m4/compile
diff --git a/tools/rtk-tools/Makefile b/tools/rtk-tools/Makefile
new file mode 100644
index 0000000000..a7f79c04b6
--- /dev/null
+++ b/tools/rtk-tools/Makefile
@@ -0,0 +1,50 @@
+# 
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=rtk-tools
+PKG_VERSION:=0.1
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/${PKG_NAME}-$(PKG_VERSION)
+HOST_CFLAGS += -DCOMPACT_FILENAME_BUFFER -DHOME_GATEWAY
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_8196C src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl8196c
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_8196C src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl8196c
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_8196E src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl8196e
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_8196E src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl8196e
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl819xd
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl819xd
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl819xdt
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl819xdt
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl89xxd
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl8198c
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl8954e
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl8197f
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl89xxd
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl8198c
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl8954e
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_819XD src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl8197f
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_8881A src/cvimg.c -o $(HOST_BUILD_DIR)/cvimg-rtl8881a
+	$(HOSTCC) $(HOST_CFLAGS) -DCONFIG_RTL_8881A src/mgbin.c -o $(HOST_BUILD_DIR)/mgbin-rtl8881a
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/cvimg* $(STAGING_DIR_HOST)/bin/
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/mgbin* $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/cvimg*
+	rm -f $(STAGING_DIR_HOST)/bin/mgbin*
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/rtk-tools/src/apmib.h b/tools/rtk-tools/src/apmib.h
new file mode 100644
index 0000000000..bf7257efa1
--- /dev/null
+++ b/tools/rtk-tools/src/apmib.h
@@ -0,0 +1,77 @@
+#ifndef __APMIB_H
+#define __APMIB_H
+
+#ifndef WIN32
+#define __PACK__        __attribute__ ((packed))
+#else
+#define __PACK__
+#endif
+
+#define BOOT_HEADER         ((char *)"boot")
+
+#if defined(CONFIG_RTL_8196B)
+#define ROOT_HEADER         ((char *)"r6br")
+#elif defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) || defined(CONFIG_RTL_819XD) || defined(CONFIG_RTL_8196E) || defined(CONFIG_RTL_8881A)
+#define ROOT_HEADER         ((char *)"r6cr")
+#else
+#define ROOT_HEADER         ((char *)"root")
+#endif //#if defined(CONFIG_RTL_8196B)
+
+#if defined(CONFIG_RTL_8196B)
+#if (defined(HOME_GATEWAY) && defined(VPN_SUPPORT))
+#define WEB_HEADER          ((char *)"w6bv")
+#elif (defined(HOME_GATEWAY))
+#define WEB_HEADER          ((char *)"w6bg")
+#else
+#define WEB_HEADER          ((char *)"w6ba")
+#endif
+#elif defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) || defined(CONFIG_RTL_819XD) || defined(CONFIG_RTL_8196E) || defined(CONFIG_RTL_8881A)
+#if (defined(HOME_GATEWAY) && defined(VPN_SUPPORT))
+#define WEB_HEADER          ((char *)"w6cv")
+#elif (defined(HOME_GATEWAY))
+#define WEB_HEADER          ((char *)"w6cg")
+#else
+#define WEB_HEADER          ((char *)"w6ca")
+#endif
+#else
+#if (defined(HOME_GATEWAY) && defined(VPN_SUPPORT))
+#define WEB_HEADER          ((char *)"webv")
+#elif (defined(HOME_GATEWAY))
+#define WEB_HEADER          ((char *)"webg")
+#else
+#define WEB_HEADER          ((char *)"weba")
+#endif
+#endif //#if defined(CONFIG_RTL_8196B)
+
+#if defined(CONFIG_RTL_8196B)
+#define FW_HEADER_WITH_ROOT ((char *)"cr6b")
+#define FW_HEADER           ((char *)"cs6b")
+#elif defined(CONFIG_RTL_8196C) || defined(CONFIG_RTL_8198) || defined(CONFIG_RTL_819XD) || defined(CONFIG_RTL_8196E) || defined(CONFIG_RTL_8881A)
+#define FW_HEADER_WITH_ROOT ((char *)"cr6c")
+#define FW_HEADER           ((char *)"cs6c")
+#else
+#define FW_HEADER_WITH_ROOT ((char *)"csro")
+#define FW_HEADER           ((char *)"csys")
+#endif //#if defined(CONFIG_RTL_8196B)
+
+#define ALL_HEADER          ((char *)"allp")
+
+#define HW_SETTING_OFFSET			0x6000
+#define DEFAULT_SETTING_OFFSET		0x8000
+#define CURRENT_SETTING_OFFSET		0xc000
+
+#define DWORD_SWAP(v) ( (((v&0xff)<<24)&0xff000000) | ((((v>>8)&0xff)<<16)&0xff0000) | \
+				                ((((v>>16)&0xff)<<8)&0xff00) | (((v>>24)&0xff)&0xff) )
+
+#define WORD_SWAP(v) ((unsigned short)(((v>>8)&0xff) | ((v<<8)&0xff00)))
+
+#define SIGNATURE_LEN           4
+
+typedef struct img_header {
+    unsigned char signature[SIGNATURE_LEN];
+    unsigned int startAddr;
+    unsigned int burnAddr;
+    unsigned int len;
+}__PACK__ IMG_HEADER_T, *IMG_HEADER_Tp;
+
+#endif
diff --git a/tools/rtk-tools/src/cvimg.c b/tools/rtk-tools/src/cvimg.c
new file mode 100644
index 0000000000..de681d803e
--- /dev/null
+++ b/tools/rtk-tools/src/cvimg.c
@@ -0,0 +1,443 @@
+/*
+ *      Tool to convert ELF image to be the AP downloadable binary
+ *
+ *      Authors: David Hsu	<davidhsu@realtek.com.tw>
+ *
+ *      $Id: cvimg.c,v 1.4 2009/06/12 07:10:44 michael Exp $
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#undef HOME_GATEWAY
+#define HOME_GATEWAY
+#define RTK_4K_CHKSUM_FIX
+
+#include "apmib.h"
+
+/* 32-bit ELF base types. */
+typedef unsigned int	Elf32_Addr;
+typedef unsigned short	Elf32_Half;
+typedef unsigned int	Elf32_Off;
+typedef unsigned int	Elf32_Word;
+
+#define EI_NIDENT	16
+
+typedef struct elf32_hdr{
+  unsigned char	e_ident[EI_NIDENT];
+  Elf32_Half	e_type;
+  Elf32_Half	e_machine;
+  Elf32_Word	e_version;
+  Elf32_Addr	e_entry;  /* Entry point */
+  Elf32_Off	e_phoff;
+  Elf32_Off	e_shoff;
+  Elf32_Word	e_flags;
+  Elf32_Half	e_ehsize;
+  Elf32_Half	e_phentsize;
+  Elf32_Half	e_phnum;
+  Elf32_Half	e_shentsize;
+  Elf32_Half	e_shnum;
+  Elf32_Half	e_shstrndx;
+} Elf32_Ehdr;
+
+#define DEFAULT_START_ADDR	0x80500000
+#define DEFAULT_BASE_ADDR	0x80000000
+
+static unsigned short calculateChecksum(char *buf, int len);
+
+/////////////////////////////////////////////////////////
+static unsigned int calculate_long_checksum(unsigned int *buf, int len)
+{
+	int i, j;
+	unsigned int sum=0, tmp;
+
+	j = len/4;
+
+	for (i=0; i<j; buf++, i++) {
+		tmp = *buf;
+		sum += DWORD_SWAP(tmp);
+	}
+	return ~sum+1;
+}
+
+unsigned int extractStartAddr(char *filename)
+{
+    int fh;
+    Elf32_Ehdr hdr;
+    char *buf;
+    
+    buf = (char *)&hdr;
+    fh = open(filename, O_RDONLY);
+	if ( fh == -1 ) {
+		printf("Open input file error2!\n");
+		exit(1);
+	}
+	lseek(fh, 0L, SEEK_SET);
+	if ( read(fh, buf, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)) {
+		printf("Read file error2!\n");
+		close(fh);
+		exit(1);
+	}
+	close(fh);
+	
+	return(hdr.e_entry);
+}
+
+void printf_usage(void)
+{
+    printf("Version: 1.1\n");
+    printf("Usage: cvimg <option> input-filename output-filename start-addr burn-addr [signature]\n");
+    printf("<option>: root|linux|boot|all|vmlinux|vmlinuxhdr|signature\n");
+    printf("[signature]: user-specified signature (4 characters)\n");
+}
+
+#ifdef RTK_4K_CHKSUM_FIX
+#define JFFS2_ENDMARK_LEN 4
+static int rtk_fix_4k_chk(char *inputFile,char *outFile)
+{
+	struct stat status;
+	char *buf;
+	int fh, size;
+	IMG_HEADER_Tp pHeader;
+	unsigned short checksum=0;
+	int old_linx_len=0;
+	
+	if ( stat(inputFile, &status) < 0 ) {
+		printf("Can't stat file! [%s]\n", inputFile );
+		exit(1);
+	}
+	
+	//decide output size , current , stat+(checksum)	
+	size= status.st_size ;	
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		printf("Malloc buffer failed!\n");
+		exit(1);
+	}
+	memset(buf, '\0', size);
+
+	pHeader = (IMG_HEADER_Tp)buf;
+	
+	fh = open(inputFile, O_RDONLY);
+	if ( fh == -1 ) {
+		printf("Open input file error!\n");
+		free( pHeader );
+		exit(1);
+	}
+	lseek(fh, 0L, SEEK_SET);
+
+	if ( read(fh, buf, status.st_size) != status.st_size) {
+		printf("Read file error!\n");
+		close(fh);
+		free(pHeader);
+		exit(1);
+	}
+	close(fh);
+
+	//update  len(not include jffs2 endmark)
+	old_linx_len = DWORD_SWAP(pHeader->len);
+	//printf("old_linx_len = %8x\n !!",old_linx_len);
+	pHeader->len = DWORD_SWAP((size-sizeof(IMG_HEADER_T)-JFFS2_ENDMARK_LEN));
+
+	//erase old chksum
+	//printf("old_cksum = %8x\n !!",*((unsigned short *)&buf[sizeof(IMG_HEADER_T)+old_linx_len-sizeof(checksum)]));
+	*((unsigned short *)&buf[sizeof(IMG_HEADER_T)+old_linx_len-sizeof(checksum)]) = 0;
+
+	//add new chksum		
+	checksum = WORD_SWAP(calculateChecksum(buf+sizeof(IMG_HEADER_T), (size-sizeof(IMG_HEADER_T)-JFFS2_ENDMARK_LEN)));
+	//*((unsigned short *)&buf[status.st_size]) = checksum;
+	*((unsigned short *)&buf[sizeof(IMG_HEADER_T)+old_linx_len-sizeof(checksum)]) = checksum;
+
+	//write to new file	
+	fh = open(outFile, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU); //mark_88
+	if ( fh == -1 ) {
+		printf("Create output file error! [%s]\n", outFile);
+		free(pHeader);
+		exit(1);
+	}
+	write(fh, pHeader, size);
+	close(fh);
+	chmod(outFile, DEFFILEMODE);	
+	
+	printf("Generate 4k alignment image(with jffs2 end mark)successfully, length=%d, checksum=0x%x\n", (int)DWORD_SWAP(pHeader->len), checksum);
+
+	free(pHeader);
+
+	return 0;	
+}
+#endif
+
+int main(int argc, char** argv)
+{
+#ifdef COMPACT_FILENAME_BUFFER
+	const char *inFile = NULL, *outFile = NULL;
+#else
+	char inFile[80]={0}, outFile[80]={0};
+#endif
+	int fh, size;
+	struct stat status;
+	char *buf;
+	IMG_HEADER_Tp pHeader;
+	unsigned int startAddr;
+	unsigned int burnAddr;
+	unsigned short checksum=0;
+	int is_vmlinux = 0;
+	int is_vmlinuxhdr = 0;
+    int is_signature = 0;
+	unsigned int lchecksum, padding_len=0;
+	unsigned int start_addr=0;		
+
+	if (argc == 4 && !strcmp(argv[1], "size_chk")) {
+		unsigned int total_size;
+
+#ifdef COMPACT_FILENAME_BUFFER
+		inFile = argv[2];
+#else
+		sscanf(argv[2], "%s", inFile);
+#endif
+		sscanf(argv[3], "%x", &startAddr);
+		if ( stat(inFile, &status) < 0 ) {
+			printf("Can't stat file! [%s]\n", inFile );
+			exit(1);
+		}
+		printf("==============================================\n");
+		printf("Summary ==>\n");
+		printf("Image loading  addr          :0x%x\n", (int)startAddr);
+		printf("Image decompress end addr    :0x%x\n", ((unsigned int)DEFAULT_BASE_ADDR)+(unsigned int)status.st_size);
+
+		total_size = startAddr - ((unsigned int)DEFAULT_BASE_ADDR);
+
+		if (status.st_size > (int)total_size)
+		{
+			printf("Error!!!! : Kernel image decompress will overwirte load image\n");
+			exit(1);
+		}
+		else
+			printf("Available size               :0x%08x\n",
+					 (unsigned int)(total_size - status.st_size));
+
+		exit(0);
+	}
+
+#ifdef CONFIG_RTL_FLASH_MAPPING_ENABLE
+	if (argc == 3 && !strcmp(argv[1], "flash_size_chk")) {
+		unsigned int total_size;
+
+#ifdef COMPACT_FILENAME_BUFFER
+		inFile = argv[2];
+#else
+		sscanf(argv[2], "%s", inFile);
+#endif
+		if ( stat(inFile, &status) < 0 ) {
+			printf("Can't stat file! [%s]\n", inFile );
+			exit(1);
+		}
+		printf("==============================================\n");
+		printf("Summary ==>\n");
+		printf("Image flash start  addr          :0x%x\n", (unsigned int)CODE_IMAGE_OFFSET);
+		printf("Image flash end addr             :0x%x\n", (unsigned int)CODE_IMAGE_OFFSET+(unsigned int)status.st_size);
+
+#ifdef CONFIG_RTL_802_1X_CLIENT_SUPPORT
+		total_size = ROOT_IMAGE_OFFSET - CODE_IMAGE_OFFSET - CERT_SIZE;	// To reserve CERT_SIZE for 802.1x wlan client mode to store 802.1x certs
+#else
+		total_size = ROOT_IMAGE_OFFSET - CODE_IMAGE_OFFSET;
+#endif
+
+		if (status.st_size > (int)total_size)
+		{
+			printf("Error!!!! : Kernel image too big will overwirte rootfs image, cur size(%d), available size(%d).\n",(int)status.st_size, total_size);
+			exit(1);
+		}
+		else
+			printf("Available size               :0x%08x\n",
+					 (unsigned int)(total_size - status.st_size));
+
+		exit(0);
+	}
+#endif
+
+#ifdef RTK_4K_CHKSUM_FIX
+	if (argc == 4 && !strcmp(argv[1], "fix_chksum"))
+	{
+	    rtk_fix_4k_chk(argv[2],argv[3]);
+	    return 0;
+	}
+#endif
+
+	if (argc == 4 && !strcmp(argv[1], "vmlinux"))
+		is_vmlinux = 1;
+
+    if (argc == 5 && !strcmp(argv[1], "vmlinuxhdr")) {
+		is_vmlinuxhdr = 1;
+		start_addr = extractStartAddr(argv[4]);
+	}
+
+	if (!strcmp(argv[1], "signature")) {
+		is_signature = 1;
+		if (argc != 7) {
+		    printf_usage();
+		    exit(1);
+		}
+	}
+		
+	// parse input arguments
+	if ( argc != 6 && !is_vmlinux && !is_vmlinuxhdr && !is_signature) {
+	    printf_usage();
+		exit(1);
+	}
+
+
+
+#ifdef COMPACT_FILENAME_BUFFER
+	inFile = argv[2];
+	outFile = argv[3];
+#else
+	sscanf(argv[2], "%s", inFile);
+	sscanf(argv[3], "%s", outFile);
+#endif
+
+	if ((!is_vmlinux) && (!is_vmlinuxhdr)) {
+		sscanf(argv[4], "%x", &startAddr);
+		sscanf(argv[5], "%x", &burnAddr);
+	}
+	// check input file and allocate buffer
+	if ( stat(inFile, &status) < 0 ) {
+		printf("Can't stat file! [%s]\n", inFile );
+		exit(1);
+	}
+
+	if (is_vmlinuxhdr) {
+		size = status.st_size + sizeof(padding_len) + sizeof(lchecksum) + sizeof(start_addr);
+		padding_len = 4 - (size%4);	
+		size += padding_len;
+	}
+	else if (!is_vmlinux) {
+		size = status.st_size + sizeof(IMG_HEADER_T) + sizeof(checksum);
+		if (size%2)
+			size++; // pad
+	}
+	else {
+		size = status.st_size + sizeof(padding_len) + sizeof(lchecksum);
+		padding_len = 4 - (size%4);	
+		size += padding_len;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		printf("Malloc buffer failed!\n");
+		exit(1);
+	}
+	memset(buf, '\0', size);
+	pHeader = (IMG_HEADER_Tp)buf;
+
+    if (is_vmlinuxhdr)
+        buf += 8; // skip padding-length field and start-address field
+	else if (!is_vmlinux)
+		buf += sizeof(IMG_HEADER_T);
+	else
+		buf += 4; // skip padding-length field
+
+	// Read data and generate header
+	fh = open(inFile, O_RDONLY);
+	if ( fh == -1 ) {
+		printf("Open input file error!\n");
+		free( pHeader );
+		exit(1);
+	}
+	lseek(fh, 0L, SEEK_SET);
+	if ( read(fh, buf, status.st_size) != status.st_size) {
+		printf("Read file error!\n");
+		close(fh);
+		free(pHeader);
+		exit(1);
+	}
+	close(fh);
+
+	if (is_vmlinuxhdr) {
+		*((unsigned int *)pHeader) = DWORD_SWAP(padding_len);
+		*((unsigned int *)((char *)pHeader+4)) = start_addr;
+		lchecksum = DWORD_SWAP(calculate_long_checksum((unsigned int *)buf, size-12));
+		memcpy(&buf[size-12], &lchecksum, 4);		
+	}
+	else if (!is_vmlinux) {
+		if( !strcmp("root", argv[1]))
+			memcpy(pHeader->signature, ROOT_HEADER, SIGNATURE_LEN);
+		else if ( !strcmp("boot", argv[1]))
+			memcpy(pHeader->signature, BOOT_HEADER, SIGNATURE_LEN);
+		else if ( !strcmp("linux", argv[1]))
+			memcpy(pHeader->signature, FW_HEADER, SIGNATURE_LEN);
+		else if ( !strcmp("linux-ro", argv[1]))
+			memcpy(pHeader->signature, FW_HEADER_WITH_ROOT, SIGNATURE_LEN);
+		else if ( !strcmp("signature", argv[1]))
+			memcpy(pHeader->signature, argv[6], SIGNATURE_LEN);
+		else{
+			printf("not supported signature\n");
+			exit(1);
+		}
+		pHeader->len = DWORD_SWAP((size-sizeof(IMG_HEADER_T)));
+		pHeader->startAddr = DWORD_SWAP(startAddr);
+		pHeader->burnAddr = DWORD_SWAP(burnAddr);
+
+		if( !strcmp("root", argv[1])) {
+			#define SIZE_OF_SQFS_SUPER_BLOCK 640		
+			unsigned int fs_len;
+			fs_len = DWORD_SWAP((size-sizeof(IMG_HEADER_T) - sizeof(checksum)- SIZE_OF_SQFS_SUPER_BLOCK));
+			memcpy(buf + 8, &fs_len, 4);	
+		}		
+		
+		checksum = WORD_SWAP(calculateChecksum(buf, status.st_size));
+		*((unsigned short *)&buf[size-sizeof(IMG_HEADER_T)-sizeof(checksum)]) = checksum;
+	}
+	else { // is_vmlinux=1
+		*((unsigned int *)pHeader) = DWORD_SWAP(padding_len);
+		lchecksum = DWORD_SWAP(calculate_long_checksum((unsigned int *)buf, size-8));
+		memcpy(&buf[size-8], &lchecksum, 4);		
+	}
+	
+	// Write image to output file
+	fh = open(outFile, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU); //mark_88
+	if ( fh == -1 ) {
+		printf("Create output file error! [%s]\n", outFile);
+		free(pHeader);
+		exit(1);
+	}
+	write(fh, pHeader, size);
+	close(fh);
+	chmod(outFile, DEFFILEMODE);
+	
+	if (is_vmlinuxhdr)
+	    printf("Generate image successfully, length=%d, checksum=0x%x, padding=%d, start address=0x%08x\n", size-12-padding_len, lchecksum, padding_len, DWORD_SWAP(start_addr));
+	else if (!is_vmlinux)
+		printf("Generate image successfully, length=%d, checksum=0x%x\n", (int)DWORD_SWAP(pHeader->len), checksum);
+	else
+		printf("Generate image successfully, length=%d, checksum=0x%x, padding=%d\n", size-8-padding_len, lchecksum, padding_len);
+
+	free(pHeader);
+	return 0;
+}
+
+static unsigned short calculateChecksum(char *buf, int len)
+{
+	int i, j;
+	unsigned short sum=0, tmp;
+
+	j = (len/2)*2;
+
+	for (i=0; i<j; i+=2) {
+		tmp = *((unsigned short *)(buf + i));
+		sum += WORD_SWAP(tmp);
+	}
+
+	if ( len % 2 ) {
+		tmp = buf[len-1];
+		sum += WORD_SWAP(tmp);
+	}
+	return ~sum+1;
+}
diff --git a/tools/rtk-tools/src/mgbin.c b/tools/rtk-tools/src/mgbin.c
new file mode 100644
index 0000000000..411c86aaae
--- /dev/null
+++ b/tools/rtk-tools/src/mgbin.c
@@ -0,0 +1,429 @@
+/*
+ *      utility to merge all binary into one image
+ *
+ *      Authors: David Hsu	<davidhsu@realtek.com.tw>
+ *
+ *      $Id: mgbin.c,v 1.7 2008/11/25 15:09:22 bradhuang Exp $
+ *
+ */
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef WIN32
+	#include <io.h>
+#else
+	#include <unistd.h>
+#endif
+#define __mips__
+
+#include "apmib.h"
+
+//#define DEBUG_PRINT	printf
+#define DEBUG_PRINT(...)  do {} while(0)
+
+/////////////////////////////////////////////////////////////////////////////
+/* Input file type */
+typedef enum { BOOT_CODE=0, CONFIG, WEB_PAGES, SYS, ROOT, ALL, INVALID_FILE=-1 } TYPE_T;
+
+typedef struct _sector {
+	TYPE_T type;
+#ifdef COMPACT_FILENAME_BUFFER
+	const char *filename;
+#else
+	char filename[80];
+#endif
+	unsigned long offset;
+	unsigned long size;
+	int with_header;
+} SECTOR_T;
+
+/////////////////////////////////////////////////////////////////////////////
+static char *copyright="Copyright (c) Realtek Semiconductor Corp., 2007. All Rights Reserved.";
+static char *version="1.0";
+
+static SECTOR_T sector[ROOT+1];
+static int no_hw_config=0;
+
+#define BYTE_SWAP(word) (((word >> 8) &0xff) | ((((unsigned char)word)<<8)&0xff00) )
+
+/////////////////////////////////////////////////////////////////////////////
+static TYPE_T checkInputFile(char *filename, int *pWith_header)
+{
+	int fh;
+	char signature[6];
+
+#ifdef WIN32
+	fh = open(filename, O_RDONLY|O_BINARY);
+#else
+	fh = open(filename, O_RDONLY,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+#endif
+	if ( fh == -1 )
+		return INVALID_FILE;
+
+	lseek(fh, 0, SEEK_SET);
+
+	if ( read(fh, signature, sizeof(signature)) != sizeof(signature)) {
+		close(fh);
+		return INVALID_FILE;
+	}
+	close(fh);
+
+	*pWith_header = 1;
+	if ( !memcmp(signature, BOOT_HEADER, 4))
+		return BOOT_CODE;
+	else if ( !memcmp(signature, WEB_HEADER, 3) )
+		return WEB_PAGES;
+
+	else if ( !memcmp(signature, FW_HEADER, 4) || 
+			!memcmp(signature, FW_HEADER_WITH_ROOT, 4))
+		return SYS;
+
+	else if ( !memcmp(signature, ROOT_HEADER, 4) )
+		return ROOT;
+	
+	else if ( !memcmp(signature, "h", 1) || !memcmp(signature, "COMPHS", 6))
+		return CONFIG;
+	else if ( !memcmp(signature, "6G", 2) || !memcmp(signature, "6A", 2) || !memcmp(signature, "6g", 2) || !memcmp(signature, "6a", 2) || !memcmp(signature, "COMPDS", 6)) {
+		no_hw_config = 1;
+		return CONFIG;	
+	}
+	else if ( !memcmp(signature, "\x0b\xf0\x00\x02", 4)) {
+		*pWith_header = 0;
+		return BOOT_CODE;
+	}
+	return INVALID_FILE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+static void showHelp(void)
+{
+	printf("\nRTL865x utility to merge binary.\n");
+	printf("%s Ver %s.\n\n", copyright, version);
+	printf("usage: mgbin [-s] [-c] [-a] -o outputfile bootcode config webpages linux root\n");
+	printf("	-s : do byte swap\n");
+	printf("	-c : cascade. May use this option to merge image for web upload\n");
+	printf("	-a : add all tag in header\n");
+	
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+static void do_byteswap(unsigned char *buf, int len)
+{
+	unsigned short wVal, *ptr;
+	int i=0;
+
+	while (len > 0) {
+		len -= 2;
+		ptr = (unsigned short *)&buf[2*i];
+		wVal = *ptr;
+		*ptr = BYTE_SWAP( wVal );
+		i++;
+	}
+}
+
+static unsigned short calculateChecksum(char *buf, int len, unsigned short oldv)
+{
+	int i, j;
+	unsigned short sum=oldv, tmp;
+
+	j = (len/2)*2;
+
+	for (i=0; i<j; i+=2) {
+		tmp = *((unsigned short *)(buf + i));
+		sum += WORD_SWAP(tmp);
+	}
+
+	if ( len % 2 ) {
+		tmp = buf[len-1];
+		sum += WORD_SWAP(tmp);
+	}
+	return sum;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+	int argNum=1;
+#ifdef COMPACT_FILENAME_BUFFER
+	const char *outFile = NULL;
+#else
+	char outFile[80]={0};
+#endif
+	TYPE_T type;
+	int mask=0, fh_out, fh_in, len, i, total=0;
+	unsigned char *buf, *buf1;
+	struct stat sbuf;
+	int byteswap=0, cascade=0, last_idx=-1, is_all=0;
+	int offset=0, with_header;
+	IMG_HEADER_Tp pHeader;
+	unsigned long burnAddr=0;
+	IMG_HEADER_T allHeader;
+	unsigned short checksum=0;
+		
+	memset(&sector, 0, sizeof(sector));
+
+	while (argNum < argc) {
+		if ( !strcmp(argv[argNum], "-o") ) {
+			if (++argNum >= argc)
+				break;
+#ifdef COMPACT_FILENAME_BUFFER
+			outFile = argv[argNum];
+#else
+			sscanf(argv[argNum], "%s", outFile);
+#endif
+		}
+		else if ( !strcmp(argv[argNum], "-s") ) {
+			byteswap = 1;
+		}
+		else if ( !strcmp(argv[argNum], "-c") ) {
+			cascade = 1;
+		}
+		else if ( !strcmp(argv[argNum], "-a") ) {
+			is_all = 1;
+			memset(&allHeader, '\0', sizeof(IMG_HEADER_T));
+			memcpy(allHeader.signature, ALL_HEADER, SIGNATURE_LEN);			
+		}
+#if 0
+		else if ( !strcmp(argv[argNum], "-a2") ) {
+			is_all = 1;
+			memset(&allHeader, '\0', sizeof(IMG_HEADER_T));
+			memcpy(allHeader.signature, ALL_HEADER2, SIGNATURE_LEN);			
+		}						
+#endif
+		else {
+			if (is_all) {
+				if ((argNum+1) < argc) {
+					printf("argument error, only input file could be specified!\n");
+					return -1;					
+				}				
+#ifdef COMPACT_FILENAME_BUFFER
+				sector[0].filename = argv[argNum];
+#else
+				strcpy(sector[0].filename,argv[argNum]);				
+#endif
+				sector[0].type=ALL;
+				sector[0].with_header=0;
+				mask |= (1 << ALL);
+		}
+		else {
+			type=checkInputFile(argv[argNum], &with_header);
+			DEBUG_PRINT("filename=%s, type=%d\n", argv[argNum], type);			
+			if (type == INVALID_FILE) {
+				printf("\nInvalid input file %s!!\n", argv[argNum]);
+				showHelp();
+				exit(1);
+			}
+#ifdef COMPACT_FILENAME_BUFFER
+			sector[type].filename = argv[argNum];
+#else
+			strcpy(sector[type].filename, argv[argNum]);
+#endif
+			sector[type].with_header = with_header;
+			sector[type].type = type;
+			mask |= (1 << type);
+			}
+		}
+		argNum++;
+	}
+
+#ifdef COMPACT_FILENAME_BUFFER
+	if( outFile == NULL )
+#else
+	if (!outFile[0]) 
+#endif
+	{
+		printf("No output file specified!\n");
+		showHelp();
+		exit(1);
+	}
+
+	if (mask == 0) {
+		printf("No valid input image found!\n");
+		exit(1);
+	}
+
+	// Create output file
+#ifdef WIN32
+	_chmod(outFile, S_IREAD|S_IWRITE);
+	fh_out = open(outFile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY);
+#else
+	chmod(outFile, S_IREAD|S_IWRITE);
+	fh_out = open(outFile, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);//mark_88
+#endif
+	if (fh_out == -1) {
+		printf("Create output file %s error!\n", outFile);
+		exit(1);
+	}
+
+	if (is_all) {
+		write(fh_out, &allHeader, sizeof(allHeader));
+		total += sizeof(allHeader);
+		printf("\nGenerate ");
+	}
+	else
+	printf("\nMerge ");
+
+	for (i=BOOT_CODE; i<=ROOT ; i++) {
+#ifdef COMPACT_FILENAME_BUFFER
+		if (sector[i].filename) 
+#else
+		if (sector[i].filename[0]) 
+#endif
+		{
+			if ( stat(sector[i].filename, &sbuf) != 0 ) {
+				printf("Stat file %s error!\n", sector[i].filename);
+				exit(1);
+			}
+			buf = malloc(sbuf.st_size+1);
+			if (buf == NULL) {
+				printf("allocate buffer failed %d!\n", (int)sbuf.st_size);
+				exit(1);
+			}
+#ifdef WIN32
+			fh_in = open(sector[i].filename, O_RDONLY|O_BINARY);
+#else
+			fh_in = open(sector[i].filename, O_RDONLY,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+#endif
+			if (fh_in < 0) {
+				printf("Open file %s error!\n", sector[i].filename);
+				close(fh_out);
+				exit(1);
+			}
+
+			switch(sector[i].type) {
+			case BOOT_CODE:
+				printf("BOOT-CODE ");
+				break;
+			case CONFIG:
+				printf("CONFIG-DATA(%s) ", (no_hw_config ? "no-hw" : "all"));
+				break;
+			case WEB_PAGES:
+				printf("WEB-PAGES ");
+				break;
+			case SYS:
+				printf("LINUX ");
+				break;
+			case ROOT:
+				printf("ROOT ");
+				break;
+			case ALL:
+				printf("ALL ");
+				break;				
+			case INVALID_FILE:
+				break;
+			}
+
+			if (read(fh_in, buf, sbuf.st_size) != sbuf.st_size) {
+				printf("Read file %s error!\n", sector[i].filename);
+				close(fh_in);
+				close(fh_out);
+				free(buf);
+				exit(1);
+			}
+
+			if (is_all) 
+				checksum = calculateChecksum((char *)buf, sbuf.st_size, checksum);			
+			else {
+			if (sector[i].with_header) {
+				if (sector[i].type == CONFIG) {
+					if (no_hw_config == 0)
+						burnAddr = HW_SETTING_OFFSET;
+					else
+						burnAddr = DEFAULT_SETTING_OFFSET;
+				}
+				else {
+					pHeader = (IMG_HEADER_Tp)buf;
+					burnAddr = DWORD_SWAP(pHeader->burnAddr);
+				}
+			}
+			else 
+				burnAddr = 0;			
+
+			if (byteswap) {
+				if (sbuf.st_size % 2) {
+					buf[sbuf.st_size] = '\0';
+					sbuf.st_size++;
+				}
+				do_byteswap(buf, sbuf.st_size);
+			}
+			
+			// try to append 0 if necessary
+			if (!cascade && last_idx!=-1 && sector[i].with_header) {
+				if ((sector[last_idx].offset+sector[last_idx].size) < burnAddr) {
+					len = burnAddr - (sector[last_idx].offset+sector[last_idx].size);
+					buf1 = calloc(len, 1);
+					if (buf1 == NULL) {
+						printf("allocate buffer failed %d!\n", len);
+						exit(1);
+					}
+					write(fh_out, buf1, len);	// pad 0
+					
+					free(buf1);
+					total += len;
+//				printf("pad size=%d, last_idx=%d, burnAddr=%d\n", len, last_idx, burnAddr);			
+				}				
+			}			
+
+			// skip header if necessary
+			if (!cascade && sector[i].with_header &&
+					((sector[i].type == ROOT) || (sector[i].type == BOOT_CODE))) {
+				offset = sizeof(IMG_HEADER_T);
+//				sbuf.st_size -= sizeof(IMG_HEADER_T);
+			}
+			else
+				offset = 0;
+			}			
+
+//		printf("write offset=%d, size=%d\n", offset, 	sbuf.st_size);
+			if ( write(fh_out, buf + offset , sbuf.st_size-offset) != sbuf.st_size-offset) {
+				printf("Write output file %s error!\n", outFile);
+				close(fh_in);
+				close(fh_out);
+				free(buf);
+				exit(1);
+			}
+			close(fh_in);
+			if (burnAddr > 0)
+				sector[i].offset = burnAddr;
+			else
+				sector[i].offset = total;
+			sector[i].size = sbuf.st_size-offset;
+
+//	printf("section[%d], offset=%d, size=%d\n", i, sector[i].offset, sector[i].size);
+			
+			total += sbuf.st_size;
+			free(buf);
+			last_idx = i;
+			if (is_all)
+				break;			
+		}
+	}
+
+	if (is_all) {
+		allHeader.len = DWORD_SWAP((total+2));
+		checksum = calculateChecksum((char *)&allHeader, sizeof(allHeader), checksum);		
+		checksum = WORD_SWAP((~checksum+1));
+		write(fh_out, &checksum, 2);
+		lseek(fh_out, 0, SEEK_SET);
+		allHeader.len = DWORD_SWAP((total+2));
+//		allHeader.startAddr = DWORD_SWAP(image_num);
+		write(fh_out, &allHeader, sizeof(allHeader));		
+		total += (2 + sizeof(allHeader));
+	}
+	close(fh_out);
+
+#ifdef WIN32
+	_chmod(outFile, S_IREAD);
+#else
+	chmod(outFile, DEFFILEMODE);
+#endif
+
+	printf("=> %s ok, size=%d.\n", outFile, total);
+	exit(0);
+}
+
-- 
2.25.1

