OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net> |
||
3 | All rights reserved. |
||
4 | |||
5 | Redistribution and use in source and binary forms, with or without |
||
6 | modification, are permitted provided that the following conditions are met: |
||
7 | |||
8 | 1. Redistributions of source code must retain the above copyright notice, |
||
9 | this list of conditions and the following disclaimer. |
||
10 | 2. Redistributions in binary form must reproduce the above copyright notice, |
||
11 | this list of conditions and the following disclaimer in the documentation |
||
12 | and/or other materials provided with the distribution. |
||
13 | |||
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
||
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
||
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
24 | */ |
||
25 | |||
26 | |||
27 | /* |
||
28 | tplink-safeloader |
||
29 | |||
30 | Image generation tool for the TP-LINK SafeLoader as seen on |
||
31 | TP-LINK Pharos devices (CPE210/220/510/520) |
||
32 | */ |
||
33 | |||
34 | |||
35 | #include <assert.h> |
||
36 | #include <errno.h> |
||
37 | #include <stdbool.h> |
||
38 | #include <stdio.h> |
||
39 | #include <stdint.h> |
||
40 | #include <stdlib.h> |
||
41 | #include <string.h> |
||
42 | #include <time.h> |
||
43 | #include <unistd.h> |
||
44 | |||
45 | #include <arpa/inet.h> |
||
46 | |||
47 | #include <sys/types.h> |
||
48 | #include <sys/stat.h> |
||
49 | #include <limits.h> |
||
50 | |||
51 | #include "md5.h" |
||
52 | |||
53 | |||
54 | #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); }) |
||
55 | |||
56 | |||
57 | #define MAX_PARTITIONS 32 |
||
58 | |||
59 | /** An image partition table entry */ |
||
60 | struct image_partition_entry { |
||
61 | const char *name; |
||
62 | size_t size; |
||
63 | uint8_t *data; |
||
64 | }; |
||
65 | |||
66 | /** A flash partition table entry */ |
||
67 | struct flash_partition_entry { |
||
68 | char *name; |
||
69 | uint32_t base; |
||
70 | uint32_t size; |
||
71 | }; |
||
72 | |||
73 | /** Firmware layout description */ |
||
74 | struct device_info { |
||
75 | const char *id; |
||
76 | const char *vendor; |
||
77 | const char *support_list; |
||
78 | char support_trail; |
||
79 | const char *soft_ver; |
||
80 | struct flash_partition_entry partitions[MAX_PARTITIONS+1]; |
||
81 | const char *first_sysupgrade_partition; |
||
82 | const char *last_sysupgrade_partition; |
||
83 | }; |
||
84 | |||
85 | /** The content of the soft-version structure */ |
||
86 | struct __attribute__((__packed__)) soft_version { |
||
87 | uint32_t magic; |
||
88 | uint32_t zero; |
||
89 | uint8_t pad1; |
||
90 | uint8_t version_major; |
||
91 | uint8_t version_minor; |
||
92 | uint8_t version_patch; |
||
93 | uint8_t year_hi; |
||
94 | uint8_t year_lo; |
||
95 | uint8_t month; |
||
96 | uint8_t day; |
||
97 | uint32_t rev; |
||
98 | uint8_t pad2; |
||
99 | }; |
||
100 | |||
101 | |||
102 | static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; |
||
103 | |||
104 | |||
105 | /** |
||
106 | Salt for the MD5 hash |
||
107 | |||
108 | Fortunately, TP-LINK seems to use the same salt for most devices which use |
||
109 | the new image format. |
||
110 | */ |
||
111 | static const uint8_t md5_salt[16] = { |
||
112 | 0x7a, 0x2b, 0x15, 0xed, |
||
113 | 0x9b, 0x98, 0x59, 0x6d, |
||
114 | 0xe5, 0x04, 0xab, 0x44, |
||
115 | 0xac, 0x2a, 0x9f, 0x4e, |
||
116 | }; |
||
117 | |||
118 | |||
119 | /** Firmware layout table */ |
||
120 | static struct device_info boards[] = { |
||
121 | /** Firmware layout for the CPE210/220 */ |
||
122 | { |
||
123 | .id = "CPE210", |
||
124 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
125 | .support_list = |
||
126 | "SupportList:\r\n" |
||
127 | "CPE210(TP-LINK|UN|N300-2):1.0\r\n" |
||
128 | "CPE210(TP-LINK|UN|N300-2):1.1\r\n" |
||
129 | "CPE210(TP-LINK|US|N300-2):1.1\r\n" |
||
130 | "CPE210(TP-LINK|EU|N300-2):1.1\r\n" |
||
131 | "CPE220(TP-LINK|UN|N300-2):1.1\r\n" |
||
132 | "CPE220(TP-LINK|US|N300-2):1.1\r\n" |
||
133 | "CPE220(TP-LINK|EU|N300-2):1.1\r\n", |
||
134 | .support_trail = '\xff', |
||
135 | .soft_ver = NULL, |
||
136 | |||
137 | .partitions = { |
||
138 | {"fs-uboot", 0x00000, 0x20000}, |
||
139 | {"partition-table", 0x20000, 0x02000}, |
||
140 | {"default-mac", 0x30000, 0x00020}, |
||
141 | {"product-info", 0x31100, 0x00100}, |
||
142 | {"signature", 0x32000, 0x00400}, |
||
143 | {"os-image", 0x40000, 0x1c0000}, |
||
144 | {"file-system", 0x200000, 0x5b0000}, |
||
145 | {"soft-version", 0x7b0000, 0x00100}, |
||
146 | {"support-list", 0x7b1000, 0x00400}, |
||
147 | {"user-config", 0x7c0000, 0x10000}, |
||
148 | {"default-config", 0x7d0000, 0x10000}, |
||
149 | {"log", 0x7e0000, 0x10000}, |
||
150 | {"radio", 0x7f0000, 0x10000}, |
||
151 | {NULL, 0, 0} |
||
152 | }, |
||
153 | |||
154 | .first_sysupgrade_partition = "os-image", |
||
155 | .last_sysupgrade_partition = "support-list", |
||
156 | }, |
||
157 | |||
158 | /** Firmware layout for the CPE210 V2 */ |
||
159 | { |
||
160 | .id = "CPE210V2", |
||
161 | .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n", |
||
162 | .support_list = |
||
163 | "SupportList:\r\n" |
||
164 | "CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n" |
||
165 | "CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n" |
||
166 | "CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n" |
||
167 | "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n" |
||
168 | "CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n" |
||
169 | "CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n" |
||
170 | "CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n" |
||
171 | "CPE210(TP-LINK|UN|N300-2):2.0\r\n" |
||
172 | "CPE210(TP-LINK|EU|N300-2):2.0\r\n" |
||
173 | "CPE210(TP-LINK|US|N300-2):2.0\r\n", |
||
174 | .support_trail = '\xff', |
||
175 | .soft_ver = NULL, |
||
176 | |||
177 | .partitions = { |
||
178 | {"fs-uboot", 0x00000, 0x20000}, |
||
179 | {"partition-table", 0x20000, 0x02000}, |
||
180 | {"default-mac", 0x30000, 0x00020}, |
||
181 | {"product-info", 0x31100, 0x00100}, |
||
182 | {"device-info", 0x31400, 0x00400}, |
||
183 | {"signature", 0x32000, 0x00400}, |
||
184 | {"device-id", 0x33000, 0x00100}, |
||
185 | {"os-image", 0x40000, 0x1c0000}, |
||
186 | {"file-system", 0x200000, 0x5b0000}, |
||
187 | {"soft-version", 0x7b0000, 0x00100}, |
||
188 | {"support-list", 0x7b1000, 0x01000}, |
||
189 | {"user-config", 0x7c0000, 0x10000}, |
||
190 | {"default-config", 0x7d0000, 0x10000}, |
||
191 | {"log", 0x7e0000, 0x10000}, |
||
192 | {"radio", 0x7f0000, 0x10000}, |
||
193 | {NULL, 0, 0} |
||
194 | }, |
||
195 | |||
196 | .first_sysupgrade_partition = "os-image", |
||
197 | .last_sysupgrade_partition = "support-list", |
||
198 | }, |
||
199 | |||
200 | /** Firmware layout for the CPE510/520 */ |
||
201 | { |
||
202 | .id = "CPE510", |
||
203 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
204 | .support_list = |
||
205 | "SupportList:\r\n" |
||
206 | "CPE510(TP-LINK|UN|N300-5):1.0\r\n" |
||
207 | "CPE510(TP-LINK|UN|N300-5):1.1\r\n" |
||
208 | "CPE510(TP-LINK|UN|N300-5):1.1\r\n" |
||
209 | "CPE510(TP-LINK|US|N300-5):1.1\r\n" |
||
210 | "CPE510(TP-LINK|EU|N300-5):1.1\r\n" |
||
211 | "CPE520(TP-LINK|UN|N300-5):1.1\r\n" |
||
212 | "CPE520(TP-LINK|US|N300-5):1.1\r\n" |
||
213 | "CPE520(TP-LINK|EU|N300-5):1.1\r\n" |
||
214 | "CPE510(TP-LINK|EU|N300-5|00000000):2.0\r\n" |
||
215 | "CPE510(TP-LINK|EU|N300-5|45550000):2.0\r\n" |
||
216 | "CPE510(TP-LINK|EU|N300-5|55530000):2.0\r\n" |
||
217 | "CPE510(TP-LINK|UN|N300-5|00000000):2.0\r\n" |
||
218 | "CPE510(TP-LINK|UN|N300-5|45550000):2.0\r\n" |
||
219 | "CPE510(TP-LINK|UN|N300-5|55530000):2.0\r\n" |
||
220 | "CPE510(TP-LINK|US|N300-5|55530000):2.0\r\n" |
||
221 | "CPE510(TP-LINK|UN|N300-5):2.0\r\n" |
||
222 | "CPE510(TP-LINK|EU|N300-5):2.0\r\n" |
||
223 | "CPE510(TP-LINK|US|N300-5):2.0\r\n", |
||
224 | .support_trail = '\xff', |
||
225 | .soft_ver = NULL, |
||
226 | |||
227 | .partitions = { |
||
228 | {"fs-uboot", 0x00000, 0x20000}, |
||
229 | {"partition-table", 0x20000, 0x02000}, |
||
230 | {"default-mac", 0x30000, 0x00020}, |
||
231 | {"product-info", 0x31100, 0x00100}, |
||
232 | {"signature", 0x32000, 0x00400}, |
||
233 | {"os-image", 0x40000, 0x1c0000}, |
||
234 | {"file-system", 0x200000, 0x5b0000}, |
||
235 | {"soft-version", 0x7b0000, 0x00100}, |
||
236 | {"support-list", 0x7b1000, 0x00400}, |
||
237 | {"user-config", 0x7c0000, 0x10000}, |
||
238 | {"default-config", 0x7d0000, 0x10000}, |
||
239 | {"log", 0x7e0000, 0x10000}, |
||
240 | {"radio", 0x7f0000, 0x10000}, |
||
241 | {NULL, 0, 0} |
||
242 | }, |
||
243 | |||
244 | .first_sysupgrade_partition = "os-image", |
||
245 | .last_sysupgrade_partition = "support-list", |
||
246 | }, |
||
247 | |||
248 | { |
||
249 | .id = "WBS210", |
||
250 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
251 | .support_list = |
||
252 | "SupportList:\r\n" |
||
253 | "WBS210(TP-LINK|UN|N300-2):1.20\r\n" |
||
254 | "WBS210(TP-LINK|US|N300-2):1.20\r\n" |
||
255 | "WBS210(TP-LINK|EU|N300-2):1.20\r\n", |
||
256 | .support_trail = '\xff', |
||
257 | .soft_ver = NULL, |
||
258 | |||
259 | .partitions = { |
||
260 | {"fs-uboot", 0x00000, 0x20000}, |
||
261 | {"partition-table", 0x20000, 0x02000}, |
||
262 | {"default-mac", 0x30000, 0x00020}, |
||
263 | {"product-info", 0x31100, 0x00100}, |
||
264 | {"signature", 0x32000, 0x00400}, |
||
265 | {"os-image", 0x40000, 0x1c0000}, |
||
266 | {"file-system", 0x200000, 0x5b0000}, |
||
267 | {"soft-version", 0x7b0000, 0x00100}, |
||
268 | {"support-list", 0x7b1000, 0x00400}, |
||
269 | {"user-config", 0x7c0000, 0x10000}, |
||
270 | {"default-config", 0x7d0000, 0x10000}, |
||
271 | {"log", 0x7e0000, 0x10000}, |
||
272 | {"radio", 0x7f0000, 0x10000}, |
||
273 | {NULL, 0, 0} |
||
274 | }, |
||
275 | |||
276 | .first_sysupgrade_partition = "os-image", |
||
277 | .last_sysupgrade_partition = "support-list", |
||
278 | }, |
||
279 | |||
280 | { |
||
281 | .id = "WBS510", |
||
282 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
283 | .support_list = |
||
284 | "SupportList:\r\n" |
||
285 | "WBS510(TP-LINK|UN|N300-5):1.20\r\n" |
||
286 | "WBS510(TP-LINK|US|N300-5):1.20\r\n" |
||
287 | "WBS510(TP-LINK|EU|N300-5):1.20\r\n", |
||
288 | .support_trail = '\xff', |
||
289 | .soft_ver = NULL, |
||
290 | |||
291 | .partitions = { |
||
292 | {"fs-uboot", 0x00000, 0x20000}, |
||
293 | {"partition-table", 0x20000, 0x02000}, |
||
294 | {"default-mac", 0x30000, 0x00020}, |
||
295 | {"product-info", 0x31100, 0x00100}, |
||
296 | {"signature", 0x32000, 0x00400}, |
||
297 | {"os-image", 0x40000, 0x1c0000}, |
||
298 | {"file-system", 0x200000, 0x5b0000}, |
||
299 | {"soft-version", 0x7b0000, 0x00100}, |
||
300 | {"support-list", 0x7b1000, 0x00400}, |
||
301 | {"user-config", 0x7c0000, 0x10000}, |
||
302 | {"default-config", 0x7d0000, 0x10000}, |
||
303 | {"log", 0x7e0000, 0x10000}, |
||
304 | {"radio", 0x7f0000, 0x10000}, |
||
305 | {NULL, 0, 0} |
||
306 | }, |
||
307 | |||
308 | .first_sysupgrade_partition = "os-image", |
||
309 | .last_sysupgrade_partition = "support-list", |
||
310 | }, |
||
311 | |||
312 | /** Firmware layout for the C2600 */ |
||
313 | { |
||
314 | .id = "C2600", |
||
315 | .vendor = "", |
||
316 | .support_list = |
||
317 | "SupportList:\r\n" |
||
318 | "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n", |
||
319 | .support_trail = '\x00', |
||
320 | .soft_ver = NULL, |
||
321 | |||
322 | /** |
||
323 | We use a bigger os-image partition than the stock images (and thus |
||
324 | smaller file-system), as our kernel doesn't fit in the stock firmware's |
||
325 | 2 MB os-image since kernel 4.14. |
||
326 | */ |
||
327 | .partitions = { |
||
328 | {"SBL1", 0x00000, 0x20000}, |
||
329 | {"MIBIB", 0x20000, 0x20000}, |
||
330 | {"SBL2", 0x40000, 0x20000}, |
||
331 | {"SBL3", 0x60000, 0x30000}, |
||
332 | {"DDRCONFIG", 0x90000, 0x10000}, |
||
333 | {"SSD", 0xa0000, 0x10000}, |
||
334 | {"TZ", 0xb0000, 0x30000}, |
||
335 | {"RPM", 0xe0000, 0x20000}, |
||
336 | {"fs-uboot", 0x100000, 0x70000}, |
||
337 | {"uboot-env", 0x170000, 0x40000}, |
||
338 | {"radio", 0x1b0000, 0x40000}, |
||
339 | {"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */ |
||
340 | {"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */ |
||
341 | {"default-mac", 0x1ef0000, 0x00200}, |
||
342 | {"pin", 0x1ef0200, 0x00200}, |
||
343 | {"product-info", 0x1ef0400, 0x0fc00}, |
||
344 | {"partition-table", 0x1f00000, 0x10000}, |
||
345 | {"soft-version", 0x1f10000, 0x10000}, |
||
346 | {"support-list", 0x1f20000, 0x10000}, |
||
347 | {"profile", 0x1f30000, 0x10000}, |
||
348 | {"default-config", 0x1f40000, 0x10000}, |
||
349 | {"user-config", 0x1f50000, 0x40000}, |
||
350 | {"qos-db", 0x1f90000, 0x40000}, |
||
351 | {"usb-config", 0x1fd0000, 0x10000}, |
||
352 | {"log", 0x1fe0000, 0x20000}, |
||
353 | {NULL, 0, 0} |
||
354 | }, |
||
355 | |||
356 | .first_sysupgrade_partition = "os-image", |
||
357 | .last_sysupgrade_partition = "file-system" |
||
358 | }, |
||
359 | |||
360 | /** Firmware layout for the A7-V5 */ |
||
361 | { |
||
362 | .id = "ARCHER-A7-V5", |
||
363 | .support_list = |
||
364 | "SupportList:\n" |
||
365 | "{product_name:Archer A7,product_ver:5.0.0,special_id:45550000}\n" |
||
366 | "{product_name:Archer A7,product_ver:5.0.0,special_id:55530000}\n" |
||
367 | "{product_name:Archer A7,product_ver:5.0.0,special_id:43410000}\n" |
||
368 | "{product_name:Archer A7,product_ver:5.0.0,special_id:4A500000}\n" |
||
369 | "{product_name:Archer A7,product_ver:5.0.0,special_id:54570000}\n", |
||
370 | .support_trail = '\x00', |
||
371 | .soft_ver = "soft_ver:1.0.0\n", |
||
372 | |||
373 | /* We're using a dynamic kernel/rootfs split here */ |
||
374 | .partitions = { |
||
375 | {"factory-boot", 0x00000, 0x20000}, |
||
376 | {"fs-uboot", 0x20000, 0x20000}, |
||
377 | {"firmware", 0x40000, 0xec0000}, /* Stock: name os-image base 0x40000 size 0x120000 */ |
||
378 | /* Stock: name file-system base 0x160000 size 0xda0000 */ |
||
379 | {"default-mac", 0xf40000, 0x00200}, |
||
380 | {"pin", 0xf40200, 0x00200}, |
||
381 | {"device-id", 0xf40400, 0x00100}, |
||
382 | {"product-info", 0xf40500, 0x0fb00}, |
||
383 | {"soft-version", 0xf50000, 0x00100}, |
||
384 | {"extra-para", 0xf51000, 0x01000}, |
||
385 | {"support-list", 0xf52000, 0x0a000}, |
||
386 | {"profile", 0xf5c000, 0x04000}, |
||
387 | {"default-config", 0xf60000, 0x10000}, |
||
388 | {"user-config", 0xf70000, 0x40000}, |
||
389 | {"certificate", 0xfb0000, 0x10000}, |
||
390 | {"partition-table", 0xfc0000, 0x10000}, |
||
391 | {"log", 0xfd0000, 0x20000}, |
||
392 | {"radio", 0xff0000, 0x10000}, |
||
393 | {NULL, 0, 0} |
||
394 | }, |
||
395 | |||
396 | .first_sysupgrade_partition = "os-image", |
||
397 | .last_sysupgrade_partition = "file-system", |
||
398 | }, |
||
399 | |||
400 | /** Firmware layout for the C2v3 */ |
||
401 | { |
||
402 | .id = "ARCHER-C2-V3", |
||
403 | .support_list = |
||
404 | "SupportList:\n" |
||
405 | "{product_name:ArcherC2,product_ver:3.0.0,special_id:00000000}\n" |
||
406 | "{product_name:ArcherC2,product_ver:3.0.0,special_id:55530000}\n" |
||
407 | "{product_name:ArcherC2,product_ver:3.0.0,special_id:45550000}\n", |
||
408 | .support_trail = '\x00', |
||
409 | .soft_ver = "soft_ver:3.0.1\n", |
||
410 | |||
411 | /** We're using a dynamic kernel/rootfs split here */ |
||
412 | |||
413 | .partitions = { |
||
414 | {"factory-boot", 0x00000, 0x20000}, |
||
415 | {"fs-uboot", 0x20000, 0x10000}, |
||
416 | {"firmware", 0x30000, 0x7a0000}, |
||
417 | {"user-config", 0x7d0000, 0x04000}, |
||
418 | {"default-mac", 0x7e0000, 0x00100}, |
||
419 | {"device-id", 0x7e0100, 0x00100}, |
||
420 | {"extra-para", 0x7e0200, 0x00100}, |
||
421 | {"pin", 0x7e0300, 0x00100}, |
||
422 | {"support-list", 0x7e0400, 0x00400}, |
||
423 | {"soft-version", 0x7e0800, 0x00400}, |
||
424 | {"product-info", 0x7e0c00, 0x01400}, |
||
425 | {"partition-table", 0x7e2000, 0x01000}, |
||
426 | {"profile", 0x7e3000, 0x01000}, |
||
427 | {"default-config", 0x7e4000, 0x04000}, |
||
428 | {"merge-config", 0x7ec000, 0x02000}, |
||
429 | {"qos-db", 0x7ee000, 0x02000}, |
||
430 | {"radio", 0x7f0000, 0x10000}, |
||
431 | {NULL, 0, 0} |
||
432 | }, |
||
433 | |||
434 | .first_sysupgrade_partition = "os-image", |
||
435 | .last_sysupgrade_partition = "file-system", |
||
436 | }, |
||
437 | |||
438 | /** Firmware layout for the C25v1 */ |
||
439 | { |
||
440 | .id = "ARCHER-C25-V1", |
||
441 | .support_list = |
||
442 | "SupportList:\n" |
||
443 | "{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n" |
||
444 | "{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n" |
||
445 | "{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n", |
||
446 | .support_trail = '\x00', |
||
447 | .soft_ver = "soft_ver:1.0.0\n", |
||
448 | |||
449 | /* We're using a dynamic kernel/rootfs split here */ |
||
450 | .partitions = { |
||
451 | {"factory-boot", 0x00000, 0x20000}, |
||
452 | {"fs-uboot", 0x20000, 0x10000}, |
||
453 | {"firmware", 0x30000, 0x7a0000}, /* Stock: name os-image base 0x30000 size 0x100000 */ |
||
454 | /* Stock: name file-system base 0x130000 size 0x6a0000 */ |
||
455 | {"user-config", 0x7d0000, 0x04000}, |
||
456 | {"default-mac", 0x7e0000, 0x00100}, |
||
457 | {"device-id", 0x7e0100, 0x00100}, |
||
458 | {"extra-para", 0x7e0200, 0x00100}, |
||
459 | {"pin", 0x7e0300, 0x00100}, |
||
460 | {"support-list", 0x7e0400, 0x00400}, |
||
461 | {"soft-version", 0x7e0800, 0x00400}, |
||
462 | {"product-info", 0x7e0c00, 0x01400}, |
||
463 | {"partition-table", 0x7e2000, 0x01000}, |
||
464 | {"profile", 0x7e3000, 0x01000}, |
||
465 | {"default-config", 0x7e4000, 0x04000}, |
||
466 | {"merge-config", 0x7ec000, 0x02000}, |
||
467 | {"qos-db", 0x7ee000, 0x02000}, |
||
468 | {"radio", 0x7f0000, 0x10000}, |
||
469 | {NULL, 0, 0} |
||
470 | }, |
||
471 | |||
472 | .first_sysupgrade_partition = "os-image", |
||
473 | .last_sysupgrade_partition = "file-system", |
||
474 | }, |
||
475 | |||
476 | /** Firmware layout for the C58v1 */ |
||
477 | { |
||
478 | .id = "ARCHER-C58-V1", |
||
479 | .vendor = "", |
||
480 | .support_list = |
||
481 | "SupportList:\r\n" |
||
482 | "{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n" |
||
483 | "{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n" |
||
484 | "{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n", |
||
485 | .support_trail = '\x00', |
||
486 | .soft_ver = "soft_ver:1.0.0\n", |
||
487 | |||
488 | .partitions = { |
||
489 | {"fs-uboot", 0x00000, 0x10000}, |
||
490 | {"default-mac", 0x10000, 0x00200}, |
||
491 | {"pin", 0x10200, 0x00200}, |
||
492 | {"product-info", 0x10400, 0x00100}, |
||
493 | {"partition-table", 0x10500, 0x00800}, |
||
494 | {"soft-version", 0x11300, 0x00200}, |
||
495 | {"support-list", 0x11500, 0x00100}, |
||
496 | {"device-id", 0x11600, 0x00100}, |
||
497 | {"profile", 0x11700, 0x03900}, |
||
498 | {"default-config", 0x15000, 0x04000}, |
||
499 | {"user-config", 0x19000, 0x04000}, |
||
500 | {"firmware", 0x20000, 0x7c8000}, |
||
501 | {"certyficate", 0x7e8000, 0x08000}, |
||
502 | {"radio", 0x7f0000, 0x10000}, |
||
503 | {NULL, 0, 0} |
||
504 | }, |
||
505 | |||
506 | .first_sysupgrade_partition = "os-image", |
||
507 | .last_sysupgrade_partition = "file-system", |
||
508 | }, |
||
509 | |||
510 | /** Firmware layout for the C59v1 */ |
||
511 | { |
||
512 | .id = "ARCHER-C59-V1", |
||
513 | .vendor = "", |
||
514 | .support_list = |
||
515 | "SupportList:\r\n" |
||
516 | "{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n" |
||
517 | "{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n" |
||
518 | "{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n" |
||
519 | "{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n", |
||
520 | .support_trail = '\x00', |
||
521 | .soft_ver = "soft_ver:1.0.0\n", |
||
522 | |||
523 | /* We're using a dynamic kernel/rootfs split here */ |
||
524 | .partitions = { |
||
525 | {"fs-uboot", 0x00000, 0x10000}, |
||
526 | {"default-mac", 0x10000, 0x00200}, |
||
527 | {"pin", 0x10200, 0x00200}, |
||
528 | {"device-id", 0x10400, 0x00100}, |
||
529 | {"product-info", 0x10500, 0x0fb00}, |
||
530 | {"firmware", 0x20000, 0xe30000}, |
||
531 | {"partition-table", 0xe50000, 0x10000}, |
||
532 | {"soft-version", 0xe60000, 0x10000}, |
||
533 | {"support-list", 0xe70000, 0x10000}, |
||
534 | {"profile", 0xe80000, 0x10000}, |
||
535 | {"default-config", 0xe90000, 0x10000}, |
||
536 | {"user-config", 0xea0000, 0x40000}, |
||
537 | {"usb-config", 0xee0000, 0x10000}, |
||
538 | {"certificate", 0xef0000, 0x10000}, |
||
539 | {"qos-db", 0xf00000, 0x40000}, |
||
540 | {"log", 0xfe0000, 0x10000}, |
||
541 | {"radio", 0xff0000, 0x10000}, |
||
542 | {NULL, 0, 0} |
||
543 | }, |
||
544 | |||
545 | .first_sysupgrade_partition = "os-image", |
||
546 | .last_sysupgrade_partition = "file-system", |
||
547 | }, |
||
548 | |||
549 | /** Firmware layout for the C59v2 */ |
||
550 | { |
||
551 | .id = "ARCHER-C59-V2", |
||
552 | .vendor = "", |
||
553 | .support_list = |
||
554 | "SupportList:\r\n" |
||
555 | "{product_name:Archer C59,product_ver:2.0.0,special_id:00000000}\r\n" |
||
556 | "{product_name:Archer C59,product_ver:2.0.0,special_id:45550000}\r\n" |
||
557 | "{product_name:Archer C59,product_ver:2.0.0,special_id:55530000}\r\n", |
||
558 | .support_trail = '\x00', |
||
559 | .soft_ver = "soft_ver:2.0.0 Build 20161206 rel.7303\n", |
||
560 | |||
561 | /** We're using a dynamic kernel/rootfs split here */ |
||
562 | .partitions = { |
||
563 | {"factory-boot", 0x00000, 0x20000}, |
||
564 | {"fs-uboot", 0x20000, 0x10000}, |
||
565 | {"default-mac", 0x30000, 0x00200}, |
||
566 | {"pin", 0x30200, 0x00200}, |
||
567 | {"device-id", 0x30400, 0x00100}, |
||
568 | {"product-info", 0x30500, 0x0fb00}, |
||
569 | {"firmware", 0x40000, 0xe10000}, |
||
570 | {"partition-table", 0xe50000, 0x10000}, |
||
571 | {"soft-version", 0xe60000, 0x10000}, |
||
572 | {"support-list", 0xe70000, 0x10000}, |
||
573 | {"profile", 0xe80000, 0x10000}, |
||
574 | {"default-config", 0xe90000, 0x10000}, |
||
575 | {"user-config", 0xea0000, 0x40000}, |
||
576 | {"usb-config", 0xee0000, 0x10000}, |
||
577 | {"certificate", 0xef0000, 0x10000}, |
||
578 | {"extra-para", 0xf00000, 0x10000}, |
||
579 | {"qos-db", 0xf10000, 0x30000}, |
||
580 | {"log", 0xfe0000, 0x10000}, |
||
581 | {"radio", 0xff0000, 0x10000}, |
||
582 | {NULL, 0, 0} |
||
583 | }, |
||
584 | |||
585 | .first_sysupgrade_partition = "os-image", |
||
586 | .last_sysupgrade_partition = "file-system", |
||
587 | }, |
||
588 | |||
589 | /** Firmware layout for the C6v2 */ |
||
590 | { |
||
591 | .id = "ARCHER-C6-V2", |
||
592 | .vendor = "", |
||
593 | .support_list = |
||
594 | "SupportList:\r\n" |
||
595 | "{product_name:Archer C6,product_ver:2.0.0,special_id:45550000}\r\n" |
||
596 | "{product_name:Archer C6,product_ver:2.0.0,special_id:52550000}\r\n" |
||
597 | "{product_name:Archer C6,product_ver:2.0.0,special_id:4A500000}\r\n", |
||
598 | .support_trail = '\x00', |
||
599 | .soft_ver = "soft_ver:1.0.0\n", |
||
600 | |||
601 | .partitions = { |
||
602 | {"fs-uboot", 0x00000, 0x20000}, |
||
603 | {"default-mac", 0x20000, 0x00200}, |
||
604 | {"pin", 0x20200, 0x00100}, |
||
605 | {"product-info", 0x20300, 0x00200}, |
||
606 | {"device-id", 0x20500, 0x0fb00}, |
||
607 | {"firmware", 0x30000, 0x7a9400}, |
||
608 | {"soft-version", 0x7d9400, 0x00100}, |
||
609 | {"extra-para", 0x7d9500, 0x00100}, |
||
610 | {"support-list", 0x7d9600, 0x00200}, |
||
611 | {"profile", 0x7d9800, 0x03000}, |
||
612 | {"default-config", 0x7dc800, 0x03000}, |
||
613 | {"partition-table", 0x7df800, 0x00800}, |
||
614 | {"user-config", 0x7e0000, 0x0c000}, |
||
615 | {"certificate", 0x7ec000, 0x04000}, |
||
616 | {"radio", 0x7f0000, 0x10000}, |
||
617 | {NULL, 0, 0} |
||
618 | }, |
||
619 | |||
620 | .first_sysupgrade_partition = "os-image", |
||
621 | .last_sysupgrade_partition = "file-system", |
||
622 | }, |
||
623 | |||
624 | |||
625 | /** Firmware layout for the C60v1 */ |
||
626 | { |
||
627 | .id = "ARCHER-C60-V1", |
||
628 | .vendor = "", |
||
629 | .support_list = |
||
630 | "SupportList:\r\n" |
||
631 | "{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n" |
||
632 | "{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n" |
||
633 | "{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n", |
||
634 | .support_trail = '\x00', |
||
635 | .soft_ver = "soft_ver:1.0.0\n", |
||
636 | |||
637 | .partitions = { |
||
638 | {"fs-uboot", 0x00000, 0x10000}, |
||
639 | {"default-mac", 0x10000, 0x00200}, |
||
640 | {"pin", 0x10200, 0x00200}, |
||
641 | {"product-info", 0x10400, 0x00100}, |
||
642 | {"partition-table", 0x10500, 0x00800}, |
||
643 | {"soft-version", 0x11300, 0x00200}, |
||
644 | {"support-list", 0x11500, 0x00100}, |
||
645 | {"device-id", 0x11600, 0x00100}, |
||
646 | {"profile", 0x11700, 0x03900}, |
||
647 | {"default-config", 0x15000, 0x04000}, |
||
648 | {"user-config", 0x19000, 0x04000}, |
||
649 | {"firmware", 0x20000, 0x7c8000}, |
||
650 | {"certyficate", 0x7e8000, 0x08000}, |
||
651 | {"radio", 0x7f0000, 0x10000}, |
||
652 | {NULL, 0, 0} |
||
653 | }, |
||
654 | |||
655 | .first_sysupgrade_partition = "os-image", |
||
656 | .last_sysupgrade_partition = "file-system", |
||
657 | }, |
||
658 | |||
659 | /** Firmware layout for the C60v2 */ |
||
660 | { |
||
661 | .id = "ARCHER-C60-V2", |
||
662 | .vendor = "", |
||
663 | .support_list = |
||
664 | "SupportList:\r\n" |
||
665 | "{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n" |
||
666 | "{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n" |
||
667 | "{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n", |
||
668 | .support_trail = '\x00', |
||
669 | .soft_ver = "soft_ver:2.0.0\n", |
||
670 | |||
671 | .partitions = { |
||
672 | {"factory-boot", 0x00000, 0x1fb00}, |
||
673 | {"default-mac", 0x1fb00, 0x00200}, |
||
674 | {"pin", 0x1fd00, 0x00100}, |
||
675 | {"product-info", 0x1fe00, 0x00100}, |
||
676 | {"device-id", 0x1ff00, 0x00100}, |
||
677 | {"fs-uboot", 0x20000, 0x10000}, |
||
678 | {"firmware", 0x30000, 0x7a0000}, |
||
679 | {"soft-version", 0x7d9500, 0x00100}, |
||
680 | {"support-list", 0x7d9600, 0x00100}, |
||
681 | {"extra-para", 0x7d9700, 0x00100}, |
||
682 | {"profile", 0x7d9800, 0x03000}, |
||
683 | {"default-config", 0x7dc800, 0x03000}, |
||
684 | {"partition-table", 0x7df800, 0x00800}, |
||
685 | {"user-config", 0x7e0000, 0x0c000}, |
||
686 | {"certificate", 0x7ec000, 0x04000}, |
||
687 | {"radio", 0x7f0000, 0x10000}, |
||
688 | {NULL, 0, 0} |
||
689 | }, |
||
690 | |||
691 | .first_sysupgrade_partition = "os-image", |
||
692 | .last_sysupgrade_partition = "file-system", |
||
693 | }, |
||
694 | |||
695 | /** Firmware layout for the C5 */ |
||
696 | { |
||
697 | .id = "ARCHER-C5-V2", |
||
698 | .vendor = "", |
||
699 | .support_list = |
||
700 | "SupportList:\r\n" |
||
701 | "{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n" |
||
702 | "{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n" |
||
703 | "{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */ |
||
704 | .support_trail = '\x00', |
||
705 | .soft_ver = NULL, |
||
706 | |||
707 | .partitions = { |
||
708 | {"fs-uboot", 0x00000, 0x40000}, |
||
709 | {"os-image", 0x40000, 0x200000}, |
||
710 | {"file-system", 0x240000, 0xc00000}, |
||
711 | {"default-mac", 0xe40000, 0x00200}, |
||
712 | {"pin", 0xe40200, 0x00200}, |
||
713 | {"product-info", 0xe40400, 0x00200}, |
||
714 | {"partition-table", 0xe50000, 0x10000}, |
||
715 | {"soft-version", 0xe60000, 0x00200}, |
||
716 | {"support-list", 0xe61000, 0x0f000}, |
||
717 | {"profile", 0xe70000, 0x10000}, |
||
718 | {"default-config", 0xe80000, 0x10000}, |
||
719 | {"user-config", 0xe90000, 0x50000}, |
||
720 | {"log", 0xee0000, 0x100000}, |
||
721 | {"radio_bk", 0xfe0000, 0x10000}, |
||
722 | {"radio", 0xff0000, 0x10000}, |
||
723 | {NULL, 0, 0} |
||
724 | }, |
||
725 | |||
726 | .first_sysupgrade_partition = "os-image", |
||
727 | .last_sysupgrade_partition = "file-system" |
||
728 | }, |
||
729 | |||
730 | /** Firmware layout for the C7 */ |
||
731 | { |
||
732 | .id = "ARCHER-C7-V4", |
||
733 | .support_list = |
||
734 | "SupportList:\n" |
||
735 | "{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n" |
||
736 | "{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n" |
||
737 | "{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n" |
||
738 | "{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n" |
||
739 | "{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n" |
||
740 | "{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n" |
||
741 | "{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n" |
||
742 | "{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n" |
||
743 | "{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n" |
||
744 | "{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n", |
||
745 | .support_trail = '\x00', |
||
746 | .soft_ver = "soft_ver:1.0.0\n", |
||
747 | |||
748 | /* We're using a dynamic kernel/rootfs split here */ |
||
749 | .partitions = { |
||
750 | {"factory-boot", 0x00000, 0x20000}, |
||
751 | {"fs-uboot", 0x20000, 0x20000}, |
||
752 | {"firmware", 0x40000, 0xEC0000}, /* Stock: name os-image base 0x40000 size 0x120000 */ |
||
753 | /* Stock: name file-system base 0x160000 size 0xda0000 */ |
||
754 | {"default-mac", 0xf00000, 0x00200}, |
||
755 | {"pin", 0xf00200, 0x00200}, |
||
756 | {"device-id", 0xf00400, 0x00100}, |
||
757 | {"product-info", 0xf00500, 0x0fb00}, |
||
758 | {"soft-version", 0xf10000, 0x00100}, |
||
759 | {"extra-para", 0xf11000, 0x01000}, |
||
760 | {"support-list", 0xf12000, 0x0a000}, |
||
761 | {"profile", 0xf1c000, 0x04000}, |
||
762 | {"default-config", 0xf20000, 0x10000}, |
||
763 | {"user-config", 0xf30000, 0x40000}, |
||
764 | {"qos-db", 0xf70000, 0x40000}, |
||
765 | {"certificate", 0xfb0000, 0x10000}, |
||
766 | {"partition-table", 0xfc0000, 0x10000}, |
||
767 | {"log", 0xfd0000, 0x20000}, |
||
768 | {"radio", 0xff0000, 0x10000}, |
||
769 | {NULL, 0, 0} |
||
770 | }, |
||
771 | |||
772 | .first_sysupgrade_partition = "os-image", |
||
773 | .last_sysupgrade_partition = "file-system", |
||
774 | }, |
||
775 | |||
776 | /** Firmware layout for the C7 v5*/ |
||
777 | { |
||
778 | .id = "ARCHER-C7-V5", |
||
779 | .support_list = |
||
780 | "SupportList:\n" |
||
781 | "{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n" |
||
782 | "{product_name:Archer C7,product_ver:5.0.0,special_id:45550000}\n" |
||
783 | "{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n" |
||
784 | "{product_name:Archer C7,product_ver:5.0.0,special_id:43410000}\n" |
||
785 | "{product_name:Archer C7,product_ver:5.0.0,special_id:4A500000}\n" |
||
786 | "{product_name:Archer C7,product_ver:5.0.0,special_id:54570000}\n" |
||
787 | "{product_name:Archer C7,product_ver:5.0.0,special_id:52550000}\n", |
||
788 | |||
789 | .support_trail = '\x00', |
||
790 | .soft_ver = "soft_ver:1.0.0\n", |
||
791 | |||
792 | /* We're using a dynamic kernel/rootfs split here */ |
||
793 | .partitions = { |
||
794 | {"factory-boot", 0x00000, 0x20000}, |
||
795 | {"fs-uboot", 0x20000, 0x20000}, |
||
796 | {"partition-table", 0x40000, 0x10000}, |
||
797 | {"radio", 0x50000, 0x10000}, |
||
798 | {"default-mac", 0x60000, 0x00200}, |
||
799 | {"pin", 0x60200, 0x00200}, |
||
800 | {"device-id", 0x60400, 0x00100}, |
||
801 | {"product-info", 0x60500, 0x0fb00}, |
||
802 | {"soft-version", 0x70000, 0x01000}, |
||
803 | {"extra-para", 0x71000, 0x01000}, |
||
804 | {"support-list", 0x72000, 0x0a000}, |
||
805 | {"profile", 0x7c000, 0x04000}, |
||
806 | {"user-config", 0x80000, 0x40000}, |
||
807 | |||
808 | |||
809 | {"firmware", 0xc0000, 0xf00000}, /* Stock: name os-image base 0xc0000 size 0x120000 */ |
||
810 | /* Stock: name file-system base 0x1e0000 size 0xde0000 */ |
||
811 | |||
812 | {"log", 0xfc0000, 0x20000}, |
||
813 | {"certificate", 0xfe0000, 0x10000}, |
||
814 | {"default-config", 0xff0000, 0x10000}, |
||
815 | {NULL, 0, 0} |
||
816 | |||
817 | }, |
||
818 | |||
819 | .first_sysupgrade_partition = "os-image", |
||
820 | .last_sysupgrade_partition = "file-system", |
||
821 | }, |
||
822 | |||
823 | /** Firmware layout for the C9 */ |
||
824 | { |
||
825 | .id = "ARCHERC9", |
||
826 | .vendor = "", |
||
827 | .support_list = |
||
828 | "SupportList:\n" |
||
829 | "{product_name:ArcherC9," |
||
830 | "product_ver:1.0.0," |
||
831 | "special_id:00000000}\n", |
||
832 | .support_trail = '\x00', |
||
833 | .soft_ver = NULL, |
||
834 | |||
835 | .partitions = { |
||
836 | {"fs-uboot", 0x00000, 0x40000}, |
||
837 | {"os-image", 0x40000, 0x200000}, |
||
838 | {"file-system", 0x240000, 0xc00000}, |
||
839 | {"default-mac", 0xe40000, 0x00200}, |
||
840 | {"pin", 0xe40200, 0x00200}, |
||
841 | {"product-info", 0xe40400, 0x00200}, |
||
842 | {"partition-table", 0xe50000, 0x10000}, |
||
843 | {"soft-version", 0xe60000, 0x00200}, |
||
844 | {"support-list", 0xe61000, 0x0f000}, |
||
845 | {"profile", 0xe70000, 0x10000}, |
||
846 | {"default-config", 0xe80000, 0x10000}, |
||
847 | {"user-config", 0xe90000, 0x50000}, |
||
848 | {"log", 0xee0000, 0x100000}, |
||
849 | {"radio_bk", 0xfe0000, 0x10000}, |
||
850 | {"radio", 0xff0000, 0x10000}, |
||
851 | {NULL, 0, 0} |
||
852 | }, |
||
853 | |||
854 | .first_sysupgrade_partition = "os-image", |
||
855 | .last_sysupgrade_partition = "file-system" |
||
856 | }, |
||
857 | |||
858 | /** Firmware layout for the EAP120 */ |
||
859 | { |
||
860 | .id = "EAP120", |
||
861 | .vendor = "EAP120(TP-LINK|UN|N300-2):1.0\r\n", |
||
862 | .support_list = |
||
863 | "SupportList:\r\n" |
||
864 | "EAP120(TP-LINK|UN|N300-2):1.0\r\n", |
||
865 | .support_trail = '\xff', |
||
866 | .soft_ver = NULL, |
||
867 | |||
868 | .partitions = { |
||
869 | {"fs-uboot", 0x00000, 0x20000}, |
||
870 | {"partition-table", 0x20000, 0x02000}, |
||
871 | {"default-mac", 0x30000, 0x00020}, |
||
872 | {"support-list", 0x31000, 0x00100}, |
||
873 | {"product-info", 0x31100, 0x00100}, |
||
874 | {"soft-version", 0x32000, 0x00100}, |
||
875 | {"os-image", 0x40000, 0x180000}, |
||
876 | {"file-system", 0x1c0000, 0x600000}, |
||
877 | {"user-config", 0x7c0000, 0x10000}, |
||
878 | {"backup-config", 0x7d0000, 0x10000}, |
||
879 | {"log", 0x7e0000, 0x10000}, |
||
880 | {"radio", 0x7f0000, 0x10000}, |
||
881 | {NULL, 0, 0} |
||
882 | }, |
||
883 | |||
884 | .first_sysupgrade_partition = "os-image", |
||
885 | .last_sysupgrade_partition = "file-system" |
||
886 | }, |
||
887 | |||
888 | /** Firmware layout for the TL-WA850RE v2 */ |
||
889 | { |
||
890 | .id = "TLWA850REV2", |
||
891 | .vendor = "", |
||
892 | .support_list = |
||
893 | "SupportList:\n" |
||
894 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n" |
||
895 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n" |
||
896 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n" |
||
897 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n" |
||
898 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n" |
||
899 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n" |
||
900 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n" |
||
901 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n" |
||
902 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n" |
||
903 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n", |
||
904 | .support_trail = '\x00', |
||
905 | .soft_ver = NULL, |
||
906 | |||
907 | /** |
||
908 | 576KB were moved from file-system to os-image |
||
909 | in comparison to the stock image |
||
910 | */ |
||
911 | .partitions = { |
||
912 | {"fs-uboot", 0x00000, 0x20000}, |
||
913 | {"os-image", 0x20000, 0x150000}, |
||
914 | {"file-system", 0x170000, 0x240000}, |
||
915 | {"partition-table", 0x3b0000, 0x02000}, |
||
916 | {"default-mac", 0x3c0000, 0x00020}, |
||
917 | {"pin", 0x3c0100, 0x00020}, |
||
918 | {"product-info", 0x3c1000, 0x01000}, |
||
919 | {"soft-version", 0x3c2000, 0x00100}, |
||
920 | {"support-list", 0x3c3000, 0x01000}, |
||
921 | {"profile", 0x3c4000, 0x08000}, |
||
922 | {"user-config", 0x3d0000, 0x10000}, |
||
923 | {"default-config", 0x3e0000, 0x10000}, |
||
924 | {"radio", 0x3f0000, 0x10000}, |
||
925 | {NULL, 0, 0} |
||
926 | }, |
||
927 | |||
928 | .first_sysupgrade_partition = "os-image", |
||
929 | .last_sysupgrade_partition = "file-system" |
||
930 | }, |
||
931 | |||
932 | /** Firmware layout for the TL-WA855RE v1 */ |
||
933 | { |
||
934 | .id = "TLWA855REV1", |
||
935 | .vendor = "", |
||
936 | .support_list = |
||
937 | "SupportList:\n" |
||
938 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n" |
||
939 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n" |
||
940 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n" |
||
941 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n" |
||
942 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n" |
||
943 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n" |
||
944 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n" |
||
945 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n" |
||
946 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n", |
||
947 | .support_trail = '\x00', |
||
948 | .soft_ver = NULL, |
||
949 | |||
950 | .partitions = { |
||
951 | {"fs-uboot", 0x00000, 0x20000}, |
||
952 | {"os-image", 0x20000, 0x150000}, |
||
953 | {"file-system", 0x170000, 0x240000}, |
||
954 | {"partition-table", 0x3b0000, 0x02000}, |
||
955 | {"default-mac", 0x3c0000, 0x00020}, |
||
956 | {"pin", 0x3c0100, 0x00020}, |
||
957 | {"product-info", 0x3c1000, 0x01000}, |
||
958 | {"soft-version", 0x3c2000, 0x00100}, |
||
959 | {"support-list", 0x3c3000, 0x01000}, |
||
960 | {"profile", 0x3c4000, 0x08000}, |
||
961 | {"user-config", 0x3d0000, 0x10000}, |
||
962 | {"default-config", 0x3e0000, 0x10000}, |
||
963 | {"radio", 0x3f0000, 0x10000}, |
||
964 | {NULL, 0, 0} |
||
965 | }, |
||
966 | |||
967 | .first_sysupgrade_partition = "os-image", |
||
968 | .last_sysupgrade_partition = "file-system" |
||
969 | }, |
||
970 | |||
971 | /** Firmware layout for the TL-WR1043 v5 */ |
||
972 | { |
||
973 | .id = "TLWR1043NV5", |
||
974 | .vendor = "", |
||
975 | .support_list = |
||
976 | "SupportList:\n" |
||
977 | "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n" |
||
978 | "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n", |
||
979 | .support_trail = '\x00', |
||
980 | .soft_ver = "soft_ver:1.0.0\n", |
||
981 | .partitions = { |
||
982 | {"factory-boot", 0x00000, 0x20000}, |
||
983 | {"fs-uboot", 0x20000, 0x20000}, |
||
984 | {"firmware", 0x40000, 0xec0000}, |
||
985 | {"default-mac", 0xf00000, 0x00200}, |
||
986 | {"pin", 0xf00200, 0x00200}, |
||
987 | {"device-id", 0xf00400, 0x00100}, |
||
988 | {"product-info", 0xf00500, 0x0fb00}, |
||
989 | {"soft-version", 0xf10000, 0x01000}, |
||
990 | {"extra-para", 0xf11000, 0x01000}, |
||
991 | {"support-list", 0xf12000, 0x0a000}, |
||
992 | {"profile", 0xf1c000, 0x04000}, |
||
993 | {"default-config", 0xf20000, 0x10000}, |
||
994 | {"user-config", 0xf30000, 0x40000}, |
||
995 | {"qos-db", 0xf70000, 0x40000}, |
||
996 | {"certificate", 0xfb0000, 0x10000}, |
||
997 | {"partition-table", 0xfc0000, 0x10000}, |
||
998 | {"log", 0xfd0000, 0x20000}, |
||
999 | {"radio", 0xff0000, 0x10000}, |
||
1000 | {NULL, 0, 0} |
||
1001 | }, |
||
1002 | .first_sysupgrade_partition = "os-image", |
||
1003 | .last_sysupgrade_partition = "file-system" |
||
1004 | }, |
||
1005 | |||
1006 | /** Firmware layout for the TL-WR1043 v4 */ |
||
1007 | { |
||
1008 | .id = "TLWR1043NDV4", |
||
1009 | .vendor = "", |
||
1010 | .support_list = |
||
1011 | "SupportList:\n" |
||
1012 | "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n", |
||
1013 | .support_trail = '\x00', |
||
1014 | .soft_ver = NULL, |
||
1015 | |||
1016 | /* We're using a dynamic kernel/rootfs split here */ |
||
1017 | .partitions = { |
||
1018 | {"fs-uboot", 0x00000, 0x20000}, |
||
1019 | {"firmware", 0x20000, 0xf30000}, |
||
1020 | {"default-mac", 0xf50000, 0x00200}, |
||
1021 | {"pin", 0xf50200, 0x00200}, |
||
1022 | {"product-info", 0xf50400, 0x0fc00}, |
||
1023 | {"soft-version", 0xf60000, 0x0b000}, |
||
1024 | {"support-list", 0xf6b000, 0x04000}, |
||
1025 | {"profile", 0xf70000, 0x04000}, |
||
1026 | {"default-config", 0xf74000, 0x0b000}, |
||
1027 | {"user-config", 0xf80000, 0x40000}, |
||
1028 | {"partition-table", 0xfc0000, 0x10000}, |
||
1029 | {"log", 0xfd0000, 0x20000}, |
||
1030 | {"radio", 0xff0000, 0x10000}, |
||
1031 | {NULL, 0, 0} |
||
1032 | }, |
||
1033 | |||
1034 | .first_sysupgrade_partition = "os-image", |
||
1035 | .last_sysupgrade_partition = "file-system" |
||
1036 | }, |
||
1037 | |||
1038 | /** Firmware layout for the TL-WR902AC v1 */ |
||
1039 | { |
||
1040 | .id = "TL-WR902AC-V1", |
||
1041 | .vendor = "", |
||
1042 | .support_list = |
||
1043 | "SupportList:\n" |
||
1044 | "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n" |
||
1045 | "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n", |
||
1046 | .support_trail = '\x00', |
||
1047 | .soft_ver = NULL, |
||
1048 | |||
1049 | /** |
||
1050 | 384KB were moved from file-system to os-image |
||
1051 | in comparison to the stock image |
||
1052 | */ |
||
1053 | .partitions = { |
||
1054 | {"fs-uboot", 0x00000, 0x20000}, |
||
1055 | {"firmware", 0x20000, 0x730000}, |
||
1056 | {"default-mac", 0x750000, 0x00200}, |
||
1057 | {"pin", 0x750200, 0x00200}, |
||
1058 | {"product-info", 0x750400, 0x0fc00}, |
||
1059 | {"soft-version", 0x760000, 0x0b000}, |
||
1060 | {"support-list", 0x76b000, 0x04000}, |
||
1061 | {"profile", 0x770000, 0x04000}, |
||
1062 | {"default-config", 0x774000, 0x0b000}, |
||
1063 | {"user-config", 0x780000, 0x40000}, |
||
1064 | {"partition-table", 0x7c0000, 0x10000}, |
||
1065 | {"log", 0x7d0000, 0x20000}, |
||
1066 | {"radio", 0x7f0000, 0x10000}, |
||
1067 | {NULL, 0, 0} |
||
1068 | }, |
||
1069 | |||
1070 | .first_sysupgrade_partition = "os-image", |
||
1071 | .last_sysupgrade_partition = "file-system", |
||
1072 | }, |
||
1073 | |||
1074 | /** Firmware layout for the TL-WR942N V1 */ |
||
1075 | { |
||
1076 | .id = "TLWR942NV1", |
||
1077 | .vendor = "", |
||
1078 | .support_list = |
||
1079 | "SupportList:\r\n" |
||
1080 | "{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n" |
||
1081 | "{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n", |
||
1082 | .support_trail = '\x00', |
||
1083 | .soft_ver = NULL, |
||
1084 | |||
1085 | .partitions = { |
||
1086 | {"fs-uboot", 0x00000, 0x20000}, |
||
1087 | {"firmware", 0x20000, 0xe20000}, |
||
1088 | {"default-mac", 0xe40000, 0x00200}, |
||
1089 | {"pin", 0xe40200, 0x00200}, |
||
1090 | {"product-info", 0xe40400, 0x0fc00}, |
||
1091 | {"partition-table", 0xe50000, 0x10000}, |
||
1092 | {"soft-version", 0xe60000, 0x10000}, |
||
1093 | {"support-list", 0xe70000, 0x10000}, |
||
1094 | {"profile", 0xe80000, 0x10000}, |
||
1095 | {"default-config", 0xe90000, 0x10000}, |
||
1096 | {"user-config", 0xea0000, 0x40000}, |
||
1097 | {"qos-db", 0xee0000, 0x40000}, |
||
1098 | {"certificate", 0xf20000, 0x10000}, |
||
1099 | {"usb-config", 0xfb0000, 0x10000}, |
||
1100 | {"log", 0xfc0000, 0x20000}, |
||
1101 | {"radio-bk", 0xfe0000, 0x10000}, |
||
1102 | {"radio", 0xff0000, 0x10000}, |
||
1103 | {NULL, 0, 0} |
||
1104 | }, |
||
1105 | |||
1106 | .first_sysupgrade_partition = "os-image", |
||
1107 | .last_sysupgrade_partition = "file-system", |
||
1108 | }, |
||
1109 | |||
1110 | /** Firmware layout for the RE350 v1 */ |
||
1111 | { |
||
1112 | .id = "RE350-V1", |
||
1113 | .vendor = "", |
||
1114 | .support_list = |
||
1115 | "SupportList:\n" |
||
1116 | "{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n" |
||
1117 | "{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n" |
||
1118 | "{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n" |
||
1119 | "{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n" |
||
1120 | "{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n" |
||
1121 | "{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n" |
||
1122 | "{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n", |
||
1123 | .support_trail = '\x00', |
||
1124 | .soft_ver = NULL, |
||
1125 | |||
1126 | /** We're using a dynamic kernel/rootfs split here */ |
||
1127 | .partitions = { |
||
1128 | {"fs-uboot", 0x00000, 0x20000}, |
||
1129 | {"firmware", 0x20000, 0x5e0000}, |
||
1130 | {"partition-table", 0x600000, 0x02000}, |
||
1131 | {"default-mac", 0x610000, 0x00020}, |
||
1132 | {"pin", 0x610100, 0x00020}, |
||
1133 | {"product-info", 0x611100, 0x01000}, |
||
1134 | {"soft-version", 0x620000, 0x01000}, |
||
1135 | {"support-list", 0x621000, 0x01000}, |
||
1136 | {"profile", 0x622000, 0x08000}, |
||
1137 | {"user-config", 0x630000, 0x10000}, |
||
1138 | {"default-config", 0x640000, 0x10000}, |
||
1139 | {"radio", 0x7f0000, 0x10000}, |
||
1140 | {NULL, 0, 0} |
||
1141 | }, |
||
1142 | |||
1143 | .first_sysupgrade_partition = "os-image", |
||
1144 | .last_sysupgrade_partition = "file-system" |
||
1145 | }, |
||
1146 | |||
1147 | /** Firmware layout for the RE355 */ |
||
1148 | { |
||
1149 | .id = "RE355", |
||
1150 | .vendor = "", |
||
1151 | .support_list = |
||
1152 | "SupportList:\r\n" |
||
1153 | "{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n" |
||
1154 | "{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n" |
||
1155 | "{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n" |
||
1156 | "{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n" |
||
1157 | "{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n" |
||
1158 | "{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n" |
||
1159 | "{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n" |
||
1160 | "{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n", |
||
1161 | .support_trail = '\x00', |
||
1162 | .soft_ver = NULL, |
||
1163 | |||
1164 | /* We're using a dynamic kernel/rootfs split here */ |
||
1165 | .partitions = { |
||
1166 | {"fs-uboot", 0x00000, 0x20000}, |
||
1167 | {"firmware", 0x20000, 0x5e0000}, |
||
1168 | {"partition-table", 0x600000, 0x02000}, |
||
1169 | {"default-mac", 0x610000, 0x00020}, |
||
1170 | {"pin", 0x610100, 0x00020}, |
||
1171 | {"product-info", 0x611100, 0x01000}, |
||
1172 | {"soft-version", 0x620000, 0x01000}, |
||
1173 | {"support-list", 0x621000, 0x01000}, |
||
1174 | {"profile", 0x622000, 0x08000}, |
||
1175 | {"user-config", 0x630000, 0x10000}, |
||
1176 | {"default-config", 0x640000, 0x10000}, |
||
1177 | {"radio", 0x7f0000, 0x10000}, |
||
1178 | {NULL, 0, 0} |
||
1179 | }, |
||
1180 | |||
1181 | .first_sysupgrade_partition = "os-image", |
||
1182 | .last_sysupgrade_partition = "file-system" |
||
1183 | }, |
||
1184 | |||
1185 | /** Firmware layout for the RE450 */ |
||
1186 | { |
||
1187 | .id = "RE450", |
||
1188 | .vendor = "", |
||
1189 | .support_list = |
||
1190 | "SupportList:\r\n" |
||
1191 | "{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n" |
||
1192 | "{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n" |
||
1193 | "{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n" |
||
1194 | "{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n" |
||
1195 | "{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n" |
||
1196 | "{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n" |
||
1197 | "{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n" |
||
1198 | "{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n", |
||
1199 | .support_trail = '\x00', |
||
1200 | .soft_ver = NULL, |
||
1201 | |||
1202 | /** We're using a dynamic kernel/rootfs split here */ |
||
1203 | .partitions = { |
||
1204 | {"fs-uboot", 0x00000, 0x20000}, |
||
1205 | {"firmware", 0x20000, 0x5e0000}, |
||
1206 | {"partition-table", 0x600000, 0x02000}, |
||
1207 | {"default-mac", 0x610000, 0x00020}, |
||
1208 | {"pin", 0x610100, 0x00020}, |
||
1209 | {"product-info", 0x611100, 0x01000}, |
||
1210 | {"soft-version", 0x620000, 0x01000}, |
||
1211 | {"support-list", 0x621000, 0x01000}, |
||
1212 | {"profile", 0x622000, 0x08000}, |
||
1213 | {"user-config", 0x630000, 0x10000}, |
||
1214 | {"default-config", 0x640000, 0x10000}, |
||
1215 | {"radio", 0x7f0000, 0x10000}, |
||
1216 | {NULL, 0, 0} |
||
1217 | }, |
||
1218 | |||
1219 | .first_sysupgrade_partition = "os-image", |
||
1220 | .last_sysupgrade_partition = "file-system" |
||
1221 | }, |
||
1222 | |||
1223 | /** Firmware layout for the RE450 v2 */ |
||
1224 | { |
||
1225 | .id = "RE450-V2", |
||
1226 | .vendor = "", |
||
1227 | .support_list = |
||
1228 | "SupportList:\r\n" |
||
1229 | "{product_name:RE450,product_ver:2.0.0,special_id:00000000}\r\n" |
||
1230 | "{product_name:RE450,product_ver:2.0.0,special_id:55530000}\r\n" |
||
1231 | "{product_name:RE450,product_ver:2.0.0,special_id:45550000}\r\n" |
||
1232 | "{product_name:RE450,product_ver:2.0.0,special_id:4A500000}\r\n" |
||
1233 | "{product_name:RE450,product_ver:2.0.0,special_id:43410000}\r\n" |
||
1234 | "{product_name:RE450,product_ver:2.0.0,special_id:41550000}\r\n" |
||
1235 | "{product_name:RE450,product_ver:2.0.0,special_id:41530000}\r\n" |
||
1236 | "{product_name:RE450,product_ver:2.0.0,special_id:4B520000}\r\n" |
||
1237 | "{product_name:RE450,product_ver:2.0.0,special_id:42520000}\r\n", |
||
1238 | .support_trail = '\x00', |
||
1239 | .soft_ver = NULL, |
||
1240 | |||
1241 | /* We're using a dynamic kernel/rootfs split here */ |
||
1242 | .partitions = { |
||
1243 | {"fs-uboot", 0x00000, 0x20000}, |
||
1244 | {"firmware", 0x20000, 0x5e0000}, |
||
1245 | {"partition-table", 0x600000, 0x02000}, |
||
1246 | {"default-mac", 0x610000, 0x00020}, |
||
1247 | {"pin", 0x610100, 0x00020}, |
||
1248 | {"product-info", 0x611100, 0x01000}, |
||
1249 | {"soft-version", 0x620000, 0x01000}, |
||
1250 | {"support-list", 0x621000, 0x01000}, |
||
1251 | {"profile", 0x622000, 0x08000}, |
||
1252 | {"user-config", 0x630000, 0x10000}, |
||
1253 | {"default-config", 0x640000, 0x10000}, |
||
1254 | {"radio", 0x7f0000, 0x10000}, |
||
1255 | |||
1256 | {NULL, 0, 0} |
||
1257 | }, |
||
1258 | |||
1259 | .first_sysupgrade_partition = "os-image", |
||
1260 | .last_sysupgrade_partition = "file-system" |
||
1261 | }, |
||
1262 | |||
1263 | {} |
||
1264 | }; |
||
1265 | |||
1266 | #define error(_ret, _errno, _str, ...) \ |
||
1267 | do { \ |
||
1268 | fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \ |
||
1269 | strerror(_errno)); \ |
||
1270 | if (_ret) \ |
||
1271 | exit(_ret); \ |
||
1272 | } while (0) |
||
1273 | |||
1274 | |||
1275 | /** Stores a uint32 as big endian */ |
||
1276 | static inline void put32(uint8_t *buf, uint32_t val) { |
||
1277 | buf[0] = val >> 24; |
||
1278 | buf[1] = val >> 16; |
||
1279 | buf[2] = val >> 8; |
||
1280 | buf[3] = val; |
||
1281 | } |
||
1282 | |||
1283 | /** Allocates a new image partition */ |
||
1284 | static struct image_partition_entry alloc_image_partition(const char *name, size_t len) { |
||
1285 | struct image_partition_entry entry = {name, len, malloc(len)}; |
||
1286 | if (!entry.data) |
||
1287 | error(1, errno, "malloc"); |
||
1288 | |||
1289 | return entry; |
||
1290 | } |
||
1291 | |||
1292 | /** Frees an image partition */ |
||
1293 | static void free_image_partition(struct image_partition_entry entry) { |
||
1294 | free(entry.data); |
||
1295 | } |
||
1296 | |||
1297 | static time_t source_date_epoch = -1; |
||
1298 | static void set_source_date_epoch() { |
||
1299 | char *env = getenv("SOURCE_DATE_EPOCH"); |
||
1300 | char *endptr = env; |
||
1301 | errno = 0; |
||
1302 | if (env && *env) { |
||
1303 | source_date_epoch = strtoull(env, &endptr, 10); |
||
1304 | if (errno || (endptr && *endptr != '\0')) { |
||
1305 | fprintf(stderr, "Invalid SOURCE_DATE_EPOCH"); |
||
1306 | exit(1); |
||
1307 | } |
||
1308 | } |
||
1309 | } |
||
1310 | |||
1311 | /** Generates the partition-table partition */ |
||
1312 | static struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) { |
||
1313 | struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800); |
||
1314 | |||
1315 | char *s = (char *)entry.data, *end = (char *)(s+entry.size); |
||
1316 | |||
1317 | *(s++) = 0x00; |
||
1318 | *(s++) = 0x04; |
||
1319 | *(s++) = 0x00; |
||
1320 | *(s++) = 0x00; |
||
1321 | |||
1322 | size_t i; |
||
1323 | for (i = 0; p[i].name; i++) { |
||
1324 | size_t len = end-s; |
||
1325 | size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size); |
||
1326 | |||
1327 | if (w > len-1) |
||
1328 | error(1, 0, "flash partition table overflow?"); |
||
1329 | |||
1330 | s += w; |
||
1331 | } |
||
1332 | |||
1333 | s++; |
||
1334 | |||
1335 | memset(s, 0xff, end-s); |
||
1336 | |||
1337 | return entry; |
||
1338 | } |
||
1339 | |||
1340 | |||
1341 | /** Generates a binary-coded decimal representation of an integer in the range [0, 99] */ |
||
1342 | static inline uint8_t bcd(uint8_t v) { |
||
1343 | return 0x10 * (v/10) + v%10; |
||
1344 | } |
||
1345 | |||
1346 | |||
1347 | /** Generates the soft-version partition */ |
||
1348 | static struct image_partition_entry make_soft_version(uint32_t rev) { |
||
1349 | struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version)); |
||
1350 | struct soft_version *s = (struct soft_version *)entry.data; |
||
1351 | |||
1352 | time_t t; |
||
1353 | |||
1354 | if (source_date_epoch != -1) |
||
1355 | t = source_date_epoch; |
||
1356 | else if (time(&t) == (time_t)(-1)) |
||
1357 | error(1, errno, "time"); |
||
1358 | |||
1359 | struct tm *tm = localtime(&t); |
||
1360 | |||
1361 | s->magic = htonl(0x0000000c); |
||
1362 | s->zero = 0; |
||
1363 | s->pad1 = 0xff; |
||
1364 | |||
1365 | s->version_major = 0; |
||
1366 | s->version_minor = 0; |
||
1367 | s->version_patch = 0; |
||
1368 | |||
1369 | s->year_hi = bcd((1900+tm->tm_year)/100); |
||
1370 | s->year_lo = bcd(tm->tm_year%100); |
||
1371 | s->month = bcd(tm->tm_mon+1); |
||
1372 | s->day = bcd(tm->tm_mday); |
||
1373 | s->rev = htonl(rev); |
||
1374 | |||
1375 | s->pad2 = 0xff; |
||
1376 | |||
1377 | return entry; |
||
1378 | } |
||
1379 | |||
1380 | static struct image_partition_entry make_soft_version_from_string(const char *soft_ver) { |
||
1381 | /** String length _including_ the terminating zero byte */ |
||
1382 | uint32_t ver_len = strlen(soft_ver) + 1; |
||
1383 | /** Partition contains 64 bit header, the version string, and one additional null byte */ |
||
1384 | size_t partition_len = 2*sizeof(uint32_t) + ver_len + 1; |
||
1385 | struct image_partition_entry entry = alloc_image_partition("soft-version", partition_len); |
||
1386 | |||
1387 | uint32_t *len = (uint32_t *)entry.data; |
||
1388 | len[0] = htonl(ver_len); |
||
1389 | len[1] = 0; |
||
1390 | memcpy(&len[2], soft_ver, ver_len); |
||
1391 | |||
1392 | entry.data[partition_len - 1] = 0; |
||
1393 | |||
1394 | return entry; |
||
1395 | } |
||
1396 | |||
1397 | /** Generates the support-list partition */ |
||
1398 | static struct image_partition_entry make_support_list(struct device_info *info) { |
||
1399 | size_t len = strlen(info->support_list); |
||
1400 | struct image_partition_entry entry = alloc_image_partition("support-list", len + 9); |
||
1401 | |||
1402 | put32(entry.data, len); |
||
1403 | memset(entry.data+4, 0, 4); |
||
1404 | memcpy(entry.data+8, info->support_list, len); |
||
1405 | entry.data[len+8] = info->support_trail; |
||
1406 | |||
1407 | return entry; |
||
1408 | } |
||
1409 | |||
1410 | /** Creates a new image partition with an arbitrary name from a file */ |
||
1411 | static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof, struct flash_partition_entry *file_system_partition) { |
||
1412 | struct stat statbuf; |
||
1413 | |||
1414 | if (stat(filename, &statbuf) < 0) |
||
1415 | error(1, errno, "unable to stat file `%s'", filename); |
||
1416 | |||
1417 | size_t len = statbuf.st_size; |
||
1418 | |||
1419 | if (add_jffs2_eof) |
||
1420 | if (file_system_partition) |
||
1421 | len = ALIGN(len + file_system_partition->base, 0x10000) + sizeof(jffs2_eof_mark) - file_system_partition->base; |
||
1422 | else |
||
1423 | len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark); |
||
1424 | |||
1425 | struct image_partition_entry entry = alloc_image_partition(part_name, len); |
||
1426 | |||
1427 | FILE *file = fopen(filename, "rb"); |
||
1428 | if (!file) |
||
1429 | error(1, errno, "unable to open file `%s'", filename); |
||
1430 | |||
1431 | if (fread(entry.data, statbuf.st_size, 1, file) != 1) |
||
1432 | error(1, errno, "unable to read file `%s'", filename); |
||
1433 | |||
1434 | if (add_jffs2_eof) { |
||
1435 | uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size; |
||
1436 | |||
1437 | memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark)); |
||
1438 | memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark)); |
||
1439 | } |
||
1440 | |||
1441 | fclose(file); |
||
1442 | |||
1443 | return entry; |
||
1444 | } |
||
1445 | |||
1446 | /** Creates a new image partition from arbitrary data */ |
||
1447 | static struct image_partition_entry put_data(const char *part_name, const char *datain, size_t len) { |
||
1448 | |||
1449 | struct image_partition_entry entry = alloc_image_partition(part_name, len); |
||
1450 | |||
1451 | memcpy(entry.data, datain, len); |
||
1452 | |||
1453 | return entry; |
||
1454 | } |
||
1455 | |||
1456 | /** |
||
1457 | Copies a list of image partitions into an image buffer and generates the image partition table while doing so |
||
1458 | |||
1459 | Example image partition table: |
||
1460 | |||
1461 | fwup-ptn partition-table base 0x00800 size 0x00800 |
||
1462 | fwup-ptn os-image base 0x01000 size 0x113b45 |
||
1463 | fwup-ptn file-system base 0x114b45 size 0x1d0004 |
||
1464 | fwup-ptn support-list base 0x2e4b49 size 0x000d1 |
||
1465 | |||
1466 | Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"), |
||
1467 | the end of the partition table is marked with a zero byte. |
||
1468 | |||
1469 | The firmware image must contain at least the partition-table and support-list partitions |
||
1470 | to be accepted. There aren't any alignment constraints for the image partitions. |
||
1471 | |||
1472 | The partition-table partition contains the actual flash layout; partitions |
||
1473 | from the image partition table are mapped to the corresponding flash partitions during |
||
1474 | the firmware upgrade. The support-list partition contains a list of devices supported by |
||
1475 | the firmware image. |
||
1476 | |||
1477 | The base offsets in the firmware partition table are relative to the end |
||
1478 | of the vendor information block, so the partition-table partition will |
||
1479 | actually start at offset 0x1814 of the image. |
||
1480 | |||
1481 | I think partition-table must be the first partition in the firmware image. |
||
1482 | */ |
||
1483 | static void put_partitions(uint8_t *buffer, const struct flash_partition_entry *flash_parts, const struct image_partition_entry *parts) { |
||
1484 | size_t i, j; |
||
1485 | char *image_pt = (char *)buffer, *end = image_pt + 0x800; |
||
1486 | |||
1487 | size_t base = 0x800; |
||
1488 | for (i = 0; parts[i].name; i++) { |
||
1489 | for (j = 0; flash_parts[j].name; j++) { |
||
1490 | if (!strcmp(flash_parts[j].name, parts[i].name)) { |
||
1491 | if (parts[i].size > flash_parts[j].size) |
||
1492 | error(1, 0, "%s partition too big (more than %u bytes)", flash_parts[j].name, (unsigned)flash_parts[j].size); |
||
1493 | break; |
||
1494 | } |
||
1495 | } |
||
1496 | |||
1497 | assert(flash_parts[j].name); |
||
1498 | |||
1499 | memcpy(buffer + base, parts[i].data, parts[i].size); |
||
1500 | |||
1501 | size_t len = end-image_pt; |
||
1502 | size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size); |
||
1503 | |||
1504 | if (w > len-1) |
||
1505 | error(1, 0, "image partition table overflow?"); |
||
1506 | |||
1507 | image_pt += w; |
||
1508 | |||
1509 | base += parts[i].size; |
||
1510 | } |
||
1511 | } |
||
1512 | |||
1513 | /** Generates and writes the image MD5 checksum */ |
||
1514 | static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) { |
||
1515 | MD5_CTX ctx; |
||
1516 | |||
1517 | MD5_Init(&ctx); |
||
1518 | MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt)); |
||
1519 | MD5_Update(&ctx, buffer, len); |
||
1520 | MD5_Final(md5, &ctx); |
||
1521 | } |
||
1522 | |||
1523 | |||
1524 | /** |
||
1525 | Generates the firmware image in factory format |
||
1526 | |||
1527 | Image format: |
||
1528 | |||
1529 | Bytes (hex) Usage |
||
1530 | ----------- ----- |
||
1531 | 0000-0003 Image size (4 bytes, big endian) |
||
1532 | 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14) |
||
1533 | 0014-0017 Vendor information length (without padding) (4 bytes, big endian) |
||
1534 | 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older |
||
1535 | (VxWorks-based) TP-LINK devices which use a smaller vendor information block) |
||
1536 | 1014-1813 Image partition table (2048 bytes, padded with 0xff) |
||
1537 | 1814-xxxx Firmware partitions |
||
1538 | */ |
||
1539 | static void * generate_factory_image(struct device_info *info, const struct image_partition_entry *parts, size_t *len) { |
||
1540 | *len = 0x1814; |
||
1541 | |||
1542 | size_t i; |
||
1543 | for (i = 0; parts[i].name; i++) |
||
1544 | *len += parts[i].size; |
||
1545 | |||
1546 | uint8_t *image = malloc(*len); |
||
1547 | if (!image) |
||
1548 | error(1, errno, "malloc"); |
||
1549 | |||
1550 | memset(image, 0xff, *len); |
||
1551 | put32(image, *len); |
||
1552 | |||
1553 | if (info->vendor) { |
||
1554 | size_t vendor_len = strlen(info->vendor); |
||
1555 | put32(image+0x14, vendor_len); |
||
1556 | memcpy(image+0x18, info->vendor, vendor_len); |
||
1557 | } |
||
1558 | |||
1559 | put_partitions(image + 0x1014, info->partitions, parts); |
||
1560 | put_md5(image+0x04, image+0x14, *len-0x14); |
||
1561 | |||
1562 | return image; |
||
1563 | } |
||
1564 | |||
1565 | /** |
||
1566 | Generates the firmware image in sysupgrade format |
||
1567 | |||
1568 | This makes some assumptions about the provided flash and image partition tables and |
||
1569 | should be generalized when TP-LINK starts building its safeloader into hardware with |
||
1570 | different flash layouts. |
||
1571 | */ |
||
1572 | static void * generate_sysupgrade_image(struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) { |
||
1573 | size_t i, j; |
||
1574 | size_t flash_first_partition_index = 0; |
||
1575 | size_t flash_last_partition_index = 0; |
||
1576 | const struct flash_partition_entry *flash_first_partition = NULL; |
||
1577 | const struct flash_partition_entry *flash_last_partition = NULL; |
||
1578 | const struct image_partition_entry *image_last_partition = NULL; |
||
1579 | |||
1580 | /** Find first and last partitions */ |
||
1581 | for (i = 0; info->partitions[i].name; i++) { |
||
1582 | if (!strcmp(info->partitions[i].name, info->first_sysupgrade_partition)) { |
||
1583 | flash_first_partition = &info->partitions[i]; |
||
1584 | flash_first_partition_index = i; |
||
1585 | } else if (!strcmp(info->partitions[i].name, info->last_sysupgrade_partition)) { |
||
1586 | flash_last_partition = &info->partitions[i]; |
||
1587 | flash_last_partition_index = i; |
||
1588 | } |
||
1589 | } |
||
1590 | |||
1591 | assert(flash_first_partition && flash_last_partition); |
||
1592 | assert(flash_first_partition_index < flash_last_partition_index); |
||
1593 | |||
1594 | /** Find last partition from image to calculate needed size */ |
||
1595 | for (i = 0; image_parts[i].name; i++) { |
||
1596 | if (!strcmp(image_parts[i].name, info->last_sysupgrade_partition)) { |
||
1597 | image_last_partition = &image_parts[i]; |
||
1598 | break; |
||
1599 | } |
||
1600 | } |
||
1601 | |||
1602 | assert(image_last_partition); |
||
1603 | |||
1604 | *len = flash_last_partition->base - flash_first_partition->base + image_last_partition->size; |
||
1605 | |||
1606 | uint8_t *image = malloc(*len); |
||
1607 | if (!image) |
||
1608 | error(1, errno, "malloc"); |
||
1609 | |||
1610 | memset(image, 0xff, *len); |
||
1611 | |||
1612 | for (i = flash_first_partition_index; i <= flash_last_partition_index; i++) { |
||
1613 | for (j = 0; image_parts[j].name; j++) { |
||
1614 | if (!strcmp(info->partitions[i].name, image_parts[j].name)) { |
||
1615 | if (image_parts[j].size > info->partitions[i].size) |
||
1616 | error(1, 0, "%s partition too big (more than %u bytes)", info->partitions[i].name, (unsigned)info->partitions[i].size); |
||
1617 | memcpy(image + info->partitions[i].base - flash_first_partition->base, image_parts[j].data, image_parts[j].size); |
||
1618 | break; |
||
1619 | } |
||
1620 | |||
1621 | assert(image_parts[j].name); |
||
1622 | } |
||
1623 | } |
||
1624 | |||
1625 | return image; |
||
1626 | } |
||
1627 | |||
1628 | /** Generates an image according to a given layout and writes it to a file */ |
||
1629 | static void build_image(const char *output, |
||
1630 | const char *kernel_image, |
||
1631 | const char *rootfs_image, |
||
1632 | uint32_t rev, |
||
1633 | bool add_jffs2_eof, |
||
1634 | bool sysupgrade, |
||
1635 | struct device_info *info) { |
||
1636 | |||
1637 | size_t i; |
||
1638 | |||
1639 | struct image_partition_entry parts[7] = {}; |
||
1640 | |||
1641 | struct flash_partition_entry *firmware_partition = NULL; |
||
1642 | struct flash_partition_entry *os_image_partition = NULL; |
||
1643 | struct flash_partition_entry *file_system_partition = NULL; |
||
1644 | size_t firmware_partition_index = 0; |
||
1645 | |||
1646 | for (i = 0; info->partitions[i].name; i++) { |
||
1647 | if (!strcmp(info->partitions[i].name, "firmware")) |
||
1648 | { |
||
1649 | firmware_partition = &info->partitions[i]; |
||
1650 | firmware_partition_index = i; |
||
1651 | } |
||
1652 | } |
||
1653 | |||
1654 | if (firmware_partition) |
||
1655 | { |
||
1656 | os_image_partition = &info->partitions[firmware_partition_index]; |
||
1657 | file_system_partition = &info->partitions[firmware_partition_index + 1]; |
||
1658 | |||
1659 | struct stat kernel; |
||
1660 | if (stat(kernel_image, &kernel) < 0) |
||
1661 | error(1, errno, "unable to stat file `%s'", kernel_image); |
||
1662 | |||
1663 | if (kernel.st_size > firmware_partition->size) |
||
1664 | error(1, 0, "kernel overflowed firmware partition\n"); |
||
1665 | |||
1666 | for (i = MAX_PARTITIONS-1; i >= firmware_partition_index + 1; i--) |
||
1667 | info->partitions[i+1] = info->partitions[i]; |
||
1668 | |||
1669 | file_system_partition->name = "file-system"; |
||
1670 | file_system_partition->base = firmware_partition->base + kernel.st_size; |
||
1671 | |||
1672 | /* Align partition start to erase blocks for factory images only */ |
||
1673 | if (!sysupgrade) |
||
1674 | file_system_partition->base = ALIGN(firmware_partition->base + kernel.st_size, 0x10000); |
||
1675 | |||
1676 | file_system_partition->size = firmware_partition->size - file_system_partition->base; |
||
1677 | |||
1678 | os_image_partition->name = "os-image"; |
||
1679 | os_image_partition->size = kernel.st_size; |
||
1680 | } |
||
1681 | |||
1682 | parts[0] = make_partition_table(info->partitions); |
||
1683 | if (info->soft_ver) |
||
1684 | parts[1] = make_soft_version_from_string(info->soft_ver); |
||
1685 | else |
||
1686 | parts[1] = make_soft_version(rev); |
||
1687 | |||
1688 | parts[2] = make_support_list(info); |
||
1689 | parts[3] = read_file("os-image", kernel_image, false, NULL); |
||
1690 | parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof, file_system_partition); |
||
1691 | |||
1692 | /* Some devices need the extra-para partition to accept the firmware */ |
||
1693 | if (strcasecmp(info->id, "ARCHER-C2-V3") == 0 || |
||
1694 | strcasecmp(info->id, "ARCHER-C25-V1") == 0 || |
||
1695 | strcasecmp(info->id, "ARCHER-C59-V2") == 0 || |
||
1696 | strcasecmp(info->id, "ARCHER-C60-V2") == 0 || |
||
1697 | strcasecmp(info->id, "TLWR1043NV5") == 0) { |
||
1698 | const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; |
||
1699 | parts[5] = put_data("extra-para", mdat, 11); |
||
1700 | } else if (strcasecmp(info->id, "ARCHER-A7-V5") == 0 || strcasecmp(info->id, "ARCHER-C7-V4") == 0 || strcasecmp(info->id, "ARCHER-C7-V5") == 0) { |
||
1701 | const char mdat[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00}; |
||
1702 | parts[5] = put_data("extra-para", mdat, 11); |
||
1703 | } else if (strcasecmp(info->id, "ARCHER-C6-V2") == 0) { |
||
1704 | const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}; |
||
1705 | parts[5] = put_data("extra-para", mdat, 11); |
||
1706 | } |
||
1707 | |||
1708 | size_t len; |
||
1709 | void *image; |
||
1710 | if (sysupgrade) |
||
1711 | image = generate_sysupgrade_image(info, parts, &len); |
||
1712 | else |
||
1713 | image = generate_factory_image(info, parts, &len); |
||
1714 | |||
1715 | FILE *file = fopen(output, "wb"); |
||
1716 | if (!file) |
||
1717 | error(1, errno, "unable to open output file"); |
||
1718 | |||
1719 | if (fwrite(image, len, 1, file) != 1) |
||
1720 | error(1, 0, "unable to write output file"); |
||
1721 | |||
1722 | fclose(file); |
||
1723 | |||
1724 | free(image); |
||
1725 | |||
1726 | for (i = 0; parts[i].name; i++) |
||
1727 | free_image_partition(parts[i]); |
||
1728 | } |
||
1729 | |||
1730 | /** Usage output */ |
||
1731 | static void usage(const char *argv0) { |
||
1732 | fprintf(stderr, |
||
1733 | "Usage: %s [OPTIONS...]\n" |
||
1734 | "\n" |
||
1735 | "Options:\n" |
||
1736 | " -h show this help\n" |
||
1737 | "\n" |
||
1738 | "Create a new image:\n" |
||
1739 | " -B <board> create image for the board specified with <board>\n" |
||
1740 | " -k <file> read kernel image from the file <file>\n" |
||
1741 | " -r <file> read rootfs image from the file <file>\n" |
||
1742 | " -o <file> write output to the file <file>\n" |
||
1743 | " -V <rev> sets the revision number to <rev>\n" |
||
1744 | " -j add jffs2 end-of-filesystem markers\n" |
||
1745 | " -S create sysupgrade instead of factory image\n" |
||
1746 | "Extract an old image:\n" |
||
1747 | " -x <file> extract all oem firmware partition\n" |
||
1748 | " -d <dir> destination to extract the firmware partition\n" |
||
1749 | " -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n", |
||
1750 | argv0 |
||
1751 | ); |
||
1752 | }; |
||
1753 | |||
1754 | |||
1755 | static struct device_info *find_board(const char *id) |
||
1756 | { |
||
1757 | struct device_info *board = NULL; |
||
1758 | |||
1759 | for (board = boards; board->id != NULL; board++) |
||
1760 | if (strcasecmp(id, board->id) == 0) |
||
1761 | return board; |
||
1762 | |||
1763 | return NULL; |
||
1764 | } |
||
1765 | |||
1766 | static int add_flash_partition( |
||
1767 | struct flash_partition_entry *part_list, |
||
1768 | size_t max_entries, |
||
1769 | const char *name, |
||
1770 | unsigned long base, |
||
1771 | unsigned long size) |
||
1772 | { |
||
1773 | int ptr; |
||
1774 | /* check if the list has a free entry */ |
||
1775 | for (ptr = 0; ptr < max_entries; ptr++, part_list++) { |
||
1776 | if (part_list->name == NULL && |
||
1777 | part_list->base == 0 && |
||
1778 | part_list->size == 0) |
||
1779 | break; |
||
1780 | } |
||
1781 | |||
1782 | if (ptr == max_entries) { |
||
1783 | error(1, 0, "No free flash part entry available."); |
||
1784 | } |
||
1785 | |||
1786 | part_list->name = calloc(1, strlen(name) + 1); |
||
1787 | if (!part_list->name) { |
||
1788 | error(1, 0, "Unable to allocate memory"); |
||
1789 | } |
||
1790 | |||
1791 | memcpy((char *)part_list->name, name, strlen(name)); |
||
1792 | part_list->base = base; |
||
1793 | part_list->size = size; |
||
1794 | |||
1795 | return 0; |
||
1796 | } |
||
1797 | |||
1798 | /** read the partition table into struct flash_partition_entry */ |
||
1799 | static int read_partition_table( |
||
1800 | FILE *file, long offset, |
||
1801 | struct flash_partition_entry *entries, size_t max_entries, |
||
1802 | int type) |
||
1803 | { |
||
1804 | char buf[2048]; |
||
1805 | char *ptr, *end; |
||
1806 | const char *parthdr = NULL; |
||
1807 | const char *fwuphdr = "fwup-ptn"; |
||
1808 | const char *flashhdr = "partition"; |
||
1809 | |||
1810 | /* TODO: search for the partition table */ |
||
1811 | |||
1812 | switch(type) { |
||
1813 | case 0: |
||
1814 | parthdr = fwuphdr; |
||
1815 | break; |
||
1816 | case 1: |
||
1817 | parthdr = flashhdr; |
||
1818 | break; |
||
1819 | default: |
||
1820 | error(1, 0, "Invalid partition table"); |
||
1821 | } |
||
1822 | |||
1823 | if (fseek(file, offset, SEEK_SET) < 0) |
||
1824 | error(1, errno, "Can not seek in the firmware"); |
||
1825 | |||
1826 | if (fread(buf, 1, 2048, file) < 0) |
||
1827 | error(1, errno, "Can not read fwup-ptn from the firmware"); |
||
1828 | |||
1829 | buf[2047] = '\0'; |
||
1830 | |||
1831 | /* look for the partition header */ |
||
1832 | if (memcmp(buf, parthdr, strlen(parthdr)) != 0) { |
||
1833 | fprintf(stderr, "DEBUG: can not find fwuphdr\n"); |
||
1834 | return 1; |
||
1835 | } |
||
1836 | |||
1837 | ptr = buf; |
||
1838 | end = buf + sizeof(buf); |
||
1839 | while ((ptr + strlen(parthdr)) < end && |
||
1840 | memcmp(ptr, parthdr, strlen(parthdr)) == 0) { |
||
1841 | char *end_part; |
||
1842 | char *end_element; |
||
1843 | |||
1844 | char name[32] = { 0 }; |
||
1845 | int name_len = 0; |
||
1846 | unsigned long base = 0; |
||
1847 | unsigned long size = 0; |
||
1848 | |||
1849 | end_part = memchr(ptr, '\n', (end - ptr)); |
||
1850 | if (end_part == NULL) { |
||
1851 | /* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */ |
||
1852 | break; |
||
1853 | } |
||
1854 | |||
1855 | for (int i = 0; i <= 4; i++) { |
||
1856 | if (end_part <= ptr) |
||
1857 | break; |
||
1858 | |||
1859 | end_element = memchr(ptr, 0x20, (end_part - ptr)); |
||
1860 | if (end_element == NULL) { |
||
1861 | error(1, errno, "Ignoring the rest of the partition entries."); |
||
1862 | break; |
||
1863 | } |
||
1864 | |||
1865 | switch (i) { |
||
1866 | /* partition header */ |
||
1867 | case 0: |
||
1868 | ptr = end_element + 1; |
||
1869 | continue; |
||
1870 | /* name */ |
||
1871 | case 1: |
||
1872 | name_len = (end_element - ptr) > 31 ? 31 : (end_element - ptr); |
||
1873 | strncpy(name, ptr, name_len); |
||
1874 | name[name_len] = '\0'; |
||
1875 | ptr = end_element + 1; |
||
1876 | continue; |
||
1877 | |||
1878 | /* string "base" */ |
||
1879 | case 2: |
||
1880 | ptr = end_element + 1; |
||
1881 | continue; |
||
1882 | |||
1883 | /* actual base */ |
||
1884 | case 3: |
||
1885 | base = strtoul(ptr, NULL, 16); |
||
1886 | ptr = end_element + 1; |
||
1887 | continue; |
||
1888 | |||
1889 | /* string "size" */ |
||
1890 | case 4: |
||
1891 | ptr = end_element + 1; |
||
1892 | /* actual size. The last element doesn't have a sepeartor */ |
||
1893 | size = strtoul(ptr, NULL, 16); |
||
1894 | /* the part ends with 0x09, 0x0d, 0x0a */ |
||
1895 | ptr = end_part + 1; |
||
1896 | add_flash_partition(entries, max_entries, name, base, size); |
||
1897 | continue; |
||
1898 | } |
||
1899 | } |
||
1900 | } |
||
1901 | |||
1902 | return 0; |
||
1903 | } |
||
1904 | |||
1905 | static void write_partition( |
||
1906 | FILE *input_file, |
||
1907 | size_t firmware_offset, |
||
1908 | struct flash_partition_entry *entry, |
||
1909 | FILE *output_file) |
||
1910 | { |
||
1911 | char buf[4096]; |
||
1912 | size_t offset; |
||
1913 | |||
1914 | fseek(input_file, entry->base + firmware_offset, SEEK_SET); |
||
1915 | |||
1916 | for (offset = 0; sizeof(buf) + offset <= entry->size; offset += sizeof(buf)) { |
||
1917 | if (fread(buf, sizeof(buf), 1, input_file) < 0) |
||
1918 | error(1, errno, "Can not read partition from input_file"); |
||
1919 | |||
1920 | if (fwrite(buf, sizeof(buf), 1, output_file) < 0) |
||
1921 | error(1, errno, "Can not write partition to output_file"); |
||
1922 | } |
||
1923 | /* write last chunk smaller than buffer */ |
||
1924 | if (offset < entry->size) { |
||
1925 | offset = entry->size - offset; |
||
1926 | if (fread(buf, offset, 1, input_file) < 0) |
||
1927 | error(1, errno, "Can not read partition from input_file"); |
||
1928 | if (fwrite(buf, offset, 1, output_file) < 0) |
||
1929 | error(1, errno, "Can not write partition to output_file"); |
||
1930 | } |
||
1931 | } |
||
1932 | |||
1933 | static int extract_firmware_partition(FILE *input_file, size_t firmware_offset, struct flash_partition_entry *entry, const char *output_directory) |
||
1934 | { |
||
1935 | FILE *output_file; |
||
1936 | char output[PATH_MAX]; |
||
1937 | |||
1938 | snprintf(output, PATH_MAX, "%s/%s", output_directory, entry->name); |
||
1939 | output_file = fopen(output, "wb+"); |
||
1940 | if (output_file == NULL) { |
||
1941 | error(1, errno, "Can not open output file %s", output); |
||
1942 | } |
||
1943 | |||
1944 | write_partition(input_file, firmware_offset, entry, output_file); |
||
1945 | |||
1946 | fclose(output_file); |
||
1947 | |||
1948 | return 0; |
||
1949 | } |
||
1950 | |||
1951 | /** extract all partitions from the firmware file */ |
||
1952 | static int extract_firmware(const char *input, const char *output_directory) |
||
1953 | { |
||
1954 | struct flash_partition_entry entries[16] = { 0 }; |
||
1955 | size_t max_entries = 16; |
||
1956 | size_t firmware_offset = 0x1014; |
||
1957 | FILE *input_file; |
||
1958 | |||
1959 | struct stat statbuf; |
||
1960 | |||
1961 | /* check input file */ |
||
1962 | if (stat(input, &statbuf)) { |
||
1963 | error(1, errno, "Can not read input firmware %s", input); |
||
1964 | } |
||
1965 | |||
1966 | /* check if output directory exists */ |
||
1967 | if (stat(output_directory, &statbuf)) { |
||
1968 | error(1, errno, "Failed to stat output directory %s", output_directory); |
||
1969 | } |
||
1970 | |||
1971 | if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { |
||
1972 | error(1, errno, "Given output directory is not a directory %s", output_directory); |
||
1973 | } |
||
1974 | |||
1975 | input_file = fopen(input, "rb"); |
||
1976 | |||
1977 | if (read_partition_table(input_file, firmware_offset, entries, 16, 0) != 0) { |
||
1978 | error(1, 0, "Error can not read the partition table (fwup-ptn)"); |
||
1979 | } |
||
1980 | |||
1981 | for (int i = 0; i < max_entries; i++) { |
||
1982 | if (entries[i].name == NULL && |
||
1983 | entries[i].base == 0 && |
||
1984 | entries[i].size == 0) |
||
1985 | continue; |
||
1986 | |||
1987 | extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory); |
||
1988 | } |
||
1989 | |||
1990 | return 0; |
||
1991 | } |
||
1992 | |||
1993 | static struct flash_partition_entry *find_partition( |
||
1994 | struct flash_partition_entry *entries, size_t max_entries, |
||
1995 | const char *name, const char *error_msg) |
||
1996 | { |
||
1997 | for (int i = 0; i < max_entries; i++, entries++) { |
||
1998 | if (strcmp(entries->name, name) == 0) |
||
1999 | return entries; |
||
2000 | } |
||
2001 | |||
2002 | error(1, 0, "%s", error_msg); |
||
2003 | return NULL; |
||
2004 | } |
||
2005 | |||
2006 | static void write_ff(FILE *output_file, size_t size) |
||
2007 | { |
||
2008 | char buf[4096]; |
||
2009 | int offset; |
||
2010 | |||
2011 | memset(buf, 0xff, sizeof(buf)); |
||
2012 | |||
2013 | for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) { |
||
2014 | if (fwrite(buf, sizeof(buf), 1, output_file) < 0) |
||
2015 | error(1, errno, "Can not write 0xff to output_file"); |
||
2016 | } |
||
2017 | |||
2018 | /* write last chunk smaller than buffer */ |
||
2019 | if (offset < size) { |
||
2020 | offset = size - offset; |
||
2021 | if (fwrite(buf, offset, 1, output_file) < 0) |
||
2022 | error(1, errno, "Can not write partition to output_file"); |
||
2023 | } |
||
2024 | } |
||
2025 | |||
2026 | static void convert_firmware(const char *input, const char *output) |
||
2027 | { |
||
2028 | struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 }; |
||
2029 | struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 }; |
||
2030 | struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL; |
||
2031 | struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL; |
||
2032 | struct flash_partition_entry *fwup_partition_table = NULL; |
||
2033 | size_t firmware_offset = 0x1014; |
||
2034 | FILE *input_file, *output_file; |
||
2035 | |||
2036 | struct stat statbuf; |
||
2037 | |||
2038 | /* check input file */ |
||
2039 | if (stat(input, &statbuf)) { |
||
2040 | error(1, errno, "Can not read input firmware %s", input); |
||
2041 | } |
||
2042 | |||
2043 | input_file = fopen(input, "rb"); |
||
2044 | if (!input_file) |
||
2045 | error(1, 0, "Can not open input firmware %s", input); |
||
2046 | |||
2047 | output_file = fopen(output, "wb"); |
||
2048 | if (!output_file) |
||
2049 | error(1, 0, "Can not open output firmware %s", output); |
||
2050 | |||
2051 | if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) { |
||
2052 | error(1, 0, "Error can not read the partition table (fwup-ptn)"); |
||
2053 | } |
||
2054 | |||
2055 | fwup_os_image = find_partition(fwup, MAX_PARTITIONS, |
||
2056 | "os-image", "Error can not find os-image partition (fwup)"); |
||
2057 | fwup_file_system = find_partition(fwup, MAX_PARTITIONS, |
||
2058 | "file-system", "Error can not find file-system partition (fwup)"); |
||
2059 | fwup_partition_table = find_partition(fwup, MAX_PARTITIONS, |
||
2060 | "partition-table", "Error can not find partition-table partition"); |
||
2061 | |||
2062 | /* the flash partition table has a 0x00000004 magic haeder */ |
||
2063 | if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0) |
||
2064 | error(1, 0, "Error can not read the partition table (flash)"); |
||
2065 | |||
2066 | flash_os_image = find_partition(flash, MAX_PARTITIONS, |
||
2067 | "os-image", "Error can not find os-image partition (flash)"); |
||
2068 | flash_file_system = find_partition(flash, MAX_PARTITIONS, |
||
2069 | "file-system", "Error can not find file-system partition (flash)"); |
||
2070 | |||
2071 | /* write os_image to 0x0 */ |
||
2072 | write_partition(input_file, firmware_offset, fwup_os_image, output_file); |
||
2073 | write_ff(output_file, flash_os_image->size - fwup_os_image->size); |
||
2074 | |||
2075 | /* write file-system behind os_image */ |
||
2076 | fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET); |
||
2077 | write_partition(input_file, firmware_offset, fwup_file_system, output_file); |
||
2078 | write_ff(output_file, flash_file_system->size - fwup_file_system->size); |
||
2079 | |||
2080 | fclose(output_file); |
||
2081 | fclose(input_file); |
||
2082 | } |
||
2083 | |||
2084 | int main(int argc, char *argv[]) { |
||
2085 | const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL; |
||
2086 | const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL; |
||
2087 | bool add_jffs2_eof = false, sysupgrade = false; |
||
2088 | unsigned rev = 0; |
||
2089 | struct device_info *info; |
||
2090 | set_source_date_epoch(); |
||
2091 | |||
2092 | while (true) { |
||
2093 | int c; |
||
2094 | |||
2095 | c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:"); |
||
2096 | if (c == -1) |
||
2097 | break; |
||
2098 | |||
2099 | switch (c) { |
||
2100 | case 'B': |
||
2101 | board = optarg; |
||
2102 | break; |
||
2103 | |||
2104 | case 'k': |
||
2105 | kernel_image = optarg; |
||
2106 | break; |
||
2107 | |||
2108 | case 'r': |
||
2109 | rootfs_image = optarg; |
||
2110 | break; |
||
2111 | |||
2112 | case 'o': |
||
2113 | output = optarg; |
||
2114 | break; |
||
2115 | |||
2116 | case 'V': |
||
2117 | sscanf(optarg, "r%u", &rev); |
||
2118 | break; |
||
2119 | |||
2120 | case 'j': |
||
2121 | add_jffs2_eof = true; |
||
2122 | break; |
||
2123 | |||
2124 | case 'S': |
||
2125 | sysupgrade = true; |
||
2126 | break; |
||
2127 | |||
2128 | case 'h': |
||
2129 | usage(argv[0]); |
||
2130 | return 0; |
||
2131 | |||
2132 | case 'd': |
||
2133 | output_directory = optarg; |
||
2134 | break; |
||
2135 | |||
2136 | case 'x': |
||
2137 | extract_image = optarg; |
||
2138 | break; |
||
2139 | |||
2140 | case 'z': |
||
2141 | convert_image = optarg; |
||
2142 | break; |
||
2143 | |||
2144 | default: |
||
2145 | usage(argv[0]); |
||
2146 | return 1; |
||
2147 | } |
||
2148 | } |
||
2149 | |||
2150 | if (extract_image || output_directory) { |
||
2151 | if (!extract_image) |
||
2152 | error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x"); |
||
2153 | if (!output_directory) |
||
2154 | error(1, 0, "Can not extract an image without output directory. Use -d <dir>"); |
||
2155 | extract_firmware(extract_image, output_directory); |
||
2156 | } else if (convert_image) { |
||
2157 | if (!output) |
||
2158 | error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>"); |
||
2159 | convert_firmware(convert_image, output); |
||
2160 | } else { |
||
2161 | if (!board) |
||
2162 | error(1, 0, "no board has been specified"); |
||
2163 | if (!kernel_image) |
||
2164 | error(1, 0, "no kernel image has been specified"); |
||
2165 | if (!rootfs_image) |
||
2166 | error(1, 0, "no rootfs image has been specified"); |
||
2167 | if (!output) |
||
2168 | error(1, 0, "no output filename has been specified"); |
||
2169 | |||
2170 | info = find_board(board); |
||
2171 | |||
2172 | if (info == NULL) |
||
2173 | error(1, 0, "unsupported board %s", board); |
||
2174 | |||
2175 | build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info); |
||
2176 | } |
||
2177 | |||
2178 | return 0; |
||
2179 | } |