diff options
Diffstat (limited to 'utils/imxtools/sbtoelf.c')
-rw-r--r-- | utils/imxtools/sbtoelf.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/utils/imxtools/sbtoelf.c b/utils/imxtools/sbtoelf.c new file mode 100644 index 0000000000..fda70b1180 --- /dev/null +++ b/utils/imxtools/sbtoelf.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Bertrik Sikken | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* | ||
23 | * .sb file parser and chunk extractor | ||
24 | * | ||
25 | * Based on amsinfo, which is | ||
26 | * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com> | ||
27 | */ | ||
28 | |||
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> | ||
39 | |||
40 | #include "crypto.h" | ||
41 | #include "elf.h" | ||
42 | #include "sb.h" | ||
43 | #include "misc.h" | ||
44 | |||
45 | /* all blocks are sized as a multiple of 0x1ff */ | ||
46 | #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) | ||
47 | |||
48 | /* If you find a firmware that breaks the known format ^^ */ | ||
49 | #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) | ||
50 | |||
51 | #define crypto_cbc(...) \ | ||
52 | do { int ret = crypto_cbc(__VA_ARGS__); \ | ||
53 | if(ret != CRYPTO_ERROR_SUCCESS) \ | ||
54 | bug("crypto_cbc error: %d\n", ret); \ | ||
55 | }while(0) | ||
56 | |||
57 | /* globals */ | ||
58 | |||
59 | char *g_out_prefix; | ||
60 | |||
61 | static void elf_printf(void *user, bool error, const char *fmt, ...) | ||
62 | { | ||
63 | if(!g_debug && !error) | ||
64 | return; | ||
65 | (void) user; | ||
66 | va_list args; | ||
67 | va_start(args, fmt); | ||
68 | vprintf(fmt, args); | ||
69 | va_end(args); | ||
70 | } | ||
71 | |||
72 | static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) | ||
73 | { | ||
74 | FILE *f = user; | ||
75 | fseek(f, addr, SEEK_SET); | ||
76 | fwrite(buf, count, 1, f); | ||
77 | } | ||
78 | |||
79 | static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id) | ||
80 | { | ||
81 | char name[5]; | ||
82 | char *filename = xmalloc(strlen(g_out_prefix) + 32); | ||
83 | sb_fill_section_name(name, id); | ||
84 | sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count); | ||
85 | if(g_debug) | ||
86 | printf("Write boot section %s to %s\n", name, filename); | ||
87 | |||
88 | FILE *fd = fopen(filename, "wb"); | ||
89 | free(filename); | ||
90 | |||
91 | if(fd == NULL) | ||
92 | return ; | ||
93 | elf_write_file(elf, elf_write, elf_printf, fd); | ||
94 | fclose(fd); | ||
95 | } | ||
96 | |||
97 | static void extract_sb_section(struct sb_section_t *sec) | ||
98 | { | ||
99 | if(sec->is_data) | ||
100 | { | ||
101 | char sec_name[5]; | ||
102 | char *filename = xmalloc(strlen(g_out_prefix) + 32); | ||
103 | sb_fill_section_name(sec_name, sec->identifier); | ||
104 | sprintf(filename, "%s%s.bin", g_out_prefix, sec_name); | ||
105 | FILE *fd = fopen(filename, "wb"); | ||
106 | if(fd == NULL) | ||
107 | bugp("Cannot open %s for writing\n", filename); | ||
108 | if(g_debug) | ||
109 | printf("Write data section %s to %s\n", sec_name, filename); | ||
110 | free(filename); | ||
111 | |||
112 | for(int j = 0; j < sec->nr_insts; j++) | ||
113 | { | ||
114 | assert(sec->insts[j].inst == SB_INST_DATA); | ||
115 | fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd); | ||
116 | } | ||
117 | fclose(fd); | ||
118 | } | ||
119 | |||
120 | int elf_count = 0; | ||
121 | struct elf_params_t elf; | ||
122 | elf_init(&elf); | ||
123 | |||
124 | for(int i = 0; i < sec->nr_insts; i++) | ||
125 | { | ||
126 | struct sb_inst_t *inst = &sec->insts[i]; | ||
127 | switch(inst->inst) | ||
128 | { | ||
129 | case SB_INST_LOAD: | ||
130 | elf_add_load_section(&elf, inst->addr, inst->size, inst->data); | ||
131 | break; | ||
132 | case SB_INST_FILL: | ||
133 | elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern); | ||
134 | break; | ||
135 | case SB_INST_CALL: | ||
136 | case SB_INST_JUMP: | ||
137 | elf_set_start_addr(&elf, inst->addr); | ||
138 | extract_elf_section(&elf, elf_count++, sec->identifier); | ||
139 | elf_release(&elf); | ||
140 | elf_init(&elf); | ||
141 | break; | ||
142 | default: | ||
143 | /* ignore mode and nop */ | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | if(!elf_is_empty(&elf)) | ||
149 | extract_elf_section(&elf, elf_count, sec->identifier); | ||
150 | elf_release(&elf); | ||
151 | } | ||
152 | |||
153 | static void extract_sb_file(struct sb_file_t *file) | ||
154 | { | ||
155 | for(int i = 0; i < file->nr_sections; i++) | ||
156 | extract_sb_section(&file->sections[i]); | ||
157 | } | ||
158 | |||
159 | static void usage(void) | ||
160 | { | ||
161 | printf("Usage: sbtoelf [options] sb-file\n"); | ||
162 | printf("Options:\n"); | ||
163 | printf(" -?/--help\tDisplay this message\n"); | ||
164 | printf(" -o <prefix>\tEnable output and set prefix\n"); | ||
165 | printf(" -d/--debug\tEnable debug output*\n"); | ||
166 | printf(" -k <file>\tAdd key file\n"); | ||
167 | printf(" -z\t\tAdd zero key\n"); | ||
168 | printf(" -r\t\tUse raw command mode\n"); | ||
169 | printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); | ||
170 | printf(" -n/--no-color\tDisable output colors\n"); | ||
171 | printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n"); | ||
172 | printf("Options marked with a * are for debug purpose only\n"); | ||
173 | exit(1); | ||
174 | } | ||
175 | |||
176 | static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...) | ||
177 | { | ||
178 | (void) user; | ||
179 | (void) error; | ||
180 | va_list args; | ||
181 | va_start(args, fmt); | ||
182 | color(c); | ||
183 | vprintf(fmt, args); | ||
184 | va_end(args); | ||
185 | } | ||
186 | |||
187 | static struct crypto_key_t g_zero_key = | ||
188 | { | ||
189 | .method = CRYPTO_KEY, | ||
190 | .u.key = {0} | ||
191 | }; | ||
192 | |||
193 | int main(int argc, char **argv) | ||
194 | { | ||
195 | bool raw_mode = false; | ||
196 | const char *loopback = NULL; | ||
197 | |||
198 | while(1) | ||
199 | { | ||
200 | static struct option long_options[] = | ||
201 | { | ||
202 | {"help", no_argument, 0, '?'}, | ||
203 | {"debug", no_argument, 0, 'd'}, | ||
204 | {"add-key", required_argument, 0, 'a'}, | ||
205 | {"no-color", no_argument, 0, 'n'}, | ||
206 | {"loopback", required_argument, 0, 'l'}, | ||
207 | {0, 0, 0, 0} | ||
208 | }; | ||
209 | |||
210 | int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL); | ||
211 | if(c == -1) | ||
212 | break; | ||
213 | switch(c) | ||
214 | { | ||
215 | case -1: | ||
216 | break; | ||
217 | case 'l': | ||
218 | if(loopback) | ||
219 | bug("Only one loopback file can be specified !\n"); | ||
220 | loopback = optarg; | ||
221 | break; | ||
222 | case 'n': | ||
223 | enable_color(false); | ||
224 | break; | ||
225 | case 'd': | ||
226 | g_debug = true; | ||
227 | break; | ||
228 | case '?': | ||
229 | usage(); | ||
230 | break; | ||
231 | case 'o': | ||
232 | g_out_prefix = optarg; | ||
233 | break; | ||
234 | case 'k': | ||
235 | { | ||
236 | add_keys_from_file(optarg); | ||
237 | break; | ||
238 | } | ||
239 | case 'z': | ||
240 | { | ||
241 | add_keys(&g_zero_key, 1); | ||
242 | break; | ||
243 | } | ||
244 | case 'r': | ||
245 | raw_mode = true; | ||
246 | break; | ||
247 | case 'a': | ||
248 | { | ||
249 | struct crypto_key_t key; | ||
250 | char *s = optarg; | ||
251 | if(!parse_key(&s, &key)) | ||
252 | bug("Invalid key specified as argument"); | ||
253 | if(*s != 0) | ||
254 | bug("Trailing characters after key specified as argument"); | ||
255 | add_keys(&key, 1); | ||
256 | break; | ||
257 | } | ||
258 | default: | ||
259 | abort(); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if(argc - optind != 1) | ||
264 | { | ||
265 | usage(); | ||
266 | return 1; | ||
267 | } | ||
268 | |||
269 | const char *sb_filename = argv[optind]; | ||
270 | |||
271 | enum sb_error_t err; | ||
272 | struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err); | ||
273 | if(file == NULL) | ||
274 | { | ||
275 | color(OFF); | ||
276 | printf("SB read failed: %d\n", err); | ||
277 | return 1; | ||
278 | } | ||
279 | |||
280 | color(OFF); | ||
281 | if(g_out_prefix) | ||
282 | extract_sb_file(file); | ||
283 | if(g_debug) | ||
284 | { | ||
285 | color(GREY); | ||
286 | printf("[Debug output]\n"); | ||
287 | sb_dump(file, NULL, sb_printf); | ||
288 | } | ||
289 | if(loopback) | ||
290 | { | ||
291 | /* sb_read_file will fill real key and IV but we don't want to override | ||
292 | * them when looping back otherwise the output will be inconsistent and | ||
293 | * garbage */ | ||
294 | file->override_real_key = false; | ||
295 | file->override_crypto_iv = false; | ||
296 | sb_write_file(file, loopback); | ||
297 | } | ||
298 | sb_free(file); | ||
299 | clear_keys(); | ||
300 | |||
301 | return 0; | ||
302 | } | ||