1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 Amaury Pouly
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 ****************************************************************************/
22 #define _ISOC99_SOURCE
23 #define _POSIX_C_SOURCE 200809L /* for strdup */
43 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
45 #define crypto_cbc(...) \
46 do { int ret = crypto_cbc(__VA_ARGS__); \
47 if(ret != CRYPTO_ERROR_SUCCESS) \
48 bug("crypto_cbc error: %d\n", ret); \
52 * command file to sb conversion
55 static bool elf_read(void *user
, uint32_t addr
, void *buf
, size_t count
)
57 if(fseek((FILE *)user
, addr
, SEEK_SET
) == -1)
59 return fread(buf
, 1, count
, (FILE *)user
) == count
;
62 static void elf_printf(void *user
, bool error
, const char *fmt
, ...)
64 if(!g_debug
&& !error
)
73 static void resolve_extern(struct cmd_source_t
*src
)
77 src
->is_extern
= false;
78 if(src
->extern_nr
< 0 || src
->extern_nr
>= g_extern_count
)
79 bug("There aren't enough file on command file to resolve extern(%d)\n", src
->extern_nr
);
80 /* first free the old src->filename content */
82 src
->filename
= strdup(g_extern
[src
->extern_nr
]);
85 static void load_elf_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
87 struct cmd_source_t
*src
= db_find_source_by_id(cmd_file
, id
);
89 bug("undefined reference to source '%s'\n", id
);
91 if(src
->type
== CMD_SRC_ELF
&& src
->loaded
)
93 if(src
->type
!= CMD_SRC_UNK
)
94 bug("source '%s' seen both as elf and binary file\n", id
);
95 /* resolve potential extern file */
98 src
->type
= CMD_SRC_ELF
;
99 FILE *fd
= fopen(src
->filename
, "rb");
101 bug("cannot open '%s' (id '%s')\n", src
->filename
, id
);
103 printf("Loading ELF file '%s'...\n", src
->filename
);
105 src
->loaded
= elf_read_file(&src
->elf
, elf_read
, elf_printf
, fd
);
108 bug("error loading elf file '%s' (id '%s')\n", src
->filename
, id
);
109 elf_translate_addresses(&src
->elf
);
112 static void load_bin_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
114 struct cmd_source_t
*src
= db_find_source_by_id(cmd_file
, id
);
116 bug("undefined reference to source '%s'\n", id
);
117 /* avoid reloading */
118 if(src
->type
== CMD_SRC_BIN
&& src
->loaded
)
120 if(src
->type
!= CMD_SRC_UNK
)
121 bug("source '%s' seen both as elf and binary file\n", id
);
122 /* resolve potential extern file */
125 src
->type
= CMD_SRC_BIN
;
126 FILE *fd
= fopen(src
->filename
, "rb");
128 bug("cannot open '%s' (id '%s')\n", src
->filename
, id
);
130 printf("Loading BIN file '%s'...\n", src
->filename
);
131 fseek(fd
, 0, SEEK_END
);
132 src
->bin
.size
= ftell(fd
);
133 fseek(fd
, 0, SEEK_SET
);
134 src
->bin
.data
= xmalloc(src
->bin
.size
);
135 fread(src
->bin
.data
, 1, src
->bin
.size
, fd
);
140 static struct sb_file_t
*apply_cmd_file(struct cmd_file_t
*cmd_file
)
142 struct sb_file_t
*sb
= xmalloc(sizeof(struct sb_file_t
));
143 memset(sb
, 0, sizeof(struct sb_file_t
));
145 db_generate_default_sb_version(&sb
->product_ver
);
146 db_generate_default_sb_version(&sb
->component_ver
);
149 printf("Applying command file...\n");
151 struct cmd_section_t
*csec
= cmd_file
->section_list
;
158 sb
->sections
= xmalloc(sb
->nr_sections
* sizeof(struct sb_section_t
));
159 memset(sb
->sections
, 0, sb
->nr_sections
* sizeof(struct sb_section_t
));
160 /* flatten sections */
161 csec
= cmd_file
->section_list
;
162 for(int i
= 0; i
< sb
->nr_sections
; i
++, csec
= csec
->next
)
164 struct sb_section_t
*sec
= &sb
->sections
[i
];
165 sec
->identifier
= csec
->identifier
;
171 struct cmd_option_t
*opt
= db_find_option_by_id(csec
->opt_list
, "cleartext");
175 bug("Cleartext section attribute must be an integer\n");
176 if(opt
->val
!= 0 && opt
->val
!= 1)
177 bug("Cleartext section attribute must be 0 or 1\n");
178 sec
->is_cleartext
= opt
->val
;
181 opt
= db_find_option_by_id(csec
->opt_list
, "alignment");
185 bug("Cleartext section attribute must be an integer\n");
186 // n is a power of 2 iff n & (n - 1) = 0
187 // alignement cannot be lower than block size
188 if((opt
->val
& (opt
->val
- 1)) != 0)
189 bug("Cleartext section attribute must be a power of two\n");
190 if(opt
->val
< BLOCK_SIZE
)
191 sec
->alignment
= BLOCK_SIZE
;
193 sec
->alignment
= opt
->val
;
196 sec
->alignment
= BLOCK_SIZE
;
203 sec
->insts
= xmalloc(sec
->nr_insts
* sizeof(struct sb_inst_t
));
204 memset(sec
->insts
, 0, sec
->nr_insts
* sizeof(struct sb_inst_t
));
206 load_bin_by_id(cmd_file
, csec
->source_id
);
207 struct bin_param_t
*bin
= &db_find_source_by_id(cmd_file
, csec
->source_id
)->bin
;
209 sec
->insts
[0].inst
= SB_INST_DATA
;
210 sec
->insts
[0].size
= bin
->size
;
211 sec
->insts
[0].data
= memdup(bin
->data
, bin
->size
);
215 sec
->is_data
= false;
216 /* count instructions and loads things */
217 struct cmd_inst_t
*cinst
= csec
->inst_list
;
220 if(cinst
->type
== CMD_LOAD
)
222 load_elf_by_id(cmd_file
, cinst
->identifier
);
223 struct elf_params_t
*elf
= &db_find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
224 sec
->nr_insts
+= elf_get_nr_sections(elf
);
226 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
228 load_elf_by_id(cmd_file
, cinst
->identifier
);
229 struct elf_params_t
*elf
= &db_find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
230 if(!elf_get_start_addr(elf
, NULL
))
231 bug("cannot jump/call '%s' because it has no starting point !\n", cinst
->identifier
);
234 else if(cinst
->type
== CMD_CALL_AT
|| cinst
->type
== CMD_JUMP_AT
)
238 else if(cinst
->type
== CMD_LOAD_AT
)
240 load_bin_by_id(cmd_file
, cinst
->identifier
);
243 else if(cinst
->type
== CMD_MODE
)
253 sec
->insts
= xmalloc(sec
->nr_insts
* sizeof(struct sb_inst_t
));
254 memset(sec
->insts
, 0, sec
->nr_insts
* sizeof(struct sb_inst_t
));
257 cinst
= csec
->inst_list
;
260 if(cinst
->type
== CMD_LOAD
)
262 struct elf_params_t
*elf
= &db_find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
263 struct elf_section_t
*esec
= elf
->first_section
;
266 if(esec
->type
== EST_LOAD
)
268 sec
->insts
[idx
].inst
= SB_INST_LOAD
;
269 sec
->insts
[idx
].addr
= esec
->addr
;
270 sec
->insts
[idx
].size
= esec
->size
;
271 sec
->insts
[idx
++].data
= memdup(esec
->section
, esec
->size
);
273 else if(esec
->type
== EST_FILL
)
275 sec
->insts
[idx
].inst
= SB_INST_FILL
;
276 sec
->insts
[idx
].addr
= esec
->addr
;
277 sec
->insts
[idx
].size
= esec
->size
;
278 sec
->insts
[idx
++].pattern
= esec
->pattern
;
283 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
285 struct elf_params_t
*elf
= &db_find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
286 sec
->insts
[idx
].argument
= cinst
->argument
;
287 sec
->insts
[idx
].inst
= (cinst
->type
== CMD_JUMP
) ? SB_INST_JUMP
: SB_INST_CALL
;
288 sec
->insts
[idx
++].addr
= elf
->start_addr
;
290 else if(cinst
->type
== CMD_JUMP_AT
|| cinst
->type
== CMD_CALL_AT
)
292 sec
->insts
[idx
].argument
= cinst
->argument
;
293 sec
->insts
[idx
].inst
= (cinst
->type
== CMD_JUMP_AT
) ? SB_INST_JUMP
: SB_INST_CALL
;
294 sec
->insts
[idx
++].addr
= cinst
->addr
;
296 else if(cinst
->type
== CMD_LOAD_AT
)
298 struct bin_param_t
*bin
= &db_find_source_by_id(cmd_file
, cinst
->identifier
)->bin
;
299 sec
->insts
[idx
].inst
= SB_INST_LOAD
;
300 sec
->insts
[idx
].addr
= cinst
->addr
;
301 sec
->insts
[idx
].data
= memdup(bin
->data
, bin
->size
);
302 sec
->insts
[idx
++].size
= bin
->size
;
304 else if(cinst
->type
== CMD_MODE
)
306 sec
->insts
[idx
].inst
= SB_INST_MODE
;
307 sec
->insts
[idx
++].addr
= cinst
->argument
;
320 static void usage(void)
322 printf("Usage: elftosb [options | file]...\n");
323 printf("Options:\n");
324 printf(" -?/--help\tDisplay this message\n");
325 printf(" -o <file>\tSet output file\n");
326 printf(" -c <file>\tSet command file\n");
327 printf(" -d/--debug\tEnable debug output\n");
328 printf(" -k <file>\tAdd key file\n");
329 printf(" -z\t\tAdd zero key\n");
330 printf(" --add-key <key>\tAdd single key (hex or usbotp)\n");
331 printf(" --real-key <key>\tOverride real key\n");
332 printf(" --crypto-iv <iv>\tOverride crypto IV\n");
336 static struct crypto_key_t g_zero_key
=
338 .method
= CRYPTO_KEY
,
342 int main(int argc
, char **argv
)
344 char *cmd_filename
= NULL
;
345 char *output_filename
= NULL
;
346 struct crypto_key_t real_key
;
347 struct crypto_key_t crypto_iv
;
348 real_key
.method
= CRYPTO_NONE
;
349 crypto_iv
.method
= CRYPTO_NONE
;
353 static struct option long_options
[] =
355 {"help", no_argument
, 0, '?'},
356 {"debug", no_argument
, 0, 'd'},
357 {"add-key", required_argument
, 0, 'a'},
358 {"real-key", required_argument
, 0, 'r'},
359 {"crypto-iv", required_argument
, 0, 'i'},
363 int c
= getopt_long(argc
, argv
, "?do:c:k:za:", long_options
, NULL
);
375 output_filename
= optarg
;
378 cmd_filename
= optarg
;
382 if(!add_keys_from_file(optarg
))
383 bug("Cannot keys from %s\n", optarg
);
388 add_keys(&g_zero_key
, 1);
395 struct crypto_key_t key
;
397 if(!parse_key(&s
, &key
))
398 bug("Invalid key/iv specified as argument");
400 bug("Trailing characters after key/iv specified as argument");
402 memcpy(&real_key
, &key
, sizeof(key
));
404 memcpy(&crypto_iv
, &key
, sizeof(key
));
415 bug("You must specify a command file\n");
417 bug("You must specify an output file\n");
419 g_extern
= &argv
[optind
];
420 g_extern_count
= argc
- optind
;
424 printf("key: %d\n", g_nr_keys
);
425 for(int i
= 0; i
< g_nr_keys
; i
++)
428 print_key(&g_key_array
[i
], true);
431 for(int i
= 0; i
< g_extern_count
; i
++)
432 printf("extern(%d)=%s\n", i
, g_extern
[i
]);
435 struct cmd_file_t
*cmd_file
= db_parse_file(cmd_filename
);
436 struct sb_file_t
*sb_file
= apply_cmd_file(cmd_file
);
439 if(real_key
.method
== CRYPTO_KEY
)
441 sb_file
->override_real_key
= true;
442 memcpy(sb_file
->real_key
, real_key
.u
.key
, 16);
444 if(crypto_iv
.method
== CRYPTO_KEY
)
446 sb_file
->override_crypto_iv
= true;
447 memcpy(sb_file
->crypto_iv
, crypto_iv
.u
.key
, 16);
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
;
454 sb_file
->minor_version
= 1;
456 sb_write_file(sb_file
, output_filename
);