diff options
Diffstat (limited to 'utils/sbtools/elftosb.c')
-rw-r--r-- | utils/sbtools/elftosb.c | 215 |
1 files changed, 204 insertions, 11 deletions
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c index 73768dd9a3..c4887ab47a 100644 --- a/utils/sbtools/elftosb.c +++ b/utils/sbtools/elftosb.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <string.h> | 31 | #include <string.h> |
32 | #include <ctype.h> | 32 | #include <ctype.h> |
33 | #include <time.h> | 33 | #include <time.h> |
34 | #include <stdarg.h> | ||
34 | 35 | ||
35 | #include "crypto.h" | 36 | #include "crypto.h" |
36 | #include "elf.h" | 37 | #include "elf.h" |
@@ -39,6 +40,12 @@ | |||
39 | #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0) | 40 | #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0) |
40 | #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0) | 41 | #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0) |
41 | 42 | ||
43 | bool g_debug = false; | ||
44 | |||
45 | /** | ||
46 | * Misc | ||
47 | */ | ||
48 | |||
42 | void *xmalloc(size_t s) /* malloc helper, used in elf.c */ | 49 | void *xmalloc(size_t s) /* malloc helper, used in elf.c */ |
43 | { | 50 | { |
44 | void * r = malloc(s); | 51 | void * r = malloc(s); |
@@ -67,6 +74,10 @@ static int convxdigit(char digit, byte *val) | |||
67 | return 1; | 74 | return 1; |
68 | } | 75 | } |
69 | 76 | ||
77 | /** | ||
78 | * Key file parsing | ||
79 | */ | ||
80 | |||
70 | typedef byte (*key_array_t)[16]; | 81 | typedef byte (*key_array_t)[16]; |
71 | 82 | ||
72 | static key_array_t read_keys(const char *key_file, int *num_keys) | 83 | static key_array_t read_keys(const char *key_file, int *num_keys) |
@@ -117,11 +128,18 @@ static key_array_t read_keys(const char *key_file, int *num_keys) | |||
117 | return keys; | 128 | return keys; |
118 | } | 129 | } |
119 | 130 | ||
131 | /** | ||
132 | * Command file parsing | ||
133 | */ | ||
134 | |||
120 | struct cmd_source_t | 135 | struct cmd_source_t |
121 | { | 136 | { |
122 | char *identifier; | 137 | char *identifier; |
123 | char *filename; | 138 | char *filename; |
124 | struct cmd_source_t *next; | 139 | struct cmd_source_t *next; |
140 | /* for later use */ | ||
141 | bool elf_loaded; | ||
142 | struct elf_params_t elf; | ||
125 | }; | 143 | }; |
126 | 144 | ||
127 | enum cmd_inst_type_t | 145 | enum cmd_inst_type_t |
@@ -142,6 +160,7 @@ struct cmd_section_t | |||
142 | { | 160 | { |
143 | uint32_t identifier; | 161 | uint32_t identifier; |
144 | struct cmd_inst_t *inst_list; | 162 | struct cmd_inst_t *inst_list; |
163 | struct cmd_section_t *next; | ||
145 | }; | 164 | }; |
146 | 165 | ||
147 | struct cmd_file_t | 166 | struct cmd_file_t |
@@ -171,7 +190,7 @@ struct lexem_t | |||
171 | uint32_t num; | 190 | uint32_t num; |
172 | }; | 191 | }; |
173 | 192 | ||
174 | void __parse_string(char **ptr, char *end, void *user, void (*emit_fn)(void *user, char c)) | 193 | static void __parse_string(char **ptr, char *end, void *user, void (*emit_fn)(void *user, char c)) |
175 | { | 194 | { |
176 | while(*ptr != end) | 195 | while(*ptr != end) |
177 | { | 196 | { |
@@ -196,19 +215,19 @@ void __parse_string(char **ptr, char *end, void *user, void (*emit_fn)(void *use | |||
196 | (*ptr)++; | 215 | (*ptr)++; |
197 | } | 216 | } |
198 | 217 | ||
199 | void __parse_string_emit(void *user, char c) | 218 | static void __parse_string_emit(void *user, char c) |
200 | { | 219 | { |
201 | char **pstr = (char **)user; | 220 | char **pstr = (char **)user; |
202 | *(*pstr)++ = c; | 221 | *(*pstr)++ = c; |
203 | } | 222 | } |
204 | 223 | ||
205 | void __parse_string_count(void *user, char c) | 224 | static void __parse_string_count(void *user, char c) |
206 | { | 225 | { |
207 | (void) c; | 226 | (void) c; |
208 | (*(int *)user)++; | 227 | (*(int *)user)++; |
209 | } | 228 | } |
210 | 229 | ||
211 | void parse_string(char **ptr, char *end, struct lexem_t *lexem) | 230 | static void parse_string(char **ptr, char *end, struct lexem_t *lexem) |
212 | { | 231 | { |
213 | /* skip " */ | 232 | /* skip " */ |
214 | (*ptr)++; | 233 | (*ptr)++; |
@@ -224,7 +243,7 @@ void parse_string(char **ptr, char *end, struct lexem_t *lexem) | |||
224 | __parse_string(ptr, end, (void *)&pstr, __parse_string_emit); | 243 | __parse_string(ptr, end, (void *)&pstr, __parse_string_emit); |
225 | } | 244 | } |
226 | 245 | ||
227 | void parse_number(char **ptr, char *end, struct lexem_t *lexem) | 246 | static void parse_number(char **ptr, char *end, struct lexem_t *lexem) |
228 | { | 247 | { |
229 | int base = 10; | 248 | int base = 10; |
230 | if(**ptr == '0' && (*ptr) + 1 != end && (*ptr)[1] == 'x') | 249 | if(**ptr == '0' && (*ptr) + 1 != end && (*ptr)[1] == 'x') |
@@ -247,7 +266,7 @@ void parse_number(char **ptr, char *end, struct lexem_t *lexem) | |||
247 | } | 266 | } |
248 | } | 267 | } |
249 | 268 | ||
250 | void parse_identifier(char **ptr, char *end, struct lexem_t *lexem) | 269 | static void parse_identifier(char **ptr, char *end, struct lexem_t *lexem) |
251 | { | 270 | { |
252 | /* remember position */ | 271 | /* remember position */ |
253 | char *old = *ptr; | 272 | char *old = *ptr; |
@@ -260,7 +279,7 @@ void parse_identifier(char **ptr, char *end, struct lexem_t *lexem) | |||
260 | memcpy(lexem->str, old, len); | 279 | memcpy(lexem->str, old, len); |
261 | } | 280 | } |
262 | 281 | ||
263 | void next_lexem(char **ptr, char *end, struct lexem_t *lexem) | 282 | static void next_lexem(char **ptr, char *end, struct lexem_t *lexem) |
264 | { | 283 | { |
265 | #define ret_simple(t, advance) ({(*ptr) += advance; lexem->type = t; return;}) | 284 | #define ret_simple(t, advance) ({(*ptr) += advance; lexem->type = t; return;}) |
266 | while(true) | 285 | while(true) |
@@ -294,7 +313,7 @@ void next_lexem(char **ptr, char *end, struct lexem_t *lexem) | |||
294 | #undef ret_simple | 313 | #undef ret_simple |
295 | } | 314 | } |
296 | 315 | ||
297 | void log_lexem(struct lexem_t *lexem) | 316 | static void log_lexem(struct lexem_t *lexem) |
298 | { | 317 | { |
299 | switch(lexem->type) | 318 | switch(lexem->type) |
300 | { | 319 | { |
@@ -312,19 +331,19 @@ void log_lexem(struct lexem_t *lexem) | |||
312 | } | 331 | } |
313 | } | 332 | } |
314 | 333 | ||
315 | char *find_source_by_id(struct cmd_file_t *cmd_file, const char *id) | 334 | static struct cmd_source_t *find_source_by_id(struct cmd_file_t *cmd_file, const char *id) |
316 | { | 335 | { |
317 | struct cmd_source_t *src = cmd_file->source_list; | 336 | struct cmd_source_t *src = cmd_file->source_list; |
318 | while(src) | 337 | while(src) |
319 | { | 338 | { |
320 | if(strcmp(src->identifier, id) == 0) | 339 | if(strcmp(src->identifier, id) == 0) |
321 | return src->filename; | 340 | return src; |
322 | src = src->next; | 341 | src = src->next; |
323 | } | 342 | } |
324 | return NULL; | 343 | return NULL; |
325 | } | 344 | } |
326 | 345 | ||
327 | struct cmd_file_t *read_command_file(const char *file) | 346 | static struct cmd_file_t *read_command_file(const char *file) |
328 | { | 347 | { |
329 | int size; | 348 | int size; |
330 | struct stat st; | 349 | struct stat st; |
@@ -380,6 +399,7 @@ struct cmd_file_t *read_command_file(const char *file) | |||
380 | } | 399 | } |
381 | 400 | ||
382 | /* sections */ | 401 | /* sections */ |
402 | struct cmd_section_t *end_sec = NULL; | ||
383 | while(true) | 403 | while(true) |
384 | { | 404 | { |
385 | struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); | 405 | struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); |
@@ -442,12 +462,184 @@ struct cmd_file_t *read_command_file(const char *file) | |||
442 | end_list = inst; | 462 | end_list = inst; |
443 | } | 463 | } |
444 | } | 464 | } |
465 | |||
466 | if(end_sec == NULL) | ||
467 | { | ||
468 | cmd_file->section_list = sec; | ||
469 | end_sec = sec; | ||
470 | } | ||
471 | else | ||
472 | { | ||
473 | end_sec->next = sec; | ||
474 | end_sec = sec; | ||
475 | } | ||
445 | } | 476 | } |
446 | #undef next | 477 | #undef next |
447 | 478 | ||
448 | return cmd_file; | 479 | return cmd_file; |
449 | } | 480 | } |
450 | 481 | ||
482 | /** | ||
483 | * command file to sb conversion | ||
484 | */ | ||
485 | |||
486 | struct sb_inst_t | ||
487 | { | ||
488 | uint8_t inst; /* SB_INST_* */ | ||
489 | uint32_t size; | ||
490 | // <union> | ||
491 | void *data; | ||
492 | uint32_t pattern; | ||
493 | uint32_t addr; | ||
494 | // </union> | ||
495 | }; | ||
496 | |||
497 | struct sb_section_t | ||
498 | { | ||
499 | uint32_t identifier; | ||
500 | int nr_insts; | ||
501 | struct sb_inst_t *insts; | ||
502 | }; | ||
503 | |||
504 | struct sb_file_t | ||
505 | { | ||
506 | int nr_sections; | ||
507 | struct sb_section_t *sections; | ||
508 | }; | ||
509 | |||
510 | static bool elf_read(void *user, uint32_t addr, void *buf, size_t count) | ||
511 | { | ||
512 | if(lseek(*(int *)user, addr, SEEK_SET) == (off_t)-1) | ||
513 | return false; | ||
514 | return read(*(int *)user, buf, count) == (ssize_t)count; | ||
515 | } | ||
516 | |||
517 | static void elf_printf(void *user, bool error, const char *fmt, ...) | ||
518 | { | ||
519 | if(!g_debug && !error) | ||
520 | return; | ||
521 | (void) user; | ||
522 | va_list args; | ||
523 | va_start(args, fmt); | ||
524 | vprintf(fmt, args); | ||
525 | va_end(args); | ||
526 | } | ||
527 | |||
528 | static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
529 | { | ||
530 | struct cmd_source_t *src = find_source_by_id(cmd_file, id); | ||
531 | if(src == NULL) | ||
532 | bug("undefined reference to source '%s'\n", id); | ||
533 | /* avoid reloading */ | ||
534 | if(src->elf_loaded) | ||
535 | return; | ||
536 | int fd = open(src->filename, O_RDONLY); | ||
537 | if(fd < 0) | ||
538 | bug("cannot open '%s' (id '%s')\n", src->filename, id); | ||
539 | elf_init(&src->elf); | ||
540 | src->elf_loaded = elf_read_file(&src->elf, elf_read, elf_printf, &fd); | ||
541 | close(fd); | ||
542 | if(!src->elf_loaded) | ||
543 | bug("error loading elf file '%s' (id '%s')\n", src->filename, id); | ||
544 | } | ||
545 | |||
546 | static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | ||
547 | { | ||
548 | struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); | ||
549 | memset(sb, 0, sizeof(struct sb_file_t)); | ||
550 | /* count sections */ | ||
551 | struct cmd_section_t *csec = cmd_file->section_list; | ||
552 | while(csec) | ||
553 | { | ||
554 | sb->nr_sections++; | ||
555 | csec = csec->next; | ||
556 | } | ||
557 | |||
558 | sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t)); | ||
559 | memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t)); | ||
560 | /* flatten sections */ | ||
561 | csec = cmd_file->section_list; | ||
562 | for(int i = 0; i < sb->nr_sections; i++, csec = csec->next) | ||
563 | { | ||
564 | struct sb_section_t *sec = &sb->sections[i]; | ||
565 | sec->identifier = csec->identifier; | ||
566 | /* count instructions */ | ||
567 | struct cmd_inst_t *cinst = csec->inst_list; | ||
568 | while(cinst) | ||
569 | { | ||
570 | load_elf_by_id(cmd_file, cinst->identifier); | ||
571 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
572 | |||
573 | if(cinst->type == CMD_LOAD) | ||
574 | sec->nr_insts += elf_get_nr_sections(elf); | ||
575 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_LOAD) | ||
576 | { | ||
577 | if(!elf_get_start_addr(elf, NULL)) | ||
578 | bug("cannot jump/call '%s' because it has no starting point !", cinst->identifier); | ||
579 | sec->nr_insts++; | ||
580 | } | ||
581 | |||
582 | cinst = cinst->next; | ||
583 | } | ||
584 | |||
585 | sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); | ||
586 | memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); | ||
587 | /* flatten */ | ||
588 | int idx = 0; | ||
589 | cinst = csec->inst_list; | ||
590 | while(cinst) | ||
591 | { | ||
592 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
593 | |||
594 | if(cinst->type == CMD_LOAD) | ||
595 | { | ||
596 | struct elf_section_t *esec = elf->first_section; | ||
597 | while(esec) | ||
598 | { | ||
599 | if(esec->type == EST_LOAD) | ||
600 | { | ||
601 | sec->insts[idx].inst = SB_INST_LOAD; | ||
602 | sec->insts[idx].addr = esec->addr; | ||
603 | sec->insts[idx].size = esec->size; | ||
604 | sec->insts[idx++].data = esec->section; | ||
605 | if(g_debug) | ||
606 | printf("LOAD | addr=0x%08x | len=0x%08x | crc=0x%08x\n", | ||
607 | esec->addr, esec->size, 0); | ||
608 | } | ||
609 | else if(esec->type == EST_FILL) | ||
610 | { | ||
611 | sec->insts[idx].inst = SB_INST_FILL; | ||
612 | sec->insts[idx].addr = esec->addr; | ||
613 | sec->insts[idx].size = esec->size; | ||
614 | sec->insts[idx++].pattern = esec->pattern; | ||
615 | if(g_debug) | ||
616 | printf("FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n", | ||
617 | esec->addr, esec->size, esec->pattern); | ||
618 | } | ||
619 | esec = esec->next; | ||
620 | } | ||
621 | } | ||
622 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_LOAD) | ||
623 | { | ||
624 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; | ||
625 | sec->insts[idx++].addr = elf->start_addr; | ||
626 | if(g_debug) | ||
627 | printf("%s | addr=0x%08x | arg=0x%08x\n", | ||
628 | (cinst->type == CMD_JUMP) ? "JUMP" : "CALL", | ||
629 | elf->start_addr, 0); | ||
630 | } | ||
631 | |||
632 | cinst = cinst->next; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | return sb; | ||
637 | } | ||
638 | |||
639 | /** | ||
640 | * Sb file production | ||
641 | */ | ||
642 | |||
451 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | 643 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) |
452 | 644 | ||
453 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) | 645 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) |
@@ -467,6 +659,7 @@ int main(int argc, const char **argv) | |||
467 | int nr_keys; | 659 | int nr_keys; |
468 | key_array_t key_array = read_keys(argv[2], &nr_keys); | 660 | key_array_t key_array = read_keys(argv[2], &nr_keys); |
469 | struct cmd_file_t *cmd_file = read_command_file(argv[1]); | 661 | struct cmd_file_t *cmd_file = read_command_file(argv[1]); |
662 | struct sb_file_t *sb_file = apply_cmd_file(cmd_file); | ||
470 | 663 | ||
471 | return 0; | 664 | return 0; |
472 | } | 665 | } |