summaryrefslogtreecommitdiff
path: root/utils/imxtools/elftosb.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/imxtools/elftosb.c')
-rw-r--r--utils/imxtools/elftosb.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/utils/imxtools/elftosb.c b/utils/imxtools/elftosb.c
new file mode 100644
index 0000000000..2f8700551f
--- /dev/null
+++ b/utils/imxtools/elftosb.c
@@ -0,0 +1,461 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
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#define _ISOC99_SOURCE
23#define _POSIX_C_SOURCE 200809L /* for strdup */
24#include <stdio.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <time.h>
30#include <stdarg.h>
31#include <strings.h>
32#include <getopt.h>
33
34#include "crypto.h"
35#include "elf.h"
36#include "sb.h"
37#include "dbparser.h"
38#include "misc.h"
39#include "sb.h"
40
41char **g_extern;
42int g_extern_count;
43
44#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
45
46#define crypto_cbc(...) \
47 do { int ret = crypto_cbc(__VA_ARGS__); \
48 if(ret != CRYPTO_ERROR_SUCCESS) \
49 bug("crypto_cbc error: %d\n", ret); \
50 }while(0)
51
52/**
53 * command file to sb conversion
54 */
55
56static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
57{
58 if(fseek((FILE *)user, addr, SEEK_SET) == -1)
59 return false;
60 return fread(buf, 1, count, (FILE *)user) == count;
61}
62
63static void elf_printf(void *user, bool error, const char *fmt, ...)
64{
65 if(!g_debug && !error)
66 return;
67 (void) user;
68 va_list args;
69 va_start(args, fmt);
70 vprintf(fmt, args);
71 va_end(args);
72}
73
74static void resolve_extern(struct cmd_source_t *src)
75{
76 if(!src->is_extern)
77 return;
78 src->is_extern = false;
79 if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
80 bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
81 /* first free the old src->filename content */
82 free(src->filename);
83 src->filename = strdup(g_extern[src->extern_nr]);
84}
85
86static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
87{
88 struct cmd_source_t *src = db_find_source_by_id(cmd_file, id);
89 if(src == NULL)
90 bug("undefined reference to source '%s'\n", id);
91 /* avoid reloading */
92 if(src->type == CMD_SRC_ELF && src->loaded)
93 return;
94 if(src->type != CMD_SRC_UNK)
95 bug("source '%s' seen both as elf and binary file\n", id);
96 /* resolve potential extern file */
97 resolve_extern(src);
98 /* load it */
99 src->type = CMD_SRC_ELF;
100 FILE *fd = fopen(src->filename, "rb");
101 if(fd == NULL)
102 bug("cannot open '%s' (id '%s')\n", src->filename, id);
103 if(g_debug)
104 printf("Loading ELF file '%s'...\n", src->filename);
105 elf_init(&src->elf);
106 src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd);
107 fclose(fd);
108 if(!src->loaded)
109 bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
110 elf_translate_addresses(&src->elf);
111}
112
113static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id)
114{
115 struct cmd_source_t *src = db_find_source_by_id(cmd_file, id);
116 if(src == NULL)
117 bug("undefined reference to source '%s'\n", id);
118 /* avoid reloading */
119 if(src->type == CMD_SRC_BIN && src->loaded)
120 return;
121 if(src->type != CMD_SRC_UNK)
122 bug("source '%s' seen both as elf and binary file\n", id);
123 /* resolve potential extern file */
124 resolve_extern(src);
125 /* load it */
126 src->type = CMD_SRC_BIN;
127 FILE *fd = fopen(src->filename, "rb");
128 if(fd == NULL)
129 bug("cannot open '%s' (id '%s')\n", src->filename, id);
130 if(g_debug)
131 printf("Loading BIN file '%s'...\n", src->filename);
132 fseek(fd, 0, SEEK_END);
133 src->bin.size = ftell(fd);
134 fseek(fd, 0, SEEK_SET);
135 src->bin.data = xmalloc(src->bin.size);
136 fread(src->bin.data, 1, src->bin.size, fd);
137 fclose(fd);
138 src->loaded = true;
139}
140
141static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
142{
143 struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t));
144 memset(sb, 0, sizeof(struct sb_file_t));
145
146 db_generate_default_sb_version(&sb->product_ver);
147 db_generate_default_sb_version(&sb->component_ver);
148
149 if(g_debug)
150 printf("Applying command file...\n");
151 /* count sections */
152 struct cmd_section_t *csec = cmd_file->section_list;
153 while(csec)
154 {
155 sb->nr_sections++;
156 csec = csec->next;
157 }
158
159 sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t));
160 memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t));
161 /* flatten sections */
162 csec = cmd_file->section_list;
163 for(int i = 0; i < sb->nr_sections; i++, csec = csec->next)
164 {
165 struct sb_section_t *sec = &sb->sections[i];
166 sec->identifier = csec->identifier;
167
168 /* options */
169 do
170 {
171 /* cleartext */
172 struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext");
173 if(opt != NULL)
174 {
175 if(opt->is_string)
176 bug("Cleartext section attribute must be an integer\n");
177 if(opt->val != 0 && opt->val != 1)
178 bug("Cleartext section attribute must be 0 or 1\n");
179 sec->is_cleartext = opt->val;
180 }
181 /* alignment */
182 opt = db_find_option_by_id(csec->opt_list, "alignment");
183 if(opt != NULL)
184 {
185 if(opt->is_string)
186 bug("Cleartext section attribute must be an integer\n");
187 // n is a power of 2 iff n & (n - 1) = 0
188 // alignement cannot be lower than block size
189 if((opt->val & (opt->val - 1)) != 0)
190 bug("Cleartext section attribute must be a power of two\n");
191 if(opt->val < BLOCK_SIZE)
192 sec->alignment = BLOCK_SIZE;
193 else
194 sec->alignment = opt->val;
195 }
196 else
197 sec->alignment = BLOCK_SIZE;
198 }while(0);
199
200 if(csec->is_data)
201 {
202 sec->is_data = true;
203 sec->nr_insts = 1;
204 sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t));
205 memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t));
206
207 load_bin_by_id(cmd_file, csec->source_id);
208 struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin;
209
210 sec->insts[0].inst = SB_INST_DATA;
211 sec->insts[0].size = bin->size;
212 sec->insts[0].data = memdup(bin->data, bin->size);
213 }
214 else
215 {
216 sec->is_data = false;
217 /* count instructions and loads things */
218 struct cmd_inst_t *cinst = csec->inst_list;
219 while(cinst)
220 {
221 if(cinst->type == CMD_LOAD)
222 {
223 load_elf_by_id(cmd_file, cinst->identifier);
224 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
225 sec->nr_insts += elf_get_nr_sections(elf);
226 }
227 else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
228 {
229 load_elf_by_id(cmd_file, cinst->identifier);
230 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
231 if(!elf_get_start_addr(elf, NULL))
232 bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier);
233 sec->nr_insts++;
234 }
235 else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT)
236 {
237 sec->nr_insts++;
238 }
239 else if(cinst->type == CMD_LOAD_AT)
240 {
241 load_bin_by_id(cmd_file, cinst->identifier);
242 sec->nr_insts++;
243 }
244 else if(cinst->type == CMD_MODE)
245 {
246 sec->nr_insts++;
247 }
248 else
249 bug("die\n");
250
251 cinst = cinst->next;
252 }
253
254 sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t));
255 memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t));
256 /* flatten */
257 int idx = 0;
258 cinst = csec->inst_list;
259 while(cinst)
260 {
261 if(cinst->type == CMD_LOAD)
262 {
263 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
264 struct elf_section_t *esec = elf->first_section;
265 while(esec)
266 {
267 if(esec->type == EST_LOAD)
268 {
269 sec->insts[idx].inst = SB_INST_LOAD;
270 sec->insts[idx].addr = esec->addr;
271 sec->insts[idx].size = esec->size;
272 sec->insts[idx++].data = memdup(esec->section, esec->size);
273 }
274 else if(esec->type == EST_FILL)
275 {
276 sec->insts[idx].inst = SB_INST_FILL;
277 sec->insts[idx].addr = esec->addr;
278 sec->insts[idx].size = esec->size;
279 sec->insts[idx++].pattern = esec->pattern;
280 }
281 esec = esec->next;
282 }
283 }
284 else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
285 {
286 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
287 sec->insts[idx].argument = cinst->argument;
288 sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL;
289 sec->insts[idx++].addr = elf->start_addr;
290 }
291 else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT)
292 {
293 sec->insts[idx].argument = cinst->argument;
294 sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL;
295 sec->insts[idx++].addr = cinst->addr;
296 }
297 else if(cinst->type == CMD_LOAD_AT)
298 {
299 struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
300 sec->insts[idx].inst = SB_INST_LOAD;
301 sec->insts[idx].addr = cinst->addr;
302 sec->insts[idx].data = memdup(bin->data, bin->size);
303 sec->insts[idx++].size = bin->size;
304 }
305 else if(cinst->type == CMD_MODE)
306 {
307 sec->insts[idx].inst = SB_INST_MODE;
308 sec->insts[idx++].addr = cinst->argument;
309 }
310 else
311 bug("die\n");
312
313 cinst = cinst->next;
314 }
315 }
316 }
317
318 return sb;
319}
320
321void usage(void)
322{
323 printf("Usage: elftosb [options | file]...\n");
324 printf("Options:\n");
325 printf(" -?/--help\tDisplay this message\n");
326 printf(" -o <file>\tSet output file\n");
327 printf(" -c <file>\tSet command file\n");
328 printf(" -d/--debug\tEnable debug output\n");
329 printf(" -k <file>\tAdd key file\n");
330 printf(" -z\t\tAdd zero key\n");
331 printf(" --add-key <key>\tAdd single key (hex or usbotp)\n");
332 printf(" --real-key <key>\tOverride real key\n");
333 printf(" --crypto-iv <iv>\tOverride crypto IV\n");
334 exit(1);
335}
336
337static struct crypto_key_t g_zero_key =
338{
339 .method = CRYPTO_KEY,
340 .u.key = {0}
341};
342
343int main(int argc, char **argv)
344{
345 char *cmd_filename = NULL;
346 char *output_filename = NULL;
347 struct crypto_key_t real_key;
348 struct crypto_key_t crypto_iv;
349 real_key.method = CRYPTO_NONE;
350 crypto_iv.method = CRYPTO_NONE;
351
352 while(1)
353 {
354 static struct option long_options[] =
355 {
356 {"help", no_argument, 0, '?'},
357 {"debug", no_argument, 0, 'd'},
358 {"add-key", required_argument, 0, 'a'},
359 {"real-key", required_argument, 0, 'r'},
360 {"crypto-iv", required_argument, 0, 'i'},
361 {0, 0, 0, 0}
362 };
363
364 int c = getopt_long(argc, argv, "?do:c:k:za:", long_options, NULL);
365 if(c == -1)
366 break;
367 switch(c)
368 {
369 case 'd':
370 g_debug = true;
371 break;
372 case '?':
373 usage();
374 break;
375 case 'o':
376 output_filename = optarg;
377 break;
378 case 'c':
379 cmd_filename = optarg;
380 break;
381 case 'k':
382 {
383 add_keys_from_file(optarg);
384 break;
385 }
386 case 'z':
387 {
388 add_keys(&g_zero_key, 1);
389 break;
390 }
391 case 'a':
392 case 'r':
393 case 'i':
394 {
395 struct crypto_key_t key;
396 char *s = optarg;
397 if(!parse_key(&s, &key))
398 bug("Invalid key/iv specified as argument");
399 if(*s != 0)
400 bug("Trailing characters after key/iv specified as argument");
401 if(c == 'r')
402 memcpy(&real_key, &key, sizeof(key));
403 else if(c == 'i')
404 memcpy(&crypto_iv, &key, sizeof(key));
405 else
406 add_keys(&key, 1);
407 break;
408 }
409 default:
410 abort();
411 }
412 }
413
414 if(!cmd_filename)
415 bug("You must specify a command file\n");
416 if(!output_filename)
417 bug("You must specify an output file\n");
418
419 g_extern = &argv[optind];
420 g_extern_count = argc - optind;
421
422 if(g_debug)
423 {
424 printf("key: %d\n", g_nr_keys);
425 for(int i = 0; i < g_nr_keys; i++)
426 {
427 printf(" ");
428 print_key(&g_key_array[i], true);
429 }
430
431 for(int i = 0; i < g_extern_count; i++)
432 printf("extern(%d)=%s\n", i, g_extern[i]);
433 }
434
435 struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
436 struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
437 db_free(cmd_file);
438
439 if(real_key.method == CRYPTO_KEY)
440 {
441 sb_file->override_real_key = true;
442 memcpy(sb_file->real_key, real_key.u.key, 16);
443 }
444 if(crypto_iv.method == CRYPTO_KEY)
445 {
446 sb_file->override_crypto_iv = true;
447 memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16);
448 }
449
450 /* fill with default parameters since there is no command file support for them */
451 sb_file->drive_tag = 0;
452 sb_file->first_boot_sec_id = sb_file->sections[0].identifier;
453 sb_file->flags = 0;
454 sb_file->minor_version = 1;
455
456 sb_write_file(sb_file, output_filename);
457 sb_free(sb_file);
458 clear_keys();
459
460 return 0;
461}