sbtools: add support for the stmp36xx format
[maemo-rb.git] / utils / imxtools / sbtools / sbtoelf.c
blob0445c4a3664709113c2a3463f73c4e2e60306671
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 fwrite(file->data, file->data_size, 1, f);
166 fclose(f);
169 static void usage(void)
171 printf("Usage: sbtoelf [options] sb-file\n");
172 printf("Options:\n");
173 printf(" -?/--help\tDisplay this message\n");
174 printf(" -o <prefix>\tEnable output and set prefix\n");
175 printf(" -d/--debug\tEnable debug output*\n");
176 printf(" -k <file>\tAdd key file\n");
177 printf(" -z\t\tAdd zero key\n");
178 printf(" -r\t\tUse raw command mode\n");
179 printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n");
180 printf(" -n/--no-color\tDisable output colors\n");
181 printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n");
182 printf(" -f/--force\tForce reading even without a key*\n");
183 printf(" -1/--v1\tForce to read file as a version 1 file\n");
184 printf(" -2/--v2\tForce to read file as a version 2 file\n");
185 printf("Options marked with a * are for debug purpose only\n");
186 exit(1);
189 static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...)
191 (void) user;
192 (void) error;
193 va_list args;
194 va_start(args, fmt);
195 color(c);
196 vprintf(fmt, args);
197 va_end(args);
200 static struct crypto_key_t g_zero_key =
202 .method = CRYPTO_KEY,
203 .u.key = {0}
206 static struct crypto_key_t g_default_xor_key =
208 .method = CRYPTO_XOR_KEY,
209 .u.xor_key =
211 {.k = {0x67ECAEF6, 0xB31FB961, 0x118A9F4C, 0xA32A97DA,
212 0x6CC39617, 0x5BC00314, 0x9D430685, 0x4D7DB502,
213 0xA347685E, 0x3C87E86C, 0x8987AAA0, 0x24B78EF1,
214 0x893B9605, 0x9BB8C2BE, 0x6D9544E2, 0x375B525C}},
215 {.k = {0x3F424704, 0x53B5A331, 0x6AD345A5, 0x20DCEC51,
216 0x743C8D3B, 0x444B3792, 0x0AF429569, 0xB7EE1111,
217 0x583BF768, 0x9683BF9A, 0x0B032D799, 0xFE4E78ED,
218 0xF20D08C2, 0xFA0BE4A2, 0x4D89C317, 0x887B2D6F}}
222 enum sb_version_guess_t
224 SB_VERSION_1,
225 SB_VERSION_2,
226 SB_VERSION_UNK,
229 enum sb_version_guess_t guess_sb_version(const char *filename)
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 return SB_VERSION_UNK;
238 if(fread(sig, 4, 1, f) != 1)
239 return SB_VERSION_UNK;
240 if(memcmp(sig, "STMP", 4) != 0)
241 return SB_VERSION_UNK;
242 // check header size (v1)
243 uint32_t hdr_size;
244 if(fseek(f, 8, SEEK_SET))
245 return SB_VERSION_UNK;
246 if(fread(&hdr_size, 4, 1, f) != 1)
247 return SB_VERSION_UNK;
248 if(hdr_size == 0x34)
249 return SB_VERSION_1;
250 // check header size (v2)
251 if(fseek(f, 32, SEEK_SET))
252 return SB_VERSION_UNK;
253 if(fread(&hdr_size, 4, 1, f) != 1)
254 return SB_VERSION_UNK;
255 if(hdr_size == 0xc)
256 return SB_VERSION_2;
257 return SB_VERSION_UNK;
260 int main(int argc, char **argv)
262 bool raw_mode = false;
263 const char *loopback = NULL;
264 bool force_sb1 = false;
265 bool force_sb2 = false;
267 /* decrypt the xor key which is xor'ed */
268 for(int i = 0; i < 2; i++)
269 for(int j = 0; j < 16; j++)
270 g_default_xor_key.u.xor_key[i].k[j] ^= 0xaa55aa55;
272 while(1)
274 static struct option long_options[] =
276 {"help", no_argument, 0, '?'},
277 {"debug", no_argument, 0, 'd'},
278 {"add-key", required_argument, 0, 'a'},
279 {"no-color", no_argument, 0, 'n'},
280 {"loopback", required_argument, 0, 'l'},
281 {"force", no_argument, 0, 'f'},
282 {"v1", no_argument, 0, '1'},
283 {"v2", no_argument, 0, '2'},
284 {0, 0, 0, 0}
287 int c = getopt_long(argc, argv, "?do:k:zra:nl:f12x", long_options, NULL);
288 if(c == -1)
289 break;
290 switch(c)
292 case -1:
293 break;
294 case 'l':
295 if(loopback)
296 bug("Only one loopback file can be specified !\n");
297 loopback = optarg;
298 break;
299 case 'n':
300 enable_color(false);
301 break;
302 case 'd':
303 g_debug = true;
304 break;
305 case '?':
306 usage();
307 break;
308 case 'o':
309 g_out_prefix = optarg;
310 break;
311 case 'f':
312 g_force = true;
313 break;
314 case 'k':
316 if(!add_keys_from_file(optarg))
317 bug("Cannot add keys from %s\n", optarg);
318 break;
320 case 'z':
321 add_keys(&g_zero_key, 1);
322 break;
323 case 'x':
324 add_keys(&g_default_xor_key, 1);
325 break;
326 case 'r':
327 raw_mode = true;
328 break;
329 case 'a':
331 struct crypto_key_t key;
332 char *s = optarg;
333 if(!parse_key(&s, &key))
334 bug("Invalid key specified as argument\n");
335 if(*s != 0)
336 bug("Trailing characters after key specified as argument\n");
337 add_keys(&key, 1);
338 break;
340 case '1':
341 force_sb1 = true;
342 break;
343 case '2':
344 force_sb2 = true;
345 break;
346 default:
347 abort();
351 if(force_sb1 && force_sb2)
352 bug("You cannot force both version 1 and 2\n");
354 if(argc - optind != 1)
356 usage();
357 return 1;
360 const char *sb_filename = argv[optind];
362 enum sb_version_guess_t ver = guess_sb_version(sb_filename);
364 if(force_sb2 || ver == SB_VERSION_2)
366 enum sb_error_t err;
367 struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
368 if(file == NULL)
370 color(OFF);
371 printf("SB read failed: %d\n", err);
372 return 1;
375 color(OFF);
376 if(g_out_prefix)
377 extract_sb_file(file);
378 if(g_debug)
380 color(GREY);
381 printf("[Debug output]\n");
382 sb_dump(file, NULL, sb_printf);
384 if(loopback)
386 /* sb_read_file will fill real key and IV but we don't want to override
387 * them when looping back otherwise the output will be inconsistent and
388 * garbage */
389 file->override_real_key = false;
390 file->override_crypto_iv = false;
391 sb_write_file(file, loopback);
393 sb_free(file);
395 else if(force_sb1 || ver == SB_VERSION_1)
397 enum sb1_error_t err;
398 struct sb1_file_t *file = sb1_read_file(sb_filename, NULL, sb_printf, &err);
399 if(file == NULL)
401 color(OFF);
402 printf("SB read failed: %d\n", err);
403 return 1;
406 color(OFF);
407 if(g_out_prefix)
408 extract_sb1_file(file);
409 if(g_debug)
411 color(GREY);
412 printf("[Debug output]\n");
413 sb1_dump(file, NULL, sb_printf);
415 if(loopback)
416 sb1_write_file(file, loopback);
418 sb1_free(file);
420 else
422 color(OFF);
423 printf("Cannot guess file type, are you sure it's a valid image ?\n");
424 return 1;
426 clear_keys();
428 return 0;