[openwrt/openwrt] firmware-utils: add JBOOT bootloader image support

LEDE Commits lede-commits at lists.infradead.org
Sun Mar 18 23:51:54 PDT 2018


mkresin pushed a commit to openwrt/openwrt.git, branch master:
https://git.lede-project.org/84c1b786b9830c17034e5de915ce11965666febd

commit 84c1b786b9830c17034e5de915ce11965666febd
Author: Pawel Dembicki <paweldembicki at gmail.com>
AuthorDate: Sat Feb 3 12:59:50 2018 +0100

    firmware-utils: add JBOOT bootloader image support
    
    Tested on D-Link DWR-116.
    Based on mktplinkfw.
    
    Signed-off-by: Pawel Dembicki <paweldembicki at gmail.com>
---
 tools/firmware-utils/Makefile            |   1 +
 tools/firmware-utils/src/mkdlinkfw-lib.c | 172 ++++++++
 tools/firmware-utils/src/mkdlinkfw-lib.h |  83 ++++
 tools/firmware-utils/src/mkdlinkfw.c     | 665 +++++++++++++++++++++++++++++++
 4 files changed, 921 insertions(+)

diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
index f3fefa3..7fa6f71 100644
--- a/tools/firmware-utils/Makefile
+++ b/tools/firmware-utils/Makefile
@@ -81,6 +81,7 @@ define Host/Compile
 	$(call cc,mkbuffaloimg, -Wall)
 	$(call cc,zyimage, -Wall)
 	$(call cc,mkdhpimg buffalo-lib, -Wall)
+	$(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall)
 endef
 
 define Host/Install
