Fix FS#12824 : Malfunctioning FFT plugin in Sansa Clip Zip
[maemo-rb.git] / utils / rknanoutils / rkboottool / rkboottool.c
blobd131d9701c9f46ba23e94adb4ab6a68642dde57b
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdbool.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <getopt.h>
7 #include <stdarg.h>
8 #include "misc.h"
9 #include "elf.h"
11 #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0)
13 bool g_debug = false;
15 typedef uint8_t packed_bcd_uint8_t;
16 typedef uint16_t packed_bcd_uint16_t;
18 struct rknano_date_t
20 packed_bcd_uint16_t year;
21 packed_bcd_uint8_t mday;
22 packed_bcd_uint8_t month;
25 struct rknano_version_t
27 packed_bcd_uint16_t major;
28 packed_bcd_uint16_t minor;
29 packed_bcd_uint16_t rev;
32 struct rknano_image_t
34 uint16_t width;
35 uint16_t height;
36 uint8_t data[0];
39 struct rknano_blob_t
41 uint32_t offset;
42 uint32_t size;
45 #define VENDOR_NAME_SIZE 32
46 #define MODEL_NAME_SIZE 32
47 #define MAX_NR_STAGES 4
48 #define MAX_NR_FONTS 10
49 #define MAX_NR_GBK 5
50 #define MAX_NR_STRTBL 10
51 #define MAX_NR_IMAGERES 10
52 #define MAX_NR_UNK 10
53 #define MAGIC_RKNANOFW "RKnanoFW"
54 #define MAGIC_RKNANOFW_SIZE 8
56 struct rknano_header_t
58 struct rknano_date_t date;
59 struct rknano_version_t version;
60 uint8_t unk6[6];
61 char vendor[VENDOR_NAME_SIZE];
62 char model[MODEL_NAME_SIZE];
63 uint32_t nr_stages;
64 struct rknano_blob_t stage[MAX_NR_STAGES];
65 uint32_t nr_fonts;
66 struct rknano_blob_t font[MAX_NR_FONTS];
67 uint32_t nr_gbk;
68 struct rknano_blob_t gbk[MAX_NR_GBK];
69 uint32_t nr_strtbl;
70 struct rknano_blob_t strtbl[MAX_NR_STRTBL];
71 uint32_t nr_imageres;
72 struct rknano_blob_t imageres[MAX_NR_IMAGERES];
73 uint32_t nr_unk;
74 struct rknano_blob_t unk[MAX_NR_UNK];
75 uint32_t pad;
76 uint32_t size;
77 char magic[MAGIC_RKNANOFW_SIZE];
80 char *g_out_prefix = NULL;
82 static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size)
85 uint8_t key[] = {
86 0x7C, 0x4E, 0x03, 0x04,
87 0x55, 0x05, 0x09, 0x07,
88 0x2D, 0x2C, 0x7B, 0x38,
89 0x17, 0x0D, 0x17, 0x11
91 int i, i3, x, val, idx;
93 uint8_t key1[0x100];
94 uint8_t key2[0x100];
96 for (i=0; i<0x100; i++) {
97 key1[i] = i;
98 key2[i] = key[i&0xf];
101 i3 = 0;
102 for (i=0; i<0x100; i++) {
103 x = key1[i];
104 i3 = key1[i] + i3;
105 i3 += key2[i];
106 i3 &= 0xff;
107 key1[i] = key1[i3];
108 key1[i3] = x;
111 idx = 0;
112 for (i=0; i<size; i++) {
113 x = key1[(i+1) & 0xff];
114 val = x;
115 idx = (x + idx) & 0xff;
116 key1[(i+1) & 0xff] = key1[idx];
117 key1[idx] = (x & 0xff);
118 val = (key1[(i+1)&0xff] + x) & 0xff;
119 val = key1[val];
120 outpg[i] = val ^ inpg[i];
124 static uint16_t crc(uint8_t *buf, int size)
126 uint16_t result = 65535;
127 for(; size; buf++, size--)
129 for(int bit = 128; bit; bit >>= 1)
131 if(result & 0x80)
132 result = (2 * result) ^ 0x1021;
133 else
134 result *= 2;
135 if(*buf & bit)
136 result ^= 0x1021;
139 return result;
142 /* scramble mode */
143 enum {
144 NO_ENC,
145 CONTINOUS_ENC, /* scramble whole block at once */
146 PAGE_ENC /* nand bootloader is scrambled in 0x200 chunks */
149 static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size,
150 char *name, int suffix, int enc_mode)
152 if(g_out_prefix == NULL || b->size == 0 || b->offset + b->size > size)
153 return;
154 char *path = malloc(strlen(g_out_prefix) + strlen(name) + 32);
155 if(suffix >= 0)
156 sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix);
157 else
158 sprintf(path, "%s%s.bin", g_out_prefix, name);
159 FILE *f = fopen(path, "wb");
160 uint8_t *ptr = buf + b->offset;
161 if(enc_mode != NO_ENC)
163 ptr = malloc(b->size);
164 int len = b->size;
165 uint8_t *buff_ptr = buf + b->offset;
166 uint8_t *out_ptr = ptr;
167 if(enc_mode == PAGE_ENC)
169 while(len >= 0x200)
171 encode_page(buff_ptr, out_ptr, 0x200);
172 buff_ptr += 0x200;
173 out_ptr += 0x200;
174 len -= 0x200;
177 encode_page(buff_ptr, out_ptr, len);
180 if(f)
182 fwrite(ptr, b->size, 1, f);
183 fclose(f);
186 if(enc_mode != NO_ENC)
187 free(ptr);
190 static void print_blob_interval(const struct rknano_blob_t *b)
192 cprintf(YELLOW, "%#x -> %#x", b->offset, b->offset + b->size);
195 static int do_nanofw_image(uint8_t *buf, unsigned long size)
197 if(size < sizeof(struct rknano_header_t))
198 return 1;
199 struct rknano_header_t *hdr = (void *)buf;
200 if(size < hdr->size)
201 return 1;
202 if(strncmp(hdr->magic, MAGIC_RKNANOFW, MAGIC_RKNANOFW_SIZE))
203 return 1;
205 cprintf(BLUE, "Header\n");
206 cprintf(GREEN, " Date: ");
207 cprintf(YELLOW, "%x/%x/%x\n", hdr->date.mday, hdr->date.month, hdr->date.year);
208 cprintf(GREEN, " Version: ");
209 cprintf(YELLOW, "%x.%x.%x\n", hdr->version.major, hdr->version.minor, hdr->version.rev);
210 cprintf(GREEN, " Vendor: ");
211 cprintf(YELLOW, "%s\n", hdr->vendor);
212 cprintf(GREEN, " Model: ");
213 cprintf(YELLOW, "%s\n", hdr->model);
214 cprintf(GREEN, " Pad: ");
215 for(int i = 0; i < 6; i++)
216 cprintf(YELLOW, " %02x", hdr->unk6[i]);
217 cprintf(YELLOW, "\n");
218 cprintf(BLUE, "Stages\n");
219 for(unsigned i = 0; i < hdr->nr_stages; i++)
221 cprintf(GREEN, " %i: ", i);
222 print_blob_interval(&hdr->stage[i]);
223 cprintf(OFF, "\n");
224 save_blob(&hdr->stage[i], buf, size, "stage", i, NO_ENC);
226 cprintf(BLUE, "Fonts\n");
227 for(unsigned i = 0; i < hdr->nr_fonts; i++)
229 cprintf(GREEN, " %i: ", i);
230 print_blob_interval(&hdr->font[i]);
231 cprintf(OFF, "\n");
232 save_blob(&hdr->font[i], buf, size, "font", i, NO_ENC);
234 cprintf(BLUE, "GBK\n");
235 for(unsigned i = 0; i < hdr->nr_gbk; i++)
237 cprintf(GREEN, " %i: ", i);
238 print_blob_interval(&hdr->gbk[i]);
239 cprintf(OFF, "\n");
240 save_blob(&hdr->gbk[i], buf, size, "gbk", i, NO_ENC);
242 cprintf(BLUE, "String Tables\n");
243 for(unsigned i = 0; i < hdr->nr_strtbl; i++)
245 cprintf(GREEN, " %i: ", i);
246 print_blob_interval(&hdr->strtbl[i]);
247 cprintf(OFF, "\n");
248 save_blob(&hdr->strtbl[i], buf, size, "strtbl", i, NO_ENC);
250 cprintf(BLUE, "Image Resources\n");
251 for(unsigned i = 0; i < hdr->nr_imageres; i++)
253 cprintf(GREEN, " %i: ", i);
254 print_blob_interval(&hdr->imageres[i]);
255 cprintf(OFF, "\n");
256 save_blob(&hdr->imageres[i], buf, size, "imgres", i, NO_ENC);
258 cprintf(BLUE, "Unknown\n");
259 for(unsigned i = 0; i < hdr->nr_unk; i++)
261 cprintf(GREEN, " %i: ", i);
262 print_blob_interval(&hdr->unk[i]);
263 cprintf(OFF, "\n");
264 save_blob(&hdr->unk[i], buf, size, "unk", i, NO_ENC);
266 cprintf(BLUE, "Other\n");
267 cprintf(GREEN, " Size: ");
268 cprintf(YELLOW, "%#x\n", hdr->size);
269 cprintf(GREEN, " Magic: ");
270 cprintf(YELLOW, "%." STR(MAGIC_RKNANOFW_SIZE) "s ", hdr->magic);
271 if(strncmp(hdr->magic, MAGIC_RKNANOFW, MAGIC_RKNANOFW_SIZE) == 0)
272 cprintf(RED, "OK\n");
273 else
274 cprintf(RED, "Mismatch\n");
276 return 0;
279 struct rknano_stage_header_t
281 uint32_t addr;
282 uint32_t count;
283 } __attribute__((packed));
286 * The [code_pa,code_pa+code_sz[ and [data_pa,data_pa+data_sz[ ranges
287 * are consistent: they never overlap and have no gaps and fill the
288 * entire space. Furthermore they match the code sequences so it's
289 * reasonable to assume these fields are correct.
290 * The other fields are still quite unsure. */
292 struct rknano_stage_section_t
294 uint32_t code_pa;
295 uint32_t code_va;
296 uint32_t code_sz;
297 uint32_t data_pa;
298 uint32_t data_va;
299 uint32_t data_sz;
300 uint32_t bss_va;
301 uint32_t bss_sz;
302 } __attribute__((packed));
304 static void elf_printf(void *user, bool error, const char *fmt, ...)
306 if(!g_debug && !error)
307 return;
308 (void) user;
309 va_list args;
310 va_start(args, fmt);
311 vprintf(fmt, args);
312 va_end(args);
315 static void elf_write(void *user, uint32_t addr, const void *buf, size_t count)
317 FILE *f = user;
318 fseek(f, addr, SEEK_SET);
319 fwrite(buf, count, 1, f);
322 static void extract_elf_section(struct elf_params_t *elf, int count)
324 if(g_out_prefix == NULL)
325 return;
326 char *filename = xmalloc(strlen(g_out_prefix) + 32);
327 sprintf(filename, "%s%d.elf", g_out_prefix, count);
328 if(g_debug)
329 printf("Write entry %d to %s\n", count, filename);
331 FILE *fd = fopen(filename, "wb");
332 free(filename);
334 if(fd == NULL)
335 return ;
336 elf_write_file(elf, elf_write, elf_printf, fd);
337 fclose(fd);
340 static int do_nanostage_image(uint8_t *buf, unsigned long size)
342 if(size < sizeof(struct rknano_stage_section_t))
343 return 1;
344 struct rknano_stage_header_t *hdr = (void *)buf;
346 cprintf(BLUE, "Header\n");
347 cprintf(GREEN, " Base Address: ");
348 cprintf(YELLOW, "%#08x\n", hdr->addr);
349 cprintf(GREEN, " Load count: ");
350 cprintf(YELLOW, "%d\n", hdr->count);
352 struct rknano_stage_section_t *sec = (void *)(hdr + 1);
354 for(unsigned i = 0; i < hdr->count; i++, sec++)
356 cprintf(BLUE, "Section %d\n", i);
357 cprintf(GREEN, " Code: ");
358 cprintf(YELLOW, "0x%08x", sec->code_pa);
359 cprintf(RED, "-(txt)-");
360 cprintf(YELLOW, "0x%08x", sec->code_pa + sec->code_sz);
361 cprintf(BLUE, " |--> ");
362 cprintf(YELLOW, "0x%08x", sec->code_va);
363 cprintf(RED, "-(txt)-");
364 cprintf(YELLOW, "0x%08x\n", sec->code_va + sec->code_sz);
366 cprintf(GREEN, " Data: ");
367 cprintf(YELLOW, "0x%08x", sec->data_pa);
368 cprintf(RED, "-(dat)-");
369 cprintf(YELLOW, "0x%08x", sec->data_pa + sec->data_sz);
370 cprintf(BLUE, " |--> ");
371 cprintf(YELLOW, "0x%08x", sec->data_va);
372 cprintf(RED, "-(dat)-");
373 cprintf(YELLOW, "0x%08x\n", sec->data_va + sec->data_sz);
375 cprintf(GREEN, " Data: ");
376 cprintf(RED, " ");
377 cprintf(BLUE, " |--> ");
378 cprintf(YELLOW, "0x%08x", sec->bss_va);
379 cprintf(RED, "-(bss)-");
380 cprintf(YELLOW, "0x%08x\n", sec->bss_va + sec->bss_sz);
382 #if 0
383 struct rknano_blob_t blob;
384 blob.offset = sec->code_pa - hdr->addr;
385 blob.size = sec->code_sz;
386 save_blob(&blob, buf, size, "entry.", i, NO_ENC);
387 #else
388 struct elf_params_t elf;
389 elf_init(&elf);
390 elf_add_load_section(&elf, sec->code_va, sec->code_sz, buf + sec->code_pa - hdr->addr);
391 elf_add_load_section(&elf, sec->data_va, sec->data_sz, buf + sec->data_pa - hdr->addr);
392 elf_add_fill_section(&elf, sec->bss_va, sec->bss_sz, 0);
393 extract_elf_section(&elf, i);
394 elf_release(&elf);
395 #endif
398 return 0;
401 #define MAGIC_BOOT "BOOT"
402 #define MAGIC_BOOT_SIZE 4
404 struct rknano_boot_desc_t
406 uint8_t count;
407 uint32_t offset;
408 uint8_t stride;
409 } __attribute__((packed));
411 struct rknano_boot_header_t
413 char magic[MAGIC_BOOT_SIZE];
414 uint16_t hdr_size;
415 uint32_t version;
416 uint32_t unk;
417 uint16_t year;
418 uint8_t month;
419 uint8_t day;
420 uint8_t hour;
421 uint8_t minute;
422 uint8_t second;
423 uint32_t chip;
424 struct rknano_boot_desc_t desc_1;
425 struct rknano_boot_desc_t desc_2;
426 struct rknano_boot_desc_t desc_4;
427 uint8_t field_2B[9];
428 uint32_t field_34;
429 } __attribute__((packed));
431 struct rknano_boot_entry_t
433 uint8_t entry_size; // unsure
434 uint32_t unk;
435 uint16_t name[20];
436 uint32_t offset;
437 uint32_t size;
438 uint32_t sthg2;
439 } __attribute__((packed));
441 uint32_t boot_crc_table[256] =
443 0x00000000, 0x04C10DB7, 0x09821B6E, 0x0D4316D9,
444 0x130436DC, 0x17C53B6B, 0x1A862DB2, 0x1E472005,
445 0x26086DB8, 0x22C9600F, 0x2F8A76D6, 0x2B4B7B61,
446 0x350C5B64, 0x31CD56D3, 0x3C8E400A, 0x384F4DBD,
447 0x4C10DB70, 0x48D1D6C7, 0x4592C01E, 0x4153CDA9,
448 0x5F14EDAC, 0x5BD5E01B, 0x5696F6C2, 0x5257FB75,
449 0x6A18B6C8, 0x6ED9BB7F, 0x639AADA6, 0x675BA011,
450 0x791C8014, 0x7DDD8DA3, 0x709E9B7A, 0x745F96CD,
451 0x9821B6E0, 0x9CE0BB57, 0x91A3AD8E, 0x9562A039,
452 0x8B25803C, 0x8FE48D8B, 0x82A79B52, 0x866696E5,
453 0xBE29DB58, 0xBAE8D6EF, 0xB7ABC036, 0xB36ACD81,
454 0xAD2DED84, 0xA9ECE033, 0xA4AFF6EA, 0xA06EFB5D,
455 0xD4316D90, 0xD0F06027, 0xDDB376FE, 0xD9727B49,
456 0xC7355B4C, 0xC3F456FB, 0xCEB74022, 0xCA764D95,
457 0xF2390028, 0xF6F80D9F, 0xFBBB1B46, 0xFF7A16F1,
458 0xE13D36F4, 0xE5FC3B43, 0xE8BF2D9A, 0xEC7E202D,
459 0x34826077, 0x30436DC0, 0x3D007B19, 0x39C176AE,
460 0x278656AB, 0x23475B1C, 0x2E044DC5, 0x2AC54072,
461 0x128A0DCF, 0x164B0078, 0x1B0816A1, 0x1FC91B16,
462 0x018E3B13, 0x054F36A4, 0x080C207D, 0x0CCD2DCA,
463 0x7892BB07, 0x7C53B6B0, 0x7110A069, 0x75D1ADDE,
464 0x6B968DDB, 0x6F57806C, 0x621496B5, 0x66D59B02,
465 0x5E9AD6BF, 0x5A5BDB08, 0x5718CDD1, 0x53D9C066,
466 0x4D9EE063, 0x495FEDD4, 0x441CFB0D, 0x40DDF6BA,
467 0xACA3D697, 0xA862DB20, 0xA521CDF9, 0xA1E0C04E,
468 0xBFA7E04B, 0xBB66EDFC, 0xB625FB25, 0xB2E4F692,
469 0x8AABBB2F, 0x8E6AB698, 0x8329A041, 0x87E8ADF6,
470 0x99AF8DF3, 0x9D6E8044, 0x902D969D, 0x94EC9B2A,
471 0xE0B30DE7, 0xE4720050, 0xE9311689, 0xEDF01B3E,
472 0xF3B73B3B, 0xF776368C, 0xFA352055, 0xFEF42DE2,
473 0xC6BB605F, 0xC27A6DE8, 0xCF397B31, 0xCBF87686,
474 0xD5BF5683, 0xD17E5B34, 0xDC3D4DED, 0xD8FC405A,
475 0x6904C0EE, 0x6DC5CD59, 0x6086DB80, 0x6447D637,
476 0x7A00F632, 0x7EC1FB85, 0x7382ED5C, 0x7743E0EB,
477 0x4F0CAD56, 0x4BCDA0E1, 0x468EB638, 0x424FBB8F,
478 0x5C089B8A, 0x58C9963D, 0x558A80E4, 0x514B8D53,
479 0x25141B9E, 0x21D51629, 0x2C9600F0, 0x28570D47,
480 0x36102D42, 0x32D120F5, 0x3F92362C, 0x3B533B9B,
481 0x031C7626, 0x07DD7B91, 0x0A9E6D48, 0x0E5F60FF,
482 0x101840FA, 0x14D94D4D, 0x199A5B94, 0x1D5B5623,
483 0xF125760E, 0xF5E47BB9, 0xF8A76D60, 0xFC6660D7,
484 0xE22140D2, 0xE6E04D65, 0xEBA35BBC, 0xEF62560B,
485 0xD72D1BB6, 0xD3EC1601, 0xDEAF00D8, 0xDA6E0D6F,
486 0xC4292D6A, 0xC0E820DD, 0xCDAB3604, 0xC96A3BB3,
487 0xBD35AD7E, 0xB9F4A0C9, 0xB4B7B610, 0xB076BBA7,
488 0xAE319BA2, 0xAAF09615, 0xA7B380CC, 0xA3728D7B,
489 0x9B3DC0C6, 0x9FFCCD71, 0x92BFDBA8, 0x967ED61F,
490 0x8839F61A, 0x8CF8FBAD, 0x81BBED74, 0x857AE0C3,
491 0x5D86A099, 0x5947AD2E, 0x5404BBF7, 0x50C5B640,
492 0x4E829645, 0x4A439BF2, 0x47008D2B, 0x43C1809C,
493 0x7B8ECD21, 0x7F4FC096, 0x720CD64F, 0x76CDDBF8,
494 0x688AFBFD, 0x6C4BF64A, 0x6108E093, 0x65C9ED24,
495 0x11967BE9, 0x1557765E, 0x18146087, 0x1CD56D30,
496 0x02924D35, 0x06534082, 0x0B10565B, 0x0FD15BEC,
497 0x379E1651, 0x335F1BE6, 0x3E1C0D3F, 0x3ADD0088,
498 0x249A208D, 0x205B2D3A, 0x2D183BE3, 0x29D93654,
499 0xC5A71679, 0xC1661BCE, 0xCC250D17, 0xC8E400A0,
500 0xD6A320A5, 0xD2622D12, 0xDF213BCB, 0xDBE0367C,
501 0xE3AF7BC1, 0xE76E7676, 0xEA2D60AF, 0xEEEC6D18,
502 0xF0AB4D1D, 0xF46A40AA, 0xF9295673, 0xFDE85BC4,
503 0x89B7CD09, 0x8D76C0BE, 0x8035D667, 0x84F4DBD0,
504 0x9AB3FBD5, 0x9E72F662, 0x9331E0BB, 0x97F0ED0C,
505 0xAFBFA0B1, 0xAB7EAD06, 0xA63DBBDF, 0xA2FCB668,
506 0xBCBB966D, 0xB87A9BDA, 0xB5398D03, 0xB1F880B4,
509 static uint32_t boot_crc(uint8_t *buf, int size)
511 uint32_t crc = 0;
512 for(int i = 0; i < size; i++)
513 crc = boot_crc_table[buf[i] ^ (crc >> 24)] ^ (crc << 8);
514 return crc;
517 wchar_t *from_uni16(uint16_t *str)
519 static wchar_t buffer[64];
520 int i = 0;
521 while(str[i])
523 buffer[i] = str[i];
524 i++;
526 return buffer;
529 static int do_boot_desc(uint8_t *buf, unsigned long size,
530 struct rknano_boot_desc_t *desc, int desc_idx)
532 (void) buf;
533 (void) size;
534 cprintf(BLUE, "Desc %d\n", desc_idx);
535 cprintf(GREEN, " Count: "); cprintf(YELLOW, "%d\n", desc->count);
536 cprintf(GREEN, " Offset: "); cprintf(YELLOW, "%#x\n", desc->offset);
537 cprintf(GREEN, " Stride: "); cprintf(YELLOW, "%#x ", desc->stride);
538 if(desc->stride < sizeof(struct rknano_boot_entry_t))
539 cprintf(RED, "(too small <%#lx)\n", sizeof(struct rknano_boot_entry_t));
540 else
541 cprintf(RED, "(OK >=%#lx)\n", sizeof(struct rknano_boot_entry_t));
543 for(int i = 0; i < desc->count; i++)
545 struct rknano_boot_entry_t *entry = (void *)(buf + desc->offset + i * desc->stride);
546 cprintf(BLUE, " Entry %d\n", i);
547 cprintf(GREEN, " Entry size: "); cprintf(YELLOW, "%#x ", entry->entry_size);
548 if(desc->stride < sizeof(struct rknano_boot_entry_t))
549 cprintf(RED, "(too small <%#lx)\n", sizeof(struct rknano_boot_entry_t));
550 else
551 cprintf(RED, "(OK >=%#lx)\n", sizeof(struct rknano_boot_entry_t));
552 cprintf(GREEN, " Unk: "); cprintf(YELLOW, "%#x\n", entry->unk);
553 cprintf(GREEN, " Name: "); cprintf(YELLOW, "%S\n", from_uni16(entry->name));
554 cprintf(GREEN, " Offset: "); cprintf(YELLOW, "%#x\n", entry->offset);
555 cprintf(GREEN, " Size: "); cprintf(YELLOW, "%#x\n", entry->size);
556 cprintf(GREEN, " Sthg 2: "); cprintf(YELLOW, "%#x\n", entry->sthg2);
558 struct rknano_blob_t blob;
559 blob.offset = entry->offset;
560 blob.size = entry->size;
561 char name[128];
562 sprintf(name, "%d.%S", desc_idx, from_uni16(entry->name));
563 save_blob(&blob, buf, size, name, -1, PAGE_ENC);
566 return 0;
569 static int do_boot_image(uint8_t *buf, unsigned long size)
571 if(size < sizeof(struct rknano_boot_header_t))
572 return 1;
573 struct rknano_boot_header_t *hdr = (void *)buf;
574 if(strncmp(hdr->magic, MAGIC_BOOT, MAGIC_BOOT_SIZE))
575 return 1;
577 cprintf(BLUE, "Header\n");
578 cprintf(GREEN, " Magic: ");
579 cprintf(YELLOW, "%." STR(MAGIC_BOOT_SIZE) "s ", hdr->magic);
580 if(strncmp(hdr->magic, MAGIC_BOOT, MAGIC_BOOT_SIZE) == 0)
581 cprintf(RED, "OK\n");
582 else
583 cprintf(RED, "Mismatch\n");
585 cprintf(GREEN, " Header Size: ");
586 cprintf(YELLOW, "%#x ", hdr->hdr_size);
587 if(hdr->hdr_size >= sizeof(struct rknano_boot_header_t))
588 cprintf(RED, "OK\n");
589 else
590 cprintf(RED, "Mismatch\n");
592 #define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name)
593 #define print_arr(str, name, sz) \
594 cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n")
596 cprintf(GREEN, " Version: ");
597 cprintf(YELLOW, "%x.%x.%x\n", (hdr->version >> 24) & 0xff,
598 (hdr->version >> 16) & 0xff, hdr->version & 0xffff);
600 cprintf(GREEN, " Date: ");
601 cprintf(YELLOW, "%d/%d/%d %02d:%02d:%02d\n", hdr->day, hdr->month, hdr->year,
602 hdr->hour, hdr->minute, hdr->second);
604 cprintf(GREEN, " Chip: ");
605 cprintf(YELLOW, "%#x\n", hdr->chip);
607 print_arr("field_2A", field_2B, 9);
608 print("field_34", field_34);
610 do_boot_desc(buf, size, &hdr->desc_1, 1);
611 do_boot_desc(buf, size, &hdr->desc_2, 2);
612 do_boot_desc(buf, size, &hdr->desc_4, 4);
614 cprintf(BLUE, "Variable Header:\n");
615 cprintf(GREEN, " Value: ");
616 cprintf(YELLOW, "%#lx\n", *(unsigned long *)((uint8_t *)hdr + hdr->field_34 - 10));
618 /* The last 4 bytes are a 32-bit CRC */
619 cprintf(BLUE, "Post Header:\n");
620 cprintf(GREEN, " CRC: ");
621 uint32_t crc = *(uint32_t *)(buf + size - 4);
622 uint32_t ccrc = boot_crc(buf, size - 4);
623 cprintf(YELLOW, "%08x ", crc);
624 if(crc == ccrc)
625 cprintf(RED, "OK\n");
626 else
627 cprintf(RED, "Mismatch\n");
629 return 0;
632 typedef struct rknano_blob_t rkfw_blob_t;
634 #define MAGIC_RKFW "RKFW"
635 #define MAGIC_RKFW_SIZE 4
637 struct rkfw_header_t
639 char magic[MAGIC_RKFW_SIZE];
640 uint16_t hdr_size; // UNSURE
641 uint32_t version;
642 uint32_t code;
643 uint16_t year;
644 uint8_t month;
645 uint8_t day;
646 uint8_t hour;
647 uint8_t minute;
648 uint8_t second;
649 uint32_t chip;
650 rkfw_blob_t loader;
651 rkfw_blob_t update;
652 uint8_t pad[61];
653 } __attribute__((packed));
655 static int do_rkfw_image(uint8_t *buf, unsigned long size)
657 if(size < sizeof(struct rkfw_header_t))
658 return 1;
659 struct rkfw_header_t *hdr = (void *)buf;
660 if(strncmp(hdr->magic, MAGIC_RKFW, MAGIC_RKFW_SIZE))
661 return 1;
663 cprintf(BLUE, "Header\n");
664 cprintf(GREEN, " Magic: ");
665 cprintf(YELLOW, "%." STR(MAGIC_RKFW_SIZE) "s ", hdr->magic);
666 if(strncmp(hdr->magic, MAGIC_RKFW, MAGIC_RKFW_SIZE) == 0)
667 cprintf(RED, "OK\n");
668 else
669 cprintf(RED, "Mismatch\n");
671 cprintf(GREEN, " Header size: ");
672 cprintf(YELLOW, " %#x ", hdr->hdr_size);
673 if(hdr->hdr_size == sizeof(struct rkfw_header_t))
674 cprintf(RED, "OK\n");
675 else
676 cprintf(RED, "Mismatch\n");
677 cprintf(GREEN, " Version: ");
678 cprintf(YELLOW, "%x.%x.%x\n", (hdr->version >> 24) & 0xff,
679 (hdr->version >> 16) & 0xff, hdr->version & 0xffff);
681 cprintf(GREEN, " Code: ");
682 cprintf(YELLOW, "%#x\n", hdr->code);
684 cprintf(GREEN, " Date: ");
685 cprintf(YELLOW, "%d/%d/%d %02d:%02d:%02d\n", hdr->day, hdr->month, hdr->year,
686 hdr->hour, hdr->minute, hdr->second);
688 cprintf(GREEN, " Chip: ");
689 cprintf(YELLOW, "%#x\n", hdr->chip);
691 cprintf(GREEN, " Loader: ");
692 print_blob_interval(&hdr->loader);
693 cprintf(OFF, "\n");
694 save_blob(&hdr->loader, buf, size, "loader", 0, NO_ENC);
696 cprintf(GREEN, " Update: ");
697 print_blob_interval(&hdr->update);
698 cprintf(OFF, "\n");
699 save_blob(&hdr->update, buf, size, "update", 0, NO_ENC);
701 print_arr("pad", pad, 61);
703 return 0;
706 static int do_rkencode_image(uint8_t *buf, unsigned long size)
708 void *ptr = malloc(size);
709 int len = size;
710 uint8_t *buff_ptr = buf;
711 uint8_t *out_ptr = ptr;
712 int enc_mode = PAGE_ENC;
713 if(enc_mode == PAGE_ENC)
715 while(len >= 0x200)
717 encode_page(buff_ptr, out_ptr, 0x200);
718 buff_ptr += 0x200;
719 out_ptr += 0x200;
720 len -= 0x200;
723 encode_page(buff_ptr, out_ptr, len);
725 if(g_out_prefix)
727 FILE *f = fopen(g_out_prefix, "wb");
728 if(f)
730 fwrite(buff_ptr, 1, size, f);
731 fclose(f);
733 else
734 printf("Cannot open output file: %m\n");
736 free(ptr);
738 return 0;
741 static void usage(void)
743 printf("Usage: rkboottool [options] rknanoboot.bin\n");
744 printf("Options:\n");
745 printf(" --rkfw\tUnpack a rkfw file\n");
746 printf(" --rknanofw\tUnpack a regular RknanoFW file\n");
747 printf(" --rkboot\tUnpack a BOOT file\n");
748 printf(" --rknanostage\tUnpack a RknanoFW stage file\n");
749 printf(" --rkencode\tEncode a raw file\n");
750 printf(" -o <prefix>\tSet output prefix\n");
751 printf("The default is to try to guess the format.\n");
752 printf("If several formats are specified, all are tried.\n");
753 exit(1);
756 int main(int argc, char **argv)
758 bool try_nanofw = false;
759 bool try_rkfw = false;
760 bool try_boot = false;
761 bool try_nanostage = false;
762 bool try_rkencode = false;
764 while(1)
766 static struct option long_options[] =
768 {"help", no_argument, 0, '?'},
769 {"debug", no_argument, 0, 'd'},
770 {"rkfw", no_argument, 0, '9'},
771 {"rknanofw", no_argument, 0, 'n'},
772 {"rknanostage", no_argument, 0, 's'},
773 {"rkencode", no_argument, 0, 'e'},
774 {"rkboot", no_argument, 0, 'b'},
775 {"no-color", no_argument, 0, 'c'},
776 {0, 0, 0, 0}
779 int c = getopt_long(argc, argv, "?d9nscbeo:", long_options, NULL);
780 if(c == -1)
781 break;
782 switch(c)
784 case -1:
785 break;
786 case 'c':
787 enable_color(false);
788 break;
789 case 'b':
790 try_boot = true;
791 break;
792 case 'n':
793 try_nanofw = true;
794 break;
795 case 'd':
796 g_debug = true;
797 break;
798 case '?':
799 usage();
800 break;
801 case 'o':
802 g_out_prefix = optarg;
803 break;
804 case '9':
805 try_rkfw = true;
806 break;
807 case 's':
808 try_nanostage = true;
809 break;
810 case 'e':
811 try_rkencode = true;
812 break;
813 default:
814 printf("Invalid argument '%c'\n", c);
815 abort();
819 if(argc - optind != 1)
821 usage();
822 return 1;
825 if(!try_nanostage && !try_rkfw && !try_nanofw && !try_boot && !try_rkencode)
826 try_nanostage = try_rkfw = try_nanofw = try_boot = true;
828 FILE *fin = fopen(argv[optind], "r");
829 if(fin == NULL)
831 perror("Cannot open boot file");
832 return 1;
834 fseek(fin, 0, SEEK_END);
835 long size = ftell(fin);
836 fseek(fin, 0, SEEK_SET);
838 void *buf = malloc(size);
839 if(buf == NULL)
841 perror("Cannot allocate memory");
842 return 1;
845 if(fread(buf, size, 1, fin) != 1)
847 perror("Cannot read file");
848 return 1;
851 fclose(fin);
853 if(try_nanofw && !do_nanofw_image(buf, size))
854 goto Lsuccess;
855 if(try_rkfw && !do_rkfw_image(buf, size))
856 goto Lsuccess;
857 if(try_boot && !do_boot_image(buf, size))
858 goto Lsuccess;
859 if(try_nanostage && !do_nanostage_image(buf, size))
860 goto Lsuccess;
861 if(try_rkencode && !do_rkencode_image(buf, size))
862 goto Lsuccess;
863 cprintf(GREY, "No valid format found!\n");
864 Lsuccess:
865 free(buf);
867 return 0;