summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utils/sbtools/dbparser.c411
-rw-r--r--utils/sbtools/dbparser.h28
-rw-r--r--utils/sbtools/elftosb.c387
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
27typedef uint8_t byte; 28typedef 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
324static void generate_default_version(struct sb_version_t *ver) 337struct 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
395struct lex_ctx_t
396{
397 struct context_t ctx;
398 struct lexem_t lexem;
399};
400
401static inline void next(struct lex_ctx_t *ctx)
402{
403 next_lexem(&ctx->ctx, &ctx->lexem);
404}
405
406static 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
426static 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
437static 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
448static 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
454static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"};
455static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0};
456
378struct cmd_file_t *db_parse_file(const char *file) 457struct 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
790void 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
43struct cmd_source_t 43struct 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
79struct 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
75struct cmd_section_t 90struct 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
82struct cmd_file_t 102struct 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
90struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); 110struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id);
111struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name);
91bool db_parse_sb_version(struct sb_version_t *ver, char *str); 112bool db_parse_sb_version(struct sb_version_t *ver, char *str);
113void db_generate_default_sb_version(struct sb_version_t *ver);
92struct cmd_file_t *db_parse_file(const char *file); 114struct 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
48bool g_debug = false; 49bool g_debug = false;
50char **g_extern;
51int 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];
107int g_nr_keys; 110int g_nr_keys;
108key_array_t g_key_array; 111key_array_t g_key_array;
109 112
113static 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
110static key_array_t read_keys(const char *key_file, int *num_keys) 123static 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
171struct sb_inst_t 186struct 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
186struct sb_section_t 201struct 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
242static 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
224static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) 252static 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
405static void fill_gaps(struct sb_file_t *sb) 472static 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
550static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) 635static 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
709int main(int argc, const char **argv) 798void 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
811static byte g_zero_key[16] = {0};
812
813int 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}