imxtools/sbtools: silence warning
[maemo-rb.git] / utils / imxtools / sbtools / elftosb1.c
blobbe8cec7a99b110ac758ff215122f0ccc6bfb7ec1
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 */
24 #include <stdio.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <time.h>
30 #include <stdarg.h>
31 #include <strings.h>
33 #include "crypto.h"
34 #include "elf.h"
35 #include "sb1.h"
36 #include "misc.h"
38 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
40 /**
41 * Globals
44 char *g_output_file;
45 bool g_critical;
46 bool g_final;
47 bool g_strict = true;
48 uint32_t g_jump_arg;
50 /**
51 * Helpers
54 typedef char* (*get_next_arg_t)(void *user);
56 struct cmd_line_next_arg_user_t
58 int argc;
59 char **argv;
62 static char *cmd_line_next_arg(void *user)
64 struct cmd_line_next_arg_user_t *uu = user;
65 if(uu->argc == 0)
66 return NULL;
67 uu->argc--;
68 uu->argv++;
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)
75 return false;
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)
82 return;
83 (void) user;
84 va_list args;
85 va_start(args, fmt);
86 vprintf(fmt, args);
87 va_end(args);
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,
93 insts, nr_insts);
94 sb->nr_insts += nr_insts;
95 return 0;
98 static int sb1_add_load(struct sb1_file_t *sb, void *data, int size, uint32_t addr)
100 while(size > 0)
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;
106 inst.size = len;
107 inst.addr = addr;
108 inst.critical = g_critical;
109 inst.data = xmalloc(len);
110 memcpy(inst.data, data, len);
111 if(g_debug)
112 printf("Add instruction: load %#x bytes at %#x\n", len, addr);
113 int ret = sb1_add_inst(sb, &inst, 1);
114 if(ret < 0)
115 return ret;
116 data += len;
117 size -= len;
118 addr += len;
120 return 0;
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;
129 inst.mode = driver;
130 if(g_debug)
131 printf("Add instruction: switch driver to %#x\n", driver);
132 g_final = true;
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);
146 if(g_debug)
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;
157 inst.addr = addr;
158 inst.argument = arg;
159 if(g_debug)
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;
170 inst.addr = addr;
171 inst.argument = arg;
172 if(g_debug)
173 printf("Add instruction: jump %#x with argument %#x\n", addr, arg);
174 g_final = true;
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)
180 while(size > 0)
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;
187 inst.size = len;
188 inst.addr = addr;
189 inst.pattern = pattern;
190 inst.datatype = SB1_DATATYPE_UINT32;
191 if(g_debug)
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);
195 if(ret < 0)
196 return ret;
197 size -= len;
198 addr += len;
201 return 0;
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);
223 return sb;
226 static void *load_file(const char *filename, int *size)
228 FILE *fd = fopen(filename, "rb");
229 if(fd == NULL)
230 bug("cannot open '%s' for reading\n", filename);
231 if(g_debug)
232 printf("Loading binary file '%s'...\n", filename);
233 fseek(fd, 0, SEEK_END);
234 *size = ftell(fd);
235 fseek(fd, 0, SEEK_SET);
236 void *data = xmalloc(*size);
237 fread(data, 1, *size, fd);
238 fclose(fd);
239 return data;
242 static bool parse_sb_sub_version(uint16_t *ver, char *str)
244 *ver = 0;
245 for(int i = 0; str[i]; i++)
247 if(i >= 4)
248 return false;
249 if(str[i] < '0' || str[i] > '9')
250 return false;
251 *ver = *ver << 4 | (str[i] - '0');
253 return true;
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;
261 *p = *q = 0;
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
273 #define ARG_STR 0
274 #define ARG_UINT 1
276 #define CMD_FN(name) \
277 int name(struct sb1_file_t *sb, union cmd_arg_t args[MAX_NR_ARGS])
279 union cmd_arg_t
281 char *str;
282 unsigned long uint;
285 typedef int (*process_arg_t)(struct sb1_file_t *sb, union cmd_arg_t args[MAX_NR_ARGS]);
287 struct cmd_entry_t
289 const char *name;
290 int nr_args;
291 int arg_type[MAX_NR_ARGS];
292 process_arg_t fn;
295 /* Callbacks */
297 static void usage(void);
299 CMD_FN(cmd_help)
301 (void) args;
302 (void) sb;
303 usage();
304 return 0;
307 CMD_FN(cmd_debug)
309 (void) args;
310 (void) sb;
311 g_debug = true;
312 return 0;
315 CMD_FN(cmd_drive_tag)
317 sb->drive_tag = args[0].uint;
318 return 0;
321 CMD_FN(cmd_load_binary)
323 int size;
324 void *data = load_file(args[0].str, &size);
325 int ret = sb1_add_load(sb, data, size, args[1].uint);
326 free(data);
327 return ret;
330 CMD_FN(cmd_output)
332 (void) sb;
333 g_output_file = strdup(args[0].str);
334 return 0;
337 CMD_FN(cmd_switch)
339 return sb1_add_switch(sb, args[0].uint);
342 CMD_FN(cmd_sdram)
344 return sb1_add_sdram(sb, args[0].uint, args[1].uint);
347 CMD_FN(cmd_critical)
349 (void) sb;
350 (void) args;
351 g_critical = true;
352 return 0;
355 CMD_FN(cmd_clear_critical)
357 (void) sb;
358 (void) args;
359 g_critical = false;
360 return 0;
363 CMD_FN(cmd_strict)
365 (void) sb;
366 (void) args;
367 g_strict = true;
368 return 0;
371 CMD_FN(cmd_clear_strict)
373 (void) sb;
374 (void) args;
375 g_strict = false;
376 return 0;
379 CMD_FN(cmd_call)
381 /* FIXME: the proprietary sbtoelf always sets argument to 0 ?! */
382 return sb1_add_call(sb, args[0].uint, g_jump_arg);
385 CMD_FN(cmd_jump)
387 return sb1_add_jump(sb, args[0].uint, g_jump_arg);
390 CMD_FN(cmd_jumparg)
392 (void) sb;
393 g_jump_arg = args[0].uint;
394 return 0;
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");
401 if(fd == NULL)
402 bug("cannot open '%s'\n", filename);
403 if(g_debug)
404 printf("Loading elf file '%s'...\n", filename);
405 elf_init(&elf);
406 bool loaded = elf_read_file(&elf, elf_read, elf_printf, fd);
407 fclose(fd);
408 if(!loaded)
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;
414 while(esec)
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);
420 esec = esec->next;
423 int ret = 0;
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);
430 else
431 ret = sb1_add_call(sb, elf.start_addr, g_jump_arg);
434 elf_release(&elf);
436 return ret;
439 CMD_FN(cmd_load)
441 return load_elf(sb, args[0].str, SB1_INST_LOAD);
444 CMD_FN(cmd_loadjump)
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);
454 CMD_FN(cmd_rom)
456 sb->rom_version = args[0].uint;
457 return 0;
460 CMD_FN(cmd_product)
462 if(!parse_sb_version(&sb->product_ver, args[0].str))
463 bug("Invalid version string '%s'\n", args[0].str);
464 return 0;
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);
471 return 0;
474 CMD_FN(cmd_keyfile)
476 (void) sb;
477 if(!add_keys_from_file(args[0].str))
478 bug("Cannot add keys from file '%s'\n", args[0].str);
479 return 0;
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)
520 #undef CMD
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)
526 while(true)
528 /* next command ? */
529 char *cmd = next(user);
530 if(cmd == NULL)
531 break;
532 /* switch */
533 int i = 0;
534 while(i < NR_CMDS && strcmp(cmd, g_cmds[i].name) != 0)
535 i++;
536 if(i == NR_CMDS)
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)
546 char *end;
547 args[j].uint = strtoul(args[j].str, &end, 0);
548 if(*end)
549 bug("Option '%s' expects an integer as argument %d\n", cmd, j + 1);
552 int ret = g_cmds[i].fn(sb, args);
553 if(ret < 0)
554 return ret;
556 return 0;
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");
585 exit(1);
588 int main(int argc, char **argv)
590 if(argc <= 1)
591 usage();
593 struct sb1_file_t *sb = create_sb1_file();
595 struct cmd_line_next_arg_user_t u;
596 u.argc = argc - 1;
597 u.argv = argv + 1;
598 int ret = apply_args(sb, &cmd_line_next_arg, &u);
599 if(ret < 0)
601 sb1_free(sb);
602 return ret;
605 if(!g_output_file)
606 bug("You must specify an output file\n");
607 if(!g_final)
609 if(g_strict)
610 bug("There is no final command in this command stream!\n");
611 else
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);
619 return ret;