1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
7 * This tool is based on mktplinkfw.
8 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
9 * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
16 #include <unistd.h> /* for unlink() */
18 #include <getopt.h> /* for getopt() */
24 #include <zlib.h> /*for crc32 */
26 #include "mkdlinkfw-lib.h"
28 /* ARM update header 2.0
29 * used only in factory images to erase and flash selected area
32 uint8_t rom_id
[12]; /* 12-bit rom-id unique per router type */
33 uint16_t derange
; /* used for scramble header */
34 uint16_t image_checksum
; /* jboot_checksum of flashed data */
36 uint32_t space1
; /* zeros */
37 uint32_t space2
; /* zeros */
38 uint16_t space3
; /* zerosu */
39 uint8_t lpvs
; /* must be 0x01 */
40 uint8_t mbz
; /* bust be 0 */
41 uint32_t time_stamp
; /* timestamp calculated in jboot way */
43 uint32_t erase_start
; /* erase start address */
44 uint32_t erase_length
; /* erase length address */
45 uint32_t data_offset
; /* data start address */
46 uint32_t data_length
; /* data length address */
48 uint32_t space4
; /* zeros */
49 uint32_t space5
; /* zeros */
50 uint32_t space6
; /* zeros */
51 uint32_t space7
; /* zeros */
53 uint16_t header_id
; /* magic 0x4842 */
54 uint16_t header_version
; /* 0x02 for 2.0 */
55 uint16_t space8
; /* zeros */
56 uint8_t section_id
; /* section id */
57 uint8_t image_info_type
; /* (?) 0x04 in factory images */
58 uint32_t image_info_offset
; /* (?) zeros in factory images */
59 uint16_t family_member
; /* unique per router type */
60 uint16_t header_checksum
; /* negated jboot_checksum of header data */
63 struct stag_header
{ /* used only of sch2 wrapped kernel data */
64 uint8_t cmark
; /* in factory 0xFF ,in sysuograde must be the same as id */
65 uint8_t id
; /* 0x04 */
66 uint16_t magic
; /* magic 0x2B24 */
67 uint32_t time_stamp
; /* timestamp calculated in jboot way */
68 uint32_t image_length
; /* lentgh of kernel + sch2 header */
69 uint16_t image_checksum
; /* negated jboot_checksum of sch2 + kernel */
70 uint16_t tag_checksum
; /* negated jboot_checksum of stag header data */
73 struct sch2_header
{ /* used only in kernel partitions */
74 uint16_t magic
; /* magic 0x2124 */
75 uint8_t cp_type
; /* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */
76 uint8_t version
; /* 0x02 for sch2 */
77 uint32_t ram_addr
; /* ram entry address */
78 uint32_t image_len
; /* kernel image length */
79 uint32_t image_crc32
; /* kernel image crc */
80 uint32_t start_addr
; /* ram start address */
81 uint32_t rootfs_addr
; /* rootfs flash address */
82 uint32_t rootfs_len
; /* rootfls length */
83 uint32_t rootfs_crc32
; /* rootfs crc32 */
84 uint32_t header_crc32
; /* sch2 header crc32, durring calculation this area is replaced by zero */
85 uint16_t header_length
; /* sch2 header length: 0x28 */
86 uint16_t cmd_line_length
; /* cmd line length, known zeros */
90 static struct file_info inspect_info
;
91 struct file_info kernel_info
;
92 struct file_info rootfs_info
;
93 struct file_info image_info
;
97 uint32_t firmware_size
;
98 uint32_t image_offset
;
99 uint16_t family_member
;
100 char *rom_id
[12] = { 0 };
103 static void usage(int status
)
105 fprintf(stderr
, "Usage: %s [OPTIONS...]\n", progname
);
109 " -i <file> inspect given firmware file <file>\n"
110 " -f set family member id (hexval prefixed with 0x)\n"
111 " -F <file> read image and convert it to FACTORY\n"
112 " -k <file> read kernel image from the file <file>\n"
113 " -r <file> read rootfs image from the file <file>\n"
114 " -o <file> write output to the file <file>\n"
115 " -s <size> set firmware partition size\n"
116 " -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n"
117 " -h show this screen\n");
122 void print_auh_header(struct auh_header
*printed_header
)
124 printf("\trom_id: %s\n"
125 "\tderange: 0x%04X\n"
126 "\timage_checksum: 0x%04X\n"
132 "\ttime_stamp: 0x%08X\n"
133 "\terase_start: 0x%08X\n"
134 "\terase_length: 0x%08X\n"
135 "\tdata_offset: 0x%08X\n"
136 "\tdata_length: 0x%08X\n"
141 "\theader_id: 0x%04X\n"
142 "\theader_version: 0x%02X\n"
144 "\tsection_id: 0x%02X\n"
145 "\timage_info_type: 0x%02X\n"
146 "\timage_info_offset 0x%08X\n"
147 "\tfamily_member: 0x%04X\n"
148 "\theader_checksum: 0x%04X\n",
149 printed_header
->rom_id
,
150 printed_header
->derange
,
151 printed_header
->image_checksum
,
152 printed_header
->space1
,
153 printed_header
->space2
,
154 printed_header
->space3
,
155 printed_header
->lpvs
,
157 printed_header
->time_stamp
,
158 printed_header
->erase_start
,
159 printed_header
->erase_length
,
160 printed_header
->data_offset
,
161 printed_header
->data_length
,
162 printed_header
->space4
,
163 printed_header
->space5
,
164 printed_header
->space6
,
165 printed_header
->space7
,
166 printed_header
->header_id
,
167 printed_header
->header_version
,
168 printed_header
->space8
,
169 printed_header
->section_id
,
170 printed_header
->image_info_type
,
171 printed_header
->image_info_offset
,
172 printed_header
->family_member
, printed_header
->header_checksum
);
175 void print_stag_header(struct stag_header
*printed_header
)
177 printf("\tcmark: 0x%02X\n"
180 "\ttime_stamp: 0x%08X\n"
181 "\timage_length: 0x%04X\n"
182 "\timage_checksum: 0x%04X\n"
183 "\ttag_checksum: 0x%04X\n",
184 printed_header
->cmark
,
186 printed_header
->magic
,
187 printed_header
->time_stamp
,
188 printed_header
->image_length
,
189 printed_header
->image_checksum
, printed_header
->tag_checksum
);
192 void print_sch2_header(struct sch2_header
*printed_header
)
194 printf("\tmagic: 0x%04X\n"
195 "\tcp_type: 0x%02X\n"
196 "\tversion: 0x%02X\n"
197 "\tram_addr: 0x%08X\n"
198 "\timage_len: 0x%08X\n"
199 "\timage_crc32: 0x%08X\n"
200 "\tstart_addr: 0x%08X\n"
201 "\trootfs_addr: 0x%08X\n"
202 "\trootfs_len: 0x%08X\n"
203 "\trootfs_crc32: 0x%08X\n"
204 "\theader_crc32: 0x%08X\n"
205 "\theader_length: 0x%04X\n"
206 "\tcmd_line_length: 0x%04X\n",
207 printed_header
->magic
,
208 printed_header
->cp_type
,
209 printed_header
->version
,
210 printed_header
->ram_addr
,
211 printed_header
->image_len
,
212 printed_header
->image_crc32
,
213 printed_header
->start_addr
,
214 printed_header
->rootfs_addr
,
215 printed_header
->rootfs_len
,
216 printed_header
->rootfs_crc32
,
217 printed_header
->header_crc32
,
218 printed_header
->header_length
, printed_header
->cmd_line_length
);
221 static int find_auh_headers(char *buf
)
224 struct auh_header
*tmp_header
[MAX_HEADER_COUNTER
];
225 int header_counter
= 0;
227 int ret
= EXIT_FAILURE
;
229 while (tmp_buf
- buf
<= inspect_info
.file_size
- AUH_SIZE
) {
230 if (!memcmp(tmp_buf
, AUH_MAGIC
, 3)) {
231 if (((struct auh_header
*)tmp_buf
)->header_checksum
==
232 (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf
,
234 uint16_t checksum
= 0;
235 printf("Find proper AUH header at: 0x%lX!\n",
237 tmp_header
[header_counter
] =
238 (struct auh_header
*)tmp_buf
;
240 jboot_checksum(0, (uint16_t *) ((char *)
245 [header_counter
]->data_length
);
246 if (tmp_header
[header_counter
]->image_checksum
248 printf("Image checksum ok.\n");
250 ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header
[header_counter
]->image_checksum
, checksum
);
252 if (header_counter
> MAX_HEADER_COUNTER
)
259 if (header_counter
== 0)
260 ERR("Can't find proper AUH header!\n");
261 else if (header_counter
> MAX_HEADER_COUNTER
)
262 ERR("To many AUH headers!\n");
264 for (int i
= 0; i
< header_counter
; i
++) {
265 printf("AUH %d:\n", i
);
266 print_auh_header(tmp_header
[i
]);
275 static int check_stag_header(char *buf
, struct stag_header
*header
)
278 int ret
= EXIT_FAILURE
;
280 uint8_t cmark_tmp
= header
->cmark
;
281 header
->cmark
= header
->id
;
283 if (header
->tag_checksum
==
284 (uint16_t) ~jboot_checksum(0, (uint16_t *) header
,
286 uint16_t checksum
= 0;
287 printf("Find proper STAG header at: 0x%lX!\n",
288 (char *)header
- buf
);
290 jboot_checksum(0, (uint16_t *) ((char *)header
+ STAG_SIZE
),
291 header
->image_length
);
292 if (header
->image_checksum
== checksum
) {
293 printf("Image checksum ok.\n");
294 header
->cmark
= cmark_tmp
;
295 print_stag_header(header
);
298 ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header
->image_checksum
, checksum
);
300 ERR("STAG header checksum incorrect!");
302 header
->cmark
= cmark_tmp
;
306 static int check_sch2_header(char *buf
, struct sch2_header
*header
)
309 int ret
= EXIT_FAILURE
;
311 uint32_t crc32_tmp
= header
->header_crc32
;
312 header
->header_crc32
= 0;
314 if (crc32_tmp
== crc32(0, (uint8_t *) header
, header
->header_length
)) {
316 printf("Find proper SCH2 header at: 0x%lX!\n",
317 (char *)header
- buf
);
320 crc32(0, (uint8_t *) header
+ header
->header_length
,
322 if (header
->image_crc32
== crc32_val
) {
323 printf("Kernel checksum ok.\n");
325 header
->header_crc32
= crc32_tmp
;
326 print_sch2_header(header
);
329 ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header
->image_crc32
, crc32_val
);
332 ERR("SCH2 header checksum incorrect!");
334 header
->header_crc32
= crc32_tmp
;
338 static int inspect_fw(void)
341 struct stag_header
*stag_header_kernel
;
342 struct sch2_header
*sch2_header_kernel
;
343 int ret
= EXIT_FAILURE
;
345 buf
= malloc(inspect_info
.file_size
);
347 ERR("no memory for buffer!\n");
351 ret
= read_to_buf(&inspect_info
, buf
);
355 ret
= find_auh_headers(buf
);
359 stag_header_kernel
= (struct stag_header
*)(buf
+ AUH_SIZE
);
361 ret
= check_stag_header(buf
, stag_header_kernel
);
365 sch2_header_kernel
= (struct sch2_header
*)(buf
+ AUH_SIZE
+ STAG_SIZE
);
367 ret
= check_sch2_header(buf
, sch2_header_kernel
);
377 static int check_options(void)
381 if (inspect_info
.file_name
) {
382 ret
= get_file_stat(&inspect_info
);
392 int fill_sch2(struct sch2_header
*header
, char *kernel_ptr
, char *rootfs_ptr
)
395 header
->magic
= SCH2_MAGIC
;
396 header
->cp_type
= LZMA
;
397 header
->version
= SCH2_VER
;
398 header
->ram_addr
= RAM_LOAD_ADDR
;
399 header
->image_len
= kernel_info
.file_size
;
400 header
->image_crc32
= crc32(0, (uint8_t *) kernel_ptr
, kernel_info
.file_size
);
401 header
->start_addr
= RAM_ENTRY_ADDR
;
402 header
->rootfs_addr
=
403 image_offset
+ STAG_SIZE
+ SCH2_SIZE
+ kernel_info
.file_size
;
404 header
->rootfs_len
= rootfs_info
.file_size
;
405 header
->rootfs_crc32
= crc32(0, (uint8_t *) rootfs_ptr
, rootfs_info
.file_size
);
406 header
->header_crc32
= 0;
407 header
->header_length
= SCH2_SIZE
;
408 header
->cmd_line_length
= 0;
410 header
->header_crc32
= crc32(0, (uint8_t *) header
, header
->header_length
);
415 int fill_stag(struct stag_header
*header
, uint32_t length
)
417 header
->cmark
= STAG_ID
;
418 header
->id
= STAG_ID
;
419 header
->magic
= STAG_MAGIC
;
420 header
->time_stamp
= jboot_timestamp();
421 header
->image_length
= length
+ SCH2_SIZE
;
422 header
->image_checksum
=
423 jboot_checksum(0, (uint16_t *) ((char *)header
+ STAG_SIZE
),
424 header
->image_length
);
425 header
->tag_checksum
=
426 ~jboot_checksum(0, (uint16_t *) header
, STAG_SIZE
- 2);
428 if (image_type
== FACTORY
)
429 header
->cmark
= STAG_CMARK_FACTORY
;
434 int fill_auh(struct auh_header
*header
, uint32_t length
)
436 memcpy(header
->rom_id
, rom_id
, 12);
438 header
->image_checksum
=
439 jboot_checksum(0, (uint16_t *) ((char *)header
+ AUH_SIZE
), length
);
443 header
->lpvs
= AUH_LVPS
;
445 header
->time_stamp
= jboot_timestamp();
446 header
->erase_start
= image_offset
;
447 header
->erase_length
= firmware_size
;
448 header
->data_offset
= image_offset
;
449 header
->data_length
= length
;
454 header
->header_id
= AUH_HDR_ID
;
455 header
->header_version
= AUH_HDR_VER
;
457 header
->section_id
= AUH_SEC_ID
;
458 header
->image_info_type
= AUH_INFO_TYPE
;
459 header
->image_info_offset
= 0;
460 header
->family_member
= family_member
;
461 header
->header_checksum
=
462 ~jboot_checksum(0, (uint16_t *) header
, AUH_SIZE
- 2);
472 int ret
= EXIT_FAILURE
;
475 struct stag_header
*stag_header_kernel
;
476 struct sch2_header
*sch2_header_kernel
;
478 if (!kernel_info
.file_name
| !rootfs_info
.file_name
)
481 ret
= get_file_stat(&kernel_info
);
484 ret
= get_file_stat(&rootfs_info
);
488 buf
= malloc(firmware_size
);
490 ERR("no memory for buffer\n");
494 if (rootfs_info
.file_size
+ kernel_info
.file_size
+ ALL_HEADERS_SIZE
>
496 ERR("data is bigger than firmware_size!\n");
500 memset(buf
, 0xff, firmware_size
);
502 stag_header_kernel
= (struct stag_header
*)buf
;
505 (struct sch2_header
*)((char *)stag_header_kernel
+ STAG_SIZE
);
506 kernel_ptr
= (char *)sch2_header_kernel
+ SCH2_SIZE
;
508 ret
= read_to_buf(&kernel_info
, kernel_ptr
);
512 rootfs_ptr
= kernel_ptr
+ kernel_info
.file_size
;
514 ret
= read_to_buf(&rootfs_info
, rootfs_ptr
);
518 writelen
= rootfs_ptr
+ rootfs_info
.file_size
- buf
;
520 fill_sch2(sch2_header_kernel
, kernel_ptr
, rootfs_ptr
);
521 fill_stag(stag_header_kernel
, kernel_info
.file_size
);
523 ret
= write_fw(ofname
, buf
, writelen
);
539 int ret
= EXIT_FAILURE
;
542 struct auh_header
*auh_header_kernel
;
544 if (!image_info
.file_name
)
547 ret
= get_file_stat(&image_info
);
551 buf
= malloc(firmware_size
);
553 ERR("no memory for buffer\n");
557 if (image_info
.file_size
+ AUH_SIZE
>
559 ERR("data is bigger than firmware_size!\n");
562 if (!family_member
) {
563 ERR("No family_member!\n");
570 memset(buf
, 0xff, firmware_size
);
572 image_ptr
= (char *)(buf
+ AUH_SIZE
);
574 ret
= read_to_buf(&image_info
, image_ptr
);
578 writelen
= image_ptr
+ image_info
.file_size
- buf
;
580 auh_header_kernel
= (struct auh_header
*)buf
;
581 fill_auh(auh_header_kernel
, writelen
- AUH_SIZE
);
583 ret
= write_fw(ofname
, buf
, writelen
);
595 int main(int argc
, char *argv
[])
597 int ret
= EXIT_FAILURE
;
599 progname
= basename(argv
[0]);
600 image_type
= SYSUPGRADE
;
603 image_offset
= JBOOT_SIZE
;
608 c
= getopt(argc
, argv
, "f:F:i:hk:m:o:O:r:s:");
614 sscanf(optarg
, "0x%hx", &family_member
);
617 image_info
.file_name
= optarg
;
618 image_type
= FACTORY
;
621 inspect_info
.file_name
= optarg
;
624 kernel_info
.file_name
= optarg
;
627 if (strlen(optarg
) == 12)
628 memcpy(rom_id
, optarg
, 12);
631 rootfs_info
.file_name
= optarg
;
634 sscanf(optarg
, "0x%x", &image_offset
);
640 sscanf(optarg
, "0x%x", &firmware_size
);
648 ret
= check_options();
652 if (!inspect_info
.file_name
) {
653 if (image_type
== FACTORY
)