kernel: Add missing includes mtdsplit_*.c
[openwrt/openwrt.git] / target / linux / generic / files / drivers / mtd / mtdsplit / mtdsplit_jimage.c
1 /*
2 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
3 *
4 * Based on: mtdsplit_uimage.c
5 * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
6 *
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.
10 *
11 */
12
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
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>
23 #include <linux/of.h>
24
25 #include "mtdsplit.h"
26
27 #define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE )
28
29 #define STAG_SIZE 16
30 #define STAG_ID 0x04
31 #define STAG_MAGIC 0x2B24
32
33 #define SCH2_SIZE 40
34 #define SCH2_MAGIC 0x2124
35 #define SCH2_VER 0x02
36
37 /*
38 * Jboot image header,
39 * all data in little endian.
40 */
41
42 struct jimage_header //stag + sch2 jboot joined headers
43 {
44 uint8_t stag_cmark; // in factory 0xFF , in sysupgrade must be the same as stag_id
45 uint8_t stag_id; // 0x04
46 uint16_t stag_magic; //magic 0x2B24
47 uint32_t stag_time_stamp; // timestamp calculated in jboot way
48 uint32_t stag_image_length; // lentgh of kernel + sch2 header
49 uint16_t stag_image_checksum; // negated jboot_checksum of sch2 + kernel
50 uint16_t stag_tag_checksum; // negated jboot_checksum of stag header data
51 uint16_t sch2_magic; // magic 0x2124
52 uint8_t sch2_cp_type; // 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma
53 uint8_t sch2_version; // 0x02 for sch2
54 uint32_t sch2_ram_addr; // ram entry address
55 uint32_t sch2_image_len; // kernel image length
56 uint32_t sch2_image_crc32; // kernel image crc
57 uint32_t sch2_start_addr; // ram start address
58 uint32_t sch2_rootfs_addr; // rootfs flash address
59 uint32_t sch2_rootfs_len; // rootfls length
60 uint32_t sch2_rootfs_crc32; // rootfs crc32
61 uint32_t sch2_header_crc32; // sch2 header crc32, durring calculation this area is replaced by zero
62 uint16_t sch2_header_length; // sch2 header length: 0x28
63 uint16_t sch2_cmd_line_length; // cmd line length, known zeros
64 };
65
66 static int
67 read_jimage_header(struct mtd_info *mtd, size_t offset, u_char *buf,
68 size_t header_len)
69 {
70 size_t retlen;
71 int ret;
72
73 ret = mtd_read(mtd, offset, header_len, &retlen, buf);
74 if (ret) {
75 pr_debug("read error in \"%s\"\n", mtd->name);
76 return ret;
77 }
78
79 if (retlen != header_len) {
80 pr_debug("short read in \"%s\"\n", mtd->name);
81 return -EIO;
82 }
83
84 return 0;
85 }
86
87 /**
88 * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts
89 *
90 * @find_header: function to call for a block of data that will return offset
91 * of a valid jImage header if found
92 */
93 static int __mtdsplit_parse_jimage(struct mtd_info *master,
94 const struct mtd_partition **pparts,
95 struct mtd_part_parser_data *data,
96 ssize_t (*find_header)(u_char *buf, size_t len))
97 {
98 struct mtd_partition *parts;
99 u_char *buf;
100 int nr_parts;
101 size_t offset;
102 size_t jimage_offset;
103 size_t jimage_size = 0;
104 size_t rootfs_offset;
105 size_t rootfs_size = 0;
106 int jimage_part, rf_part;
107 int ret;
108 enum mtdsplit_part_type type;
109
110 nr_parts = 2;
111 parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
112 if (!parts)
113 return -ENOMEM;
114
115 buf = vmalloc(MAX_HEADER_LEN);
116 if (!buf) {
117 ret = -ENOMEM;
118 goto err_free_parts;
119 }
120
121 /* find jImage on erase block boundaries */
122 for (offset = 0; offset < master->size; offset += master->erasesize) {
123 struct jimage_header *header;
124
125 jimage_size = 0;
126
127 ret = read_jimage_header(master, offset, buf, MAX_HEADER_LEN);
128 if (ret)
129 continue;
130
131 ret = find_header(buf, MAX_HEADER_LEN);
132 if (ret < 0) {
133 pr_debug("no valid jImage found in \"%s\" at offset %llx\n",
134 master->name, (unsigned long long) offset);
135 continue;
136 }
137 header = (struct jimage_header *)(buf + ret);
138
139 jimage_size = sizeof(*header) + header->sch2_image_len + ret;
140 if ((offset + jimage_size) > master->size) {
141 pr_debug("jImage exceeds MTD device \"%s\"\n",
142 master->name);
143 continue;
144 }
145 break;
146 }
147
148 if (jimage_size == 0) {
149 pr_debug("no jImage found in \"%s\"\n", master->name);
150 ret = -ENODEV;
151 goto err_free_buf;
152 }
153
154 jimage_offset = offset;
155
156 if (jimage_offset == 0) {
157 jimage_part = 0;
158 rf_part = 1;
159
160 /* find the roots after the jImage */
161 ret = mtd_find_rootfs_from(master, jimage_offset + jimage_size,
162 master->size, &rootfs_offset, &type);
163 if (ret) {
164 pr_debug("no rootfs after jImage in \"%s\"\n",
165 master->name);
166 goto err_free_buf;
167 }
168
169 rootfs_size = master->size - rootfs_offset;
170 jimage_size = rootfs_offset - jimage_offset;
171 } else {
172 rf_part = 0;
173 jimage_part = 1;
174
175 /* check rootfs presence at offset 0 */
176 ret = mtd_check_rootfs_magic(master, 0, &type);
177 if (ret) {
178 pr_debug("no rootfs before jImage in \"%s\"\n",
179 master->name);
180 goto err_free_buf;
181 }
182
183 rootfs_offset = 0;
184 rootfs_size = jimage_offset;
185 }
186
187 if (rootfs_size == 0) {
188 pr_debug("no rootfs found in \"%s\"\n", master->name);
189 ret = -ENODEV;
190 goto err_free_buf;
191 }
192
193 parts[jimage_part].name = KERNEL_PART_NAME;
194 parts[jimage_part].offset = jimage_offset;
195 parts[jimage_part].size = jimage_size;
196
197 if (type == MTDSPLIT_PART_TYPE_UBI)
198 parts[rf_part].name = UBI_PART_NAME;
199 else
200 parts[rf_part].name = ROOTFS_PART_NAME;
201 parts[rf_part].offset = rootfs_offset;
202 parts[rf_part].size = rootfs_size;
203
204 vfree(buf);
205
206 *pparts = parts;
207 return nr_parts;
208
209 err_free_buf:
210 vfree(buf);
211
212 err_free_parts:
213 kfree(parts);
214 return ret;
215 }
216
217 static ssize_t jimage_verify_default(u_char *buf, size_t len)
218 {
219 struct jimage_header *header = (struct jimage_header *)buf;
220
221 /* default sanity checks */
222 if (header->stag_magic != STAG_MAGIC) {
223 pr_debug("invalid jImage stag header magic: %04x\n",
224 header->stag_magic);
225 return -EINVAL;
226 }
227 if (header->sch2_magic != SCH2_MAGIC) {
228 pr_debug("invalid jImage sch2 header magic: %04x\n",
229 header->stag_magic);
230 return -EINVAL;
231 }
232 if (header->stag_cmark != header->stag_id) {
233 pr_debug("invalid jImage stag header cmark: %02x\n",
234 header->stag_magic);
235 return -EINVAL;
236 }
237 if (header->stag_id != STAG_ID) {
238 pr_debug("invalid jImage stag header id: %02x\n",
239 header->stag_magic);
240 return -EINVAL;
241 }
242 if (header->sch2_version != SCH2_VER) {
243 pr_debug("invalid jImage sch2 header version: %02x\n",
244 header->stag_magic);
245 return -EINVAL;
246 }
247
248 return 0;
249 }
250
251 static int
252 mtdsplit_jimage_parse_generic(struct mtd_info *master,
253 const struct mtd_partition **pparts,
254 struct mtd_part_parser_data *data)
255 {
256 return __mtdsplit_parse_jimage(master, pparts, data,
257 jimage_verify_default);
258 }
259
260 static const struct of_device_id mtdsplit_jimage_of_match_table[] = {
261 { .compatible = "amit,jimage" },
262 {},
263 };
264
265 static struct mtd_part_parser jimage_generic_parser = {
266 .owner = THIS_MODULE,
267 .name = "jimage-fw",
268 .of_match_table = mtdsplit_jimage_of_match_table,
269 .parse_fn = mtdsplit_jimage_parse_generic,
270 .type = MTD_PARSER_TYPE_FIRMWARE,
271 };
272
273 /**************************************************
274 * Init
275 **************************************************/
276
277 static int __init mtdsplit_jimage_init(void)
278 {
279 register_mtd_parser(&jimage_generic_parser);
280
281 return 0;
282 }
283
284 module_init(mtdsplit_jimage_init);