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 */
44 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
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); \
53 * command file to sb conversion
56 static bool elf_read(void *user
, uint32_t addr
, void *buf
, size_t count
)
58 if(fseek((FILE *)user
, addr
, SEEK_SET
) == -1)
60 return fread(buf
, 1, count
, (FILE *)user
) == count
;
63 static void elf_printf(void *user
, bool error
, const char *fmt
, ...)
65 if(!g_debug
&& !error
)
74 static void resolve_extern(struct cmd_source_t
*src
)
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 */
83 src
->filename
= strdup(g_extern
[src
->extern_nr
]);
86 static void load_elf_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
88 struct cmd_source_t
*src
= db_find_source_by_id(cmd_file
, id
);
90 bug("undefined reference to source '%s'\n", id
);
92 if(src
->type
== CMD_SRC_ELF
&& src
->loaded
)
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 */
99 src
->type
= CMD_SRC_ELF
;
100 FILE *fd
= fopen(src
->filename
, "rb");
102 bug("cannot open '%s' (id '%s')\n", src
->filename
, id
);
104 printf("Loading ELF file '%s'...\n", src
->filename
);
106 src
->loaded
= elf_read_file(&src
->elf
, elf_read
, elf_printf
, fd
);
109 bug("error loading elf file '%s' (id '%s')\n", src
->filename
, id
);
110 elf_translate_addresses(&src
->elf
);
113 static void load_bin_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
115 struct cmd_source_t
*src
= db_find_source_by_id(cmd_file
, id
);
117 bug("undefined reference to source '%s'\n", id
);
118 /* avoid reloading */
119 if(src
->type
== CMD_SRC_BIN
&& src
->loaded
)
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 */
126 src
->type
= CMD_SRC_BIN
;
127 FILE *fd
= fopen(src
->filename
, "rb");
129 bug("cannot open '%s' (id '%s')\n", src
->filename
, id
);
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
);
141 static struct sb_file_t
*apply_cmd_file(struct cmd_file_t
*cmd_file
)
143 struct sb_file_t
*sb
= xmalloc(sizeof(struct sb_file_t
));
144 memset(sb
, 0, sizeof(struct sb_file_t
));
146 db_generate_default_sb_version(&sb
->product_ver
);
147 db_generate_default_sb_version(&sb
->component_ver
);
150 printf("Applying command file...\n");
152 struct cmd_section_t
*csec
= cmd_file
->section_list
;
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
)
165 struct sb_section_t
*sec
= &sb
->sections
[i
];
166 sec
->identifier
= csec
->identifier
;
172 struct cmd_option_t
*opt
= db_find_option_by_id(csec
->opt_list
, "cleartext");
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
;
182 opt
= db_find_option_by_id(csec
->opt_list
, "alignment");
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
;
194 sec
->alignment
= opt
->val
;
197 sec
->alignment
= BLOCK_SIZE
;
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
));
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
;
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
);
216 sec
->is_data
= false;
217 /* count instructions and loads things */
218 struct cmd_inst_t
*cinst
= csec
->inst_list
;
221 if(cinst
->type
== CMD_LOAD
)
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
);
227 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
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
);
235 else if(cinst
->type
== CMD_CALL_AT
|| cinst
->type
== CMD_JUMP_AT
)
239 else if(cinst
->type
== CMD_LOAD_AT
)
241 load_bin_by_id(cmd_file
, cinst
->identifier
);
244 else if(cinst
->type
== CMD_MODE
)
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
));
258 cinst
= csec
->inst_list
;
261 if(cinst
->type
== CMD_LOAD
)
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
;
267 if(esec
->type
== EST_LOAD
)
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
);
274 else if(esec
->type
== EST_FILL
)
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
;
284 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
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
;
291 else if(cinst
->type
== CMD_JUMP_AT
|| cinst
->type
== CMD_CALL_AT
)
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
;
297 else if(cinst
->type
== CMD_LOAD_AT
)
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
;
305 else if(cinst
->type
== CMD_MODE
)
307 sec
->insts
[idx
].inst
= SB_INST_MODE
;
308 sec
->insts
[idx
++].addr
= cinst
->argument
;
321 static void usage(void)
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");
337 static struct crypto_key_t g_zero_key
=
339 .method
= CRYPTO_KEY
,
343 int main(int argc
, char **argv
)
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
;
354 static struct option long_options
[] =
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'},
364 int c
= getopt_long(argc
, argv
, "?do:c:k:za:", long_options
, NULL
);
376 output_filename
= optarg
;
379 cmd_filename
= optarg
;
383 if(!add_keys_from_file(optarg
))
384 bug("Cannot keys from %s\n", optarg
);
389 add_keys(&g_zero_key
, 1);
396 struct crypto_key_t key
;
398 if(!parse_key(&s
, &key
))
399 bug("Invalid key/iv specified as argument");
401 bug("Trailing characters after key/iv specified as argument");
403 memcpy(&real_key
, &key
, sizeof(key
));
405 memcpy(&crypto_iv
, &key
, sizeof(key
));
416 bug("You must specify a command file\n");
418 bug("You must specify an output file\n");
420 g_extern
= &argv
[optind
];
421 g_extern_count
= argc
- optind
;
425 printf("key: %d\n", g_nr_keys
);
426 for(int i
= 0; i
< g_nr_keys
; i
++)
429 print_key(&g_key_array
[i
], true);
432 for(int i
= 0; i
< g_extern_count
; i
++)
433 printf("extern(%d)=%s\n", i
, g_extern
[i
]);
436 struct cmd_file_t
*cmd_file
= db_parse_file(cmd_filename
);
437 struct sb_file_t
*sb_file
= apply_cmd_file(cmd_file
);
440 if(real_key
.method
== CRYPTO_KEY
)
442 sb_file
->override_real_key
= true;
443 memcpy(sb_file
->real_key
, real_key
.u
.key
, 16);
445 if(crypto_iv
.method
== CRYPTO_KEY
)
447 sb_file
->override_crypto_iv
= true;
448 memcpy(sb_file
->crypto_iv
, crypto_iv
.u
.key
, 16);
451 /* fill with default parameters since there is no command file support for them */
452 sb_file
->drive_tag
= 0;
453 sb_file
->first_boot_sec_id
= sb_file
->sections
[0].identifier
;
455 sb_file
->minor_version
= 1;
457 sb_write_file(sb_file
, output_filename
);