2 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
4 * Based on: mtdsplit_uimage.c
5 * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/vmalloc.h>
20 #include <linux/mtd/mtd.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/byteorder/generic.h>
26 #define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE )
30 #define STAG_MAGIC 0x2B24
33 #define SCH2_MAGIC 0x2124
38 * all data in little endian.
41 struct jimage_header
//stag + sch2 jboot joined headers
43 uint8_t stag_cmark
; // in factory 0xFF , in sysupgrade must be the same as stag_id
44 uint8_t stag_id
; // 0x04
45 uint16_t stag_magic
; //magic 0x2B24
46 uint32_t stag_time_stamp
; // timestamp calculated in jboot way
47 uint32_t stag_image_length
; // lentgh of kernel + sch2 header
48 uint16_t stag_image_checksum
; // negated jboot_checksum of sch2 + kernel
49 uint16_t stag_tag_checksum
; // negated jboot_checksum of stag header data
50 uint16_t sch2_magic
; // magic 0x2124
51 uint8_t sch2_cp_type
; // 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma
52 uint8_t sch2_version
; // 0x02 for sch2
53 uint32_t sch2_ram_addr
; // ram entry address
54 uint32_t sch2_image_len
; // kernel image length
55 uint32_t sch2_image_crc32
; // kernel image crc
56 uint32_t sch2_start_addr
; // ram start address
57 uint32_t sch2_rootfs_addr
; // rootfs flash address
58 uint32_t sch2_rootfs_len
; // rootfls length
59 uint32_t sch2_rootfs_crc32
; // rootfs crc32
60 uint32_t sch2_header_crc32
; // sch2 header crc32, durring calculation this area is replaced by zero
61 uint16_t sch2_header_length
; // sch2 header length: 0x28
62 uint16_t sch2_cmd_line_length
; // cmd line length, known zeros
66 read_jimage_header(struct mtd_info
*mtd
, size_t offset
, u_char
*buf
,
72 ret
= mtd_read(mtd
, offset
, header_len
, &retlen
, buf
);
74 pr_debug("read error in \"%s\"\n", mtd
->name
);
78 if (retlen
!= header_len
) {
79 pr_debug("short read in \"%s\"\n", mtd
->name
);
87 * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts
89 * @find_header: function to call for a block of data that will return offset
90 * of a valid jImage header if found
92 static int __mtdsplit_parse_jimage(struct mtd_info
*master
,
93 const struct mtd_partition
**pparts
,
94 struct mtd_part_parser_data
*data
,
95 ssize_t (*find_header
)(u_char
*buf
, size_t len
))
97 struct mtd_partition
*parts
;
101 size_t jimage_offset
;
102 size_t jimage_size
= 0;
103 size_t rootfs_offset
;
104 size_t rootfs_size
= 0;
105 int jimage_part
, rf_part
;
107 enum mtdsplit_part_type type
;
110 parts
= kzalloc(nr_parts
* sizeof(*parts
), GFP_KERNEL
);
114 buf
= vmalloc(MAX_HEADER_LEN
);
120 /* find jImage on erase block boundaries */
121 for (offset
= 0; offset
< master
->size
; offset
+= master
->erasesize
) {
122 struct jimage_header
*header
;
126 ret
= read_jimage_header(master
, offset
, buf
, MAX_HEADER_LEN
);
130 ret
= find_header(buf
, MAX_HEADER_LEN
);
132 pr_debug("no valid jImage found in \"%s\" at offset %llx\n",
133 master
->name
, (unsigned long long) offset
);
136 header
= (struct jimage_header
*)(buf
+ ret
);
138 jimage_size
= sizeof(*header
) + header
->sch2_image_len
+ ret
;
139 if ((offset
+ jimage_size
) > master
->size
) {
140 pr_debug("jImage exceeds MTD device \"%s\"\n",
147 if (jimage_size
== 0) {
148 pr_debug("no jImage found in \"%s\"\n", master
->name
);
153 jimage_offset
= offset
;
155 if (jimage_offset
== 0) {
159 /* find the roots after the jImage */
160 ret
= mtd_find_rootfs_from(master
, jimage_offset
+ jimage_size
,
161 master
->size
, &rootfs_offset
, &type
);
163 pr_debug("no rootfs after jImage in \"%s\"\n",
168 rootfs_size
= master
->size
- rootfs_offset
;
169 jimage_size
= rootfs_offset
- jimage_offset
;
174 /* check rootfs presence at offset 0 */
175 ret
= mtd_check_rootfs_magic(master
, 0, &type
);
177 pr_debug("no rootfs before jImage in \"%s\"\n",
183 rootfs_size
= jimage_offset
;
186 if (rootfs_size
== 0) {
187 pr_debug("no rootfs found in \"%s\"\n", master
->name
);
192 parts
[jimage_part
].name
= KERNEL_PART_NAME
;
193 parts
[jimage_part
].offset
= jimage_offset
;
194 parts
[jimage_part
].size
= jimage_size
;
196 if (type
== MTDSPLIT_PART_TYPE_UBI
)
197 parts
[rf_part
].name
= UBI_PART_NAME
;
199 parts
[rf_part
].name
= ROOTFS_PART_NAME
;
200 parts
[rf_part
].offset
= rootfs_offset
;
201 parts
[rf_part
].size
= rootfs_size
;
216 static ssize_t
jimage_verify_default(u_char
*buf
, size_t len
)
218 struct jimage_header
*header
= (struct jimage_header
*)buf
;
220 /* default sanity checks */
221 if (header
->stag_magic
!= STAG_MAGIC
) {
222 pr_debug("invalid jImage stag header magic: %04x\n",
226 if (header
->sch2_magic
!= SCH2_MAGIC
) {
227 pr_debug("invalid jImage sch2 header magic: %04x\n",
231 if (header
->stag_cmark
!= header
->stag_id
) {
232 pr_debug("invalid jImage stag header cmark: %02x\n",
236 if (header
->stag_id
!= STAG_ID
) {
237 pr_debug("invalid jImage stag header id: %02x\n",
241 if (header
->sch2_version
!= SCH2_VER
) {
242 pr_debug("invalid jImage sch2 header version: %02x\n",
251 mtdsplit_jimage_parse_generic(struct mtd_info
*master
,
252 const struct mtd_partition
**pparts
,
253 struct mtd_part_parser_data
*data
)
255 return __mtdsplit_parse_jimage(master
, pparts
, data
,
256 jimage_verify_default
);
259 static const struct of_device_id mtdsplit_jimage_of_match_table
[] = {
260 { .compatible
= "amit,jimage" },
264 static struct mtd_part_parser jimage_generic_parser
= {
265 .owner
= THIS_MODULE
,
267 .of_match_table
= mtdsplit_jimage_of_match_table
,
268 .parse_fn
= mtdsplit_jimage_parse_generic
,
269 .type
= MTD_PARSER_TYPE_FIRMWARE
,
272 /**************************************************
274 **************************************************/
276 static int __init
mtdsplit_jimage_init(void)
278 register_mtd_parser(&jimage_generic_parser
);
283 module_init(mtdsplit_jimage_init
);