summaryrefslogtreecommitdiffstats
path: root/utils/hwstub/tools/hwstub_shell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/tools/hwstub_shell.cpp')
-rw-r--r--utils/hwstub/tools/hwstub_shell.cpp873
1 files changed, 873 insertions, 0 deletions
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;
+}