1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2012 Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #define _ISOC99_SOURCE
23 #define _POSIX_C_SOURCE 200809L /* for strdup */
38 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
54 typedef char* (*get_next_arg_t
)(void *user
);
56 struct cmd_line_next_arg_user_t
62 static char *cmd_line_next_arg(void *user
)
64 struct cmd_line_next_arg_user_t
*uu
= user
;
69 return *(uu
->argv
- 1);
72 static bool elf_read(void *user
, uint32_t addr
, void *buf
, size_t count
)
74 if(fseek((FILE *)user
, addr
, SEEK_SET
) == -1)
76 return fread(buf
, 1, count
, (FILE *)user
) == count
;
79 static void elf_printf(void *user
, bool error
, const char *fmt
, ...)
81 if(!g_debug
&& !error
)
90 static int sb1_add_inst(struct sb1_file_t
*sb
, struct sb1_inst_t
*insts
, int nr_insts
)
92 sb
->insts
= augment_array(sb
->insts
, sizeof(struct sb1_inst_t
), sb
->nr_insts
,
94 sb
->nr_insts
+= nr_insts
;
98 static int sb1_add_load(struct sb1_file_t
*sb
, void *data
, int size
, uint32_t addr
)
102 int len
= MIN(size
, SB1_CMD_MAX_LOAD_SIZE
);
103 struct sb1_inst_t inst
;
104 memset(&inst
, 0, sizeof(inst
));
105 inst
.cmd
= SB1_INST_LOAD
;
108 inst
.critical
= g_critical
;
109 inst
.data
= xmalloc(len
);
110 memcpy(inst
.data
, data
, len
);
112 printf("Add instruction: load %#x bytes at %#x\n", len
, addr
);
113 int ret
= sb1_add_inst(sb
, &inst
, 1);
123 static int sb1_add_switch(struct sb1_file_t
*sb
, uint32_t driver
)
125 struct sb1_inst_t inst
;
126 memset(&inst
, 0, sizeof(inst
));
127 inst
.cmd
= SB1_INST_MODE
;
128 inst
.critical
= g_critical
;
131 printf("Add instruction: switch driver to %#x\n", driver
);
133 return sb1_add_inst(sb
, &inst
, 1);
136 static int sb1_add_sdram(struct sb1_file_t
*sb
, uint32_t cs
, uint32_t size
)
138 struct sb1_inst_t inst
;
139 memset(&inst
, 0, sizeof(inst
));
140 inst
.cmd
= SB1_INST_SDRAM
;
141 inst
.critical
= g_critical
;
142 inst
.sdram
.chip_select
= cs
;
143 inst
.sdram
.size_index
= sb1_sdram_index_by_size(size
);
144 if(sb1_sdram_index_by_size(size
) < 0)
145 bug("Unknown SDRAM size: %d MB\n", size
);
147 printf("Add instruction: init SDRAM (chip select=%d, size=%d MB)\n", cs
, size
);
148 return sb1_add_inst(sb
, &inst
, 1);
151 static int sb1_add_call(struct sb1_file_t
*sb
, uint32_t addr
, uint32_t arg
)
153 struct sb1_inst_t inst
;
154 memset(&inst
, 0, sizeof(inst
));
155 inst
.cmd
= SB1_INST_CALL
;
156 inst
.critical
= g_critical
;
160 printf("Add instruction: call %#x with argument %#x\n", addr
, arg
);
161 return sb1_add_inst(sb
, &inst
, 1);
164 static int sb1_add_jump(struct sb1_file_t
*sb
, uint32_t addr
, uint32_t arg
)
166 struct sb1_inst_t inst
;
167 memset(&inst
, 0, sizeof(inst
));
168 inst
.cmd
= SB1_INST_JUMP
;
169 inst
.critical
= g_critical
;
173 printf("Add instruction: jump %#x with argument %#x\n", addr
, arg
);
175 return sb1_add_inst(sb
, &inst
, 1);
178 static int sb1_add_fill(struct sb1_file_t
*sb
, uint32_t pattern
, uint32_t size
, uint32_t addr
)
182 int len
= MIN(size
, SB1_CMD_MAX_FILL_SIZE
);
183 struct sb1_inst_t inst
;
184 memset(&inst
, 0, sizeof(inst
));
185 inst
.cmd
= SB1_INST_FILL
;
186 inst
.critical
= g_critical
;
189 inst
.pattern
= pattern
;
190 inst
.datatype
= SB1_DATATYPE_UINT32
;
192 printf("Add instruction: fill %#x bytes with pattern %#x at address %#x\n",
193 size
, pattern
, addr
);
194 int ret
= sb1_add_inst(sb
, &inst
, 1);
205 * SB file modification
208 static void generate_default_sb_version(struct sb1_version_t
*ver
)
210 ver
->major
= ver
->minor
= ver
->revision
= 0x9999;
213 static struct sb1_file_t
*create_sb1_file(void)
215 struct sb1_file_t
*sb
= xmalloc(sizeof(struct sb1_file_t
));
216 memset(sb
, 0, sizeof(struct sb1_file_t
));
218 /* default versions and key, apply_args() will overwrite if specified */
219 generate_default_sb_version(&sb
->product_ver
);
220 generate_default_sb_version(&sb
->component_ver
);
221 sb1_get_default_key(&sb
->key
);
226 static void *load_file(const char *filename
, int *size
)
228 FILE *fd
= fopen(filename
, "rb");
230 bug("cannot open '%s' for reading\n", filename
);
232 printf("Loading binary file '%s'...\n", filename
);
233 fseek(fd
, 0, SEEK_END
);
235 fseek(fd
, 0, SEEK_SET
);
236 void *data
= xmalloc(*size
);
237 fread(data
, 1, *size
, fd
);
242 static bool parse_sb_sub_version(uint16_t *ver
, char *str
)
245 for(int i
= 0; str
[i
]; i
++)
249 if(str
[i
] < '0' || str
[i
] > '9')
251 *ver
= *ver
<< 4 | (str
[i
] - '0');
256 static bool parse_sb_version(struct sb1_version_t
*ver
, char *str
)
258 char *p
= strchr(str
, '.');
259 char *q
= strchr(p
+ 1, '.');
260 if(p
== NULL
|| q
== NULL
) return false;
262 return parse_sb_sub_version(&ver
->major
, str
) &&
263 parse_sb_sub_version(&ver
->minor
, p
+ 1) &&
264 parse_sb_sub_version(&ver
->revision
, q
+ 1);
268 * Command line parsing
271 #define MAX_NR_ARGS 2
276 #define CMD_FN(name) \
277 int name(struct sb1_file_t *sb, union cmd_arg_t args[MAX_NR_ARGS])
285 typedef int (*process_arg_t
)(struct sb1_file_t
*sb
, union cmd_arg_t args
[MAX_NR_ARGS
]);
291 int arg_type
[MAX_NR_ARGS
];
297 static void usage(void);
315 CMD_FN(cmd_drive_tag
)
317 sb
->drive_tag
= args
[0].uint
;
321 CMD_FN(cmd_load_binary
)
324 void *data
= load_file(args
[0].str
, &size
);
325 int ret
= sb1_add_load(sb
, data
, size
, args
[1].uint
);
333 g_output_file
= strdup(args
[0].str
);
339 return sb1_add_switch(sb
, args
[0].uint
);
344 return sb1_add_sdram(sb
, args
[0].uint
, args
[1].uint
);
355 CMD_FN(cmd_clear_critical
)
371 CMD_FN(cmd_clear_strict
)
381 /* FIXME: the proprietary sbtoelf always sets argument to 0 ?! */
382 return sb1_add_call(sb
, args
[0].uint
, g_jump_arg
);
387 return sb1_add_jump(sb
, args
[0].uint
, g_jump_arg
);
393 g_jump_arg
= args
[0].uint
;
397 static int load_elf(struct sb1_file_t
*sb
, const char *filename
, int act
)
399 struct elf_params_t elf
;
400 FILE *fd
= fopen(filename
, "rb");
402 bug("cannot open '%s'\n", filename
);
404 printf("Loading elf file '%s'...\n", filename
);
406 bool loaded
= elf_read_file(&elf
, elf_read
, elf_printf
, fd
);
409 bug("error loading elf file '%s'\n", filename
);
410 elf_translate_addresses(&elf
);
411 elf_sort_by_address(&elf
);
413 struct elf_section_t
*esec
= elf
.first_section
;
416 if(esec
->type
== EST_LOAD
)
417 sb1_add_load(sb
, esec
->section
, esec
->size
, esec
->addr
);
418 else if(esec
->type
== EST_FILL
)
419 sb1_add_fill(sb
, esec
->pattern
, esec
->size
, esec
->addr
);
424 if(act
== SB1_INST_JUMP
|| act
== SB1_INST_CALL
)
426 if(!elf
.has_start_addr
)
427 bug("Cannot jump/call: '%s' has no start address!\n", filename
);
428 if(act
== SB1_INST_JUMP
)
429 ret
= sb1_add_jump(sb
, elf
.start_addr
, g_jump_arg
);
431 ret
= sb1_add_call(sb
, elf
.start_addr
, g_jump_arg
);
441 return load_elf(sb
, args
[0].str
, SB1_INST_LOAD
);
446 return load_elf(sb
, args
[0].str
, SB1_INST_JUMP
);
449 CMD_FN(cmd_loadjumpreturn
)
451 return load_elf(sb
, args
[0].str
, SB1_INST_CALL
);
456 sb
->rom_version
= args
[0].uint
;
462 if(!parse_sb_version(&sb
->product_ver
, args
[0].str
))
463 bug("Invalid version string '%s'\n", args
[0].str
);
467 CMD_FN(cmd_component
)
469 if(!parse_sb_version(&sb
->component_ver
, args
[0].str
))
470 bug("Invalid version string '%s'\n", args
[0].str
);
477 if(!add_keys_from_file(args
[0].str
))
478 bug("Cannot add keys from file '%s'\n", args
[0].str
);
482 #define CMD(name,fn,nr_args,...) {name,nr_args,{__VA_ARGS__},fn},
483 struct cmd_entry_t g_cmds
[] =
485 CMD("-d", cmd_debug
, 0)
486 CMD("-debugon", cmd_debug
, 0)
487 CMD("-h", cmd_help
, 0)
488 CMD("-?", cmd_help
, 0)
489 CMD("-load-binary", cmd_load_binary
, 2, ARG_STR
, ARG_UINT
)
490 CMD("-drive-tag", cmd_drive_tag
, 1, ARG_UINT
)
491 CMD("-o", cmd_output
, 1, ARG_STR
)
492 CMD("-w", cmd_switch
, 1, ARG_UINT
)
493 CMD("-switchdriver", cmd_switch
, 1, ARG_UINT
)
494 CMD("-sdram", cmd_sdram
, 2, ARG_UINT
, ARG_UINT
)
495 CMD("-c", cmd_critical
, 0)
496 CMD("-critical", cmd_critical
, 0)
497 CMD("-C", cmd_clear_critical
, 0)
498 CMD("-noncritical", cmd_clear_critical
, 0)
499 CMD("-n", cmd_strict
, 0)
500 CMD("-strict", cmd_strict
, 0)
501 CMD("-N", cmd_clear_strict
, 0)
502 CMD("-nonstrict", cmd_clear_strict
, 0)
503 CMD("-call", cmd_call
, 1, ARG_UINT
)
504 CMD("-jumparg", cmd_jumparg
, 1, ARG_UINT
)
505 CMD("-f", cmd_load
, 1, ARG_STR
)
506 CMD("-load", cmd_load
, 1, ARG_STR
)
507 CMD("-r", cmd_loadjumpreturn
, 1, ARG_STR
)
508 CMD("-loadjumpreturn", cmd_loadjumpreturn
, 1, ARG_STR
)
509 CMD("-j", cmd_loadjump
, 1, ARG_STR
)
510 CMD("-loadjump", cmd_loadjump
, 1, ARG_STR
)
511 CMD("-R", cmd_rom
, 1, ARG_UINT
)
512 CMD("-rom", cmd_rom
, 1, ARG_UINT
)
513 CMD("-p", cmd_product
, 1, ARG_STR
)
514 CMD("-product", cmd_product
, 1, ARG_STR
)
515 CMD("-v", cmd_component
, 1, ARG_STR
)
516 CMD("-component", cmd_component
, 1, ARG_STR
)
517 CMD("-k", cmd_keyfile
, 1, ARG_STR
)
518 CMD("-jump", cmd_jump
, 1, ARG_UINT
)
522 #define NR_CMDS (int)(sizeof(g_cmds) / sizeof(g_cmds[0]))
524 static int apply_args(struct sb1_file_t
*sb
, get_next_arg_t next
, void *user
)
529 char *cmd
= next(user
);
534 while(i
< NR_CMDS
&& strcmp(cmd
, g_cmds
[i
].name
) != 0)
537 bug("Unknown option '%s'\n", cmd
);
538 union cmd_arg_t args
[MAX_NR_ARGS
];
539 for(int j
= 0; j
< g_cmds
[i
].nr_args
; j
++)
541 args
[j
].str
= next(user
);
542 if(args
[j
].str
== NULL
)
543 bug("Option '%s' requires %d arguments, only %d given\n", cmd
, g_cmds
[i
].nr_args
, j
);
544 if(g_cmds
[i
].arg_type
[j
] == ARG_UINT
)
547 args
[j
].uint
= strtoul(args
[j
].str
, &end
, 0);
549 bug("Option '%s' expects an integer as argument %d\n", cmd
, j
+ 1);
552 int ret
= g_cmds
[i
].fn(sb
, args
);
559 static void usage(void)
561 printf("Usage: elftosb1 [options]\n");
562 printf("Options:\n");
563 printf(" -h/-?/-help\t\t\tDisplay this message\n");
564 printf(" -o <file>\t\t\tSet output file\n");
565 printf(" -d/-debugon\t\t\tEnable debug output\n");
566 printf(" -k <file>\t\t\tSet key file\n");
567 printf(" -load-binary <file> <addr>\tLoad a binary file at a specified address\n");
568 printf(" -drive-tag <tag>\t\tSpecify drive tag\n");
569 printf(" -w/-switchdriver <driver>\tSwitch driver\n");
570 printf(" -sdram <chip select> <size>\tInit SDRAM\n");
571 printf(" -jumparg <uint>\t\tSet jumpparg for jump and jumpreturn\n");
572 printf(" -f/-load <file>\t\tLoad a ELF file\n");
573 printf(" -r/-loadjumpreturn <file>\tLoad a ELF file and call it\n");
574 printf(" -j/-loadjump <file>\t\tLoad a ELF file and jump to it\n");
575 printf(" -R/-rom <uint>\t\tSet ROM version\n");
576 printf(" -p/-product <ver>\t\tSet product version (xxx.xxx.xxx)\n");
577 printf(" -v/-component <ver>\t\tSet component version (xxx.xxx.xxx)\n");
578 printf(" -c/-critical\t\t\tSet critical flag\n");
579 printf(" -C/-noncritical\t\tClear critical flag\n");
580 printf(" -n/-strict\t\t\tSet strict flag\n");
581 printf(" -N/-nonstrict\t\t\tClear strict flag\n");
582 printf(" -call <addr>\t\tCall an address\n");
583 printf(" -jump <addr>\t\tJump to an address\n");
588 int main(int argc
, char **argv
)
593 struct sb1_file_t
*sb
= create_sb1_file();
595 struct cmd_line_next_arg_user_t u
;
598 int ret
= apply_args(sb
, &cmd_line_next_arg
, &u
);
606 bug("You must specify an output file\n");
610 bug("There is no final command in this command stream!\n");
612 printf("Warning: there is no final command in this command stream!\n");
615 enum sb1_error_t err
= sb1_write_file(sb
, g_output_file
);
616 if(err
!= SB1_SUCCESS
)
617 printf("Error: %d\n", err
);