summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-12-16 21:22:15 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2012-12-16 21:28:41 +0100
commit1e2e79d66809ad0f1ff598bf9dbed8e322a1f8ea (patch)
treefaa0444ad49c3c092ba0ee1efab4dfbe6c813d11 /utils
parent212cfdf771dc0059804cf817caaf2e43ef2b3f50 (diff)
downloadrockbox-1e2e79d66809ad0f1ff598bf9dbed8e322a1f8ea.tar.gz
rockbox-1e2e79d66809ad0f1ff598bf9dbed8e322a1f8ea.tar.bz2
rockbox-1e2e79d66809ad0f1ff598bf9dbed8e322a1f8ea.zip
imxtools/sbtools: introduce elftosb1 for stmp36xx
The tool still lacks some feature of the proprietary one but can create files with all the basic features. Change-Id: Ib0c91210940ca829291ce70945f88dc510a49974
Diffstat (limited to 'utils')
-rw-r--r--utils/imxtools/sbtools/Makefile5
-rw-r--r--utils/imxtools/sbtools/elftosb1.c543
2 files changed, 547 insertions, 1 deletions
diff --git a/utils/imxtools/sbtools/Makefile b/utils/imxtools/sbtools/Makefile
index bc7180d866..16ae0878b0 100644
--- a/utils/imxtools/sbtools/Makefile
+++ b/utils/imxtools/sbtools/Makefile
@@ -3,7 +3,7 @@ CC=gcc
LD=gcc
CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
LDFLAGS=`pkg-config --libs libusb-1.0`
-BINS=elftosb sbtoelf sbloader rsrctool
+BINS=elftosb sbtoelf sbloader rsrctool elftosb1
all: $(BINS)
@@ -16,6 +16,9 @@ sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o xorcrypt.o elf.o misc.o sb.o s
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
$(LD) -o $@ $^ $(LDFLAGS)
+elftosb1: elftosb1.o xorcrypt.o elf.o misc.o sb1.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
sbloader: sbloader.o
$(LD) -o $@ $^ $(LDFLAGS)
diff --git a/utils/imxtools/sbtools/elftosb1.c b/utils/imxtools/sbtools/elftosb1.c
new file mode 100644
index 0000000000..a654b6b34a
--- /dev/null
+++ b/utils/imxtools/sbtools/elftosb1.c
@@ -0,0 +1,543 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#define _ISOC99_SOURCE
+#define _POSIX_C_SOURCE 200809L /* for strdup */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <strings.h>
+
+#include "crypto.h"
+#include "elf.h"
+#include "sb1.h"
+#include "misc.h"
+
+#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
+
+/**
+ * Globals
+ */
+
+char *g_output_file;
+bool g_critical;
+bool g_final;
+bool g_strict = true;
+uint32_t g_jump_arg;
+
+/**
+ * Helpers
+ */
+
+typedef char* (*get_next_arg_t)(void *user);
+
+struct cmd_line_next_arg_user_t
+{
+ int argc;
+ char **argv;
+};
+
+static char *cmd_line_next_arg(void *user)
+{
+ struct cmd_line_next_arg_user_t *uu = user;
+ if(uu->argc == 0)
+ return NULL;
+ uu->argc--;
+ uu->argv++;
+ return *(uu->argv - 1);
+}
+
+static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
+{
+ if(fseek((FILE *)user, addr, SEEK_SET) == -1)
+ return false;
+ return fread(buf, 1, count, (FILE *)user) == count;
+}
+
+static void elf_printf(void *user, bool error, const char *fmt, ...)
+{
+ if(!g_debug && !error)
+ return;
+ (void) user;
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+static int sb1_add_inst(struct sb1_file_t *sb, struct sb1_inst_t *insts, int nr_insts)
+{
+ sb->insts = augment_array(sb->insts, sizeof(struct sb1_inst_t), sb->nr_insts,
+ insts, nr_insts);
+ sb->nr_insts += nr_insts;
+ return 0;
+}
+
+static int sb1_add_load(struct sb1_file_t *sb, void *data, int size, uint32_t addr)
+{
+ while(size > 0)
+ {
+ int len = MIN(size, SB1_CMD_MAX_LOAD_SIZE);
+ struct sb1_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+ inst.cmd = SB1_INST_LOAD;
+ inst.size = len;
+ inst.addr = addr;
+ inst.critical = g_critical;
+ inst.data = xmalloc(len);
+ memcpy(inst.data, data, len);
+ if(g_debug)
+ printf("Add instruction: load %#x bytes at %#x\n", len, addr);
+ int ret = sb1_add_inst(sb, &inst, 1);
+ if(ret < 0)
+ return ret;
+ data += len;
+ size -= len;
+ addr += len;
+ }
+ return 0;
+}
+
+static int sb1_add_switch(struct sb1_file_t *sb, uint32_t driver)
+{
+ struct sb1_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+ inst.cmd = SB1_INST_MODE;
+ inst.critical = g_critical;
+ inst.mode = driver;
+ if(g_debug)
+ printf("Add instruction: switch driver to %#x\n", driver);
+ g_final = true;
+ return sb1_add_inst(sb, &inst, 1);
+}
+
+static int sb1_add_sdram(struct sb1_file_t *sb, uint32_t cs, uint32_t size)
+{
+ struct sb1_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+ inst.cmd = SB1_INST_SDRAM;
+ inst.critical = g_critical;
+ inst.sdram.chip_select = cs;
+ inst.sdram.size_index = sb1_sdram_index_by_size(size);
+ if(sb1_sdram_index_by_size(size) < 0)
+ bug("Unknown SDRAM size: %d MB\n", size);
+ if(g_debug)
+ printf("Add instruction: init SDRAM (chip select=%d, size=%d MB)\n", cs, size);
+ return sb1_add_inst(sb, &inst, 1);
+}
+
+static int sb1_add_call(struct sb1_file_t *sb, uint32_t addr, uint32_t arg)
+{
+ struct sb1_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+ inst.cmd = SB1_INST_CALL;
+ inst.critical = g_critical;
+ inst.addr = addr;
+ inst.argument = arg;
+ if(g_debug)
+ printf("Add instruction: call %#x with argument %#x\n", addr, arg);
+ return sb1_add_inst(sb, &inst, 1);
+}
+
+static int sb1_add_jump(struct sb1_file_t *sb, uint32_t addr, uint32_t arg)
+{
+ struct sb1_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+ inst.cmd = SB1_INST_JUMP;
+ inst.critical = g_critical;
+ inst.addr = addr;
+ inst.argument = arg;
+ if(g_debug)
+ printf("Add instruction: jump %#x with argument %#x\n", addr, arg);
+ g_final = true;
+ return sb1_add_inst(sb, &inst, 1);
+}
+
+static int sb1_add_fill(struct sb1_file_t *sb, uint32_t pattern, uint32_t size, uint32_t addr)
+{
+ while(size > 0)
+ {
+ int len = MIN(size, SB1_CMD_MAX_FILL_SIZE);
+ struct sb1_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+ inst.cmd = SB1_INST_FILL;
+ inst.critical = g_critical;
+ inst.size = len;
+ inst.addr = addr;
+ inst.pattern = pattern;
+ inst.datatype = SB1_DATATYPE_UINT32;
+ if(g_debug)
+ printf("Add instruction: fill %#x bytes with pattern %#x at address %#x\n",
+ size, pattern, addr);
+ int ret = sb1_add_inst(sb, &inst, 1);
+ if(ret < 0)
+ return ret;
+ size -= len;
+ addr += len;
+ }
+
+ return 0;
+}
+
+/**
+ * SB file modification
+ */
+
+static void generate_default_sb_version(struct sb1_version_t *ver)
+{
+ ver->major = ver->minor = ver->revision = 0x9999;
+}
+
+static struct sb1_file_t *create_sb1_file(void)
+{
+ struct sb1_file_t *sb = xmalloc(sizeof(struct sb1_file_t));
+ memset(sb, 0, sizeof(struct sb1_file_t));
+
+ /* default versions and key, apply_args() will overwrite if specified */
+ generate_default_sb_version(&sb->product_ver);
+ generate_default_sb_version(&sb->component_ver);
+ sb1_get_default_key(&sb->key);
+
+ return sb;
+}
+
+static void *load_file(const char *filename, int *size)
+{
+ FILE *fd = fopen(filename, "rb");
+ if(fd == NULL)
+ bug("cannot open '%s' for reading\n", filename);
+ if(g_debug)
+ printf("Loading binary file '%s'...\n", filename);
+ fseek(fd, 0, SEEK_END);
+ *size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ void *data = xmalloc(*size);
+ fread(data, 1, *size, fd);
+ fclose(fd);
+ return data;
+}
+
+/**
+ * Command line parsing
+ */
+
+#define MAX_NR_ARGS 2
+
+#define ARG_STR 0
+#define ARG_UINT 1
+
+#define CMD_FN(name) \
+ int name(struct sb1_file_t *sb, union cmd_arg_t args[MAX_NR_ARGS])
+
+union cmd_arg_t
+{
+ char *str;
+ unsigned long uint;
+};
+
+typedef int (*process_arg_t)(struct sb1_file_t *sb, union cmd_arg_t args[MAX_NR_ARGS]);
+
+struct cmd_entry_t
+{
+ const char *name;
+ int nr_args;
+ int arg_type[MAX_NR_ARGS];
+ process_arg_t fn;
+};
+
+/* Callbacks */
+
+static void usage(void);
+
+CMD_FN(cmd_help)
+{
+ (void) args;
+ (void) sb;
+ usage();
+ return 0;
+}
+
+CMD_FN(cmd_debug)
+{
+ (void) args;
+ (void) sb;
+ g_debug = true;
+ return 0;
+}
+
+CMD_FN(cmd_drive_tag)
+{
+ sb->drive_tag = args[0].uint;
+ return 0;
+}
+
+CMD_FN(cmd_load_binary)
+{
+ int size;
+ void *data = load_file(args[0].str, &size);
+ int ret = sb1_add_load(sb, data, size, args[1].uint);
+ free(data);
+ return ret;
+}
+
+CMD_FN(cmd_output)
+{
+ (void) sb;
+ g_output_file = strdup(args[0].str);
+ return 0;
+}
+
+CMD_FN(cmd_switch)
+{
+ return sb1_add_switch(sb, args[0].uint);
+}
+
+CMD_FN(cmd_sdram)
+{
+ return sb1_add_sdram(sb, args[0].uint, args[1].uint);
+}
+
+CMD_FN(cmd_critical)
+{
+ (void) sb;
+ (void) args;
+ g_critical = true;
+ return 0;
+}
+
+CMD_FN(cmd_clear_critical)
+{
+ (void) sb;
+ (void) args;
+ g_critical = false;
+ return 0;
+}
+
+CMD_FN(cmd_strict)
+{
+ (void) sb;
+ (void) args;
+ g_strict = true;
+ return 0;
+}
+
+CMD_FN(cmd_clear_strict)
+{
+ (void) sb;
+ (void) args;
+ g_strict = false;
+ return 0;
+}
+
+CMD_FN(cmd_call)
+{
+ /* FIXME: the proprietary sbtoelf always sets argument to 0 ?! */
+ return sb1_add_call(sb, args[0].uint, g_jump_arg);
+}
+
+CMD_FN(cmd_jumparg)
+{
+ (void) sb;
+ g_jump_arg = args[0].uint;
+ return 0;
+}
+
+static int load_elf(struct sb1_file_t *sb, const char *filename, int act)
+{
+ struct elf_params_t elf;
+ FILE *fd = fopen(filename, "rb");
+ if(fd == NULL)
+ bug("cannot open '%s'\n", filename);
+ if(g_debug)
+ printf("Loading elf file '%s'...\n", filename);
+ elf_init(&elf);
+ bool loaded = elf_read_file(&elf, elf_read, elf_printf, fd);
+ fclose(fd);
+ if(!loaded)
+ bug("error loading elf file '%s'\n", filename);
+ //elf_translate_addresses(&elf);
+ elf_sort_by_address(&elf);
+
+ struct elf_section_t *esec = elf.first_section;
+ while(esec)
+ {
+ if(esec->type == EST_LOAD)
+ sb1_add_load(sb, esec->section, esec->size, esec->addr);
+ else if(esec->type == EST_FILL)
+ sb1_add_fill(sb, esec->pattern, esec->size, esec->addr);
+ esec = esec->next;
+ }
+
+ int ret = 0;
+ if(act == SB1_INST_JUMP || act == SB1_INST_CALL)
+ {
+ if(!elf.has_start_addr)
+ bug("Cannot jump/call: '%s' has no start address!\n", filename);
+ if(act == SB1_INST_JUMP)
+ ret = sb1_add_jump(sb, elf.start_addr, g_jump_arg);
+ else
+ ret = sb1_add_call(sb, elf.start_addr, g_jump_arg);
+ }
+
+ elf_release(&elf);
+
+ return ret;
+}
+
+CMD_FN(cmd_load)
+{
+ return load_elf(sb, args[0].str, SB1_INST_LOAD);
+}
+
+CMD_FN(cmd_loadjump)
+{
+ return load_elf(sb, args[0].str, SB1_INST_JUMP);
+}
+
+CMD_FN(cmd_loadjumpreturn)
+{
+ return load_elf(sb, args[0].str, SB1_INST_CALL);
+}
+
+#define CMD(name,fn,nr_args,...) {name,nr_args,{__VA_ARGS__},fn},
+struct cmd_entry_t g_cmds[] =
+{
+ CMD("-d", cmd_debug, 0)
+ CMD("-debugon", cmd_debug, 0)
+ CMD("-h", cmd_help, 0)
+ CMD("-?", cmd_help, 0)
+ CMD("-load-binary", cmd_load_binary, 2, ARG_STR, ARG_UINT)
+ CMD("-drive-tag", cmd_drive_tag, 1, ARG_UINT)
+ CMD("-o", cmd_output, 1, ARG_STR)
+ CMD("-w", cmd_switch, 1, ARG_UINT)
+ CMD("-switchdriver", cmd_switch, 1, ARG_UINT)
+ CMD("-sdram", cmd_sdram, 2, ARG_UINT, ARG_UINT)
+ CMD("-c", cmd_critical, 0)
+ CMD("-critical", cmd_critical, 0)
+ CMD("-C", cmd_clear_critical, 0)
+ CMD("-noncritical", cmd_clear_critical, 0)
+ CMD("-n", cmd_strict, 0)
+ CMD("-strict", cmd_strict, 0)
+ CMD("-N", cmd_clear_strict, 0)
+ CMD("-nonstrict", cmd_clear_strict, 0)
+ CMD("-call", cmd_call, 1, ARG_UINT)
+ CMD("-jumparg", cmd_jumparg, 1, ARG_UINT)
+ CMD("-f", cmd_load, 1, ARG_STR)
+ CMD("-load", cmd_load, 1, ARG_STR)
+ CMD("-r", cmd_loadjumpreturn, 1, ARG_STR)
+ CMD("-loadjumpreturn", cmd_loadjumpreturn, 1, ARG_STR)
+ CMD("-j", cmd_loadjump, 1, ARG_STR)
+ CMD("-loadjump", cmd_loadjump, 1, ARG_STR)
+};
+#undef CMD
+
+#define NR_CMDS (int)(sizeof(g_cmds) / sizeof(g_cmds[0]))
+
+static int apply_args(struct sb1_file_t *sb, get_next_arg_t next, void *user)
+{
+ while(true)
+ {
+ /* next command ? */
+ char *cmd = next(user);
+ if(cmd == NULL)
+ break;
+ /* switch */
+ int i = 0;
+ while(i < NR_CMDS && strcmp(cmd, g_cmds[i].name) != 0)
+ i++;
+ if(i == NR_CMDS)
+ bug("Unknown option '%s'\n", cmd);
+ union cmd_arg_t args[MAX_NR_ARGS];
+ for(int j = 0; j < g_cmds[i].nr_args; j++)
+ {
+ args[j].str = next(user);
+ if(args[j].str == NULL)
+ bug("Option '%s' requires %d arguments, only %d given\n", cmd, g_cmds[i].nr_args, j);
+ if(g_cmds[i].arg_type[j] == ARG_UINT)
+ {
+ char *end;
+ args[j].uint = strtoul(args[j].str, &end, 0);
+ if(*end)
+ bug("Option '%s' expects an integer as argument %d\n", cmd, j + 1);
+ }
+ }
+ int ret = g_cmds[i].fn(sb, args);
+ if(ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Usage: elftosb1 [options]\n");
+ printf("Options:\n");
+ printf(" -h/-?/-help\t\t\tDisplay this message\n");
+ printf(" -o <file>\t\t\tSet output file\n");
+ printf(" -d/-debugon\t\t\tEnable debug output\n");
+ printf(" -k <file>\t\t\tSet key file\n");
+ printf(" -load-binary <file> <addr>\tLoad a binary file at a specified address\n");
+ printf(" -drive-tag <tag>\t\tSpecify drive tag\n");
+ printf(" -w/-switchdriver <driver>\tSwitch driver\n");
+ printf(" -sdram <chip select> <size>\tInit SDRAM\n");
+ printf(" -f/-load <file>\t\tLoad a ELF file\n");
+
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ if(argc <= 1)
+ usage();
+
+ struct sb1_file_t *sb = create_sb1_file();
+
+ struct cmd_line_next_arg_user_t u;
+ u.argc = argc - 1;
+ u.argv = argv + 1;
+ int ret = apply_args(sb, &cmd_line_next_arg, &u);
+ if(ret < 0)
+ {
+ sb1_free(sb);
+ return ret;
+ }
+
+ if(!g_output_file)
+ bug("You must specify an output file\n");
+ if(!g_final)
+ {
+ if(g_strict)
+ bug("There is no final command in this command stream!\n");
+ else
+ printf("Warning: there is no final command in this command stream!\n");
+ }
+
+ enum sb1_error_t err = sb1_write_file(sb, g_output_file);
+ if(err != SB1_SUCCESS)
+ printf("Error: %d\n", err);
+
+ return ret;
+}
+