sbtoelf: implement sb1 loading and dumping
[maemo-rb.git] / utils / imxtools / sbtools / sbtoelf.c
blob01a51cae904c8f4789dd68caef06e8b6fa0dbf5f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2010 Bertrik Sikken
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * .sb file parser and chunk extractor
25 * Based on amsinfo, which is
26 * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com>
29 #define _ISOC99_SOURCE /* snprintf() */
30 #include <stdio.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <stdarg.h>
37 #include <strings.h>
38 #include <getopt.h>
40 #include "crypto.h"
41 #include "elf.h"
42 #include "sb.h"
43 #include "sb1.h"
44 #include "misc.h"
46 /* all blocks are sized as a multiple of 0x1ff */
47 #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
49 /* If you find a firmware that breaks the known format ^^ */
50 #define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
52 #define crypto_cbc(...) \
53 do { int ret = crypto_cbc(__VA_ARGS__); \
54 if(ret != CRYPTO_ERROR_SUCCESS) \
55 bug("crypto_cbc error: %d\n", ret); \
56 }while(0)
58 /* globals */
60 char *g_out_prefix;
62 static void elf_printf(void *user, bool error, const char *fmt, ...)
64 if(!g_debug && !error)
65 return;
66 (void) user;
67 va_list args;
68 va_start(args, fmt);
69 vprintf(fmt, args);
70 va_end(args);
73 static void elf_write(void *user, uint32_t addr, const void *buf, size_t count)
75 FILE *f = user;
76 fseek(f, addr, SEEK_SET);
77 fwrite(buf, count, 1, f);
80 static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id)
82 char name[5];
83 char *filename = xmalloc(strlen(g_out_prefix) + 32);
84 sb_fill_section_name(name, id);
85 sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count);
86 if(g_debug)
87 printf("Write boot section %s to %s\n", name, filename);
89 FILE *fd = fopen(filename, "wb");
90 free(filename);
92 if(fd == NULL)
93 return ;
94 elf_write_file(elf, elf_write, elf_printf, fd);
95 fclose(fd);
98 static void extract_sb_section(struct sb_section_t *sec)
100 if(sec->is_data)
102 char sec_name[5];
103 char *filename = xmalloc(strlen(g_out_prefix) + 32);
104 sb_fill_section_name(sec_name, sec->identifier);
105 sprintf(filename, "%s%s.bin", g_out_prefix, sec_name);
106 FILE *fd = fopen(filename, "wb");
107 if(fd == NULL)
108 bugp("Cannot open %s for writing\n", filename);
109 if(g_debug)
110 printf("Write data section %s to %s\n", sec_name, filename);
111 free(filename);
113 for(int j = 0; j < sec->nr_insts; j++)
115 assert(sec->insts[j].inst == SB_INST_DATA);
116 fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd);
118 fclose(fd);
121 int elf_count = 0;
122 struct elf_params_t elf;
123 elf_init(&elf);
125 for(int i = 0; i < sec->nr_insts; i++)
127 struct sb_inst_t *inst = &sec->insts[i];
128 switch(inst->inst)
130 case SB_INST_LOAD:
131 elf_add_load_section(&elf, inst->addr, inst->size, inst->data);
132 break;
133 case SB_INST_FILL:
134 elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern);
135 break;
136 case SB_INST_CALL:
137 case SB_INST_JUMP:
138 elf_set_start_addr(&elf, inst->addr);
139 extract_elf_section(&elf, elf_count++, sec->identifier);
140 elf_release(&elf);
141 elf_init(&elf);
142 break;
143 default:
144 /* ignore mode and nop */
145 break;
149 if(!elf_is_empty(&elf))
150 extract_elf_section(&elf, elf_count, sec->identifier);
151 elf_release(&elf);
154 static void extract_sb_file(struct sb_file_t *file)
156 for(int i = 0; i < file->nr_sections; i++)
157 extract_sb_section(&file->sections[i]);
160 static void extract_sb1_file(struct sb1_file_t *file)
162 FILE *f = fopen(g_out_prefix, "wb");
163 if(f == NULL)
164 bugp("Cannot open %s for writing\n", g_out_prefix);
165 fclose(f);
168 static void usage(void)
170 printf("Usage: sbtoelf [options] sb-file\n");
171 printf("Options:\n");
172 printf(" -?/--help\tDisplay this message\n");
173 printf(" -o <prefix>\tEnable output and set prefix\n");
174 printf(" -d/--debug\tEnable debug output*\n");
175 printf(" -k <file>\tAdd key file\n");
176 printf(" -z\t\tAdd zero key\n");
177 printf(" -r\t\tUse raw command mode\n");
178 printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n");
179 printf(" -n/--no-color\tDisable output colors\n");
180 printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n");
181 printf(" -f/--force\tForce reading even without a key*\n");
182 printf(" -1/--v1\tForce to read file as a version 1 file\n");
183 printf(" -2/--v2\tForce to read file as a version 2 file\n");
184 printf("Options marked with a * are for debug purpose only\n");
185 exit(1);
188 static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...)
190 (void) user;
191 (void) error;
192 va_list args;
193 va_start(args, fmt);
194 color(c);
195 vprintf(fmt, args);
196 va_end(args);
199 static struct crypto_key_t g_zero_key =
201 .method = CRYPTO_KEY,
202 .u.key = {0}
205 static struct crypto_key_t g_default_xor_key =
207 .method = CRYPTO_XOR_KEY,
208 .u.xor_key =
210 {.k = {0x67ECAEF6, 0xB31FB961, 0x118A9F4C, 0xA32A97DA,
211 0x6CC39617, 0x5BC00314, 0x9D430685, 0x4D7DB502,
212 0xA347685E, 0x3C87E86C, 0x8987AAA0, 0x24B78EF1,
213 0x893B9605, 0x9BB8C2BE, 0x6D9544E2, 0x375B525C}},
214 {.k = {0x3F424704, 0x53B5A331, 0x6AD345A5, 0x20DCEC51,
215 0x743C8D3B, 0x444B3792, 0x0AF429569, 0xB7EE1111,
216 0x583BF768, 0x9683BF9A, 0x0B032D799, 0xFE4E78ED,
217 0xF20D08C2, 0xFA0BE4A2, 0x4D89C317, 0x887B2D6F}}
221 enum sb_version_guess_t
223 SB_VERSION_1,
224 SB_VERSION_2,
225 SB_VERSION_UNK,
228 enum sb_version_guess_t guess_sb_version(const char *filename)
230 #define ret(x) do { fclose(f); return x; } while(0)
231 FILE *f = fopen(filename, "rb");
232 if(f == NULL)
233 bugp("Cannot open file for reading\n");
234 // check signature
235 uint8_t sig[4];
236 if(fseek(f, 20, SEEK_SET))
237 ret(SB_VERSION_UNK);
238 if(fread(sig, 4, 1, f) != 1)
239 ret(SB_VERSION_UNK);
240 if(memcmp(sig, "STMP", 4) != 0)
241 ret(SB_VERSION_UNK);
242 // check header size (v1)
243 uint32_t hdr_size;
244 if(fseek(f, 8, SEEK_SET))
245 ret(SB_VERSION_UNK);
246 if(fread(&hdr_size, 4, 1, f) != 1)
247 ret(SB_VERSION_UNK);
248 if(hdr_size == 0x34)
249 ret(SB_VERSION_1);
250 // check header size (v2)
251 if(fseek(f, 32, SEEK_SET))
252 ret(SB_VERSION_UNK);
253 if(fread(&hdr_size, 4, 1, f) != 1)
254 ret(SB_VERSION_UNK);
255 if(hdr_size == 0xc)
256 ret(SB_VERSION_2);
257 ret(SB_VERSION_UNK);
258 #undef ret
261 int main(int argc, char **argv)
263 bool raw_mode = false;
264 const char *loopback = NULL;
265 bool force_sb1 = false;
266 bool force_sb2 = false;
268 /* decrypt the xor key which is xor'ed */
269 for(int i = 0; i < 2; i++)
270 for(int j = 0; j < 16; j++)
271 g_default_xor_key.u.xor_key[i].k[j] ^= 0xaa55aa55;
273 while(1)
275 static struct option long_options[] =
277 {"help", no_argument, 0, '?'},
278 {"debug", no_argument, 0, 'd'},
279 {"add-key", required_argument, 0, 'a'},
280 {"no-color", no_argument, 0, 'n'},
281 {"loopback", required_argument, 0, 'l'},
282 {"force", no_argument, 0, 'f'},
283 {"v1", no_argument, 0, '1'},
284 {"v2", no_argument, 0, '2'},
285 {0, 0, 0, 0}
288 int c = getopt_long(argc, argv, "?do:k:zra:nl:f12x", long_options, NULL);
289 if(c == -1)
290 break;
291 switch(c)
293 case -1:
294 break;
295 case 'l':
296 if(loopback)
297 bug("Only one loopback file can be specified !\n");
298 loopback = optarg;
299 break;
300 case 'n':
301 enable_color(false);
302 break;
303 case 'd':
304 g_debug = true;
305 break;
306 case '?':
307 usage();
308 break;
309 case 'o':
310 g_out_prefix = optarg;
311 break;
312 case 'f':
313 g_force = true;
314 break;
315 case 'k':
317 if(!add_keys_from_file(optarg))
318 bug("Cannot add keys from %s\n", optarg);
319 break;
321 case 'z':
322 add_keys(&g_zero_key, 1);
323 break;
324 case 'x':
325 add_keys(&g_default_xor_key, 1);
326 break;
327 case 'r':
328 raw_mode = true;
329 break;
330 case 'a':
332 struct crypto_key_t key;
333 char *s = optarg;
334 if(!parse_key(&s, &key))
335 bug("Invalid key specified as argument\n");
336 if(*s != 0)
337 bug("Trailing characters after key specified as argument\n");
338 add_keys(&key, 1);
339 break;
341 case '1':
342 force_sb1 = true;
343 break;
344 case '2':
345 force_sb2 = true;
346 break;
347 default:
348 abort();
352 if(force_sb1 && force_sb2)
353 bug("You cannot force both version 1 and 2\n");
355 if(argc - optind != 1)
357 usage();
358 return 1;
361 const char *sb_filename = argv[optind];
363 enum sb_version_guess_t ver = guess_sb_version(sb_filename);
365 if(force_sb2 || ver == SB_VERSION_2)
367 enum sb_error_t err;
368 struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
369 if(file == NULL)
371 color(OFF);
372 printf("SB read failed: %d\n", err);
373 return 1;
376 color(OFF);
377 if(g_out_prefix)
378 extract_sb_file(file);
379 if(g_debug)
381 color(GREY);
382 printf("[Debug output]\n");
383 sb_dump(file, NULL, sb_printf);
385 if(loopback)
387 /* sb_read_file will fill real key and IV but we don't want to override
388 * them when looping back otherwise the output will be inconsistent and
389 * garbage */
390 file->override_real_key = false;
391 file->override_crypto_iv = false;
392 sb_write_file(file, loopback);
394 sb_free(file);
396 else if(force_sb1 || ver == SB_VERSION_1)
398 enum sb1_error_t err;
399 struct sb1_file_t *file = sb1_read_file(sb_filename, NULL, sb_printf, &err);
400 if(file == NULL)
402 color(OFF);
403 printf("SB read failed: %d\n", err);
404 return 1;
407 color(OFF);
408 if(g_out_prefix)
409 extract_sb1_file(file);
410 if(g_debug)
412 color(GREY);
413 printf("[Debug output]\n");
414 sb1_dump(file, NULL, sb_printf);
416 if(loopback)
417 sb1_write_file(file, loopback);
419 sb1_free(file);
421 else
423 color(OFF);
424 printf("Cannot guess file type, are you sure it's a valid image ?\n");
425 return 1;
427 clear_keys();
429 return 0;