summaryrefslogtreecommitdiffstats
path: root/utils/hwstub/tools
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/tools')
-rw-r--r--utils/hwstub/tools/Makefile36
-rw-r--r--utils/hwstub/tools/hwemul_tool.c558
-rw-r--r--utils/hwstub/tools/hwstub_load.cpp316
-rw-r--r--utils/hwstub/tools/hwstub_shell.cpp873
-rw-r--r--utils/hwstub/tools/init.lua104
5 files changed, 1319 insertions, 568 deletions
diff --git a/utils/hwstub/tools/Makefile b/utils/hwstub/tools/Makefile
index 3466a4e776..6db0c709b1 100644
--- a/utils/hwstub/tools/Makefile
+++ b/utils/hwstub/tools/Makefile
@@ -1,22 +1,38 @@
CC=gcc
-AR=ar
-HWEMUL_LIB_DIR=../lib
-CFLAGS=-W -Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWEMUL_LIB_DIR)
-LDFLAGS=`pkg-config --libs libusb-1.0` -lreadline
-EXEC=hwemul_tool
-HWEMUL_LIB=$(HWEMUL_LIB_DIR)/libhwemul.a
+CXX=g++
+LD=g++
+HWSTUB_LIB_DIR=../lib
+REGTOOLS_LIB_DIR=../../regtools/lib
+CFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2`
+CXXFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2`
+LDFLAGS=`pkg-config --libs libusb-1.0` `pkg-config --libs lua5.2` -lreadline -L$(HWSTUB_LIB_DIR) -L$(REGTOOLS_LIB_DIR) -lsocdesc -lhwstub `xml2-config --libs`
+EXEC=hwstub_shell hwstub_load
SRC=$(wildcard *.c)
-OBJ=$(SRC:.c=.o)
+SRCXX=$(wildcard *.cpp)
+OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o)
+LIBS=$(HWSTUB_LIB_DIR)/libhwstub.a $(REGTOOLS_LIB_DIR)/libsocdesc.a
all: $(EXEC)
+$(HWSTUB_LIB_DIR)/libhwstub.a:
+ make -C $(HWSTUB_LIB_DIR)
+
+$(REGTOOLS_LIB_DIR)/libsocdesc.a:
+ make -C $(REGTOOLS_LIB_DIR)
+
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
-hwemul_tool: hwemul_tool.o $(HWEMUL_LIB)
- $(CC) -o $@ $^ $(LDFLAGS)
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
+hwstub_shell: hwstub_shell.o $(LIBS)
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+hwstub_load: hwstub_load.o $(LIBS)
+ $(LD) -o $@ $^ $(LDFLAGS)
clean:
- rm -rf $(OBJ) $(LIB)
+ rm -rf $(OBJ) $(LIB) $(EXEC)
diff --git a/utils/hwstub/tools/hwemul_tool.c b/utils/hwstub/tools/hwemul_tool.c
deleted file mode 100644
index d75cd7a957..0000000000
--- a/utils/hwstub/tools/hwemul_tool.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2012 by 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.
- *
- ****************************************************************************/
-#include "hwemul.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-
-bool g_quiet = false;
-struct hwemul_device_t hwdev;
-struct hwemul_soc_t *cur_soc = NULL;
-
-void print_log(struct hwemul_device_t *hwdev)
-{
- do
- {
- char buffer[128];
- int length = hwemul_get_log(hwdev, buffer, sizeof(buffer) - 1);
- if(length <= 0)
- break;
- buffer[length] = 0;
- printf("%s", buffer);
- }while(1);
-}
-
-int print_help()
-{
- printf("Commands:\n");
- printf(" help\t\tDisplay this help\n");
- printf(" call <addr>\tCall address <addr>\n");
- printf(" quit\t\tQuit this session\n");
- printf(" read32 <addr>\tRead a 32-bit word at <addr>\n");
- printf(" write32 <value> <addr>\tRead the 32-bit word <value> at <addr>\n");
- printf(" read <regname>\tRead a register by name\n");
- printf(" read <regname>.<field>\tRead a register field by name\n");
- printf(" soc <socname>\tSelect the soc description to use\n");
- printf(" write <value> <regname>\tWrite a register by name\n");
- printf(" write <value <regname>.<field>\tWrite a register field by name\n");
- printf(" NOTE: if the register is SCT variant, no read is performed.\n");
- return 1;
-}
-
-int syntax_error(char *str)
-{
- printf("Syntax error at '%s'. Type 'help' to get some help.\n", str);
- return 1;
-}
-
-int parse_uint32(char *str, uint32_t *u)
-{
- char *end;
- *u = strtoul(str, &end, 0);
- return *end == 0;
-}
-
-int do_call(uint32_t a)
-{
- hwemul_call(&hwdev, a);
- return 1;
-}
-
-int parse_call()
-{
- char *arg = strtok(NULL, " ");
- uint32_t addr;
- if(arg && parse_uint32(arg, &addr))
- return do_call(addr);
- else
- return syntax_error(arg);
-}
-
-int do_read32(uint32_t a)
-{
- uint32_t val;
- if(hwemul_rw_mem(&hwdev, 1, a, &val, sizeof(val)) == sizeof(val))
- printf("%#x = %#x\n", a, val);
- else
- printf("read error at %#x\n", a);
- return 1;
-}
-
-int parse_read32()
-{
- char *arg = strtok(NULL, " ");
- uint32_t addr;
- if(arg && parse_uint32(arg, &addr))
- return do_read32(addr);
- else
- return syntax_error(arg);
-}
-
-int do_write32(uint32_t val, uint32_t a)
-{
- if(hwemul_rw_mem(&hwdev, 0, a, &val, sizeof(val)) == sizeof(val))
- printf("data written\n");
- else
- printf("write error at %#x\n", a);
- return 1;
-}
-
-int parse_write32()
-{
- char *arg = strtok(NULL, " ");
- uint32_t val;
- if(!arg || !parse_uint32(arg, &val))
- return syntax_error(arg);
- uint32_t addr;
- arg = strtok(NULL, " ");
- if(arg && parse_uint32(arg, &addr))
- return do_write32(val, addr);
- else
- return syntax_error(arg);
-}
-
-struct hwemul_soc_t *find_soc_by_name(const char *soc)
-{
- struct hwemul_soc_list_t *list = hwemul_get_soc_list();
- for(size_t i = 0; i < list->nr_socs; i++)
- if(strcmp(soc, list->socs[i]->name) == 0)
- return list->socs[i];
- return NULL;
-}
-
-struct hwemul_soc_reg_t *find_reg_by_name(struct hwemul_soc_t *soc, const char *reg)
-{
- for(size_t i = 0; i < soc->nr_regs; i++)
- if(strcmp(reg, soc->regs_by_name[i]->name) == 0)
- return soc->regs_by_name[i];
- return NULL;
-}
-
-struct hwemul_soc_reg_field_t *find_field_by_name(struct hwemul_soc_reg_t *reg, const char *field)
-{
- for(size_t i = 0; i < reg->nr_fields; i++)
- if(strcmp(field, reg->fields_by_name[i]->name) == 0)
- return reg->fields_by_name[i];
- return NULL;
-}
-
-
-int do_read(char *regname)
-{
- char *dot = strchr(regname, '.');
- if(dot != NULL)
- *dot++ = 0;
- if(cur_soc == NULL)
- {
- printf("No soc selected!\n");
- return 1;
- }
- struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname);
- if(reg == NULL)
- {
- printf("no reg '%s' found\n", regname);
- return 1;
- }
- uint32_t val;
- if(hwemul_rw_mem(&hwdev, 1, reg->addr, &val, sizeof(val)) != sizeof(val))
- {
- printf("read error at %#x\n", reg->addr);
- return 1;
- }
- if(dot)
- {
- struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot);
- if(field == NULL)
- {
- printf("no field '%s' found\n", dot);
- return 1;
- }
- val >>= field->first_bit;
- val &= (1 << (field->last_bit - field->first_bit + 1)) - 1;
- printf("%s.%s = %#x\n", regname, dot, val);
- }
- else
- printf("%s = %#x\n", regname, val);
- return 1;
-}
-
-int parse_read()
-{
- char *arg = strtok(NULL, " ");
- if(arg)
- return do_read(arg);
- else
- return syntax_error(arg);
-}
-
-int do_soc(char *soc)
-{
- struct hwemul_soc_t *s = find_soc_by_name(soc);
- if(s == NULL)
- printf("no soc '%s' found\n", soc);
- else
- cur_soc = s;
- return 1;
-}
-
-int parse_soc()
-{
- char *arg = strtok(NULL, " ");
- if(arg)
- return do_soc(arg);
- else
- return syntax_error(arg);
-}
-
-int do_write(uint32_t val, char *regname)
-{
- char *dot = strchr(regname, '.');
- if(dot != NULL)
- *dot++ = 0;
- if(cur_soc == NULL)
- {
- printf("No soc selected!\n");
- return 1;
- }
- struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname);
- int is_sct = 0;
- uint32_t addr_off = 0;
- if(reg == NULL)
- {
- size_t len = strlen(regname);
- /* try SCT variant */
- if(strcmp(regname + len - 4, "_SET") == 0)
- addr_off = 4;
- else if(strcmp(regname + len - 4, "_CLR") == 0)
- addr_off = 8;
- else if(strcmp(regname + len - 4, "_TOG") == 0)
- addr_off = 12;
- else
- {
- printf("no reg '%s' found\n", regname);
- return 1;
- }
- is_sct = 1;
- regname[len - 4] = 0;
- reg = find_reg_by_name(cur_soc, regname);
- if(reg == NULL)
- {
- printf("no reg '%s' found\n", regname);
- return 1;
- }
- }
- if(dot)
- {
- struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot);
- if(field == NULL)
- {
- printf("no field '%s' found\n", dot);
- return 1;
- }
- uint32_t actual_val = 0;
- if(!is_sct)
- {
- if(hwemul_rw_mem(&hwdev, 1, reg->addr, &actual_val, sizeof(actual_val)) != sizeof(actual_val))
- {
- printf("read error at %#x\n", reg->addr);
- return 1;
- }
- printf("read %#x at %#x\n", actual_val, reg->addr);
- }
- uint32_t mask = ((1 << (field->last_bit - field->first_bit + 1)) - 1) << field->first_bit;
- printf("mask=%#x\n", mask);
- val = (actual_val & ~mask) | ((val << field->first_bit) & mask);
- }
- printf("write %#x to %#x\n", val, reg->addr + addr_off);
- if(hwemul_rw_mem(&hwdev, 0, reg->addr + addr_off, &val, sizeof(val)) != sizeof(val))
- {
- printf("write error at %#x\n", reg->addr);
- return 1;
- }
- return 1;
-}
-
-int parse_write()
-{
- char *arg = strtok(NULL, " ");
- uint32_t val;
- if(!arg || !parse_uint32(arg, &val))
- return syntax_error(arg);
- arg = strtok(NULL, " ");
- if(arg)
- return do_write(val, arg);
- else
- return syntax_error(arg);
-}
-
-int parse_command(char *cmd)
-{
- if(strcmp(cmd, "help") == 0)
- return print_help();
- if(strcmp(cmd, "quit") == 0)
- return 0;
- if(strcmp(cmd, "call") == 0)
- return parse_call();
- if(strcmp(cmd, "read32") == 0)
- return parse_read32();
- if(strcmp(cmd, "write32") == 0)
- return parse_write32();
- if(strcmp(cmd, "read") == 0)
- return parse_read();
- if(strcmp(cmd, "soc") == 0)
- return parse_soc();
- if(strcmp(cmd, "write") == 0)
- return parse_write();
- return syntax_error(cmd);
-}
-
-void interactive_mode(void)
-{
- rl_bind_key('\t', rl_complete);
- while(1)
- {
- char *input = readline("> ");
- if(!input)
- break;
- add_history(input);
- int ret = parse_command(input);
- free(input);
- if(ret == 0)
- break;
- }
-}
-
-void usage(void)
-{
- printf("hwemul_tool, compiled with hwemul %d.%d.%d\n",
- HWEMUL_VERSION_MAJOR, HWEMUL_VERSION_MINOR, HWEMUL_VERSION_REV);
- printf("available soc descriptions:");
- for(unsigned i = 0; i < hwemul_get_soc_list()->nr_socs; i++)
- printf(" %s", hwemul_get_soc_list()->socs[i]->name);
- printf("\n");
- printf("usage: hwemul_tool [options]\n");
- printf("options:\n");
- printf(" --help/-?\tDisplay this help\n");
- printf(" --quiet/-q\tQuiet non-command messages\n");
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- while(1)
- {
- static struct option long_options[] =
- {
- {"help", no_argument, 0, '?'},
- {"quiet", no_argument, 0, 'q'},
- {0, 0, 0, 0}
- };
-
- int c = getopt_long(argc, argv, "?q", long_options, NULL);
- if(c == -1)
- break;
- switch(c)
- {
- case -1:
- break;
- case 'q':
- g_quiet = true;
- break;
- case '?':
- usage();
- break;
- default:
- abort();
- }
- }
-
- if(argc - optind != 0)
- {
- usage();
- return 1;
- }
-
- libusb_context *ctx;
- libusb_init(&ctx);
- libusb_set_debug(ctx, 3);
-
- if(!g_quiet)
- printf("Looking for device %#04x:%#04x...\n", HWEMUL_USB_VID, HWEMUL_USB_PID);
-
- libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
- HWEMUL_USB_VID, HWEMUL_USB_PID);
- if(handle == NULL)
- {
- printf("No device found\n");
- return 1;
- }
-
- libusb_device *mydev = libusb_get_device(handle);
- if(!g_quiet)
- {
- printf("device found at %d:%d\n",
- libusb_get_bus_number(mydev),
- libusb_get_device_address(mydev));
- }
- hwdev.handle = handle;
- if(hwemul_probe(&hwdev))
- {
- printf("Cannot probe device!\n");
- return 1;
- }
-
- struct usb_resp_info_version_t ver;
- int ret = hwemul_get_info(&hwdev, HWEMUL_INFO_VERSION, &ver, sizeof(ver));
- if(ret != sizeof(ver))
- {
- printf("Cannot get version!\n");
- goto Lerr;
- }
- if(!g_quiet)
- printf("Device version: %d.%d.%d\n", ver.major, ver.minor, ver.revision);
-
- struct usb_resp_info_layout_t layout;
- ret = hwemul_get_info(&hwdev, HWEMUL_INFO_LAYOUT, &layout, sizeof(layout));
- if(ret != sizeof(layout))
- {
- printf("Cannot get layout: %d\n", ret);
- goto Lerr;
- }
- if(!g_quiet)
- {
- printf("Device layout:\n");
- printf(" Code: 0x%x (0x%x)\n", layout.oc_code_start, layout.oc_code_size);
- printf(" Stack: 0x%x (0x%x)\n", layout.oc_stack_start, layout.oc_stack_size);
- printf(" Buffer: 0x%x (0x%x)\n", layout.oc_buffer_start, layout.oc_buffer_size);
- }
-
- struct usb_resp_info_features_t features;
- ret = hwemul_get_info(&hwdev, HWEMUL_INFO_FEATURES, &features, sizeof(features));
- if(ret != sizeof(features))
- {
- printf("Cannot get features: %d\n", ret);
- goto Lerr;
- }
- if(!g_quiet)
- {
- printf("Device features:");
- if(features.feature_mask & HWEMUL_FEATURE_LOG)
- printf(" log");
- if(features.feature_mask & HWEMUL_FEATURE_MEM)
- printf(" mem");
- if(features.feature_mask & HWEMUL_FEATURE_CALL)
- printf(" call");
- if(features.feature_mask & HWEMUL_FEATURE_JUMP)
- printf(" jump");
- if(features.feature_mask & HWEMUL_FEATURE_AES_OTP)
- printf(" aes_otp");
- printf("\n");
- }
-
- struct usb_resp_info_stmp_t stmp;
- ret = hwemul_get_info(&hwdev, HWEMUL_INFO_STMP, &stmp, sizeof(stmp));
- if(ret != sizeof(stmp))
- {
- printf("Cannot get stmp: %d\n", ret);
- goto Lerr;
- }
- if(!g_quiet)
- {
- printf("Device stmp:\n");
- printf(" chip ID: %x (%s)\n", stmp.chipid,hwemul_get_product_string(&stmp));
- printf(" revision: %d (%s)\n", stmp.rev, hwemul_get_rev_string(&stmp));
- printf(" supported: %d\n", stmp.is_supported);
- }
-
- if(!g_quiet)
- {
- void *rom = malloc(64 * 1024);
- ret = hwemul_rw_mem(&hwdev, 1, 0xc0000000, rom, 64 * 1024);
- if(ret != 64 * 1024)
- {
- printf("Cannot read ROM: %d\n", ret);
- goto Lerr;
- }
-
- printf("ROM successfully read!\n");
- FILE *f = fopen("rom.bin", "wb");
- fwrite(rom, 64 * 1024, 1, f);
- fclose(f);
- }
-
- if(!g_quiet)
- {
- struct
- {
- uint8_t iv[16];
- uint8_t data[16];
- } __attribute__((packed)) dcp_test;
-
- for(int i = 0; i < 16; i++)
- dcp_test.iv[i] = rand();
- for(int i = 0; i < 16; i++)
- dcp_test.data[i] = rand();
- printf("DCP\n");
- printf(" IN\n");
- printf(" IV:");
- for(int i = 0; i < 16; i++)
- printf(" %02x", dcp_test.iv[i]);
- printf("\n");
- printf(" IV:");
- for(int i = 0; i < 16; i++)
- printf(" %02x", dcp_test.data[i]);
- printf("\n");
-
- if(!hwemul_aes_otp(&hwdev, &dcp_test, sizeof(dcp_test), HWEMUL_AES_OTP_ENCRYPT))
- {
- printf(" OUT\n");
- printf(" IV:");
- for(int i = 0; i < 16; i++)
- printf(" %02x", dcp_test.iv[i]);
- printf("\n");
- printf(" IV:");
- for(int i = 0; i < 16; i++)
- printf(" %02x", dcp_test.data[i]);
- printf("\n");
- }
- else
- printf("DCP error!\n");
- }
-
- if(!g_quiet)
- printf("Starting interactive session. Type 'help' to get help.\n");
-
- interactive_mode();
-
- Lerr:
- if(features.feature_mask & HWEMUL_FEATURE_LOG)
- {
- if(!g_quiet)
- printf("Device log:\n");
- print_log(&hwdev);
- }
- hwemul_release(&hwdev);
- return 1;
-}
diff --git a/utils/hwstub/tools/hwstub_load.cpp b/utils/hwstub/tools/hwstub_load.cpp
new file mode 100644
index 0000000000..d58eb83396
--- /dev/null
+++ b/utils/hwstub/tools/hwstub_load.cpp
@@ -0,0 +1,316 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2013 by 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.
+ *
+ ****************************************************************************/
+#include "hwstub.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+struct player_info_t
+{
+ const char *name;
+ const char *username;
+ int modelnum;
+};
+
+enum image_type_t
+{
+ IT_RAW,
+ IT_ROCKBOX,
+ IT_DETECT,
+ /* positive values reserved for rockbox-specific models */
+};
+
+struct player_info_t players[] =
+{
+ { "zenv", "Zen V", 85 },
+ { "zmoz", "Zen Mozaic", 87 },
+ { "zen", "Zen", 88 },
+ { "zxfi", "Zen X-Fi", 86 },
+ { NULL, 0 },
+};
+
+enum image_type_t detect_type(unsigned char *buffer, size_t size)
+{
+ if(size < 8)
+ return IT_RAW;
+ int player;
+ for(player = 0; players[player].name; player++)
+ if(memcmp(buffer + 4, players[player].name, 4) == 0)
+ break;
+ if(players[player].name == NULL)
+ return IT_RAW;
+ unsigned long checksum = players[player].modelnum;
+ for(size_t i = 8; i < size; i++)
+ checksum += buffer[i];
+ unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
+ if(checksum != expected)
+ return IT_RAW;
+ return IT_ROCKBOX;
+}
+
+const char *get_player_name(unsigned char *buffer)
+{
+ for(int player = 0; players[player].name; player++)
+ if(memcmp(buffer, players[player].name, 4) == 0)
+ return players[player].username;
+ return NULL;
+}
+
+bool could_be_rockbox(unsigned char *buffer, size_t size)
+{
+ /* usually target use 3 or 4 digits */
+ if(size >= 8 && isprint(buffer[4]) && isprint(buffer[5]) && isprint(buffer[6]) &&
+ (isprint(buffer[7]) || buffer[7] == 0))
+ {
+ unsigned long checksum = 0;
+ for(size_t i = 8; i < size; i++)
+ checksum += buffer[i];
+ unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
+ unsigned long expected_modelnm = expected - checksum;
+ if(expected_modelnm < 150)
+ fprintf(stderr, "This file looks like a valid rockbox image but I don't know this player: %.4s (modelnum=%ld)\n",
+ buffer + 4, expected_modelnm);
+ else
+ fprintf(stderr, "This file could be a valid rockbox image but I don't know this player and the checksum is strange: %.4s\n",
+ buffer + 4);
+ return true;
+ }
+ else
+ return false;
+}
+
+void usage(void)
+{
+ printf("usage: hwstub_load [options] <addr> <file>\n");
+ printf("options:\n");
+ printf(" --help/-? Display this help\n");
+ printf(" --quiet/-q Quiet output\n");
+ printf(" --type/-t <t> Override file type\n");
+ printf("file types:\n");
+ printf(" raw Load a raw binary blob\n");
+ printf(" rockbox Load a rockbox image produced by scramble\n");
+ printf(" detect Try to guess the format\n");
+ printf("known players:");
+ for(int i = 0; players[i].name; i++)
+ printf(" %s", players[i].name);
+ printf("\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ bool quiet = false;
+ struct hwstub_device_t hwdev;
+ enum image_type_t type = IT_DETECT;
+
+ // parse command line
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"quiet", no_argument, 0, 'q'},
+ {"type", required_argument, 0, 't'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?qt:", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case -1:
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case '?':
+ usage();
+ break;
+ case 't':
+ if(strcmp(optarg, "raw") == 0)
+ type = IT_RAW;
+ else if(strcmp(optarg, "rockbox") == 0)
+ type = IT_ROCKBOX;
+ else if(strcmp(optarg, "detect") == 0)
+ type = IT_DETECT;
+ else
+ {
+ fprintf(stderr, "Unknown file type '%s'\n", optarg);
+ return 1;
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if(optind + 2 != argc)
+ usage();
+
+ char *end;
+ unsigned long addr = strtoul(argv[optind], &end, 0);
+ if(*end)
+ {
+ fprintf(stderr, "Invalid load address\n");
+ return 2;
+ }
+
+ FILE *f = fopen(argv[optind + 1], "rb");
+ if(f == NULL)
+ {
+ fprintf(stderr, "Cannot open file for reading: %m\n");
+ return 3;
+ }
+ fseek(f, 0, SEEK_END);
+ size_t size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ unsigned char *buffer = (unsigned char*)malloc(size);
+ fread(buffer, size, 1, f);
+ fclose(f);
+
+ if(type == IT_ROCKBOX || type == IT_DETECT)
+ {
+ enum image_type_t det = detect_type(buffer, size);
+ if(type == IT_ROCKBOX && det != IT_ROCKBOX)
+ {
+ if(!could_be_rockbox(buffer, size))
+ fprintf(stderr, "This file does not appear to be valid rockbox image.\n");
+ return 4;
+ }
+ if(type == IT_DETECT && det == IT_RAW)
+ could_be_rockbox(buffer, size);
+ type = det;
+ if(type == IT_ROCKBOX)
+ {
+ if(!quiet)
+ printf("Rockox image is for player %s (%.4s)\n", get_player_name(buffer + 4), buffer + 4);
+ memmove(buffer, buffer + 8, size - 8);
+ size -= 8;
+ }
+ }
+
+ if(!quiet)
+ {
+ if(type == IT_RAW)
+ printf("Loading raw image at %#lx\n", addr);
+ else
+ printf("Loading rockbox image at %#lx\n", addr);
+ }
+
+ // create usb context
+ libusb_context *ctx;
+ libusb_init(&ctx);
+ libusb_set_debug(ctx, 3);
+
+ // look for device
+ if(!quiet)
+ printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID);
+
+ libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
+ HWSTUB_USB_VID, HWSTUB_USB_PID);
+ if(handle == NULL)
+ {
+ fprintf(stderr, "No device found\n");
+ return 1;
+ }
+
+ // admin stuff
+ libusb_device *mydev = libusb_get_device(handle);
+ if(!quiet)
+ {
+ printf("device found at %d:%d\n",
+ libusb_get_bus_number(mydev),
+ libusb_get_device_address(mydev));
+ }
+ hwdev.handle = handle;
+ if(hwstub_probe(&hwdev))
+ {
+ fprintf(stderr, "Cannot probe device!\n");
+ return 1;
+ }
+
+ // get hwstub information
+ struct usb_resp_info_version_t hwdev_ver;
+ int ret = hwstub_get_info(&hwdev, HWSTUB_INFO_VERSION, &hwdev_ver, sizeof(hwdev_ver));
+ if(ret != sizeof(hwdev_ver))
+ {
+ fprintf(stderr, "Cannot get version!\n");
+ goto Lerr;
+ }
+ if(hwdev_ver.major != HWSTUB_VERSION_MAJOR || hwdev_ver.minor < HWSTUB_VERSION_MINOR)
+ {
+ printf("Warning: this tool is possibly incompatible with your device:\n");
+ printf("Device version: %d.%d.%d\n", hwdev_ver.major, hwdev_ver.minor, hwdev_ver.revision);
+ printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
+ }
+
+ // get features
+ struct usb_resp_info_features_t hwdev_features;
+ ret = hwstub_get_info(&hwdev, HWSTUB_INFO_FEATURES, &hwdev_features, sizeof(hwdev_features));
+ if(ret != sizeof(hwdev_features))
+ {
+ fprintf(stderr, "Cannot get features: %d\n", ret);
+ goto Lerr;
+ }
+ if(!(hwdev_features.feature_mask & HWSTUB_RW_MEM))
+ {
+ fprintf(stderr, "Device doesn't support R/W commands\n");
+ goto Lerr;
+ }
+ if(!(hwdev_features.feature_mask & HWSTUB_JUMP))
+ {
+ fprintf(stderr, "Device doesn't support jump commands\n");
+ goto Lerr;
+ }
+ ret = hwstub_rw_mem(&hwdev, 0, addr, buffer, size);
+ if(ret != (int)size)
+ {
+ fprintf(stderr, "Image write failed\n");
+ goto Lerr;
+ }
+ hwstub_jump(&hwdev, addr);
+
+ hwstub_release(&hwdev);
+ return 0;
+
+ Lerr:
+ // display log if handled
+ if(hwdev_features.feature_mask & HWSTUB_FEATURE_LOG)
+ {
+ fprintf(stderr, "Device log:\n");
+ do
+ {
+ char buffer[128];
+ int length = hwstub_get_log(&hwdev, buffer, sizeof(buffer) - 1);
+ if(length <= 0)
+ break;
+ buffer[length] = 0;
+ fprintf(stderr, "%s", buffer);
+ }while(1);
+ }
+ hwstub_release(&hwdev);
+ return 1;
+}
+
diff --git a/utils/hwstub/tools/hwstub_shell.cpp b/utils/hwstub/tools/hwstub_shell.cpp
new file mode 100644
index 0000000000..58147319e0
--- /dev/null
+++ b/utils/hwstub/tools/hwstub_shell.cpp
@@ -0,0 +1,873 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by 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.
+ *
+ ****************************************************************************/
+#include "hwstub.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <lua.hpp>
+#include "soc_desc.hpp"
+
+#if LUA_VERSION_NUM < 502
+#warning You need at least lua 5.2
+#endif
+
+/**
+ * Global variables
+ */
+bool g_quiet = false;
+struct hwstub_device_t g_hwdev;
+struct usb_resp_info_version_t g_hwdev_ver;
+struct usb_resp_info_layout_t g_hwdev_layout;
+struct usb_resp_info_features_t g_hwdev_features;
+struct usb_resp_info_stmp_t g_hwdev_stmp;
+lua_State *g_lua;
+
+/**
+ * hw specific
+ */
+
+void print_log(struct hwstub_device_t *hwdev)
+{
+ do
+ {
+ char buffer[128];
+ int length = hwstub_get_log(hwdev, buffer, sizeof(buffer) - 1);
+ if(length <= 0)
+ break;
+ buffer[length] = 0;
+ printf("%s", buffer);
+ }while(1);
+}
+
+/**
+ * Lua specific
+ */
+int my_lua_help(lua_State *state)
+{
+ bool has_sub = false;
+ // implement help() in C so that we do not rely on the init to implement it
+ // help can take optional arguments
+ int n = lua_gettop(state);
+
+ lua_getglobal(state, "hwstub");
+ if(!lua_istable(state, -1))
+ goto Lerr;
+ lua_getfield(state, -1, "help");
+ if(!lua_istable(state, -1))
+ goto Lerr;
+
+ for(int i = 1; i <= n; i++)
+ {
+ lua_pushvalue(state, i);
+ lua_gettable(state, -2);
+ if(lua_isnil(state, -1))
+ {
+ printf("I don't know subtopic '%s'!\n", lua_tostring(state, i));
+ return 0;
+ }
+ if(!lua_istable(state, -1))
+ {
+ printf("Subtopic '%s' is not a table!\n", lua_tostring(state, i));
+ return 0;
+ }
+ }
+
+ printf("================[ HELP ");
+ for(int i = 1; i <= n; i++)
+ printf("> %s ", lua_tostring(state, i));
+ printf("]================\n");
+
+ lua_pushnil(state);
+ while(lua_next(state, -2))
+ {
+ // key is at -2 and value at -1
+ if(lua_isstring(state, -1))
+ printf("%s\n", lua_tostring(state, -1));
+ else if(lua_istable(state, -1))
+ has_sub = true;
+ // pop value but keep key
+ lua_pop(state, 1);
+ }
+
+ if(has_sub)
+ {
+ printf("\n");
+ printf("You can get more information on the following subtopics:\n");
+ lua_pushnil(state);
+ while(lua_next(state, -2))
+ {
+ // key is at -2 and value at -1
+ if(lua_istable(state, -1))
+ printf("* %s\n", lua_tostring(state, -2));
+ // pop value but keep key
+ lua_pop(state, 1);
+ }
+ }
+ printf("================[ STOP ]================\n");
+
+ return 0;
+
+ Lerr:
+ printf("There is a problem with the Lua context. Help is expected to be in hwstub.help\n");
+ printf("You must have messed badly the environment.\n");
+ return 0;
+}
+
+typedef soc_word_t (*hw_readn_fn_t)(lua_State *state, soc_addr_t addr);
+typedef void (*hw_writen_fn_t)(lua_State *state, soc_addr_t addr, soc_word_t val);
+
+soc_word_t hw_read8(lua_State *state, soc_addr_t addr)
+{
+ uint8_t u;
+ if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u))
+ luaL_error(state, "fail to read8 @ %p", addr);
+ return u;
+}
+
+soc_word_t hw_read16(lua_State *state, soc_addr_t addr)
+{
+ uint16_t u;
+ if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u))
+ luaL_error(state, "fail to read16 @ %p", addr);
+ return u;
+}
+
+soc_word_t hw_read32(lua_State *state, soc_addr_t addr)
+{
+ uint32_t u;
+ if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u))
+ luaL_error(state, "fail to read32 @ %p", addr);
+ return u;
+}
+
+void hw_write8(lua_State *state, soc_addr_t addr, soc_word_t val)
+{
+ uint8_t u = val;
+ if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u))
+ luaL_error(state, "fail to write8 @ %p", addr);
+}
+
+void hw_write16(lua_State *state, soc_addr_t addr, soc_word_t val)
+{
+ uint16_t u = val;
+ if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u))
+ luaL_error(state, "fail to write16 @ %p", addr);
+}
+
+void hw_write32(lua_State *state, soc_addr_t addr, soc_word_t val)
+{
+ uint32_t u = val;
+ if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u))
+ luaL_error(state, "fail to write32 @ %p", addr);
+}
+
+int my_lua_readn(lua_State *state)
+{
+ hw_readn_fn_t fn = (hw_readn_fn_t)lua_touserdata(state, lua_upvalueindex(1));
+ int n = lua_gettop(state);
+ if(n != 1)
+ luaL_error(state, "readn takes a single argument");
+ lua_pushunsigned(state, fn(state, luaL_checkunsigned(state, 1)));
+ return 1;
+}
+
+int my_lua_writen(lua_State *state)
+{
+ hw_writen_fn_t fn = (hw_writen_fn_t)lua_touserdata(state, lua_upvalueindex(1));
+ int n = lua_gettop(state);
+ if(n != 2)
+ luaL_error(state, "writen takes two arguments");
+ fn(state, luaL_checkunsigned(state, 1), luaL_checkunsigned(state, 2));
+ return 0;
+}
+
+int my_lua_printlog(lua_State *state)
+{
+ print_log(&g_hwdev);
+ return 0;
+}
+
+bool my_lua_import_hwstub()
+{
+ int oldtop = lua_gettop(g_lua);
+
+ lua_newtable(g_lua); // hwstub
+
+ lua_newtable(g_lua); // options
+ lua_pushboolean(g_lua, g_quiet);
+ lua_setfield(g_lua, -2, "quiet");
+ lua_setfield(g_lua, -2, "options");
+
+ lua_newtable(g_lua); // dev
+ lua_newtable(g_lua); // version
+ lua_pushinteger(g_lua, g_hwdev_ver.major);
+ lua_setfield(g_lua, -2, "major");
+ lua_pushinteger(g_lua, g_hwdev_ver.minor);
+ lua_setfield(g_lua, -2, "minor");
+ lua_pushinteger(g_lua, g_hwdev_ver.revision);
+ lua_setfield(g_lua, -2, "revision");
+ lua_setfield(g_lua, -2, "version");
+
+ lua_newtable(g_lua); // layout
+ lua_newtable(g_lua); // ocram
+ lua_newtable(g_lua); // code
+ lua_pushinteger(g_lua, g_hwdev_layout.oc_code_start);
+ lua_setfield(g_lua, -2, "start");
+ lua_pushinteger(g_lua, g_hwdev_layout.oc_code_size);
+ lua_setfield(g_lua, -2, "size");
+ lua_setfield(g_lua, -2, "code");
+ lua_newtable(g_lua); // stack
+ lua_pushinteger(g_lua, g_hwdev_layout.oc_stack_start);
+ lua_setfield(g_lua, -2, "start");
+ lua_pushinteger(g_lua, g_hwdev_layout.oc_stack_size);
+ lua_setfield(g_lua, -2, "size");
+ lua_setfield(g_lua, -2, "stack");
+ lua_newtable(g_lua); // buffer
+ lua_pushinteger(g_lua, g_hwdev_layout.oc_buffer_start);
+ lua_setfield(g_lua, -2, "start");
+ lua_pushinteger(g_lua, g_hwdev_layout.oc_buffer_size);
+ lua_setfield(g_lua, -2, "size");
+ lua_setfield(g_lua, -2, "buffer");
+ lua_setfield(g_lua, -2, "ocram");
+ lua_setfield(g_lua, -2, "layout");
+
+ lua_newtable(g_lua); // stmp
+ lua_pushinteger(g_lua, g_hwdev_stmp.chipid);
+ lua_setfield(g_lua, -2, "chipid");
+ lua_pushinteger(g_lua, g_hwdev_stmp.rev);
+ lua_setfield(g_lua, -2, "rev");
+ lua_setfield(g_lua, -2, "stmp");
+
+ lua_newtable(g_lua); // features
+ lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_LOG));
+ lua_setfield(g_lua, -2, "log");
+ lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_MEM));
+ lua_setfield(g_lua, -2, "mem");
+ lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_CALL));
+ lua_setfield(g_lua, -2, "call");
+ lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_JUMP));
+ lua_setfield(g_lua, -2, "jump");
+ lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_AES_OTP));
+ lua_setfield(g_lua, -2, "aes_otp");
+ lua_setfield(g_lua, -2, "features");
+
+ lua_pushlightuserdata(g_lua, (void *)&hw_read8);
+ lua_pushcclosure(g_lua, my_lua_readn, 1);
+ lua_setfield(g_lua, -2, "read8");
+ lua_pushlightuserdata(g_lua, (void *)&hw_read16);
+ lua_pushcclosure(g_lua, my_lua_readn, 1);
+ lua_setfield(g_lua, -2, "read16");
+ lua_pushlightuserdata(g_lua, (void *)&hw_read32);
+ lua_pushcclosure(g_lua, my_lua_readn, 1);
+ lua_setfield(g_lua, -2, "read32");
+
+ lua_pushlightuserdata(g_lua, (void *)&hw_write8);
+ lua_pushcclosure(g_lua, my_lua_writen, 1);
+ lua_setfield(g_lua, -2, "write8");
+ lua_pushlightuserdata(g_lua, (void *)&hw_write16);
+ lua_pushcclosure(g_lua, my_lua_writen, 1);
+ lua_setfield(g_lua, -2, "write16");
+ lua_pushlightuserdata(g_lua, (void *)&hw_write32);
+ lua_pushcclosure(g_lua, my_lua_writen, 1);
+ lua_setfield(g_lua, -2, "write32");
+ lua_pushcclosure(g_lua, my_lua_printlog, 0);
+ lua_setfield(g_lua, -2, "print_log");
+
+ lua_setfield(g_lua, -2, "dev");
+
+ lua_newtable(g_lua); // host
+ lua_newtable(g_lua); // version
+ lua_pushinteger(g_lua, HWSTUB_VERSION_MAJOR);
+ lua_setfield(g_lua, -2, "major");
+ lua_pushinteger(g_lua, HWSTUB_VERSION_MINOR);
+ lua_setfield(g_lua, -2, "minor");
+ lua_pushinteger(g_lua, HWSTUB_VERSION_REV);
+ lua_setfield(g_lua, -2, "revision");
+ lua_setfield(g_lua, -2, "version");
+ lua_setfield(g_lua, -2, "host");
+
+ lua_newtable(g_lua); // soc
+ lua_setfield(g_lua, -2, "soc");
+
+ lua_newtable(g_lua); // help
+ lua_pushinteger(g_lua, 1);
+ lua_pushstring(g_lua, "This is the help for hwstub_tool. This tools uses Lua to interpret commands.");
+ lua_settable(g_lua, -3);
+ lua_pushinteger(g_lua, 2);
+ lua_pushstring(g_lua, "You can get help by running help(). Help is organised in topics and subtopics and so on.");
+ lua_settable(g_lua, -3);
+ lua_pushinteger(g_lua, 3);
+ lua_pushstring(g_lua, "If you want to access the help of topic x, subtopic y, subsubtopic z, type help(x,y,z).");
+ lua_settable(g_lua, -3);
+ lua_pushinteger(g_lua, 4);
+ lua_pushstring(g_lua, "Example: help(\"hwstub\").");
+ lua_settable(g_lua, -3);
+ lua_setfield(g_lua, -2, "help");
+
+ lua_setglobal(g_lua, "hwstub");
+
+ lua_pushcfunction(g_lua, my_lua_help);
+ lua_setglobal(g_lua, "help");
+
+ if(lua_gettop(g_lua) != oldtop)
+ {
+ printf("internal error: unbalanced my_lua_import_soc");
+ return false;
+ }
+ return true;
+}
+
+int my_lua_read_reg(lua_State *state)
+{
+ int n = lua_gettop(state);
+ if(n != 0)
+ luaL_error(state, "read() takes no argument");
+ soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
+ lua_pushunsigned(state, hw_read32(state, addr));
+ return 1;
+}
+
+int my_lua_write_reg(lua_State *state)
+{
+ int n = lua_gettop(state);
+ if(n != 1)
+ luaL_error(state, "write() takes one argument");
+ soc_word_t val = luaL_checkunsigned(state, 1);
+ soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
+ hw_write32(state, addr, val);
+ return 0;
+}
+
+int my_lua_read_field(lua_State *state)
+{
+ int n = lua_gettop(state);
+ if(n != 0)
+ luaL_error(state, "read() takes no argument");
+ soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
+ soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2));
+ soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3));
+ lua_pushunsigned(state, (hw_read32(state, addr) >> shift) & mask);
+ return 1;
+}
+
+int my_lua_write_field(lua_State *state)
+{
+ int n = lua_gettop(state);
+ if(n != 0 && n!= 1)
+ luaL_error(state, "write() takes one or no argument");
+ soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
+ soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2));
+ soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3));
+ bool is_sct = lua_toboolean(state, lua_upvalueindex(5));
+
+ soc_word_t value = mask;
+ if(n == 1)
+ {
+ if(!lua_isnumber(state, 1) && lua_isstring(state, 1))
+ {
+ lua_pushvalue(state, lua_upvalueindex(4));
+ lua_pushvalue(state, 1);
+ lua_gettable(state, -2);
+ if(lua_isnil(state, -1))
+ luaL_error(state, "field has no value %s", lua_tostring(state, 1));
+ value = luaL_checkunsigned(state, -1);
+ lua_pop(state, 2);
+ }
+ else
+ value = luaL_checkunsigned(state, 1);
+ value &= mask;
+ }
+
+ if(!is_sct)
+ value = value << shift | (hw_read32(state, addr) & ~(mask << shift));
+ else
+ value <<= shift;
+
+ hw_write32(state, addr, value);
+ return 0;
+}
+
+void my_lua_create_field(soc_addr_t addr, const soc_reg_field_t& field, bool sct)
+{
+ lua_newtable(g_lua);
+
+ lua_pushstring(g_lua, field.name.c_str());
+ lua_setfield(g_lua, -2, "name");
+
+ lua_pushunsigned(g_lua, addr);
+ lua_setfield(g_lua, -2, "addr");
+
+ lua_pushboolean(g_lua, sct);
+ lua_setfield(g_lua, -2, "sct");
+
+ lua_pushunsigned(g_lua, field.first_bit);
+ lua_setfield(g_lua, -2, "first_bit");
+
+ lua_pushunsigned(g_lua, field.last_bit);
+ lua_setfield(g_lua, -2, "last_bit");
+
+ lua_pushunsigned(g_lua, field.bitmask());
+ lua_setfield(g_lua, -2, "bitmask");
+
+ soc_word_t local_bitmask = field.bitmask() >> field.first_bit;
+ lua_pushunsigned(g_lua, local_bitmask);
+ lua_setfield(g_lua, -2, "local_bitmask");
+
+ lua_pushunsigned(g_lua, addr);
+ lua_pushunsigned(g_lua, field.first_bit);
+ lua_pushunsigned(g_lua, local_bitmask);
+ lua_pushcclosure(g_lua, my_lua_read_field, 3);
+ lua_setfield(g_lua, -2, "read");
+
+ lua_pushunsigned(g_lua, addr);
+ lua_pushunsigned(g_lua, field.first_bit);
+ lua_pushunsigned(g_lua, local_bitmask);
+ lua_pushvalue(g_lua, -4);
+ lua_pushboolean(g_lua, false);
+ lua_pushcclosure(g_lua, my_lua_write_field, 5);
+ lua_setfield(g_lua, -2, "write");
+
+ if(sct)
+ {
+ lua_pushunsigned(g_lua, addr + 4);
+ lua_pushunsigned(g_lua, field.first_bit);
+ lua_pushunsigned(g_lua, local_bitmask);
+ lua_pushvalue(g_lua, -4);
+ lua_pushboolean(g_lua, true);
+ lua_pushcclosure(g_lua, my_lua_write_field, 5);
+ lua_setfield(g_lua, -2, "set");
+
+ lua_pushunsigned(g_lua, addr + 8);
+ lua_pushunsigned(g_lua, field.first_bit);
+ lua_pushunsigned(g_lua, local_bitmask);
+ lua_pushvalue(g_lua, -4);
+ lua_pushboolean(g_lua, true);
+ lua_pushcclosure(g_lua, my_lua_write_field, 5);
+ lua_setfield(g_lua, -2, "clr");
+
+ lua_pushunsigned(g_lua, addr + 12);
+ lua_pushunsigned(g_lua, field.first_bit);
+ lua_pushunsigned(g_lua, local_bitmask);
+ lua_pushvalue(g_lua, -4);
+ lua_pushboolean(g_lua, true);
+ lua_pushcclosure(g_lua, my_lua_write_field, 5);
+ lua_setfield(g_lua, -2, "tog");
+ }
+
+ for(size_t i = 0; i < field.value.size(); i++)
+ {
+ lua_pushunsigned(g_lua, field.value[i].value);
+ lua_setfield(g_lua, -2, field.value[i].name.c_str());
+ }
+}
+
+void my_lua_create_reg(soc_addr_t addr, size_t index, const soc_reg_t& reg)
+{
+ lua_newtable(g_lua);
+
+ lua_pushstring(g_lua, reg.addr[index].name.c_str());
+ lua_setfield(g_lua, -2, "name");
+
+ lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
+ lua_setfield(g_lua, -2, "addr");
+
+ lua_pushboolean(g_lua, !!(reg.flags & REG_HAS_SCT));
+ lua_setfield(g_lua, -2, "sct");
+
+ lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
+ lua_pushcclosure(g_lua, my_lua_read_reg, 1);
+ lua_setfield(g_lua, -2, "read");
+
+ lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
+ lua_pushcclosure(g_lua, my_lua_write_reg, 1);
+ lua_setfield(g_lua, -2, "write");
+
+ if(reg.flags & REG_HAS_SCT)
+ {
+ lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 4);
+ lua_pushcclosure(g_lua, my_lua_write_reg, 1);
+ lua_setfield(g_lua, -2, "set");
+
+ lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 8);
+ lua_pushcclosure(g_lua, my_lua_write_reg, 1);
+ lua_setfield(g_lua, -2, "clr");
+
+ lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 12);
+ lua_pushcclosure(g_lua, my_lua_write_reg, 1);
+ lua_setfield(g_lua, -2, "tog");
+ }
+
+ for(size_t i = 0; i < reg.field.size(); i++)
+ {
+ my_lua_create_field(addr + reg.addr[index].addr, reg.field[i],
+ reg.flags & REG_HAS_SCT);
+ lua_setfield(g_lua, -2, reg.field[i].name.c_str());
+ }
+}
+
+void my_lua_create_dev(size_t index, const soc_dev_t& dev)
+{
+ lua_newtable(g_lua);
+
+ lua_pushstring(g_lua, dev.addr[index].name.c_str());
+ lua_setfield(g_lua, -2, "name");
+
+ lua_pushunsigned(g_lua, dev.addr[index].addr);
+ lua_setfield(g_lua, -2, "addr");
+
+ for(size_t i = 0; i < dev.reg.size(); i++)
+ {
+ bool table = dev.reg[i].addr.size() > 1;
+ if(table)
+ lua_newtable(g_lua);
+ else
+ lua_pushnil(g_lua);
+
+ for(size_t k = 0; k < dev.reg[i].addr.size(); k++)
+ {
+ my_lua_create_reg(dev.addr[index].addr, k, dev.reg[i]);
+ if(table)
+ {
+ lua_pushinteger(g_lua, k);
+ lua_pushvalue(g_lua, -2);
+ lua_settable(g_lua, -4);
+ }
+ lua_setfield(g_lua, -3, dev.reg[i].addr[k].name.c_str());
+ }
+
+ if(table)
+ lua_setfield(g_lua, -2, dev.reg[i].name.c_str());
+ else
+ lua_pop(g_lua, 1);
+ }
+}
+
+bool my_lua_import_soc(const soc_t& soc)
+{
+ int oldtop = lua_gettop(g_lua);
+
+ lua_getglobal(g_lua, "hwstub");
+ lua_getfield(g_lua, -1, "soc");
+
+ lua_newtable(g_lua);
+
+ lua_pushstring(g_lua, soc.name.c_str());
+ lua_setfield(g_lua, -2, "name");
+
+ lua_pushstring(g_lua, soc.desc.c_str());
+ lua_setfield(g_lua, -2, "desc");
+
+ for(size_t i = 0; i < soc.dev.size(); i++)
+ {
+ bool table = soc.dev[i].addr.size() > 1;
+ if(table)
+ lua_newtable(g_lua);
+ else
+ lua_pushnil(g_lua);
+
+ for(size_t k = 0; k < soc.dev[i].addr.size(); k++)
+ {
+ my_lua_create_dev(k, soc.dev[i]);
+ if(table)
+ {
+ lua_pushinteger(g_lua, k + 1);
+ lua_pushvalue(g_lua, -2);
+ lua_settable(g_lua, -4);
+ }
+ lua_setfield(g_lua, -3, soc.dev[i].addr[k].name.c_str());
+ }
+
+ if(table)
+ lua_setfield(g_lua, -2, soc.dev[i].name.c_str());
+ else
+ lua_pop(g_lua, 1);
+ }
+
+ lua_setfield(g_lua, -2, soc.name.c_str());
+
+ lua_pop(g_lua, 2);
+
+ if(lua_gettop(g_lua) != oldtop)
+ {
+ printf("internal error: unbalanced my_lua_import_soc\n");
+ return false;
+ }
+ return true;
+}
+
+bool my_lua_import_soc(const std::vector< soc_t >& socs)
+{
+ for(size_t i = 0; i < socs.size(); i++)
+ {
+ if(!g_quiet)
+ printf("importing %s...\n", socs[i].name.c_str());
+ if(!my_lua_import_soc(socs[i]))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * glue
+ */
+
+void usage(void)
+{
+ printf("hwstub_tool, compiled with hwstub %d.%d.%d\n",
+ HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
+ printf("\n");
+ printf("usage: hwstub_tool [options] <soc desc files>\n");
+ printf("options:\n");
+ printf(" --help/-?\tDisplay this help\n");
+ printf(" --quiet/-q\tQuiet non-command messages\n");
+ printf(" -i <init>\tSet lua init file (default is init.lua)\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ const char *lua_init = "init.lua";
+ // parse command line
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"quiet", no_argument, 0, 'q'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?qi:", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case -1:
+ break;
+ case 'q':
+ g_quiet = true;
+ break;
+ case '?':
+ usage();
+ break;
+ case 'i':
+ lua_init = optarg;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ // load register descriptions
+ std::vector< soc_t > socs;
+ for(int i = optind; i < argc; i++)
+ if(!soc_desc_parse_xml(argv[i], socs))
+ {
+ printf("Cannot load description '%s'\n", argv[i]);
+ return 2;
+ }
+
+ // create usb context
+ libusb_context *ctx;
+ libusb_init(&ctx);
+ libusb_set_debug(ctx, 3);
+
+ // look for device
+ if(!g_quiet)
+ printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID);
+
+ libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
+ HWSTUB_USB_VID, HWSTUB_USB_PID);
+ if(handle == NULL)
+ {
+ printf("No device found\n");
+ return 1;
+ }
+
+ // admin stuff
+ libusb_device *mydev = libusb_get_device(handle);
+ if(!g_quiet)
+ {
+ printf("device found at %d:%d\n",
+ libusb_get_bus_number(mydev),
+ libusb_get_device_address(mydev));
+ }
+ g_hwdev.handle = handle;
+ if(hwstub_probe(&g_hwdev))
+ {
+ printf("Cannot probe device!\n");
+ return 1;
+ }
+
+ // get hwstub information
+ int ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_VERSION, &g_hwdev_ver, sizeof(g_hwdev_ver));
+ if(ret != sizeof(g_hwdev_ver))
+ {
+ printf("Cannot get version!\n");
+ goto Lerr;
+ }
+ if(g_hwdev_ver.major != HWSTUB_VERSION_MAJOR || g_hwdev_ver.minor < HWSTUB_VERSION_MINOR)
+ {
+ printf("Warning: this tool is possibly incompatible with your device:\n");
+ printf("Device version: %d.%d.%d\n", g_hwdev_ver.major, g_hwdev_ver.minor, g_hwdev_ver.revision);
+ printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
+ }
+
+ // get memory layout information
+ ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_LAYOUT, &g_hwdev_layout, sizeof(g_hwdev_layout));
+ if(ret != sizeof(g_hwdev_layout))
+ {
+ printf("Cannot get layout: %d\n", ret);
+ goto Lerr;
+ }
+
+ // get features
+ ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_FEATURES, &g_hwdev_features, sizeof(g_hwdev_features));
+ if(ret != sizeof(g_hwdev_features))
+ {
+ printf("Cannot get features: %d\n", ret);
+ goto Lerr;
+ }
+
+ // get STMP specific information
+ ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_STMP, &g_hwdev_stmp, sizeof(g_hwdev_stmp));
+ if(ret != sizeof(g_hwdev_stmp))
+ {
+ printf("Cannot get stmp: %d\n", ret);
+ goto Lerr;
+ }
+
+ // dump ROM
+ if(!g_quiet)
+ {
+ void *rom = malloc(64 * 1024);
+ ret = hwstub_rw_mem(&g_hwdev, 1, 0xc0000000, rom, 64 * 1024);
+ if(ret != 64 * 1024)
+ {
+ printf("Cannot read ROM: %d\n", ret);
+ goto Lerr;
+ }
+
+ printf("ROM successfully read!\n");
+ FILE *f = fopen("rom.bin", "wb");
+ fwrite(rom, 64 * 1024, 1, f);
+ fclose(f);
+ }
+
+ // test DCP
+#if 0
+ if(!g_quiet)
+ {
+ struct
+ {
+ uint8_t iv[16];
+ uint8_t data[16];
+ } __attribute__((packed)) dcp_test;
+
+ for(int i = 0; i < 16; i++)
+ dcp_test.iv[i] = rand();
+ for(int i = 0; i < 16; i++)
+ dcp_test.data[i] = rand();
+ printf("DCP\n");
+ printf(" IN\n");
+ printf(" IV:");
+ for(int i = 0; i < 16; i++)
+ printf(" %02x", dcp_test.iv[i]);
+ printf("\n");
+ printf(" IV:");
+ for(int i = 0; i < 16; i++)
+ printf(" %02x", dcp_test.data[i]);
+ printf("\n");
+
+ if(!hwstub_aes_otp(&g_hwdev, &dcp_test, sizeof(dcp_test), HWSTUB_AES_OTP_ENCRYPT))
+ {
+ printf(" OUT\n");
+ printf(" IV:");
+ for(int i = 0; i < 16; i++)
+ printf(" %02x", dcp_test.iv[i]);
+ printf("\n");
+ printf(" IV:");
+ for(int i = 0; i < 16; i++)
+ printf(" %02x", dcp_test.data[i]);
+ printf("\n");
+ }
+ else
+ printf("DCP error!\n");
+ }
+#endif
+
+ /** Init lua */
+
+ // create lua state
+ g_lua = luaL_newstate();
+ if(g_lua == NULL)
+ {
+ printf("Cannot create lua state\n");
+ return 1;
+ }
+ // import hwstub
+ if(!my_lua_import_hwstub())
+ printf("Cannot import hwstub description into Lua context\n");
+ // open all standard libraires
+ luaL_openlibs(g_lua);
+ // import socs
+ if(!my_lua_import_soc(socs))
+ printf("Cannot import SoC descriptions into Lua context\n");
+
+ if(luaL_dofile(g_lua, lua_init))
+ printf("error in init: %s\n", lua_tostring(g_lua, -1));
+ lua_pop(g_lua, lua_gettop(g_lua));
+
+ /** start interactive mode */
+ if(!g_quiet)
+ printf("Starting interactive lua session. Type 'help()' to get some help\n");
+
+ // use readline to provide some history and completion
+ rl_bind_key('\t', rl_complete);
+ while(1)
+ {
+ char *input = readline("> ");
+ if(!input)
+ break;
+ add_history(input);
+ // evaluate string
+ if(luaL_dostring(g_lua, input))
+ printf("error: %s\n", lua_tostring(g_lua, -1));
+ // pop everything to start from a clean stack
+ lua_pop(g_lua, lua_gettop(g_lua));
+ free(input);
+ }
+
+ Lerr:
+ // display log if handled
+ if(g_hwdev_features.feature_mask & HWSTUB_FEATURE_LOG)
+ {
+ if(!g_quiet)
+ printf("Device log:\n");
+ print_log(&g_hwdev);
+ }
+ hwstub_release(&g_hwdev);
+ return 1;
+}
diff --git a/utils/hwstub/tools/init.lua b/utils/hwstub/tools/init.lua
new file mode 100644
index 0000000000..142c77e20a
--- /dev/null
+++ b/utils/hwstub/tools/init.lua
@@ -0,0 +1,104 @@
+-- init code for hwstub_tools
+
+--
+-- HELP
+--
+HELP = hwstub.help
+
+function HELP:create_topic(name)
+ self[name] = { create_topic = HELP.create_topic, add = HELP.add, get_topic = HELP.get_topic }
+ return self[name]
+end
+
+function HELP:get_topic(name)
+ return self[name]
+end
+
+function HELP:add(text)
+ table.insert(self, text)
+end
+
+do
+ local h = HELP:create_topic("hwstub")
+ h:add("This tool uses a number of well-defined namespaces (tables) to organise its features.")
+ h:add("The hwstub table contains a number of information and functions related to the tool itself.")
+ h:add("Of particular interest are")
+ h:add("* hwstub.host which holds host specific information.")
+ h:add("* hwstub.dev which holds device specific information. See DEV")
+ h:add("* hwstub.help (aka HELP) which holds the help. See HELP.");
+ h:add("* hwstub.soc which holds soc specific information. See HW");
+
+ h = HELP:create_topic("HELP");
+ h:add("This variable redirects to hwstub.help and provides access to the help system.");
+ h:add("You can enhance the help using the following methods on any topic (including HELP itself).");
+ h:add("* t:create_topic(s) to create a new subtopic named s under topic t");
+ h:add("* t:add(s) to add a help line to topic t");
+ h:add("* t:get_topic(s) to get the subtopic s under topic t");
+
+ h = HELP:create_topic("DEV");
+ h:add("This variable redirects to hwstub.dev and provides direct access to the device.");
+ h:add("It contains some information about the device and the following methods.");
+ h:add("* read8/16/32(a) reads a 8/16/32-bit integer at address a");
+ h:add("* write8/16/32(a, v) writes the 8/16/32-bit integer v at address a");
+
+ h = HELP:create_topic("HW");
+ h:add("This variable redirects to the current soc under hwstub.soc and should be changed by calling hwstub:soc:select only.");
+ h:add("The complete register tree can be found under HW in a well organise fashion.");
+ h:add("* HW.dev points to device dev");
+ h:add("* HW.dev[i] points to device devi if there are several copies of the device at different addresses.");
+ h:add("* HW.dev.reg points to the register reg under dev");
+ h:add("* HW.dev.reg[i] points to the register regi if there are several copies.");
+ h:add("* HW.dev.reg.f points to the field f under register reg.");
+ h:add("* HW.dev.reg.f.v gives the value of named value v of field f.");
+ h:add("* All registers can be read using HW.dev.reg.read() and written using HW.dev.reg.write(v).");
+ h:add("* Register with a SCT variant also implement HW.dev.reg.set/clr/tog(v).");
+ h:add("* All register field can be read using HW.dev.reg.f.read() and written using HW.dev.reg.f.write(v).");
+ h:add("* Field writes can either give a integer or a named value to write(v).");
+ h:add("* Register with a SCT variant also implement HW.dev.reg.f.set/clr/tog(v) with the same properties.");
+ h:add("* All devices, registers and fields also have descriptions available such as addresses.");
+end
+
+--
+-- INFO
+--
+
+if not hwstub.options.quiet then
+ print("information")
+ print(" hwstub")
+ print(" version: " .. string.format("%d.%d.%d", hwstub.host.version.major,
+ hwstub.host.version.minor, hwstub.host.version.revision))
+ print(" device")
+ print(" version: " .. string.format("%d.%d.%d", hwstub.dev.version.major,
+ hwstub.dev.version.minor, hwstub.dev.version.revision))
+ print(" layout")
+ print(" on-chip ram")
+ print(" code: " .. string.format("%#x bytes @ %#x",
+ hwstub.dev.layout.ocram.code.size, hwstub.dev.layout.ocram.code.start))
+ print(" stack: " .. string.format("%#x bytes @ %#x",
+ hwstub.dev.layout.ocram.stack.size, hwstub.dev.layout.ocram.stack.start))
+ print(" buffer: " .. string.format("%#x bytes @ %#x",
+ hwstub.dev.layout.ocram.buffer.size, hwstub.dev.layout.ocram.buffer.start))
+ print(" features");
+ print(" log: " .. tostring(hwstub.dev.features.log))
+ print(" mem: " .. tostring(hwstub.dev.features.mem))
+ print(" call: " .. tostring(hwstub.dev.features.call))
+ print(" jump: " .. tostring(hwstub.dev.features.jump))
+ print(" aes_otp: " .. tostring(hwstub.dev.features.aes_otp))
+end
+
+--
+-- SOC
+--
+function hwstub.soc:select(soc)
+ if self[soc] == nil then return false end
+ print("Selecting soc " .. soc .. ". Redirecting HW to hwstub.soc." .. soc)
+ HW = self[soc]
+ return true
+end
+
+--
+-- DEV
+--
+DEV = hwstub.dev
+
+require "lua/load"