diff --git a/tools/firmware-utils/src/mkdlinkfw-lib.c b/tools/firmware-utils/src/mkdlinkfw-lib.c
new file mode 100644
index 0000000..fcab856
--- /dev/null
+++ b/tools/firmware-utils/src/mkdlinkfw-lib.c
@@ -0,0 +1,172 @@
+/*
+ * mkdlinkfw
+ *
+ * Copyright (C) 2018 Paweł Dembicki <paweldembicki at gmail.com>
+ *
+ * This tool is based on mktplinkfw.
+ * Copyright (C) 2009 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2008,2009 Wang Jian <lark at linux.net.cn>
+ *
+ * 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.
+ */
+
+#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 <stdbool.h>
+#include <endian.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <zlib.h>		/*for crc32 */
+
+#include "mkdlinkfw-lib.h"
+
+extern char *progname;
+
+static unsigned char jffs2_eof_mark[4] = { 0xde, 0xad, 0xc0, 0xde };
+
+uint32_t jboot_timestamp(void)
+{
+	time_t rawtime;
+	time(&rawtime);
+	return (((uint32_t) rawtime) - TIMESTAMP_MAGIC) >> 2;
+}
+
+uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size)
+{
+	uint32_t counter = start_val;
+	uint16_t *ptr = data;
+
+	while (size > 1) {
+		counter += *ptr;
+		++ptr;
+		while (counter >> 16)
+			counter = (uint16_t) counter + (counter >> 16);
+		size -= 2;
+	}
+	if (size > 0) {
+		counter += *(uint8_t *) ptr;
+		counter -= 0xFF;
+	}
+	while (counter >> 16)
+		counter = (uint16_t) counter + (counter >> 16);
+	return counter;
+}
+
+int get_file_stat(struct file_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL)
+		return 0;
+
+	res = stat(fdata->file_name, &st);
+	if (res) {
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	return 0;
+}
+
+int read_to_buf(const struct file_info *fdata, char *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+ out_close:
+	fclose(f);
+ out:
+	return ret;
+}
+
+int pad_jffs2(char *buf, int currlen, int maxlen)
+{
+	int len;
+	uint32_t pad_mask;
+
+	len = currlen;
+	pad_mask = (4 * 1024) | (64 * 1024);	/* EOF at 4KB and at 64KB */
+	while ((len < maxlen) && (pad_mask != 0)) {
+		uint32_t mask;
+		int i;
+
+		for (i = 10; i < 32; i++) {
+			mask = 1 << i;
+			if (pad_mask & mask)
+				break;
+		}
+
+		len = ALIGN(len, mask);
+
+		for (i = 10; i < 32; i++) {
+			mask = 1 << i;
+			if ((len & (mask - 1)) == 0)
+				pad_mask &= ~mask;
+		}
+
+		for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+			buf[len + i] = jffs2_eof_mark[i];
+
+		len += sizeof(jffs2_eof_mark);
+	}
+
+	return len;
+}
+
+int write_fw(const char *ofname, const char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS)
+		unlink(ofname);
+ out:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/mkdlinkfw-lib.h b/tools/firmware-utils/src/mkdlinkfw-lib.h
new file mode 100644
index 0000000..d61124c
--- /dev/null
+++ b/tools/firmware-utils/src/mkdlinkfw-lib.h
@@ -0,0 +1,83 @@
+/*
+ * mkdlinkfw
+ *
+ * Copyright (C) 2018 Paweł Dembicki <paweldembicki at gmail.com>
+ *
+ * This tool is based on mktplinkfw.
+ * Copyright (C) 2009 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2008,2009 Wang Jian <lark at linux.net.cn>
+ *
+ * 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.
+ */
+
+#ifndef mkdlinkfw_lib_h
+#define mkdlinkfw_lib_h
+
+#define AUH_MAGIC "DLK"
+#define AUH_SIZE 80
+#define AUH_LVPS 0x01
+#define AUH_HDR_ID 0x4842
+#define AUH_HDR_VER 0x02
+#define AUH_SEC_ID 0x04
+#define AUH_INFO_TYPE 0x04
+
+#define STAG_SIZE 16
+#define STAG_ID 0x04
+#define STAG_MAGIC 0x2B24
+#define STAG_CMARK_FACTORY 0xFF
+
+#define SCH2_SIZE 40
+#define SCH2_MAGIC 0x2124
+#define SCH2_VER 0x02
+
+#define FLAT 0
+#define JZ 1
+#define GZIP 2
+#define LZMA 3
+
+#define RAM_ENTRY_ADDR 0x80000000
+#define RAM_LOAD_ADDR 0x80000000
+#define JBOOT_SIZE 0x10000
+
+#define ALL_HEADERS_SIZE (AUH_SIZE + STAG_SIZE + SCH2_SIZE)
+#define MAX_HEADER_COUNTER 10
+#define TIMESTAMP_MAGIC 0x35016f00L
+
+#define FACTORY 0
+#define SYSUPGRADE 1
+
+#define ALIGN(x, a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+#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 DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__); \
+} while (0)
+
+struct file_info {
+	char *file_name;	/* name of the file */
+	uint32_t file_size;	/* length of the file */
+};
+
+uint32_t jboot_timestamp(void);
+uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size);
+int get_file_stat(struct file_info *fdata);
+int read_to_buf(const struct file_info *fdata, char *buf);
+int pad_jffs2(char *buf, int currlen, int maxlen);
+int write_fw(const char *ofname, const char *data, int len);
+
+#endif				/* mkdlinkfw_lib_h */
diff --git a/tools/firmware-utils/src/mkdlinkfw.c b/tools/firmware-utils/src/mkdlinkfw.c
new file mode 100644
index 0000000..8760500
--- /dev/null
+++ b/tools/firmware-utils/src/mkdlinkfw.c
@@ -0,0 +1,665 @@
+/*
+ * mkdlinkfw
+ *
+ * Copyright (C) 2018 Paweł Dembicki <paweldembicki at gmail.com>
+ *
+ * This tool is based on mktplinkfw.
+ * Copyright (C) 2009 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2008,2009 Wang Jian <lark at linux.net.cn>
+ *
+ * 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.
+ */
+
+#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 <stdbool.h>
+#include <endian.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <zlib.h>		/*for crc32 */
+
+#include "mkdlinkfw-lib.h"
+
+/* ARM update header 2.0
+ * used only in factory images to erase and flash selected area
+ */
+struct auh_header {
+	uint8_t rom_id[12];	/* 12-bit rom-id unique per router type */
+	uint16_t derange;	/* used for scramble header */
+	uint16_t image_checksum;	/* jboot_checksum of flashed data */
+
+	uint32_t space1;	/* zeros */
+	uint32_t space2;	/* zeros */
+	uint16_t space3;	/* zerosu */
+	uint8_t lpvs;		/* must be 0x01 */
+	uint8_t mbz;		/* bust be 0 */
+	uint32_t time_stamp;	/* timestamp calculated in jboot way */
+
+	uint32_t erase_start;	/* erase start address */
+	uint32_t erase_length;	/* erase length address */
+	uint32_t data_offset;	/* data start address */
+	uint32_t data_length;	/* data length address */
+
+	uint32_t space4;	/* zeros */
+	uint32_t space5;	/* zeros */
+	uint32_t space6;	/* zeros */
+	uint32_t space7;	/* zeros */
+
+	uint16_t header_id;	/* magic 0x4842 */
+	uint16_t header_version;	/* 0x02 for 2.0 */
+	uint16_t space8;	/* zeros */
+	uint8_t section_id;	/* section id */
+	uint8_t image_info_type;	/* (?) 0x04 in factory images */
+	uint32_t image_info_offset;	/* (?) zeros in factory images */
+	uint16_t family_member;	/* unique per router type */
+	uint16_t header_checksum;	/* negated jboot_checksum of header data */
+};
+
+struct stag_header {		/* used only of sch2 wrapped kernel data */
+	uint8_t cmark;		/* in factory 0xFF ,in sysuograde must be the same as id */
+	uint8_t id;		/* 0x04 */
+	uint16_t magic;		/* magic 0x2B24 */
+	uint32_t time_stamp;	/* timestamp calculated in jboot way */
+	uint32_t image_length;	/* lentgh of kernel + sch2 header */
+	uint16_t image_checksum;	/* negated jboot_checksum of sch2 + kernel */
+	uint16_t tag_checksum;	/* negated jboot_checksum of stag header data */
+};
+
+struct sch2_header {		/* used only in kernel partitions */
+	uint16_t magic;		/* magic 0x2124 */
+	uint8_t cp_type;	/* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */
+	uint8_t version;	/* 0x02 for sch2 */
+	uint32_t ram_addr;	/* ram entry address */
+	uint32_t image_len;	/* kernel image length */
+	uint32_t image_crc32;	/* kernel image crc */
+	uint32_t start_addr;	/* ram start address */
+	uint32_t rootfs_addr;	/* rootfs flash address */
+	uint32_t rootfs_len;	/* rootfls length */
+	uint32_t rootfs_crc32;	/* rootfs crc32 */
+	uint32_t header_crc32;	/* sch2 header crc32, durring calculation this area is replaced by zero */
+	uint16_t header_length;	/* sch2 header length: 0x28 */
+	uint16_t cmd_line_length;	/* cmd line length, known zeros */
+};
+
+/* globals */
+static struct file_info inspect_info;
+struct file_info kernel_info;
+struct file_info rootfs_info;
+struct file_info image_info;
+
+char *ofname;
+char *progname;
+uint32_t firmware_size;
+uint16_t family_member;
+char *rom_id[12] = { 0 };
+
+char image_type;
+int add_jffs2_eof;
+
+static void usage(int status)
+{
+	fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stderr,
+		"\n"
+		"Options:\n"
+		"  -i <file>       inspect given firmware file <file>\n"
+		"  -f              set family member id (hexval prefixed with 0x)\n"
+		"  -F <file>       read image and convert it to FACTORY\n"
+		"  -k <file>       read kernel image from the file <file>\n"
+		"  -r <file>       read rootfs image from the file <file>\n"
+		"  -o <file>       write output to the file <file>\n"
+		"  -s <size>       set firmware partition size\n"
+		"  -m <version>    set rom id to <version> (12-bit string val: \"DLK*********\")\n"
+		"  -h              show this screen\n");
+
+	exit(status);
+}
+
+void print_auh_header(struct auh_header *printed_header)
+{
+	printf("\trom_id: %s\n"
+	       "\tderange: 0x%04X\n"
+	       "\timage_checksum: 0x%04X\n"
+	       "\tspace1: 0x%08X\n"
+	       "\tspace2: 0x%08X\n"
+	       "\tspace3: 0x%04X\n"
+	       "\tlpvs: 0x%02X\n"
+	       "\tmbz: 0x%02X\n"
+	       "\ttime_stamp: 0x%08X\n"
+	       "\terase_start: 0x%08X\n"
+	       "\terase_length: 0x%08X\n"
+	       "\tdata_offset: 0x%08X\n"
+	       "\tdata_length: 0x%08X\n"
+	       "\tspace4: 0x%08X\n"
+	       "\tspace5: 0x%08X\n"
+	       "\tspace6: 0x%08X\n"
+	       "\tspace7: 0x%08X\n"
+	       "\theader_id: 0x%04X\n"
+	       "\theader_version: 0x%02X\n"
+	       "\tspace8: 0x%04X\n"
+	       "\tsection_id: 0x%02X\n"
+	       "\timage_info_type: 0x%02X\n"
+	       "\timage_info_offset 0x%08X\n"
+	       "\tfamily_member: 0x%04X\n"
+	       "\theader_checksum: 0x%04X\n",
+	       printed_header->rom_id,
+	       printed_header->derange,
+	       printed_header->image_checksum,
+	       printed_header->space1,
+	       printed_header->space2,
+	       printed_header->space3,
+	       printed_header->lpvs,
+	       printed_header->mbz,
+	       printed_header->time_stamp,
+	       printed_header->erase_start,
+	       printed_header->erase_length,
+	       printed_header->data_offset,
+	       printed_header->data_length,
+	       printed_header->space4,
+	       printed_header->space5,
+	       printed_header->space6,
+	       printed_header->space7,
+	       printed_header->header_id,
+	       printed_header->header_version,
+	       printed_header->space8,
+	       printed_header->section_id,
+	       printed_header->image_info_type,
+	       printed_header->image_info_offset,
+	       printed_header->family_member, printed_header->header_checksum);
+}
+
+void print_stag_header(struct stag_header *printed_header)
+{
+	printf("\tcmark: 0x%02X\n"
+	       "\tid: 0x%02X\n"
+	       "\tmagic: 0x%04X\n"
+	       "\ttime_stamp: 0x%08X\n"
+	       "\timage_length: 0x%04X\n"
+	       "\timage_checksum: 0x%04X\n"
+	       "\ttag_checksum: 0x%04X\n",
+	       printed_header->cmark,
+	       printed_header->id,
+	       printed_header->magic,
+	       printed_header->time_stamp,
+	       printed_header->image_length,
+	       printed_header->image_checksum, printed_header->tag_checksum);
+}
+
+void print_sch2_header(struct sch2_header *printed_header)
+{
+	printf("\tmagic: 0x%04X\n"
+	       "\tcp_type: 0x%02X\n"
+	       "\tversion: 0x%02X\n"
+	       "\tram_addr: 0x%08X\n"
+	       "\timage_len: 0x%08X\n"
+	       "\timage_crc32: 0x%08X\n"
+	       "\tstart_addr: 0x%08X\n"
+	       "\trootfs_addr: 0x%08X\n"
+	       "\trootfs_len: 0x%08X\n"
+	       "\trootfs_crc32: 0x%08X\n"
+	       "\theader_crc32: 0x%08X\n"
+	       "\theader_length: 0x%04X\n"
+	       "\tcmd_line_length: 0x%04X\n",
+	       printed_header->magic,
+	       printed_header->cp_type,
+	       printed_header->version,
+	       printed_header->ram_addr,
+	       printed_header->image_len,
+	       printed_header->image_crc32,
+	       printed_header->start_addr,
+	       printed_header->rootfs_addr,
+	       printed_header->rootfs_len,
+	       printed_header->rootfs_crc32,
+	       printed_header->header_crc32,
+	       printed_header->header_length, printed_header->cmd_line_length);
+}
+
+static int find_auh_headers(char *buf)
+{
+	char *tmp_buf = buf;
+	struct auh_header *tmp_header[MAX_HEADER_COUNTER];
+	int header_counter = 0;
+
+	int ret = EXIT_FAILURE;
+
+	while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) {
+		if (!memcmp(tmp_buf, AUH_MAGIC, 3)) {
+			if (((struct auh_header *)tmp_buf)->header_checksum ==
+			    (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf,
+							AUH_SIZE - 2)) {
+				uint16_t checksum = 0;
+				printf("Find proper AUH header at: 0x%lX!\n",
+				       tmp_buf - buf);
+				tmp_header[header_counter] =
+				    (struct auh_header *)tmp_buf;
+				checksum =
+				    jboot_checksum(0, (uint16_t *) ((char *)
+								    tmp_header
+								    [header_counter]
+								    + AUH_SIZE),
+						   tmp_header
+						   [header_counter]->data_length);
+				if (tmp_header[header_counter]->image_checksum
+				    == checksum)
+					printf("Image checksum ok.\n");
+				else
+					ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum);
+				header_counter++;
+				if (header_counter > MAX_HEADER_COUNTER)
+					break;
+			}
+		}
+		tmp_buf++;
+	}
+
+	if (header_counter == 0)
+		ERR("Can't find proper AUH header!\n");
+	else if (header_counter > MAX_HEADER_COUNTER)
+		ERR("To many AUH headers!\n");
+	else {
+		for (int i = 0; i < header_counter; i++) {
+			printf("AUH %d:\n", i);
+			print_auh_header(tmp_header[i]);
+		}
+
+		ret = EXIT_SUCCESS;
+	}
+
+	return ret;
+}
+
+static int check_stag_header(char *buf, struct stag_header *header)
+{
+
+	int ret = EXIT_FAILURE;
+
+	uint8_t cmark_tmp = header->cmark;
+	header->cmark = header->id;
+
+	if (header->tag_checksum ==
+	    (uint16_t) ~jboot_checksum(0, (uint16_t *) header,
+					STAG_SIZE - 2)) {
+		uint16_t checksum = 0;
+		printf("Find proper STAG header at: 0x%lX!\n",
+		       (char *)header - buf);
+		checksum =
+		    jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE),
+				   header->image_length);
+		if (header->image_checksum == checksum) {
+			printf("Image checksum ok.\n");
+			header->cmark = cmark_tmp;
+			print_stag_header(header);
+			ret = EXIT_SUCCESS;
+		} else
+			ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum);
+	} else
+		ERR("STAG header checksum incorrect!");
+
+	header->cmark = cmark_tmp;
+	return ret;
+}
+
+static int check_sch2_header(char *buf, struct sch2_header *header)
+{
+
+	int ret = EXIT_FAILURE;
+
+	uint32_t crc32_tmp = header->header_crc32;
+	header->header_crc32 = 0;
+
+	if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) {
+		uint32_t crc32_val;
+		printf("Find proper SCH2 header at: 0x%lX!\n",
+		       (char *)header - buf);
+
+		crc32_val =
+		    crc32(0, (uint8_t *) header + header->header_length,
+			  header->image_len);
+		if (header->image_crc32 == crc32_val) {
+			printf("Kernel checksum ok.\n");
+
+			header->header_crc32 = crc32_tmp;
+			print_sch2_header(header);
+			ret = EXIT_SUCCESS;
+		} else
+			ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val);
+
+	} else
+		ERR("SCH2 header checksum incorrect!");
+
+	header->header_crc32 = crc32_tmp;
+	return ret;
+}
+
+static int inspect_fw(void)
+{
+	char *buf;
+	struct stag_header *stag_header_kernel;
+	struct sch2_header *sch2_header_kernel;
+	int ret = EXIT_FAILURE;
+
+	buf = malloc(inspect_info.file_size);
+	if (!buf) {
+		ERR("no memory for buffer!\n");
+		goto out;
+	}
+
+	ret = read_to_buf(&inspect_info, buf);
+	if (ret)
+		goto out_free_buf;
+
+	ret = find_auh_headers(buf);
+	if (ret)
+		goto out_free_buf;
+
+	stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE);
+
+	ret = check_stag_header(buf, stag_header_kernel);
+	if (ret)
+		goto out_free_buf;
+
+	sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE);
+
+	ret = check_sch2_header(buf, sch2_header_kernel);
+	if (ret)
+		goto out_free_buf;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+static int check_options(void)
+{
+	int ret;
+
+	if (inspect_info.file_name) {
+		ret = get_file_stat(&inspect_info);
+		if (ret)
+			return ret;
+
+		return 0;
+	}
+
+	return 0;
+}
+
+int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr)
+{
+
+	header->magic = SCH2_MAGIC;
+	header->cp_type = LZMA;
+	header->version = SCH2_VER;
+	header->ram_addr = RAM_LOAD_ADDR;
+	header->image_len = kernel_info.file_size;
+	header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size);
+	header->start_addr = RAM_ENTRY_ADDR;
+	header->rootfs_addr =
+	    JBOOT_SIZE + STAG_SIZE + SCH2_SIZE + kernel_info.file_size;
+	header->rootfs_len = rootfs_info.file_size;
+	header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size);
+	header->header_crc32 = 0;
+	header->header_length = SCH2_SIZE;
+	header->cmd_line_length = 0;
+
+	header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length);
+
+	return EXIT_SUCCESS;
+}
+
+int fill_stag(struct stag_header *header, uint32_t length)
+{
+	header->cmark = STAG_ID;
+	header->id = STAG_ID;
+	header->magic = STAG_MAGIC;
+	header->time_stamp = jboot_timestamp();
+	header->image_length = length + SCH2_SIZE;
+	header->image_checksum =
+	    jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE),
+			   header->image_length);
+	header->tag_checksum =
+	    ~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2);
+
+	if (image_type == FACTORY)
+		header->cmark = STAG_CMARK_FACTORY;
+
+	return EXIT_SUCCESS;
+};
+
+int fill_auh(struct auh_header *header, uint32_t length)
+{
+	memcpy(header->rom_id, rom_id, 12);
+	header->derange = 0;
+	header->image_checksum =
+	    jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length);
+	header->space1 = 0;
+	header->space2 = 0;
+	header->space3 = 0;
+	header->lpvs = AUH_LVPS;
+	header->mbz = 0;
+	header->time_stamp = jboot_timestamp();
+	header->erase_start = JBOOT_SIZE;
+	header->erase_length = firmware_size;
+	header->data_offset = JBOOT_SIZE;
+	header->data_length = length;
+	header->space4 = 0;
+	header->space5 = 0;
+	header->space6 = 0;
+	header->space7 = 0;
+	header->header_id = AUH_HDR_ID;
+	header->header_version = AUH_HDR_VER;
+	header->space8 = 0;
+	header->section_id = AUH_SEC_ID;
+	header->image_info_type = AUH_INFO_TYPE;
+	header->image_info_offset = 0;
+	header->family_member = family_member;
+	header->header_checksum =
+	    ~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2);
+
+	return EXIT_SUCCESS;
+}
+
+int build_fw(void)
+{
+	char *buf;
+	char *kernel_ptr;
+	char *rootfs_ptr;
+	int ret = EXIT_FAILURE;
+	int writelen;
+
+	struct stag_header *stag_header_kernel;
+	struct sch2_header *sch2_header_kernel;
+
+	if (!kernel_info.file_name | !rootfs_info.file_name)
+		goto out;
+
+	ret = get_file_stat(&kernel_info);
+	if (ret)
+		goto out;
+	ret = get_file_stat(&rootfs_info);
+	if (ret)
+		goto out;
+
+	buf = malloc(firmware_size);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE >
+	    firmware_size) {
+		ERR("data is bigger than firmware_size!\n");
+		goto out;
+	}
+
+	memset(buf, 0xff, firmware_size);
+
+	stag_header_kernel = (struct stag_header *)buf;
+
+	sch2_header_kernel =
+	    (struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE);
+	kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE;
+
+	ret = read_to_buf(&kernel_info, kernel_ptr);
+	if (ret)
+		goto out_free_buf;
+
+	rootfs_ptr = kernel_ptr + kernel_info.file_size;
+
+	ret = read_to_buf(&rootfs_info, rootfs_ptr);
+	if (ret)
+		goto out_free_buf;
+
+	writelen = rootfs_ptr + rootfs_info.file_size - buf;
+
+	fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr);
+	fill_stag(stag_header_kernel, kernel_info.file_size);
+
+	ret = write_fw(ofname, buf, writelen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+int wrap_fw(void)
+{
+	char *buf;
+	char *image_ptr;
+	int ret = EXIT_FAILURE;
+	int writelen;
+
+	struct auh_header *auh_header_kernel;
+
+	if (!image_info.file_name)
+		goto out;
+
+	ret = get_file_stat(&image_info);
+	if (ret)
+		goto out;
+
+	buf = malloc(firmware_size);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	if (image_info.file_size + AUH_SIZE >
+	    firmware_size) {
+		ERR("data is bigger than firmware_size!\n");
+		goto out;
+	}
+	if (!family_member) {
+		ERR("No family_member!\n");
+		goto out;
+	}
+	if (!(rom_id[0])) {
+		ERR("No rom_id!\n");
+		goto out;
+	}
+	memset(buf, 0xff, firmware_size);
+
+	image_ptr = (char *)(buf + AUH_SIZE);
+
+	ret = read_to_buf(&image_info, image_ptr);
+	if (ret)
+		goto out_free_buf;
+
+	writelen = image_ptr + image_info.file_size - buf;
+
+	auh_header_kernel = (struct auh_header *)buf;
+	fill_auh(auh_header_kernel, writelen - AUH_SIZE);
+
+	ret = write_fw(ofname, buf, writelen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	progname = basename(argv[0]);
+	image_type = SYSUPGRADE;
+	family_member = 0;
+	firmware_size = 0;
+
+	while (1) {
+		int c;
+
+		c = getopt(argc, argv, "f:F:i:hk:m:o:r:s:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f':
+			sscanf(optarg, "0x%hx", &family_member);
+			break;
+		case 'F':
+			image_info.file_name = optarg;
+			image_type = FACTORY;
+			break;
+		case 'i':
+			inspect_info.file_name = optarg;
+			break;
+		case 'k':
+			kernel_info.file_name = optarg;
+			break;
+		case 'm':
+			if (strlen(optarg) == 12)
+				memcpy(rom_id, optarg, 12);
+			break;
+		case 'r':
+			rootfs_info.file_name = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			sscanf(optarg, "0x%x", &firmware_size);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	if (!inspect_info.file_name) {
+		if (image_type == FACTORY)
+			ret = wrap_fw();
+		else
+			ret = build_fw();
+		}
+	else
+		ret = inspect_fw();
+
+ out:
+	return ret;
+
+}



More information about the lede-commits mailing list