diff options
Diffstat (limited to 'utils/sbtools')
-rw-r--r-- | utils/sbtools/dbparser.c | 411 | ||||
-rw-r--r-- | utils/sbtools/dbparser.h | 28 | ||||
-rw-r--r-- | utils/sbtools/elftosb.c | 387 |
3 files changed, 588 insertions, 238 deletions
diff --git a/utils/sbtools/dbparser.c b/utils/sbtools/dbparser.c index 20f2d66c0e..2dcc21eeba 100644 --- a/utils/sbtools/dbparser.c +++ b/utils/sbtools/dbparser.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <stdio.h> | 22 | #include <stdio.h> |
23 | #include <ctype.h> | 23 | #include <ctype.h> |
24 | #include <stdint.h> | 24 | #include <stdint.h> |
25 | #include <string.h> | ||
25 | #include "dbparser.h" | 26 | #include "dbparser.h" |
26 | 27 | ||
27 | typedef uint8_t byte; | 28 | typedef uint8_t byte; |
@@ -45,6 +46,10 @@ enum lexem_type_t | |||
45 | LEX_LBRACE, | 46 | LEX_LBRACE, |
46 | LEX_RBRACE, | 47 | LEX_RBRACE, |
47 | LEX_RANGLE, | 48 | LEX_RANGLE, |
49 | LEX_OR, | ||
50 | LEX_LSHIFT, | ||
51 | LEX_COLON, | ||
52 | LEX_LE, | ||
48 | LEX_EOF | 53 | LEX_EOF |
49 | }; | 54 | }; |
50 | 55 | ||
@@ -274,6 +279,8 @@ static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) | |||
274 | } | 279 | } |
275 | if(eof(ctx)) ret_simple(LEX_EOF, 0); | 280 | if(eof(ctx)) ret_simple(LEX_EOF, 0); |
276 | char c = cur_char(ctx); | 281 | char c = cur_char(ctx); |
282 | bool nv = next_valid(ctx, 1); | ||
283 | char nc = nv ? next_char(ctx, 1) : 0; | ||
277 | if(c == '(') ret_simple(LEX_LPAREN, 1); | 284 | if(c == '(') ret_simple(LEX_LPAREN, 1); |
278 | if(c == ')') ret_simple(LEX_RPAREN, 1); | 285 | if(c == ')') ret_simple(LEX_RPAREN, 1); |
279 | if(c == '{') ret_simple(LEX_LBRACE, 1); | 286 | if(c == '{') ret_simple(LEX_LBRACE, 1); |
@@ -281,6 +288,10 @@ static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) | |||
281 | if(c == '>') ret_simple(LEX_RANGLE, 1); | 288 | if(c == '>') ret_simple(LEX_RANGLE, 1); |
282 | if(c == '=') ret_simple(LEX_EQUAL, 1); | 289 | if(c == '=') ret_simple(LEX_EQUAL, 1); |
283 | if(c == ';') ret_simple(LEX_SEMICOLON, 1); | 290 | if(c == ';') ret_simple(LEX_SEMICOLON, 1); |
291 | if(c == ',') ret_simple(LEX_COLON, 1); | ||
292 | if(c == '|') ret_simple(LEX_OR, 1); | ||
293 | if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2); | ||
294 | if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2); | ||
284 | if(c == '"') return parse_string(ctx, lexem); | 295 | if(c == '"') return parse_string(ctx, lexem); |
285 | if(c == '\'') return parse_ascii_number(ctx, lexem); | 296 | if(c == '\'') return parse_ascii_number(ctx, lexem); |
286 | if(isdigit(c)) return parse_number(ctx, lexem); | 297 | if(isdigit(c)) return parse_number(ctx, lexem); |
@@ -304,6 +315,8 @@ static void log_lexem(struct lexem_t *lexem) | |||
304 | case LEX_SEMICOLON: printf(";"); break; | 315 | case LEX_SEMICOLON: printf(";"); break; |
305 | case LEX_NUMBER: printf("num(%d)", lexem->num); break; | 316 | case LEX_NUMBER: printf("num(%d)", lexem->num); break; |
306 | case LEX_STRING: printf("str(%s)", lexem->str); break; | 317 | case LEX_STRING: printf("str(%s)", lexem->str); break; |
318 | case LEX_OR: printf("|"); break; | ||
319 | case LEX_LSHIFT: printf("<<"); break; | ||
307 | default: printf("<unk>"); | 320 | default: printf("<unk>"); |
308 | } | 321 | } |
309 | } | 322 | } |
@@ -321,11 +334,15 @@ struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const cha | |||
321 | return NULL; | 334 | return NULL; |
322 | } | 335 | } |
323 | 336 | ||
324 | static void generate_default_version(struct sb_version_t *ver) | 337 | struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name) |
325 | { | 338 | { |
326 | ver->major = 0x999; | 339 | while(opt) |
327 | ver->minor = 0x999; | 340 | { |
328 | ver->revision = 0x999; | 341 | if(strcmp(opt->name, name) == 0) |
342 | return opt; | ||
343 | opt = opt->next; | ||
344 | } | ||
345 | return NULL; | ||
329 | } | 346 | } |
330 | 347 | ||
331 | #define INVALID_SB_SUBVERSION 0xffff | 348 | #define INVALID_SB_SUBVERSION 0xffff |
@@ -375,6 +392,68 @@ bool db_parse_sb_version(struct sb_version_t *ver, char *str) | |||
375 | do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ | 392 | do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ |
376 | fprintf(stderr, __VA_ARGS__); exit(2); } while(0) | 393 | fprintf(stderr, __VA_ARGS__); exit(2); } while(0) |
377 | 394 | ||
395 | struct lex_ctx_t | ||
396 | { | ||
397 | struct context_t ctx; | ||
398 | struct lexem_t lexem; | ||
399 | }; | ||
400 | |||
401 | static inline void next(struct lex_ctx_t *ctx) | ||
402 | { | ||
403 | next_lexem(&ctx->ctx, &ctx->lexem); | ||
404 | } | ||
405 | |||
406 | static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
407 | { | ||
408 | uint32_t ret = 0; | ||
409 | if(ctx->lexem.type == LEX_NUMBER) | ||
410 | ret = ctx->lexem.num; | ||
411 | else if(ctx->lexem.type == LEX_IDENTIFIER) | ||
412 | { | ||
413 | struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str); | ||
414 | if(c == NULL) | ||
415 | parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str); | ||
416 | if(c->is_string) | ||
417 | parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str); | ||
418 | ret = c->val; | ||
419 | } | ||
420 | else | ||
421 | parse_error(ctx->lexem, "Number or constant identifier expected\n"); | ||
422 | next(ctx); | ||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
427 | { | ||
428 | uint32_t v = parse_term_expr(ctx, const_list); | ||
429 | while(ctx->lexem.type == LEX_LSHIFT) | ||
430 | { | ||
431 | next(ctx); | ||
432 | v <<= parse_term_expr(ctx, const_list); | ||
433 | } | ||
434 | return v; | ||
435 | } | ||
436 | |||
437 | static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
438 | { | ||
439 | uint32_t v = parse_shift_expr(ctx, const_list); | ||
440 | while(ctx->lexem.type == LEX_OR) | ||
441 | { | ||
442 | next(ctx); | ||
443 | v |= parse_shift_expr(ctx, const_list); | ||
444 | } | ||
445 | return v; | ||
446 | } | ||
447 | |||
448 | static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
449 | { | ||
450 | return parse_or_expr(ctx, const_list); | ||
451 | } | ||
452 | |||
453 | #define NR_INITIAL_CONSTANTS 4 | ||
454 | static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"}; | ||
455 | static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0}; | ||
456 | |||
378 | struct cmd_file_t *db_parse_file(const char *file) | 457 | struct cmd_file_t *db_parse_file(const char *file) |
379 | { | 458 | { |
380 | size_t size; | 459 | size_t size; |
@@ -394,19 +473,58 @@ struct cmd_file_t *db_parse_file(const char *file) | |||
394 | struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); | 473 | struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); |
395 | memset(cmd_file, 0, sizeof(struct cmd_file_t)); | 474 | memset(cmd_file, 0, sizeof(struct cmd_file_t)); |
396 | 475 | ||
397 | generate_default_version(&cmd_file->product_ver); | 476 | /* add initial constants */ |
398 | generate_default_version(&cmd_file->component_ver); | 477 | for(int i = 0; i < NR_INITIAL_CONSTANTS; i++) |
478 | { | ||
479 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
480 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
481 | opt->name = init_const_name[i]; | ||
482 | opt->is_string = false; | ||
483 | opt->val = init_const_value[i]; | ||
484 | opt->next = cmd_file->constant_list; | ||
485 | cmd_file->constant_list = opt; | ||
486 | } | ||
399 | 487 | ||
400 | struct lexem_t lexem; | 488 | struct lex_ctx_t lctx; |
401 | struct context_t ctx; | 489 | lctx.ctx.file = file; |
402 | ctx.file = file; | 490 | lctx.ctx.line = 1; |
403 | ctx.line = 1; | 491 | lctx.ctx.begin = buf; |
404 | ctx.begin = buf; | 492 | lctx.ctx.ptr = buf; |
405 | ctx.ptr = buf; | 493 | lctx.ctx.end = buf + size; |
406 | ctx.end = buf + size; | 494 | #define next() next(&lctx) |
407 | #define next() next_lexem(&ctx, &lexem) | 495 | #define lexem lctx.lexem |
408 | /* init lexer */ | 496 | /* init lexer */ |
409 | next(); | 497 | next(); |
498 | /* constants ? */ | ||
499 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants")) | ||
500 | { | ||
501 | next(); | ||
502 | if(lexem.type != LEX_LBRACE) | ||
503 | parse_error(lexem, "'{' expected after 'constants'\n"); | ||
504 | |||
505 | while(true) | ||
506 | { | ||
507 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
508 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
509 | next(); | ||
510 | if(lexem.type == LEX_RBRACE) | ||
511 | break; | ||
512 | if(lexem.type != LEX_IDENTIFIER) | ||
513 | parse_error(lexem, "Identifier expected in constants\n"); | ||
514 | opt->name = lexem.str; | ||
515 | next(); | ||
516 | if(lexem.type != LEX_EQUAL) | ||
517 | parse_error(lexem, "'=' expected after identifier\n"); | ||
518 | next(); | ||
519 | opt->is_string = false; | ||
520 | opt->val = parse_intexpr(&lctx, cmd_file->constant_list); | ||
521 | opt->next = cmd_file->constant_list; | ||
522 | cmd_file->constant_list = opt; | ||
523 | if(lexem.type != LEX_SEMICOLON) | ||
524 | parse_error(lexem, "';' expected after string\n"); | ||
525 | } | ||
526 | next(); | ||
527 | } | ||
410 | /* options ? */ | 528 | /* options ? */ |
411 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) | 529 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) |
412 | { | 530 | { |
@@ -416,31 +534,31 @@ struct cmd_file_t *db_parse_file(const char *file) | |||
416 | 534 | ||
417 | while(true) | 535 | while(true) |
418 | { | 536 | { |
537 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
538 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
419 | next(); | 539 | next(); |
420 | if(lexem.type == LEX_RBRACE) | 540 | if(lexem.type == LEX_RBRACE) |
421 | break; | 541 | break; |
422 | if(lexem.type != LEX_IDENTIFIER) | 542 | if(lexem.type != LEX_IDENTIFIER) |
423 | parse_error(lexem, "Identifier expected in options\n"); | 543 | parse_error(lexem, "Identifier expected in options\n"); |
424 | char *opt = lexem.str; | 544 | opt->name = lexem.str; |
425 | next(); | 545 | next(); |
426 | if(lexem.type != LEX_EQUAL) | 546 | if(lexem.type != LEX_EQUAL) |
427 | parse_error(lexem, "'=' expected after identifier\n"); | 547 | parse_error(lexem, "'=' expected after identifier\n"); |
428 | next(); | 548 | next(); |
429 | if(!strcmp(opt, "productVersion") || !strcmp(opt, "componentVersion")) | 549 | if(lexem.type == LEX_STRING) |
430 | { | 550 | { |
431 | if(lexem.type != LEX_STRING) | 551 | opt->is_string = true; |
432 | parse_error(lexem, "String expected after '='\n"); | 552 | opt->str = lexem.str; |
433 | bool ret; | 553 | next(); |
434 | if(!strcmp(opt, "productVersion")) | ||
435 | ret = db_parse_sb_version(&cmd_file->product_ver, lexem.str); | ||
436 | else | ||
437 | ret = db_parse_sb_version(&cmd_file->component_ver, lexem.str); | ||
438 | if(!ret) | ||
439 | parse_error(lexem, "Invalid product/component version"); | ||
440 | } | 554 | } |
441 | else | 555 | else |
442 | parse_error(lexem, "Unknown option '%s'\n", opt); | 556 | { |
443 | next(); | 557 | opt->is_string = false; |
558 | opt->val = parse_intexpr(&lctx, cmd_file->constant_list); | ||
559 | } | ||
560 | opt->next = cmd_file->opt_list; | ||
561 | cmd_file->opt_list = opt; | ||
444 | if(lexem.type != LEX_SEMICOLON) | 562 | if(lexem.type != LEX_SEMICOLON) |
445 | parse_error(lexem, "';' expected after string\n"); | 563 | parse_error(lexem, "';' expected after string\n"); |
446 | } | 564 | } |
@@ -460,7 +578,6 @@ struct cmd_file_t *db_parse_file(const char *file) | |||
460 | break; | 578 | break; |
461 | struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); | 579 | struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); |
462 | memset(src, 0, sizeof(struct cmd_source_t)); | 580 | memset(src, 0, sizeof(struct cmd_source_t)); |
463 | src->next = cmd_file->source_list; | ||
464 | if(lexem.type != LEX_IDENTIFIER) | 581 | if(lexem.type != LEX_IDENTIFIER) |
465 | parse_error(lexem, "identifier expected in sources\n"); | 582 | parse_error(lexem, "identifier expected in sources\n"); |
466 | src->identifier = lexem.str; | 583 | src->identifier = lexem.str; |
@@ -468,16 +585,34 @@ struct cmd_file_t *db_parse_file(const char *file) | |||
468 | if(lexem.type != LEX_EQUAL) | 585 | if(lexem.type != LEX_EQUAL) |
469 | parse_error(lexem, "'=' expected after identifier\n"); | 586 | parse_error(lexem, "'=' expected after identifier\n"); |
470 | next(); | 587 | next(); |
471 | if(lexem.type != LEX_STRING) | 588 | if(lexem.type == LEX_STRING) |
472 | parse_error(lexem, "String expected after '='\n"); | 589 | { |
473 | src->filename = lexem.str; | 590 | src->is_extern = false; |
474 | next(); | 591 | src->filename = lexem.str; |
592 | next(); | ||
593 | } | ||
594 | else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern")) | ||
595 | { | ||
596 | src->is_extern = true; | ||
597 | src->filename = "<extern>"; | ||
598 | next(); | ||
599 | if(lexem.type != LEX_LPAREN) | ||
600 | parse_error(lexem, "'(' expected after 'extern'\n"); | ||
601 | next(); | ||
602 | src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list); | ||
603 | if(lexem.type != LEX_RPAREN) | ||
604 | parse_error(lexem, "')' expected\n"); | ||
605 | next(); | ||
606 | } | ||
607 | else | ||
608 | parse_error(lexem, "String or 'extern' expected after '='\n"); | ||
475 | if(lexem.type != LEX_SEMICOLON) | 609 | if(lexem.type != LEX_SEMICOLON) |
476 | parse_error(lexem, "';' expected after string\n"); | 610 | parse_error(lexem, "';' expected\n"); |
477 | if(db_find_source_by_id(cmd_file, src->identifier) != NULL) | 611 | if(db_find_source_by_id(cmd_file, src->identifier) != NULL) |
478 | parse_error(lexem, "Duplicate source identifier\n"); | 612 | parse_error(lexem, "Duplicate source identifier\n"); |
479 | /* type filled later */ | 613 | /* type filled later */ |
480 | src->type = CMD_SRC_UNK; | 614 | src->type = CMD_SRC_UNK; |
615 | src->next = cmd_file->source_list; | ||
481 | cmd_file->source_list = src; | 616 | cmd_file->source_list = src; |
482 | } | 617 | } |
483 | 618 | ||
@@ -497,117 +632,143 @@ struct cmd_file_t *db_parse_file(const char *file) | |||
497 | if(lexem.type != LEX_LPAREN) | 632 | if(lexem.type != LEX_LPAREN) |
498 | parse_error(lexem, "'(' expected after 'section'\n"); | 633 | parse_error(lexem, "'(' expected after 'section'\n"); |
499 | next(); | 634 | next(); |
500 | /* can be a number or a 4 character long string */ | 635 | /* can be any number */ |
501 | if(lexem.type == LEX_NUMBER) | 636 | sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list); |
637 | /* options ? */ | ||
638 | if(lexem.type == LEX_SEMICOLON) | ||
502 | { | 639 | { |
503 | sec->identifier = lexem.num; | 640 | do |
641 | { | ||
642 | next(); | ||
643 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
644 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
645 | if(lexem.type != LEX_IDENTIFIER) | ||
646 | parse_error(lexem, "Identifier expected for section option\n"); | ||
647 | opt->name = lexem.str; | ||
648 | next(); | ||
649 | if(lexem.type != LEX_EQUAL) | ||
650 | parse_error(lexem, "'=' expected after option identifier\n"); | ||
651 | next(); | ||
652 | if(lexem.type == LEX_STRING) | ||
653 | { | ||
654 | opt->is_string = true; | ||
655 | opt->str = lexem.str; | ||
656 | next(); | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | opt->is_string = false; | ||
661 | opt->val = parse_intexpr(&lctx, cmd_file->constant_list); | ||
662 | } | ||
663 | opt->next = sec->opt_list; | ||
664 | sec->opt_list = opt; | ||
665 | }while(lexem.type == LEX_COLON); | ||
504 | } | 666 | } |
505 | else | ||
506 | parse_error(lexem, "Number expected as section identifier\n"); | ||
507 | |||
508 | next(); | ||
509 | if(lexem.type != LEX_RPAREN) | 667 | if(lexem.type != LEX_RPAREN) |
510 | parse_error(lexem, "')' expected after section identifier\n"); | 668 | parse_error(lexem, "')' expected after section identifier\n"); |
511 | next(); | 669 | next(); |
512 | if(lexem.type != LEX_LBRACE) | 670 | if(lexem.type == LEX_LBRACE) |
513 | parse_error(lexem, "'{' expected after section directive\n"); | ||
514 | /* commands */ | ||
515 | while(true) | ||
516 | { | 671 | { |
517 | struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); | 672 | sec->is_data = false; |
518 | memset(inst, 0, sizeof(struct cmd_inst_t)); | 673 | /* commands */ |
519 | next(); | 674 | while(true) |
520 | if(lexem.type == LEX_RBRACE) | ||
521 | break; | ||
522 | if(lexem.type != LEX_IDENTIFIER) | ||
523 | parse_error(lexem, "Instruction expected in section\n"); | ||
524 | if(strcmp(lexem.str, "load") == 0) | ||
525 | inst->type = CMD_LOAD; | ||
526 | else if(strcmp(lexem.str, "call") == 0) | ||
527 | inst->type = CMD_CALL; | ||
528 | else if(strcmp(lexem.str, "jump") == 0) | ||
529 | inst->type = CMD_JUMP; | ||
530 | else if(strcmp(lexem.str, "mode") == 0) | ||
531 | inst->type = CMD_MODE; | ||
532 | else | ||
533 | parse_error(lexem, "Instruction expected in section\n"); | ||
534 | next(); | ||
535 | |||
536 | if(inst->type == CMD_LOAD) | ||
537 | { | 675 | { |
676 | struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); | ||
677 | memset(inst, 0, sizeof(struct cmd_inst_t)); | ||
678 | next(); | ||
679 | if(lexem.type == LEX_RBRACE) | ||
680 | break; | ||
538 | if(lexem.type != LEX_IDENTIFIER) | 681 | if(lexem.type != LEX_IDENTIFIER) |
539 | parse_error(lexem, "Identifier expected after instruction\n"); | 682 | parse_error(lexem, "Instruction expected in section\n"); |
540 | inst->identifier = lexem.str; | 683 | if(strcmp(lexem.str, "load") == 0) |
541 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | 684 | inst->type = CMD_LOAD; |
542 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | 685 | else if(strcmp(lexem.str, "call") == 0) |
686 | inst->type = CMD_CALL; | ||
687 | else if(strcmp(lexem.str, "jump") == 0) | ||
688 | inst->type = CMD_JUMP; | ||
689 | else if(strcmp(lexem.str, "mode") == 0) | ||
690 | inst->type = CMD_MODE; | ||
691 | else | ||
692 | parse_error(lexem, "Instruction expected in section\n"); | ||
543 | next(); | 693 | next(); |
544 | if(lexem.type == LEX_RANGLE) | 694 | |
545 | { | 695 | if(inst->type == CMD_LOAD) |
546 | // load at | ||
547 | inst->type = CMD_LOAD_AT; | ||
548 | next(); | ||
549 | if(lexem.type != LEX_NUMBER) | ||
550 | parse_error(lexem, "Number expected for loading address\n"); | ||
551 | inst->addr = lexem.num; | ||
552 | next(); | ||
553 | } | ||
554 | if(lexem.type != LEX_SEMICOLON) | ||
555 | parse_error(lexem, "';' expected after command\n"); | ||
556 | } | ||
557 | else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) | ||
558 | { | ||
559 | if(lexem.type == LEX_IDENTIFIER) | ||
560 | { | 696 | { |
697 | if(lexem.type != LEX_IDENTIFIER) | ||
698 | parse_error(lexem, "Identifier expected after instruction\n"); | ||
561 | inst->identifier = lexem.str; | 699 | inst->identifier = lexem.str; |
562 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | 700 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) |
563 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | 701 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); |
564 | next(); | 702 | next(); |
703 | if(lexem.type == LEX_RANGLE) | ||
704 | { | ||
705 | // load at | ||
706 | inst->type = CMD_LOAD_AT; | ||
707 | next(); | ||
708 | inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); | ||
709 | } | ||
710 | if(lexem.type != LEX_SEMICOLON) | ||
711 | parse_error(lexem, "';' expected after command\n"); | ||
565 | } | 712 | } |
566 | else if(lexem.type == LEX_NUMBER) | 713 | else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) |
567 | { | 714 | { |
568 | inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; | 715 | if(lexem.type == LEX_IDENTIFIER) |
569 | inst->addr = lexem.num; | 716 | { |
570 | next(); | 717 | inst->identifier = lexem.str; |
718 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
719 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | ||
720 | next(); | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; | ||
725 | inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); | ||
726 | } | ||
727 | |||
728 | if(lexem.type == LEX_LPAREN) | ||
729 | { | ||
730 | next(); | ||
731 | inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); | ||
732 | if(lexem.type != LEX_RPAREN) | ||
733 | parse_error(lexem, "Expected closing brace\n"); | ||
734 | next(); | ||
735 | } | ||
736 | if(lexem.type != LEX_SEMICOLON) | ||
737 | parse_error(lexem, "';' expected after command\n"); | ||
738 | } | ||
739 | else if(inst->type == CMD_MODE) | ||
740 | { | ||
741 | inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); | ||
742 | if(lexem.type != LEX_SEMICOLON) | ||
743 | parse_error(lexem, "Expected ';' after command\n"); | ||
571 | } | 744 | } |
572 | else | 745 | else |
573 | parse_error(lexem, "Identifier or number expected after jump/load\n"); | 746 | parse_error(lexem, "Internal error"); |
574 | 747 | if(end_list == NULL) | |
575 | if(lexem.type == LEX_LPAREN) | ||
576 | { | 748 | { |
577 | next(); | 749 | sec->inst_list = inst; |
578 | if(lexem.type != LEX_NUMBER) | 750 | end_list = inst; |
579 | parse_error(lexem, "Expected numeral expression after (\n"); | 751 | } |
580 | inst->argument = lexem.num; | 752 | else |
581 | next(); | 753 | { |
582 | if(lexem.type != LEX_RPAREN) | 754 | end_list->next = inst; |
583 | parse_error(lexem, "Expected closing brace\n"); | 755 | end_list = inst; |
584 | next(); | ||
585 | } | 756 | } |
586 | if(lexem.type != LEX_SEMICOLON) | ||
587 | parse_error(lexem, "Expected ';' after command\n"); | ||
588 | } | ||
589 | else if(inst->type == CMD_MODE) | ||
590 | { | ||
591 | if(lexem.type != LEX_NUMBER) | ||
592 | parse_error(lexem, "Number expected after 'mode'\n"); | ||
593 | inst->argument = lexem.num; | ||
594 | next(); | ||
595 | if(lexem.type != LEX_SEMICOLON) | ||
596 | parse_error(lexem, "Expected ';' after command\n"); | ||
597 | } | ||
598 | else | ||
599 | parse_error(lexem, "Internal error"); | ||
600 | if(end_list == NULL) | ||
601 | { | ||
602 | sec->inst_list = inst; | ||
603 | end_list = inst; | ||
604 | } | ||
605 | else | ||
606 | { | ||
607 | end_list->next = inst; | ||
608 | end_list = inst; | ||
609 | } | 757 | } |
610 | } | 758 | } |
759 | else if(lexem.type == LEX_LE) | ||
760 | { | ||
761 | sec->is_data = true; | ||
762 | next(); | ||
763 | if(lexem.type != LEX_IDENTIFIER) | ||
764 | parse_error(lexem, "Identifier expected after '<='\n"); | ||
765 | sec->source_id = lexem.str; | ||
766 | next(); | ||
767 | if(lexem.type != LEX_SEMICOLON) | ||
768 | parse_error(lexem, "';' expected after identifier\n"); | ||
769 | } | ||
770 | else | ||
771 | parse_error(lexem, "'{' or '<=' expected after section directive\n"); | ||
611 | 772 | ||
612 | if(end_sec == NULL) | 773 | if(end_sec == NULL) |
613 | { | 774 | { |
@@ -620,7 +781,13 @@ struct cmd_file_t *db_parse_file(const char *file) | |||
620 | end_sec = sec; | 781 | end_sec = sec; |
621 | } | 782 | } |
622 | } | 783 | } |
784 | #undef lexem | ||
623 | #undef next | 785 | #undef next |
624 | 786 | ||
625 | return cmd_file; | 787 | return cmd_file; |
626 | } | 788 | } |
789 | |||
790 | void db_generate_default_sb_version(struct sb_version_t *ver) | ||
791 | { | ||
792 | ver->major = ver->minor = ver->revision = 0x999; | ||
793 | } | ||
diff --git a/utils/sbtools/dbparser.h b/utils/sbtools/dbparser.h index f1b7ffd77e..cfb1a692fa 100644 --- a/utils/sbtools/dbparser.h +++ b/utils/sbtools/dbparser.h | |||
@@ -43,7 +43,11 @@ struct bin_param_t | |||
43 | struct cmd_source_t | 43 | struct cmd_source_t |
44 | { | 44 | { |
45 | char *identifier; | 45 | char *identifier; |
46 | bool is_extern; | ||
47 | // <union> | ||
48 | int extern_nr; | ||
46 | char *filename; | 49 | char *filename; |
50 | // </union> | ||
47 | struct cmd_source_t *next; | 51 | struct cmd_source_t *next; |
48 | /* for later use */ | 52 | /* for later use */ |
49 | enum cmd_source_type_t type; | 53 | enum cmd_source_type_t type; |
@@ -72,23 +76,41 @@ struct cmd_inst_t | |||
72 | struct cmd_inst_t *next; | 76 | struct cmd_inst_t *next; |
73 | }; | 77 | }; |
74 | 78 | ||
79 | struct cmd_option_t | ||
80 | { | ||
81 | char *name; | ||
82 | bool is_string; | ||
83 | /* <union> */ | ||
84 | uint32_t val; | ||
85 | char *str; | ||
86 | /* </union> */ | ||
87 | struct cmd_option_t *next; | ||
88 | }; | ||
89 | |||
75 | struct cmd_section_t | 90 | struct cmd_section_t |
76 | { | 91 | { |
77 | uint32_t identifier; | 92 | uint32_t identifier; |
78 | struct cmd_inst_t *inst_list; | 93 | bool is_data; |
94 | // <union> | ||
95 | struct cmd_inst_t *inst_list; | ||
96 | char *source_id; | ||
97 | // </union> | ||
79 | struct cmd_section_t *next; | 98 | struct cmd_section_t *next; |
99 | struct cmd_option_t *opt_list; | ||
80 | }; | 100 | }; |
81 | 101 | ||
82 | struct cmd_file_t | 102 | struct cmd_file_t |
83 | { | 103 | { |
84 | struct sb_version_t product_ver; | 104 | struct cmd_option_t *opt_list; |
85 | struct sb_version_t component_ver; | 105 | struct cmd_option_t *constant_list; /* constant all always integers */ |
86 | struct cmd_source_t *source_list; | 106 | struct cmd_source_t *source_list; |
87 | struct cmd_section_t *section_list; | 107 | struct cmd_section_t *section_list; |
88 | }; | 108 | }; |
89 | 109 | ||
90 | struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); | 110 | struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); |
111 | struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name); | ||
91 | bool db_parse_sb_version(struct sb_version_t *ver, char *str); | 112 | bool db_parse_sb_version(struct sb_version_t *ver, char *str); |
113 | void db_generate_default_sb_version(struct sb_version_t *ver); | ||
92 | struct cmd_file_t *db_parse_file(const char *file); | 114 | struct cmd_file_t *db_parse_file(const char *file); |
93 | 115 | ||
94 | #endif /* __DBPARSER__ */ | 116 | #endif /* __DBPARSER__ */ |
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c index 0b659eaf26..f78c6cf64b 100644 --- a/utils/sbtools/elftosb.c +++ b/utils/sbtools/elftosb.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <time.h> | 33 | #include <time.h> |
34 | #include <stdarg.h> | 34 | #include <stdarg.h> |
35 | #include <strings.h> | 35 | #include <strings.h> |
36 | #include <getopt.h> | ||
36 | 37 | ||
37 | #include "crypto.h" | 38 | #include "crypto.h" |
38 | #include "elf.h" | 39 | #include "elf.h" |
@@ -46,6 +47,8 @@ | |||
46 | #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0) | 47 | #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0) |
47 | 48 | ||
48 | bool g_debug = false; | 49 | bool g_debug = false; |
50 | char **g_extern; | ||
51 | int g_extern_count; | ||
49 | 52 | ||
50 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | 53 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) |
51 | 54 | ||
@@ -107,6 +110,16 @@ typedef byte (*key_array_t)[16]; | |||
107 | int g_nr_keys; | 110 | int g_nr_keys; |
108 | key_array_t g_key_array; | 111 | key_array_t g_key_array; |
109 | 112 | ||
113 | static void add_keys(key_array_t ka, int kac) | ||
114 | { | ||
115 | key_array_t new_ka = xmalloc((g_nr_keys + kac) * 16); | ||
116 | memcpy(new_ka, g_key_array, g_nr_keys * 16); | ||
117 | memcpy(new_ka + g_nr_keys, ka, kac * 16); | ||
118 | free(g_key_array); | ||
119 | g_key_array = new_ka; | ||
120 | g_nr_keys += kac; | ||
121 | } | ||
122 | |||
110 | static key_array_t read_keys(const char *key_file, int *num_keys) | 123 | static key_array_t read_keys(const char *key_file, int *num_keys) |
111 | { | 124 | { |
112 | int size; | 125 | int size; |
@@ -168,6 +181,8 @@ static key_array_t read_keys(const char *key_file, int *num_keys) | |||
168 | * command file to sb conversion | 181 | * command file to sb conversion |
169 | */ | 182 | */ |
170 | 183 | ||
184 | #define SB_INST_DATA 0xff | ||
185 | |||
171 | struct sb_inst_t | 186 | struct sb_inst_t |
172 | { | 187 | { |
173 | uint8_t inst; /* SB_INST_* */ | 188 | uint8_t inst; /* SB_INST_* */ |
@@ -186,6 +201,9 @@ struct sb_inst_t | |||
186 | struct sb_section_t | 201 | struct sb_section_t |
187 | { | 202 | { |
188 | uint32_t identifier; | 203 | uint32_t identifier; |
204 | bool is_data; | ||
205 | bool is_cleartext; | ||
206 | // data sections are handled as a single SB_INST_DATA virtual instruction | ||
189 | int nr_insts; | 207 | int nr_insts; |
190 | struct sb_inst_t *insts; | 208 | struct sb_inst_t *insts; |
191 | /* for production use */ | 209 | /* for production use */ |
@@ -221,6 +239,16 @@ static void elf_printf(void *user, bool error, const char *fmt, ...) | |||
221 | va_end(args); | 239 | va_end(args); |
222 | } | 240 | } |
223 | 241 | ||
242 | static void resolve_extern(struct cmd_source_t *src) | ||
243 | { | ||
244 | if(!src->is_extern) | ||
245 | return; | ||
246 | src->is_extern = false; | ||
247 | if(src->extern_nr < 0 || src->extern_nr >= g_extern_count) | ||
248 | bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr); | ||
249 | src->filename = g_extern[src->extern_nr]; | ||
250 | } | ||
251 | |||
224 | static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | 252 | static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) |
225 | { | 253 | { |
226 | struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); | 254 | struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); |
@@ -231,6 +259,9 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | |||
231 | return; | 259 | return; |
232 | if(src->type != CMD_SRC_UNK) | 260 | if(src->type != CMD_SRC_UNK) |
233 | bug("source '%s' seen both as elf and binary file\n", id); | 261 | bug("source '%s' seen both as elf and binary file\n", id); |
262 | /* resolve potential extern file */ | ||
263 | resolve_extern(src); | ||
264 | /* load it */ | ||
234 | src->type = CMD_SRC_ELF; | 265 | src->type = CMD_SRC_ELF; |
235 | int fd = open(src->filename, O_RDONLY); | 266 | int fd = open(src->filename, O_RDONLY); |
236 | if(fd < 0) | 267 | if(fd < 0) |
@@ -255,6 +286,9 @@ static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) | |||
255 | return; | 286 | return; |
256 | if(src->type != CMD_SRC_UNK) | 287 | if(src->type != CMD_SRC_UNK) |
257 | bug("source '%s' seen both as elf and binary file\n", id); | 288 | bug("source '%s' seen both as elf and binary file\n", id); |
289 | /* resolve potential extern file */ | ||
290 | resolve_extern(src); | ||
291 | /* load it */ | ||
258 | src->type = CMD_SRC_BIN; | 292 | src->type = CMD_SRC_BIN; |
259 | int fd = open(src->filename, O_RDONLY); | 293 | int fd = open(src->filename, O_RDONLY); |
260 | if(fd < 0) | 294 | if(fd < 0) |
@@ -274,8 +308,8 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
274 | struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); | 308 | struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); |
275 | memset(sb, 0, sizeof(struct sb_file_t)); | 309 | memset(sb, 0, sizeof(struct sb_file_t)); |
276 | 310 | ||
277 | sb->product_ver = cmd_file->product_ver; | 311 | db_generate_default_sb_version(&sb->product_ver); |
278 | sb->component_ver = cmd_file->component_ver; | 312 | db_generate_default_sb_version(&sb->component_ver); |
279 | 313 | ||
280 | if(g_debug) | 314 | if(g_debug) |
281 | printf("Applying command file...\n"); | 315 | printf("Applying command file...\n"); |
@@ -295,103 +329,136 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
295 | { | 329 | { |
296 | struct sb_section_t *sec = &sb->sections[i]; | 330 | struct sb_section_t *sec = &sb->sections[i]; |
297 | sec->identifier = csec->identifier; | 331 | sec->identifier = csec->identifier; |
298 | /* count instructions */ | 332 | |
299 | struct cmd_inst_t *cinst = csec->inst_list; | 333 | /* options */ |
300 | while(cinst) | 334 | do |
301 | { | 335 | { |
302 | if(cinst->type == CMD_LOAD) | 336 | struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext"); |
303 | { | 337 | if(opt != NULL) |
304 | load_elf_by_id(cmd_file, cinst->identifier); | ||
305 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
306 | sec->nr_insts += elf_get_nr_sections(elf); | ||
307 | } | ||
308 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | ||
309 | { | 338 | { |
310 | load_elf_by_id(cmd_file, cinst->identifier); | 339 | if(opt->is_string) |
311 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | 340 | bug("Cleartext section attribute must be an integer\n"); |
312 | if(!elf_get_start_addr(elf, NULL)) | 341 | if(opt->val != 0 && opt->val != 1) |
313 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); | 342 | bug("Cleartext section attribute must be 0 or 1\n"); |
314 | sec->nr_insts++; | 343 | sec->is_cleartext = opt->val; |
315 | } | 344 | } |
316 | else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) | 345 | }while(0); |
317 | { | 346 | |
318 | sec->nr_insts++; | 347 | if(csec->is_data) |
319 | } | 348 | { |
320 | else if(cinst->type == CMD_LOAD_AT) | 349 | sec->is_data = true; |
321 | { | 350 | sec->nr_insts = 1; |
322 | load_bin_by_id(cmd_file, cinst->identifier); | 351 | sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); |
323 | sec->nr_insts++; | 352 | memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); |
324 | } | 353 | |
325 | else if(cinst->type == CMD_MODE) | 354 | load_bin_by_id(cmd_file, csec->source_id); |
355 | struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin; | ||
356 | |||
357 | sec->insts[0].inst = SB_INST_DATA; | ||
358 | sec->insts[0].size = bin->size; | ||
359 | sec->insts[0].data = bin->data; | ||
360 | } | ||
361 | else | ||
362 | { | ||
363 | sec->is_data = false; | ||
364 | /* count instructions and loads things */ | ||
365 | struct cmd_inst_t *cinst = csec->inst_list; | ||
366 | while(cinst) | ||
326 | { | 367 | { |
327 | sec->nr_insts++; | 368 | if(cinst->type == CMD_LOAD) |
369 | { | ||
370 | load_elf_by_id(cmd_file, cinst->identifier); | ||
371 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
372 | sec->nr_insts += elf_get_nr_sections(elf); | ||
373 | } | ||
374 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | ||
375 | { | ||
376 | load_elf_by_id(cmd_file, cinst->identifier); | ||
377 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
378 | if(!elf_get_start_addr(elf, NULL)) | ||
379 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); | ||
380 | sec->nr_insts++; | ||
381 | } | ||
382 | else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) | ||
383 | { | ||
384 | sec->nr_insts++; | ||
385 | } | ||
386 | else if(cinst->type == CMD_LOAD_AT) | ||
387 | { | ||
388 | load_bin_by_id(cmd_file, cinst->identifier); | ||
389 | sec->nr_insts++; | ||
390 | } | ||
391 | else if(cinst->type == CMD_MODE) | ||
392 | { | ||
393 | sec->nr_insts++; | ||
394 | } | ||
395 | else | ||
396 | bug("die\n"); | ||
397 | |||
398 | cinst = cinst->next; | ||
328 | } | 399 | } |
329 | else | ||
330 | bug("die\n"); | ||
331 | |||
332 | cinst = cinst->next; | ||
333 | } | ||
334 | 400 | ||
335 | sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); | 401 | sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); |
336 | memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); | 402 | memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); |
337 | /* flatten */ | 403 | /* flatten */ |
338 | int idx = 0; | 404 | int idx = 0; |
339 | cinst = csec->inst_list; | 405 | cinst = csec->inst_list; |
340 | while(cinst) | 406 | while(cinst) |
341 | { | ||
342 | if(cinst->type == CMD_LOAD) | ||
343 | { | 407 | { |
344 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | 408 | if(cinst->type == CMD_LOAD) |
345 | struct elf_section_t *esec = elf->first_section; | ||
346 | while(esec) | ||
347 | { | 409 | { |
348 | if(esec->type == EST_LOAD) | 410 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; |
349 | { | 411 | struct elf_section_t *esec = elf->first_section; |
350 | sec->insts[idx].inst = SB_INST_LOAD; | 412 | while(esec) |
351 | sec->insts[idx].addr = esec->addr; | ||
352 | sec->insts[idx].size = esec->size; | ||
353 | sec->insts[idx++].data = esec->section; | ||
354 | } | ||
355 | else if(esec->type == EST_FILL) | ||
356 | { | 413 | { |
357 | sec->insts[idx].inst = SB_INST_FILL; | 414 | if(esec->type == EST_LOAD) |
358 | sec->insts[idx].addr = esec->addr; | 415 | { |
359 | sec->insts[idx].size = esec->size; | 416 | sec->insts[idx].inst = SB_INST_LOAD; |
360 | sec->insts[idx++].pattern = esec->pattern; | 417 | sec->insts[idx].addr = esec->addr; |
418 | sec->insts[idx].size = esec->size; | ||
419 | sec->insts[idx++].data = esec->section; | ||
420 | } | ||
421 | else if(esec->type == EST_FILL) | ||
422 | { | ||
423 | sec->insts[idx].inst = SB_INST_FILL; | ||
424 | sec->insts[idx].addr = esec->addr; | ||
425 | sec->insts[idx].size = esec->size; | ||
426 | sec->insts[idx++].pattern = esec->pattern; | ||
427 | } | ||
428 | esec = esec->next; | ||
361 | } | 429 | } |
362 | esec = esec->next; | ||
363 | } | 430 | } |
431 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | ||
432 | { | ||
433 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
434 | sec->insts[idx].argument = cinst->argument; | ||
435 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; | ||
436 | sec->insts[idx++].addr = elf->start_addr; | ||
437 | } | ||
438 | else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) | ||
439 | { | ||
440 | sec->insts[idx].argument = cinst->argument; | ||
441 | sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; | ||
442 | sec->insts[idx++].addr = cinst->addr; | ||
443 | } | ||
444 | else if(cinst->type == CMD_LOAD_AT) | ||
445 | { | ||
446 | struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; | ||
447 | sec->insts[idx].inst = SB_INST_LOAD; | ||
448 | sec->insts[idx].addr = cinst->addr; | ||
449 | sec->insts[idx].data = bin->data; | ||
450 | sec->insts[idx++].size = bin->size; | ||
451 | } | ||
452 | else if(cinst->type == CMD_MODE) | ||
453 | { | ||
454 | sec->insts[idx].inst = SB_INST_MODE; | ||
455 | sec->insts[idx++].addr = cinst->argument; | ||
456 | } | ||
457 | else | ||
458 | bug("die\n"); | ||
459 | |||
460 | cinst = cinst->next; | ||
364 | } | 461 | } |
365 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | ||
366 | { | ||
367 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
368 | sec->insts[idx].argument = cinst->argument; | ||
369 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; | ||
370 | sec->insts[idx++].addr = elf->start_addr; | ||
371 | } | ||
372 | else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) | ||
373 | { | ||
374 | sec->insts[idx].argument = cinst->argument; | ||
375 | sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; | ||
376 | sec->insts[idx++].addr = cinst->addr; | ||
377 | } | ||
378 | else if(cinst->type == CMD_LOAD_AT) | ||
379 | { | ||
380 | struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; | ||
381 | sec->insts[idx].inst = SB_INST_LOAD; | ||
382 | sec->insts[idx].addr = cinst->addr; | ||
383 | sec->insts[idx].data = bin->data; | ||
384 | sec->insts[idx++].size = bin->size; | ||
385 | } | ||
386 | else if(cinst->type == CMD_MODE) | ||
387 | { | ||
388 | sec->insts[idx].inst = SB_INST_MODE; | ||
389 | sec->insts[idx++].addr = cinst->argument; | ||
390 | } | ||
391 | else | ||
392 | bug("die\n"); | ||
393 | |||
394 | cinst = cinst->next; | ||
395 | } | 462 | } |
396 | } | 463 | } |
397 | 464 | ||
@@ -399,7 +466,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
399 | } | 466 | } |
400 | 467 | ||
401 | /** | 468 | /** |
402 | * Sb file production | 469 | * SB file production |
403 | */ | 470 | */ |
404 | 471 | ||
405 | static void fill_gaps(struct sb_file_t *sb) | 472 | static void fill_gaps(struct sb_file_t *sb) |
@@ -436,6 +503,16 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
436 | sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE; | 503 | sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE; |
437 | 504 | ||
438 | struct sb_section_t *sec = &sb->sections[i]; | 505 | struct sb_section_t *sec = &sb->sections[i]; |
506 | |||
507 | if(g_debug) | ||
508 | { | ||
509 | printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot", | ||
510 | sec->identifier); | ||
511 | if(sec->is_cleartext) | ||
512 | printf(" (cleartext)"); | ||
513 | printf("\n"); | ||
514 | } | ||
515 | |||
439 | sec->file_offset = sb->image_size; | 516 | sec->file_offset = sb->image_size; |
440 | for(int j = 0; j < sec->nr_insts; j++) | 517 | for(int j = 0; j < sec->nr_insts; j++) |
441 | { | 518 | { |
@@ -443,7 +520,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
443 | if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP) | 520 | if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP) |
444 | { | 521 | { |
445 | if(g_debug) | 522 | if(g_debug) |
446 | printf("%s | addr=0x%08x | arg=0x%08x\n", | 523 | printf(" %s | addr=0x%08x | arg=0x%08x\n", |
447 | inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument); | 524 | inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument); |
448 | sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; | 525 | sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; |
449 | sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; | 526 | sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; |
@@ -451,7 +528,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
451 | else if(inst->inst == SB_INST_FILL) | 528 | else if(inst->inst == SB_INST_FILL) |
452 | { | 529 | { |
453 | if(g_debug) | 530 | if(g_debug) |
454 | printf("FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n", | 531 | printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n", |
455 | inst->addr, inst->size, inst->pattern); | 532 | inst->addr, inst->size, inst->pattern); |
456 | sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; | 533 | sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; |
457 | sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; | 534 | sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; |
@@ -459,7 +536,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
459 | else if(inst->inst == SB_INST_LOAD) | 536 | else if(inst->inst == SB_INST_LOAD) |
460 | { | 537 | { |
461 | if(g_debug) | 538 | if(g_debug) |
462 | printf("LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size); | 539 | printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size); |
463 | /* load header */ | 540 | /* load header */ |
464 | sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; | 541 | sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; |
465 | sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; | 542 | sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; |
@@ -470,10 +547,17 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
470 | else if(inst->inst == SB_INST_MODE) | 547 | else if(inst->inst == SB_INST_MODE) |
471 | { | 548 | { |
472 | if(g_debug) | 549 | if(g_debug) |
473 | printf("MODE | mod=0x%08x", inst->addr); | 550 | printf(" MODE | mod=0x%08x", inst->addr); |
474 | sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; | 551 | sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; |
475 | sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; | 552 | sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; |
476 | } | 553 | } |
554 | else if(inst->inst == SB_INST_DATA) | ||
555 | { | ||
556 | if(g_debug) | ||
557 | printf(" DATA | size=0x%08x\n", inst->size); | ||
558 | sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; | ||
559 | sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; | ||
560 | } | ||
477 | else | 561 | else |
478 | bug("die on inst %d\n", inst->inst); | 562 | bug("die on inst %d\n", inst->inst); |
479 | } | 563 | } |
@@ -544,7 +628,8 @@ static void produce_sb_section_header(struct sb_section_t *sec, | |||
544 | sec_hdr->identifier = sec->identifier; | 628 | sec_hdr->identifier = sec->identifier; |
545 | sec_hdr->offset = sec->file_offset; | 629 | sec_hdr->offset = sec->file_offset; |
546 | sec_hdr->size = sec->sec_size; | 630 | sec_hdr->size = sec->sec_size; |
547 | sec_hdr->flags = SECTION_BOOTABLE; | 631 | sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) |
632 | | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); | ||
548 | } | 633 | } |
549 | 634 | ||
550 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) | 635 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) |
@@ -563,7 +648,8 @@ static void produce_section_tag_cmd(struct sb_section_t *sec, | |||
563 | tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0; | 648 | tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0; |
564 | tag->identifier = sec->identifier; | 649 | tag->identifier = sec->identifier; |
565 | tag->len = sec->sec_size; | 650 | tag->len = sec->sec_size; |
566 | tag->flags = SECTION_BOOTABLE; | 651 | tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) |
652 | | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); | ||
567 | tag->hdr.checksum = instruction_checksum(&tag->hdr); | 653 | tag->hdr.checksum = instruction_checksum(&tag->hdr); |
568 | } | 654 | } |
569 | 655 | ||
@@ -671,21 +757,24 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename) | |||
671 | { | 757 | { |
672 | struct sb_inst_t *inst = &sb->sections[i].insts[j]; | 758 | struct sb_inst_t *inst = &sb->sections[i].insts[j]; |
673 | /* command */ | 759 | /* command */ |
674 | struct sb_instruction_common_t cmd; | 760 | if(inst->inst != SB_INST_DATA) |
675 | produce_sb_instruction(inst, &cmd); | 761 | { |
676 | if(g_nr_keys > 0) | 762 | struct sb_instruction_common_t cmd; |
677 | cbc_mac((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, | 763 | produce_sb_instruction(inst, &cmd); |
678 | real_key, cur_cbc_mac, &cur_cbc_mac, 1); | 764 | if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) |
679 | sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); | 765 | cbc_mac((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, |
680 | write(fd, &cmd, sizeof(cmd)); | 766 | real_key, cur_cbc_mac, &cur_cbc_mac, 1); |
767 | sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); | ||
768 | write(fd, &cmd, sizeof(cmd)); | ||
769 | } | ||
681 | /* data */ | 770 | /* data */ |
682 | if(inst->inst == SB_INST_LOAD) | 771 | if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA) |
683 | { | 772 | { |
684 | uint32_t sz = inst->size + inst->padding_size; | 773 | uint32_t sz = inst->size + inst->padding_size; |
685 | byte *data = xmalloc(sz); | 774 | byte *data = xmalloc(sz); |
686 | memcpy(data, inst->data, inst->size); | 775 | memcpy(data, inst->data, inst->size); |
687 | memcpy(data + inst->size, inst->padding, inst->padding_size); | 776 | memcpy(data + inst->size, inst->padding, inst->padding_size); |
688 | if(g_nr_keys > 0) | 777 | if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) |
689 | cbc_mac(data, data, sz / BLOCK_SIZE, | 778 | cbc_mac(data, data, sz / BLOCK_SIZE, |
690 | real_key, cur_cbc_mac, &cur_cbc_mac, 1); | 779 | real_key, cur_cbc_mac, &cur_cbc_mac, 1); |
691 | sha_1_update(&file_sha1, data, sz); | 780 | sha_1_update(&file_sha1, data, sz); |
@@ -706,22 +795,94 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename) | |||
706 | close(fd); | 795 | close(fd); |
707 | } | 796 | } |
708 | 797 | ||
709 | int main(int argc, const char **argv) | 798 | void usage(void) |
799 | { | ||
800 | printf("Usage: elftosb [options | file]...\n"); | ||
801 | printf("Options:\n"); | ||
802 | printf(" -?/--help:\t\tDisplay this message\n"); | ||
803 | printf(" -o <file>\tSet output file\n"); | ||
804 | printf(" -c <file>\tSet command file\n"); | ||
805 | printf(" -d/--debug\tEnable debug output\n"); | ||
806 | printf(" -k <file>\t\tAdd key file\n"); | ||
807 | printf(" -z\t\tAdd zero key\n"); | ||
808 | exit(1); | ||
809 | } | ||
810 | |||
811 | static byte g_zero_key[16] = {0}; | ||
812 | |||
813 | int main(int argc, char **argv) | ||
710 | { | 814 | { |
711 | if(argc != 4) | 815 | char *cmd_filename = NULL; |
816 | char *output_filename = NULL; | ||
817 | |||
818 | while(1) | ||
712 | { | 819 | { |
713 | printf("Usage: %s <cmd file> <key file> <out file>\n",*argv); | 820 | static struct option long_options[] = |
714 | printf("To enable debug mode, set environement variable SB_DEBUG to YES\n"); | 821 | { |
715 | return 1; | 822 | {"help", no_argument, 0, '?'}, |
823 | {"debug", no_argument, 0, 'd'}, | ||
824 | {0, 0, 0, 0} | ||
825 | }; | ||
826 | |||
827 | int c = getopt_long(argc, argv, "?do:c:k:z", long_options, NULL); | ||
828 | if(c == -1) | ||
829 | break; | ||
830 | switch(c) | ||
831 | { | ||
832 | case 'd': | ||
833 | g_debug = true; | ||
834 | break; | ||
835 | case '?': | ||
836 | usage(); | ||
837 | break; | ||
838 | case 'o': | ||
839 | output_filename = optarg; | ||
840 | break; | ||
841 | case 'c': | ||
842 | cmd_filename = optarg; | ||
843 | break; | ||
844 | case 'k': | ||
845 | { | ||
846 | int kac; | ||
847 | key_array_t ka = read_keys(optarg, &kac); | ||
848 | add_keys(ka, kac); | ||
849 | break; | ||
850 | } | ||
851 | case 'z': | ||
852 | { | ||
853 | add_keys(&g_zero_key, 1); | ||
854 | break; | ||
855 | } | ||
856 | default: | ||
857 | abort(); | ||
858 | } | ||
716 | } | 859 | } |
717 | 860 | ||
718 | if(strcasecmp(s_getenv("SB_DEBUG"), "YES") == 0) | 861 | if(!cmd_filename) |
719 | g_debug = true; | 862 | bug("You must specify a command file\n"); |
863 | if(!output_filename) | ||
864 | bug("You must specify an output file\n"); | ||
865 | |||
866 | g_extern = &argv[optind]; | ||
867 | g_extern_count = argc - optind; | ||
868 | |||
869 | if(g_debug) | ||
870 | { | ||
871 | printf("key: %d\n", g_nr_keys); | ||
872 | for(int i = 0; i < g_nr_keys; i++) | ||
873 | { | ||
874 | for(int j = 0; j < 16; j++) | ||
875 | printf(" %02x", g_key_array[i][j]); | ||
876 | printf("\n"); | ||
877 | } | ||
878 | |||
879 | for(int i = 0; i < g_extern_count; i++) | ||
880 | printf("extern(%d)=%s\n", i, g_extern[i]); | ||
881 | } | ||
720 | 882 | ||
721 | g_key_array = read_keys(argv[2], &g_nr_keys); | 883 | struct cmd_file_t *cmd_file = db_parse_file(cmd_filename); |
722 | struct cmd_file_t *cmd_file = db_parse_file(argv[1]); | ||
723 | struct sb_file_t *sb_file = apply_cmd_file(cmd_file); | 884 | struct sb_file_t *sb_file = apply_cmd_file(cmd_file); |
724 | produce_sb_file(sb_file, argv[3]); | 885 | produce_sb_file(sb_file, output_filename); |
725 | 886 | ||
726 | return 0; | 887 | return 0; |
727 | } | 888 | } |