summaryrefslogtreecommitdiff
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 @@
1CC=gcc 1CC=gcc
2AR=ar 2CXX=g++
3HWEMUL_LIB_DIR=../lib 3LD=g++
4CFLAGS=-W -Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWEMUL_LIB_DIR) 4HWSTUB_LIB_DIR=../lib
5LDFLAGS=`pkg-config --libs libusb-1.0` -lreadline 5REGTOOLS_LIB_DIR=../../regtools/lib
6EXEC=hwemul_tool 6CFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2`
7HWEMUL_LIB=$(HWEMUL_LIB_DIR)/libhwemul.a 7CXXFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2`
8LDFLAGS=`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`
9EXEC=hwstub_shell hwstub_load
8SRC=$(wildcard *.c) 10SRC=$(wildcard *.c)
9OBJ=$(SRC:.c=.o) 11SRCXX=$(wildcard *.cpp)
12OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o)
13LIBS=$(HWSTUB_LIB_DIR)/libhwstub.a $(REGTOOLS_LIB_DIR)/libsocdesc.a
10 14
11all: $(EXEC) 15all: $(EXEC)
12 16
17$(HWSTUB_LIB_DIR)/libhwstub.a:
18 make -C $(HWSTUB_LIB_DIR)
19
20$(REGTOOLS_LIB_DIR)/libsocdesc.a:
21 make -C $(REGTOOLS_LIB_DIR)
22
13%.o: %.c 23%.o: %.c
14 $(CC) $(CFLAGS) -c -o $@ $< 24 $(CC) $(CFLAGS) -c -o $@ $<
15 25
16hwemul_tool: hwemul_tool.o $(HWEMUL_LIB) 26%.o: %.cpp
17 $(CC) -o $@ $^ $(LDFLAGS) 27 $(CXX) $(CXXFLAGS) -c -o $@ $<
28
29hwstub_shell: hwstub_shell.o $(LIBS)
30 $(LD) -o $@ $^ $(LDFLAGS)
31
32hwstub_load: hwstub_load.o $(LIBS)
33 $(LD) -o $@ $^ $(LDFLAGS)
18 34
19clean: 35clean:
20 rm -rf $(OBJ) $(LIB) 36 rm -rf $(OBJ) $(LIB) $(EXEC)
21 37
22 38
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 by Amaury Pouly
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "hwemul.h"
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <getopt.h>
26#include <stdbool.h>
27#include <readline/readline.h>
28#include <readline/history.h>
29
30bool g_quiet = false;
31struct hwemul_device_t hwdev;
32struct hwemul_soc_t *cur_soc = NULL;
33
34void print_log(struct hwemul_device_t *hwdev)
35{
36 do
37 {
38 char buffer[128];
39 int length = hwemul_get_log(hwdev, buffer, sizeof(buffer) - 1);
40 if(length <= 0)
41 break;
42 buffer[length] = 0;
43 printf("%s", buffer);
44 }while(1);
45}
46
47int print_help()
48{
49 printf("Commands:\n");
50 printf(" help\t\tDisplay this help\n");
51 printf(" call <addr>\tCall address <addr>\n");
52 printf(" quit\t\tQuit this session\n");
53 printf(" read32 <addr>\tRead a 32-bit word at <addr>\n");
54 printf(" write32 <value> <addr>\tRead the 32-bit word <value> at <addr>\n");
55 printf(" read <regname>\tRead a register by name\n");
56 printf(" read <regname>.<field>\tRead a register field by name\n");
57 printf(" soc <socname>\tSelect the soc description to use\n");
58 printf(" write <value> <regname>\tWrite a register by name\n");
59 printf(" write <value <regname>.<field>\tWrite a register field by name\n");
60 printf(" NOTE: if the register is SCT variant, no read is performed.\n");
61 return 1;
62}
63
64int syntax_error(char *str)
65{
66 printf("Syntax error at '%s'. Type 'help' to get some help.\n", str);
67 return 1;
68}
69
70int parse_uint32(char *str, uint32_t *u)
71{
72 char *end;
73 *u = strtoul(str, &end, 0);
74 return *end == 0;
75}
76
77int do_call(uint32_t a)
78{
79 hwemul_call(&hwdev, a);
80 return 1;
81}
82
83int parse_call()
84{
85 char *arg = strtok(NULL, " ");
86 uint32_t addr;
87 if(arg && parse_uint32(arg, &addr))
88 return do_call(addr);
89 else
90 return syntax_error(arg);
91}
92
93int do_read32(uint32_t a)
94{
95 uint32_t val;
96 if(hwemul_rw_mem(&hwdev, 1, a, &val, sizeof(val)) == sizeof(val))
97 printf("%#x = %#x\n", a, val);
98 else
99 printf("read error at %#x\n", a);
100 return 1;
101}
102
103int parse_read32()
104{
105 char *arg = strtok(NULL, " ");
106 uint32_t addr;
107 if(arg && parse_uint32(arg, &addr))
108 return do_read32(addr);
109 else
110 return syntax_error(arg);
111}
112
113int do_write32(uint32_t val, uint32_t a)
114{
115 if(hwemul_rw_mem(&hwdev, 0, a, &val, sizeof(val)) == sizeof(val))
116 printf("data written\n");
117 else
118 printf("write error at %#x\n", a);
119 return 1;
120}
121
122int parse_write32()
123{
124 char *arg = strtok(NULL, " ");
125 uint32_t val;
126 if(!arg || !parse_uint32(arg, &val))
127 return syntax_error(arg);
128 uint32_t addr;
129 arg = strtok(NULL, " ");
130 if(arg && parse_uint32(arg, &addr))
131 return do_write32(val, addr);
132 else
133 return syntax_error(arg);
134}
135
136struct hwemul_soc_t *find_soc_by_name(const char *soc)
137{
138 struct hwemul_soc_list_t *list = hwemul_get_soc_list();
139 for(size_t i = 0; i < list->nr_socs; i++)
140 if(strcmp(soc, list->socs[i]->name) == 0)
141 return list->socs[i];
142 return NULL;
143}
144
145struct hwemul_soc_reg_t *find_reg_by_name(struct hwemul_soc_t *soc, const char *reg)
146{
147 for(size_t i = 0; i < soc->nr_regs; i++)
148 if(strcmp(reg, soc->regs_by_name[i]->name) == 0)
149 return soc->regs_by_name[i];
150 return NULL;
151}
152
153struct hwemul_soc_reg_field_t *find_field_by_name(struct hwemul_soc_reg_t *reg, const char *field)
154{
155 for(size_t i = 0; i < reg->nr_fields; i++)
156 if(strcmp(field, reg->fields_by_name[i]->name) == 0)
157 return reg->fields_by_name[i];
158 return NULL;
159}
160
161
162int do_read(char *regname)
163{
164 char *dot = strchr(regname, '.');
165 if(dot != NULL)
166 *dot++ = 0;
167 if(cur_soc == NULL)
168 {
169 printf("No soc selected!\n");
170 return 1;
171 }
172 struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname);
173 if(reg == NULL)
174 {
175 printf("no reg '%s' found\n", regname);
176 return 1;
177 }
178 uint32_t val;
179 if(hwemul_rw_mem(&hwdev, 1, reg->addr, &val, sizeof(val)) != sizeof(val))
180 {
181 printf("read error at %#x\n", reg->addr);
182 return 1;
183 }
184 if(dot)
185 {
186 struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot);
187 if(field == NULL)
188 {
189 printf("no field '%s' found\n", dot);
190 return 1;
191 }
192 val >>= field->first_bit;
193 val &= (1 << (field->last_bit - field->first_bit + 1)) - 1;
194 printf("%s.%s = %#x\n", regname, dot, val);
195 }
196 else
197 printf("%s = %#x\n", regname, val);
198 return 1;
199}
200
201int parse_read()
202{
203 char *arg = strtok(NULL, " ");
204 if(arg)
205 return do_read(arg);
206 else
207 return syntax_error(arg);
208}
209
210int do_soc(char *soc)
211{
212 struct hwemul_soc_t *s = find_soc_by_name(soc);
213 if(s == NULL)
214 printf("no soc '%s' found\n", soc);
215 else
216 cur_soc = s;
217 return 1;
218}
219
220int parse_soc()
221{
222 char *arg = strtok(NULL, " ");
223 if(arg)
224 return do_soc(arg);
225 else
226 return syntax_error(arg);
227}
228
229int do_write(uint32_t val, char *regname)
230{
231 char *dot = strchr(regname, '.');
232 if(dot != NULL)
233 *dot++ = 0;
234 if(cur_soc == NULL)
235 {
236 printf("No soc selected!\n");
237 return 1;
238 }
239 struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname);
240 int is_sct = 0;
241 uint32_t addr_off = 0;
242 if(reg == NULL)
243 {
244 size_t len = strlen(regname);
245 /* try SCT variant */
246 if(strcmp(regname + len - 4, "_SET") == 0)
247 addr_off = 4;
248 else if(strcmp(regname + len - 4, "_CLR") == 0)
249 addr_off = 8;
250 else if(strcmp(regname + len - 4, "_TOG") == 0)
251 addr_off = 12;
252 else
253 {
254 printf("no reg '%s' found\n", regname);
255 return 1;
256 }
257 is_sct = 1;
258 regname[len - 4] = 0;
259 reg = find_reg_by_name(cur_soc, regname);
260 if(reg == NULL)
261 {
262 printf("no reg '%s' found\n", regname);
263 return 1;
264 }
265 }
266 if(dot)
267 {
268 struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot);
269 if(field == NULL)
270 {
271 printf("no field '%s' found\n", dot);
272 return 1;
273 }
274 uint32_t actual_val = 0;
275 if(!is_sct)
276 {
277 if(hwemul_rw_mem(&hwdev, 1, reg->addr, &actual_val, sizeof(actual_val)) != sizeof(actual_val))
278 {
279 printf("read error at %#x\n", reg->addr);
280 return 1;
281 }
282 printf("read %#x at %#x\n", actual_val, reg->addr);
283 }
284 uint32_t mask = ((1 << (field->last_bit - field->first_bit + 1)) - 1) << field->first_bit;
285 printf("mask=%#x\n", mask);
286 val = (actual_val & ~mask) | ((val << field->first_bit) & mask);
287 }
288 printf("write %#x to %#x\n", val, reg->addr + addr_off);
289 if(hwemul_rw_mem(&hwdev, 0, reg->addr + addr_off, &val, sizeof(val)) != sizeof(val))
290 {
291 printf("write error at %#x\n", reg->addr);
292 return 1;
293 }
294 return 1;
295}
296
297int parse_write()
298{
299 char *arg = strtok(NULL, " ");
300 uint32_t val;
301 if(!arg || !parse_uint32(arg, &val))
302 return syntax_error(arg);
303 arg = strtok(NULL, " ");
304 if(arg)
305 return do_write(val, arg);
306 else
307 return syntax_error(arg);
308}
309
310int parse_command(char *cmd)
311{
312 if(strcmp(cmd, "help") == 0)
313 return print_help();
314 if(strcmp(cmd, "quit") == 0)
315 return 0;
316 if(strcmp(cmd, "call") == 0)
317 return parse_call();
318 if(strcmp(cmd, "read32") == 0)
319 return parse_read32();
320 if(strcmp(cmd, "write32") == 0)
321 return parse_write32();
322 if(strcmp(cmd, "read") == 0)
323 return parse_read();
324 if(strcmp(cmd, "soc") == 0)
325 return parse_soc();
326 if(strcmp(cmd, "write") == 0)
327 return parse_write();
328 return syntax_error(cmd);
329}
330
331void interactive_mode(void)
332{
333 rl_bind_key('\t', rl_complete);
334 while(1)
335 {
336 char *input = readline("> ");
337 if(!input)
338 break;
339 add_history(input);
340 int ret = parse_command(input);
341 free(input);
342 if(ret == 0)
343 break;
344 }
345}
346
347void usage(void)
348{
349 printf("hwemul_tool, compiled with hwemul %d.%d.%d\n",
350 HWEMUL_VERSION_MAJOR, HWEMUL_VERSION_MINOR, HWEMUL_VERSION_REV);
351 printf("available soc descriptions:");
352 for(unsigned i = 0; i < hwemul_get_soc_list()->nr_socs; i++)
353 printf(" %s", hwemul_get_soc_list()->socs[i]->name);
354 printf("\n");
355 printf("usage: hwemul_tool [options]\n");
356 printf("options:\n");
357 printf(" --help/-?\tDisplay this help\n");
358 printf(" --quiet/-q\tQuiet non-command messages\n");
359 exit(1);
360}
361
362int main(int argc, char **argv)
363{
364 while(1)
365 {
366 static struct option long_options[] =
367 {
368 {"help", no_argument, 0, '?'},
369 {"quiet", no_argument, 0, 'q'},
370 {0, 0, 0, 0}
371 };
372
373 int c = getopt_long(argc, argv, "?q", long_options, NULL);
374 if(c == -1)
375 break;
376 switch(c)
377 {
378 case -1:
379 break;
380 case 'q':
381 g_quiet = true;
382 break;
383 case '?':
384 usage();
385 break;
386 default:
387 abort();
388 }
389 }
390
391 if(argc - optind != 0)
392 {
393 usage();
394 return 1;
395 }
396
397 libusb_context *ctx;
398 libusb_init(&ctx);
399 libusb_set_debug(ctx, 3);
400
401 if(!g_quiet)
402 printf("Looking for device %#04x:%#04x...\n", HWEMUL_USB_VID, HWEMUL_USB_PID);
403
404 libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
405 HWEMUL_USB_VID, HWEMUL_USB_PID);
406 if(handle == NULL)
407 {
408 printf("No device found\n");
409 return 1;
410 }
411
412 libusb_device *mydev = libusb_get_device(handle);
413 if(!g_quiet)
414 {
415 printf("device found at %d:%d\n",
416 libusb_get_bus_number(mydev),
417 libusb_get_device_address(mydev));
418 }
419 hwdev.handle = handle;
420 if(hwemul_probe(&hwdev))
421 {
422 printf("Cannot probe device!\n");
423 return 1;
424 }
425
426 struct usb_resp_info_version_t ver;
427 int ret = hwemul_get_info(&hwdev, HWEMUL_INFO_VERSION, &ver, sizeof(ver));
428 if(ret != sizeof(ver))
429 {
430 printf("Cannot get version!\n");
431 goto Lerr;
432 }
433 if(!g_quiet)
434 printf("Device version: %d.%d.%d\n", ver.major, ver.minor, ver.revision);
435
436 struct usb_resp_info_layout_t layout;
437 ret = hwemul_get_info(&hwdev, HWEMUL_INFO_LAYOUT, &layout, sizeof(layout));
438 if(ret != sizeof(layout))
439 {
440 printf("Cannot get layout: %d\n", ret);
441 goto Lerr;
442 }
443 if(!g_quiet)
444 {
445 printf("Device layout:\n");
446 printf(" Code: 0x%x (0x%x)\n", layout.oc_code_start, layout.oc_code_size);
447 printf(" Stack: 0x%x (0x%x)\n", layout.oc_stack_start, layout.oc_stack_size);
448 printf(" Buffer: 0x%x (0x%x)\n", layout.oc_buffer_start, layout.oc_buffer_size);
449 }
450
451 struct usb_resp_info_features_t features;
452 ret = hwemul_get_info(&hwdev, HWEMUL_INFO_FEATURES, &features, sizeof(features));
453 if(ret != sizeof(features))
454 {
455 printf("Cannot get features: %d\n", ret);
456 goto Lerr;
457 }
458 if(!g_quiet)
459 {
460 printf("Device features:");
461 if(features.feature_mask & HWEMUL_FEATURE_LOG)
462 printf(" log");
463 if(features.feature_mask & HWEMUL_FEATURE_MEM)
464 printf(" mem");
465 if(features.feature_mask & HWEMUL_FEATURE_CALL)
466 printf(" call");
467 if(features.feature_mask & HWEMUL_FEATURE_JUMP)
468 printf(" jump");
469 if(features.feature_mask & HWEMUL_FEATURE_AES_OTP)
470 printf(" aes_otp");
471 printf("\n");
472 }
473
474 struct usb_resp_info_stmp_t stmp;
475 ret = hwemul_get_info(&hwdev, HWEMUL_INFO_STMP, &stmp, sizeof(stmp));
476 if(ret != sizeof(stmp))
477 {
478 printf("Cannot get stmp: %d\n", ret);
479 goto Lerr;
480 }
481 if(!g_quiet)
482 {
483 printf("Device stmp:\n");
484 printf(" chip ID: %x (%s)\n", stmp.chipid,hwemul_get_product_string(&stmp));
485 printf(" revision: %d (%s)\n", stmp.rev, hwemul_get_rev_string(&stmp));
486 printf(" supported: %d\n", stmp.is_supported);
487 }
488
489 if(!g_quiet)
490 {
491 void *rom = malloc(64 * 1024);
492 ret = hwemul_rw_mem(&hwdev, 1, 0xc0000000, rom, 64 * 1024);
493 if(ret != 64 * 1024)
494 {
495 printf("Cannot read ROM: %d\n", ret);
496 goto Lerr;
497 }
498
499 printf("ROM successfully read!\n");
500 FILE *f = fopen("rom.bin", "wb");
501 fwrite(rom, 64 * 1024, 1, f);
502 fclose(f);
503 }
504
505 if(!g_quiet)
506 {
507 struct
508 {
509 uint8_t iv[16];
510 uint8_t data[16];
511 } __attribute__((packed)) dcp_test;
512
513 for(int i = 0; i < 16; i++)
514 dcp_test.iv[i] = rand();
515 for(int i = 0; i < 16; i++)
516 dcp_test.data[i] = rand();
517 printf("DCP\n");
518 printf(" IN\n");
519 printf(" IV:");
520 for(int i = 0; i < 16; i++)
521 printf(" %02x", dcp_test.iv[i]);
522 printf("\n");
523 printf(" IV:");
524 for(int i = 0; i < 16; i++)
525 printf(" %02x", dcp_test.data[i]);
526 printf("\n");
527
528 if(!hwemul_aes_otp(&hwdev, &dcp_test, sizeof(dcp_test), HWEMUL_AES_OTP_ENCRYPT))
529 {
530 printf(" OUT\n");
531 printf(" IV:");
532 for(int i = 0; i < 16; i++)
533 printf(" %02x", dcp_test.iv[i]);
534 printf("\n");
535 printf(" IV:");
536 for(int i = 0; i < 16; i++)
537 printf(" %02x", dcp_test.data[i]);
538 printf("\n");
539 }
540 else
541 printf("DCP error!\n");
542 }
543
544 if(!g_quiet)
545 printf("Starting interactive session. Type 'help' to get help.\n");
546
547 interactive_mode();
548
549 Lerr:
550 if(features.feature_mask & HWEMUL_FEATURE_LOG)
551 {
552 if(!g_quiet)
553 printf("Device log:\n");
554 print_log(&hwdev);
555 }
556 hwemul_release(&hwdev);
557 return 1;
558}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "hwstub.h"
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <getopt.h>
26#include <stdbool.h>
27#include <ctype.h>
28
29struct player_info_t
30{
31 const char *name;
32 const char *username;
33 int modelnum;
34};
35
36enum image_type_t
37{
38 IT_RAW,
39 IT_ROCKBOX,
40 IT_DETECT,
41 /* positive values reserved for rockbox-specific models */
42};
43
44struct player_info_t players[] =
45{
46 { "zenv", "Zen V", 85 },
47 { "zmoz", "Zen Mozaic", 87 },
48 { "zen", "Zen", 88 },
49 { "zxfi", "Zen X-Fi", 86 },
50 { NULL, 0 },
51};
52
53enum image_type_t detect_type(unsigned char *buffer, size_t size)
54{
55 if(size < 8)
56 return IT_RAW;
57 int player;
58 for(player = 0; players[player].name; player++)
59 if(memcmp(buffer + 4, players[player].name, 4) == 0)
60 break;
61 if(players[player].name == NULL)
62 return IT_RAW;
63 unsigned long checksum = players[player].modelnum;
64 for(size_t i = 8; i < size; i++)
65 checksum += buffer[i];
66 unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
67 if(checksum != expected)
68 return IT_RAW;
69 return IT_ROCKBOX;
70}
71
72const char *get_player_name(unsigned char *buffer)
73{
74 for(int player = 0; players[player].name; player++)
75 if(memcmp(buffer, players[player].name, 4) == 0)
76 return players[player].username;
77 return NULL;
78}
79
80bool could_be_rockbox(unsigned char *buffer, size_t size)
81{
82 /* usually target use 3 or 4 digits */
83 if(size >= 8 && isprint(buffer[4]) && isprint(buffer[5]) && isprint(buffer[6]) &&
84 (isprint(buffer[7]) || buffer[7] == 0))
85 {
86 unsigned long checksum = 0;
87 for(size_t i = 8; i < size; i++)
88 checksum += buffer[i];
89 unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
90 unsigned long expected_modelnm = expected - checksum;
91 if(expected_modelnm < 150)
92 fprintf(stderr, "This file looks like a valid rockbox image but I don't know this player: %.4s (modelnum=%ld)\n",
93 buffer + 4, expected_modelnm);
94 else
95 fprintf(stderr, "This file could be a valid rockbox image but I don't know this player and the checksum is strange: %.4s\n",
96 buffer + 4);
97 return true;
98 }
99 else
100 return false;
101}
102
103void usage(void)
104{
105 printf("usage: hwstub_load [options] <addr> <file>\n");
106 printf("options:\n");
107 printf(" --help/-? Display this help\n");
108 printf(" --quiet/-q Quiet output\n");
109 printf(" --type/-t <t> Override file type\n");
110 printf("file types:\n");
111 printf(" raw Load a raw binary blob\n");
112 printf(" rockbox Load a rockbox image produced by scramble\n");
113 printf(" detect Try to guess the format\n");
114 printf("known players:");
115 for(int i = 0; players[i].name; i++)
116 printf(" %s", players[i].name);
117 printf("\n");
118 exit(1);
119}
120
121int main(int argc, char **argv)
122{
123 bool quiet = false;
124 struct hwstub_device_t hwdev;
125 enum image_type_t type = IT_DETECT;
126
127 // parse command line
128 while(1)
129 {
130 static struct option long_options[] =
131 {
132 {"help", no_argument, 0, '?'},
133 {"quiet", no_argument, 0, 'q'},
134 {"type", required_argument, 0, 't'},
135 {0, 0, 0, 0}
136 };
137
138 int c = getopt_long(argc, argv, "?qt:", long_options, NULL);
139 if(c == -1)
140 break;
141 switch(c)
142 {
143 case -1:
144 break;
145 case 'q':
146 quiet = true;
147 break;
148 case '?':
149 usage();
150 break;
151 case 't':
152 if(strcmp(optarg, "raw") == 0)
153 type = IT_RAW;
154 else if(strcmp(optarg, "rockbox") == 0)
155 type = IT_ROCKBOX;
156 else if(strcmp(optarg, "detect") == 0)
157 type = IT_DETECT;
158 else
159 {
160 fprintf(stderr, "Unknown file type '%s'\n", optarg);
161 return 1;
162 }
163 break;
164 default:
165 abort();
166 }
167 }
168
169 if(optind + 2 != argc)
170 usage();
171
172 char *end;
173 unsigned long addr = strtoul(argv[optind], &end, 0);
174 if(*end)
175 {
176 fprintf(stderr, "Invalid load address\n");
177 return 2;
178 }
179
180 FILE *f = fopen(argv[optind + 1], "rb");
181 if(f == NULL)
182 {
183 fprintf(stderr, "Cannot open file for reading: %m\n");
184 return 3;
185 }
186 fseek(f, 0, SEEK_END);
187 size_t size = ftell(f);
188 fseek(f, 0, SEEK_SET);
189 unsigned char *buffer = (unsigned char*)malloc(size);
190 fread(buffer, size, 1, f);
191 fclose(f);
192
193 if(type == IT_ROCKBOX || type == IT_DETECT)
194 {
195 enum image_type_t det = detect_type(buffer, size);
196 if(type == IT_ROCKBOX && det != IT_ROCKBOX)
197 {
198 if(!could_be_rockbox(buffer, size))
199 fprintf(stderr, "This file does not appear to be valid rockbox image.\n");
200 return 4;
201 }
202 if(type == IT_DETECT && det == IT_RAW)
203 could_be_rockbox(buffer, size);
204 type = det;
205 if(type == IT_ROCKBOX)
206 {
207 if(!quiet)
208 printf("Rockox image is for player %s (%.4s)\n", get_player_name(buffer + 4), buffer + 4);
209 memmove(buffer, buffer + 8, size - 8);
210 size -= 8;
211 }
212 }
213
214 if(!quiet)
215 {
216 if(type == IT_RAW)
217 printf("Loading raw image at %#lx\n", addr);
218 else
219 printf("Loading rockbox image at %#lx\n", addr);
220 }
221
222 // create usb context
223 libusb_context *ctx;
224 libusb_init(&ctx);
225 libusb_set_debug(ctx, 3);
226
227 // look for device
228 if(!quiet)
229 printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID);
230
231 libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
232 HWSTUB_USB_VID, HWSTUB_USB_PID);
233 if(handle == NULL)
234 {
235 fprintf(stderr, "No device found\n");
236 return 1;
237 }
238
239 // admin stuff
240 libusb_device *mydev = libusb_get_device(handle);
241 if(!quiet)
242 {
243 printf("device found at %d:%d\n",
244 libusb_get_bus_number(mydev),
245 libusb_get_device_address(mydev));
246 }
247 hwdev.handle = handle;
248 if(hwstub_probe(&hwdev))
249 {
250 fprintf(stderr, "Cannot probe device!\n");
251 return 1;
252 }
253
254 // get hwstub information
255 struct usb_resp_info_version_t hwdev_ver;
256 int ret = hwstub_get_info(&hwdev, HWSTUB_INFO_VERSION, &hwdev_ver, sizeof(hwdev_ver));
257 if(ret != sizeof(hwdev_ver))
258 {
259 fprintf(stderr, "Cannot get version!\n");
260 goto Lerr;
261 }
262 if(hwdev_ver.major != HWSTUB_VERSION_MAJOR || hwdev_ver.minor < HWSTUB_VERSION_MINOR)
263 {
264 printf("Warning: this tool is possibly incompatible with your device:\n");
265 printf("Device version: %d.%d.%d\n", hwdev_ver.major, hwdev_ver.minor, hwdev_ver.revision);
266 printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
267 }
268
269 // get features
270 struct usb_resp_info_features_t hwdev_features;
271 ret = hwstub_get_info(&hwdev, HWSTUB_INFO_FEATURES, &hwdev_features, sizeof(hwdev_features));
272 if(ret != sizeof(hwdev_features))
273 {
274 fprintf(stderr, "Cannot get features: %d\n", ret);
275 goto Lerr;
276 }
277 if(!(hwdev_features.feature_mask & HWSTUB_RW_MEM))
278 {
279 fprintf(stderr, "Device doesn't support R/W commands\n");
280 goto Lerr;
281 }
282 if(!(hwdev_features.feature_mask & HWSTUB_JUMP))
283 {
284 fprintf(stderr, "Device doesn't support jump commands\n");
285 goto Lerr;
286 }
287 ret = hwstub_rw_mem(&hwdev, 0, addr, buffer, size);
288 if(ret != (int)size)
289 {
290 fprintf(stderr, "Image write failed\n");
291 goto Lerr;
292 }
293 hwstub_jump(&hwdev, addr);
294
295 hwstub_release(&hwdev);
296 return 0;
297
298 Lerr:
299 // display log if handled
300 if(hwdev_features.feature_mask & HWSTUB_FEATURE_LOG)
301 {
302 fprintf(stderr, "Device log:\n");
303 do
304 {
305 char buffer[128];
306 int length = hwstub_get_log(&hwdev, buffer, sizeof(buffer) - 1);
307 if(length <= 0)
308 break;
309 buffer[length] = 0;
310 fprintf(stderr, "%s", buffer);
311 }while(1);
312 }
313 hwstub_release(&hwdev);
314 return 1;
315}
316
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 by Amaury Pouly
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "hwstub.h"
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <getopt.h>
26#include <stdbool.h>
27#include <readline/readline.h>
28#include <readline/history.h>
29#include <lua.hpp>
30#include "soc_desc.hpp"
31
32#if LUA_VERSION_NUM < 502
33#warning You need at least lua 5.2
34#endif
35
36/**
37 * Global variables
38 */
39bool g_quiet = false;
40struct hwstub_device_t g_hwdev;
41struct usb_resp_info_version_t g_hwdev_ver;
42struct usb_resp_info_layout_t g_hwdev_layout;
43struct usb_resp_info_features_t g_hwdev_features;
44struct usb_resp_info_stmp_t g_hwdev_stmp;
45lua_State *g_lua;
46
47/**
48 * hw specific
49 */
50
51void print_log(struct hwstub_device_t *hwdev)
52{
53 do
54 {
55 char buffer[128];
56 int length = hwstub_get_log(hwdev, buffer, sizeof(buffer) - 1);
57 if(length <= 0)
58 break;
59 buffer[length] = 0;
60 printf("%s", buffer);
61 }while(1);
62}
63
64/**
65 * Lua specific
66 */
67int my_lua_help(lua_State *state)
68{
69 bool has_sub = false;
70 // implement help() in C so that we do not rely on the init to implement it
71 // help can take optional arguments
72 int n = lua_gettop(state);
73
74 lua_getglobal(state, "hwstub");
75 if(!lua_istable(state, -1))
76 goto Lerr;
77 lua_getfield(state, -1, "help");
78 if(!lua_istable(state, -1))
79 goto Lerr;
80
81 for(int i = 1; i <= n; i++)
82 {
83 lua_pushvalue(state, i);
84 lua_gettable(state, -2);
85 if(lua_isnil(state, -1))
86 {
87 printf("I don't know subtopic '%s'!\n", lua_tostring(state, i));
88 return 0;
89 }
90 if(!lua_istable(state, -1))
91 {
92 printf("Subtopic '%s' is not a table!\n", lua_tostring(state, i));
93 return 0;
94 }
95 }
96
97 printf("================[ HELP ");
98 for(int i = 1; i <= n; i++)
99 printf("> %s ", lua_tostring(state, i));
100 printf("]================\n");
101
102 lua_pushnil(state);
103 while(lua_next(state, -2))
104 {
105 // key is at -2 and value at -1
106 if(lua_isstring(state, -1))
107 printf("%s\n", lua_tostring(state, -1));
108 else if(lua_istable(state, -1))
109 has_sub = true;
110 // pop value but keep key
111 lua_pop(state, 1);
112 }
113
114 if(has_sub)
115 {
116 printf("\n");
117 printf("You can get more information on the following subtopics:\n");
118 lua_pushnil(state);
119 while(lua_next(state, -2))
120 {
121 // key is at -2 and value at -1
122 if(lua_istable(state, -1))
123 printf("* %s\n", lua_tostring(state, -2));
124 // pop value but keep key
125 lua_pop(state, 1);
126 }
127 }
128 printf("================[ STOP ]================\n");
129
130 return 0;
131
132 Lerr:
133 printf("There is a problem with the Lua context. Help is expected to be in hwstub.help\n");
134 printf("You must have messed badly the environment.\n");
135 return 0;
136}
137
138typedef soc_word_t (*hw_readn_fn_t)(lua_State *state, soc_addr_t addr);
139typedef void (*hw_writen_fn_t)(lua_State *state, soc_addr_t addr, soc_word_t val);
140
141soc_word_t hw_read8(lua_State *state, soc_addr_t addr)
142{
143 uint8_t u;
144 if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u))
145 luaL_error(state, "fail to read8 @ %p", addr);
146 return u;
147}
148
149soc_word_t hw_read16(lua_State *state, soc_addr_t addr)
150{
151 uint16_t u;
152 if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u))
153 luaL_error(state, "fail to read16 @ %p", addr);
154 return u;
155}
156
157soc_word_t hw_read32(lua_State *state, soc_addr_t addr)
158{
159 uint32_t u;
160 if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u))
161 luaL_error(state, "fail to read32 @ %p", addr);
162 return u;
163}
164
165void hw_write8(lua_State *state, soc_addr_t addr, soc_word_t val)
166{
167 uint8_t u = val;
168 if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u))
169 luaL_error(state, "fail to write8 @ %p", addr);
170}
171
172void hw_write16(lua_State *state, soc_addr_t addr, soc_word_t val)
173{
174 uint16_t u = val;
175 if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u))
176 luaL_error(state, "fail to write16 @ %p", addr);
177}
178
179void hw_write32(lua_State *state, soc_addr_t addr, soc_word_t val)
180{
181 uint32_t u = val;
182 if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u))
183 luaL_error(state, "fail to write32 @ %p", addr);
184}
185
186int my_lua_readn(lua_State *state)
187{
188 hw_readn_fn_t fn = (hw_readn_fn_t)lua_touserdata(state, lua_upvalueindex(1));
189 int n = lua_gettop(state);
190 if(n != 1)
191 luaL_error(state, "readn takes a single argument");
192 lua_pushunsigned(state, fn(state, luaL_checkunsigned(state, 1)));
193 return 1;
194}
195
196int my_lua_writen(lua_State *state)
197{
198 hw_writen_fn_t fn = (hw_writen_fn_t)lua_touserdata(state, lua_upvalueindex(1));
199 int n = lua_gettop(state);
200 if(n != 2)
201 luaL_error(state, "writen takes two arguments");
202 fn(state, luaL_checkunsigned(state, 1), luaL_checkunsigned(state, 2));
203 return 0;
204}
205
206int my_lua_printlog(lua_State *state)
207{
208 print_log(&g_hwdev);
209 return 0;
210}
211
212bool my_lua_import_hwstub()
213{
214 int oldtop = lua_gettop(g_lua);
215
216 lua_newtable(g_lua); // hwstub
217
218 lua_newtable(g_lua); // options
219 lua_pushboolean(g_lua, g_quiet);
220 lua_setfield(g_lua, -2, "quiet");
221 lua_setfield(g_lua, -2, "options");
222
223 lua_newtable(g_lua); // dev
224 lua_newtable(g_lua); // version
225 lua_pushinteger(g_lua, g_hwdev_ver.major);
226 lua_setfield(g_lua, -2, "major");
227 lua_pushinteger(g_lua, g_hwdev_ver.minor);
228 lua_setfield(g_lua, -2, "minor");
229 lua_pushinteger(g_lua, g_hwdev_ver.revision);
230 lua_setfield(g_lua, -2, "revision");
231 lua_setfield(g_lua, -2, "version");
232
233 lua_newtable(g_lua); // layout
234 lua_newtable(g_lua); // ocram
235 lua_newtable(g_lua); // code
236 lua_pushinteger(g_lua, g_hwdev_layout.oc_code_start);
237 lua_setfield(g_lua, -2, "start");
238 lua_pushinteger(g_lua, g_hwdev_layout.oc_code_size);
239 lua_setfield(g_lua, -2, "size");
240 lua_setfield(g_lua, -2, "code");
241 lua_newtable(g_lua); // stack
242 lua_pushinteger(g_lua, g_hwdev_layout.oc_stack_start);
243 lua_setfield(g_lua, -2, "start");
244 lua_pushinteger(g_lua, g_hwdev_layout.oc_stack_size);
245 lua_setfield(g_lua, -2, "size");
246 lua_setfield(g_lua, -2, "stack");
247 lua_newtable(g_lua); // buffer
248 lua_pushinteger(g_lua, g_hwdev_layout.oc_buffer_start);
249 lua_setfield(g_lua, -2, "start");
250 lua_pushinteger(g_lua, g_hwdev_layout.oc_buffer_size);
251 lua_setfield(g_lua, -2, "size");
252 lua_setfield(g_lua, -2, "buffer");
253 lua_setfield(g_lua, -2, "ocram");
254 lua_setfield(g_lua, -2, "layout");
255
256 lua_newtable(g_lua); // stmp
257 lua_pushinteger(g_lua, g_hwdev_stmp.chipid);
258 lua_setfield(g_lua, -2, "chipid");
259 lua_pushinteger(g_lua, g_hwdev_stmp.rev);
260 lua_setfield(g_lua, -2, "rev");
261 lua_setfield(g_lua, -2, "stmp");
262
263 lua_newtable(g_lua); // features
264 lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_LOG));
265 lua_setfield(g_lua, -2, "log");
266 lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_MEM));
267 lua_setfield(g_lua, -2, "mem");
268 lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_CALL));
269 lua_setfield(g_lua, -2, "call");
270 lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_JUMP));
271 lua_setfield(g_lua, -2, "jump");
272 lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_AES_OTP));
273 lua_setfield(g_lua, -2, "aes_otp");
274 lua_setfield(g_lua, -2, "features");
275
276 lua_pushlightuserdata(g_lua, (void *)&hw_read8);
277 lua_pushcclosure(g_lua, my_lua_readn, 1);
278 lua_setfield(g_lua, -2, "read8");
279 lua_pushlightuserdata(g_lua, (void *)&hw_read16);
280 lua_pushcclosure(g_lua, my_lua_readn, 1);
281 lua_setfield(g_lua, -2, "read16");
282 lua_pushlightuserdata(g_lua, (void *)&hw_read32);
283 lua_pushcclosure(g_lua, my_lua_readn, 1);
284 lua_setfield(g_lua, -2, "read32");
285
286 lua_pushlightuserdata(g_lua, (void *)&hw_write8);
287 lua_pushcclosure(g_lua, my_lua_writen, 1);
288 lua_setfield(g_lua, -2, "write8");
289 lua_pushlightuserdata(g_lua, (void *)&hw_write16);
290 lua_pushcclosure(g_lua, my_lua_writen, 1);
291 lua_setfield(g_lua, -2, "write16");
292 lua_pushlightuserdata(g_lua, (void *)&hw_write32);
293 lua_pushcclosure(g_lua, my_lua_writen, 1);
294 lua_setfield(g_lua, -2, "write32");
295 lua_pushcclosure(g_lua, my_lua_printlog, 0);
296 lua_setfield(g_lua, -2, "print_log");
297
298 lua_setfield(g_lua, -2, "dev");
299
300 lua_newtable(g_lua); // host
301 lua_newtable(g_lua); // version
302 lua_pushinteger(g_lua, HWSTUB_VERSION_MAJOR);
303 lua_setfield(g_lua, -2, "major");
304 lua_pushinteger(g_lua, HWSTUB_VERSION_MINOR);
305 lua_setfield(g_lua, -2, "minor");
306 lua_pushinteger(g_lua, HWSTUB_VERSION_REV);
307 lua_setfield(g_lua, -2, "revision");
308 lua_setfield(g_lua, -2, "version");
309 lua_setfield(g_lua, -2, "host");
310
311 lua_newtable(g_lua); // soc
312 lua_setfield(g_lua, -2, "soc");
313
314 lua_newtable(g_lua); // help
315 lua_pushinteger(g_lua, 1);
316 lua_pushstring(g_lua, "This is the help for hwstub_tool. This tools uses Lua to interpret commands.");
317 lua_settable(g_lua, -3);
318 lua_pushinteger(g_lua, 2);
319 lua_pushstring(g_lua, "You can get help by running help(). Help is organised in topics and subtopics and so on.");
320 lua_settable(g_lua, -3);
321 lua_pushinteger(g_lua, 3);
322 lua_pushstring(g_lua, "If you want to access the help of topic x, subtopic y, subsubtopic z, type help(x,y,z).");
323 lua_settable(g_lua, -3);
324 lua_pushinteger(g_lua, 4);
325 lua_pushstring(g_lua, "Example: help(\"hwstub\").");
326 lua_settable(g_lua, -3);
327 lua_setfield(g_lua, -2, "help");
328
329 lua_setglobal(g_lua, "hwstub");
330
331 lua_pushcfunction(g_lua, my_lua_help);
332 lua_setglobal(g_lua, "help");
333
334 if(lua_gettop(g_lua) != oldtop)
335 {
336 printf("internal error: unbalanced my_lua_import_soc");
337 return false;
338 }
339 return true;
340}
341
342int my_lua_read_reg(lua_State *state)
343{
344 int n = lua_gettop(state);
345 if(n != 0)
346 luaL_error(state, "read() takes no argument");
347 soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
348 lua_pushunsigned(state, hw_read32(state, addr));
349 return 1;
350}
351
352int my_lua_write_reg(lua_State *state)
353{
354 int n = lua_gettop(state);
355 if(n != 1)
356 luaL_error(state, "write() takes one argument");
357 soc_word_t val = luaL_checkunsigned(state, 1);
358 soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
359 hw_write32(state, addr, val);
360 return 0;
361}
362
363int my_lua_read_field(lua_State *state)
364{
365 int n = lua_gettop(state);
366 if(n != 0)
367 luaL_error(state, "read() takes no argument");
368 soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
369 soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2));
370 soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3));
371 lua_pushunsigned(state, (hw_read32(state, addr) >> shift) & mask);
372 return 1;
373}
374
375int my_lua_write_field(lua_State *state)
376{
377 int n = lua_gettop(state);
378 if(n != 0 && n!= 1)
379 luaL_error(state, "write() takes one or no argument");
380 soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
381 soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2));
382 soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3));
383 bool is_sct = lua_toboolean(state, lua_upvalueindex(5));
384
385 soc_word_t value = mask;
386 if(n == 1)
387 {
388 if(!lua_isnumber(state, 1) && lua_isstring(state, 1))
389 {
390 lua_pushvalue(state, lua_upvalueindex(4));
391 lua_pushvalue(state, 1);
392 lua_gettable(state, -2);
393 if(lua_isnil(state, -1))
394 luaL_error(state, "field has no value %s", lua_tostring(state, 1));
395 value = luaL_checkunsigned(state, -1);
396 lua_pop(state, 2);
397 }
398 else
399 value = luaL_checkunsigned(state, 1);
400 value &= mask;
401 }
402
403 if(!is_sct)
404 value = value << shift | (hw_read32(state, addr) & ~(mask << shift));
405 else
406 value <<= shift;
407
408 hw_write32(state, addr, value);
409 return 0;
410}
411
412void my_lua_create_field(soc_addr_t addr, const soc_reg_field_t& field, bool sct)
413{
414 lua_newtable(g_lua);
415
416 lua_pushstring(g_lua, field.name.c_str());
417 lua_setfield(g_lua, -2, "name");
418
419 lua_pushunsigned(g_lua, addr);
420 lua_setfield(g_lua, -2, "addr");
421
422 lua_pushboolean(g_lua, sct);
423 lua_setfield(g_lua, -2, "sct");
424
425 lua_pushunsigned(g_lua, field.first_bit);
426 lua_setfield(g_lua, -2, "first_bit");
427
428 lua_pushunsigned(g_lua, field.last_bit);
429 lua_setfield(g_lua, -2, "last_bit");
430
431 lua_pushunsigned(g_lua, field.bitmask());
432 lua_setfield(g_lua, -2, "bitmask");
433
434 soc_word_t local_bitmask = field.bitmask() >> field.first_bit;
435 lua_pushunsigned(g_lua, local_bitmask);
436 lua_setfield(g_lua, -2, "local_bitmask");
437
438 lua_pushunsigned(g_lua, addr);
439 lua_pushunsigned(g_lua, field.first_bit);
440 lua_pushunsigned(g_lua, local_bitmask);
441 lua_pushcclosure(g_lua, my_lua_read_field, 3);
442 lua_setfield(g_lua, -2, "read");
443
444 lua_pushunsigned(g_lua, addr);
445 lua_pushunsigned(g_lua, field.first_bit);
446 lua_pushunsigned(g_lua, local_bitmask);
447 lua_pushvalue(g_lua, -4);
448 lua_pushboolean(g_lua, false);
449 lua_pushcclosure(g_lua, my_lua_write_field, 5);
450 lua_setfield(g_lua, -2, "write");
451
452 if(sct)
453 {
454 lua_pushunsigned(g_lua, addr + 4);
455 lua_pushunsigned(g_lua, field.first_bit);
456 lua_pushunsigned(g_lua, local_bitmask);
457 lua_pushvalue(g_lua, -4);
458 lua_pushboolean(g_lua, true);
459 lua_pushcclosure(g_lua, my_lua_write_field, 5);
460 lua_setfield(g_lua, -2, "set");
461
462 lua_pushunsigned(g_lua, addr + 8);
463 lua_pushunsigned(g_lua, field.first_bit);
464 lua_pushunsigned(g_lua, local_bitmask);
465 lua_pushvalue(g_lua, -4);
466 lua_pushboolean(g_lua, true);
467 lua_pushcclosure(g_lua, my_lua_write_field, 5);
468 lua_setfield(g_lua, -2, "clr");
469
470 lua_pushunsigned(g_lua, addr + 12);
471 lua_pushunsigned(g_lua, field.first_bit);
472 lua_pushunsigned(g_lua, local_bitmask);
473 lua_pushvalue(g_lua, -4);
474 lua_pushboolean(g_lua, true);
475 lua_pushcclosure(g_lua, my_lua_write_field, 5);
476 lua_setfield(g_lua, -2, "tog");
477 }
478
479 for(size_t i = 0; i < field.value.size(); i++)
480 {
481 lua_pushunsigned(g_lua, field.value[i].value);
482 lua_setfield(g_lua, -2, field.value[i].name.c_str());
483 }
484}
485
486void my_lua_create_reg(soc_addr_t addr, size_t index, const soc_reg_t& reg)
487{
488 lua_newtable(g_lua);
489
490 lua_pushstring(g_lua, reg.addr[index].name.c_str());
491 lua_setfield(g_lua, -2, "name");
492
493 lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
494 lua_setfield(g_lua, -2, "addr");
495
496 lua_pushboolean(g_lua, !!(reg.flags & REG_HAS_SCT));
497 lua_setfield(g_lua, -2, "sct");
498
499 lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
500 lua_pushcclosure(g_lua, my_lua_read_reg, 1);
501 lua_setfield(g_lua, -2, "read");
502
503 lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
504 lua_pushcclosure(g_lua, my_lua_write_reg, 1);
505 lua_setfield(g_lua, -2, "write");
506
507 if(reg.flags & REG_HAS_SCT)
508 {
509 lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 4);
510 lua_pushcclosure(g_lua, my_lua_write_reg, 1);
511 lua_setfield(g_lua, -2, "set");
512
513 lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 8);
514 lua_pushcclosure(g_lua, my_lua_write_reg, 1);
515 lua_setfield(g_lua, -2, "clr");
516
517 lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 12);
518 lua_pushcclosure(g_lua, my_lua_write_reg, 1);
519 lua_setfield(g_lua, -2, "tog");
520 }
521
522 for(size_t i = 0; i < reg.field.size(); i++)
523 {
524 my_lua_create_field(addr + reg.addr[index].addr, reg.field[i],
525 reg.flags & REG_HAS_SCT);
526 lua_setfield(g_lua, -2, reg.field[i].name.c_str());
527 }
528}
529
530void my_lua_create_dev(size_t index, const soc_dev_t& dev)
531{
532 lua_newtable(g_lua);
533
534 lua_pushstring(g_lua, dev.addr[index].name.c_str());
535 lua_setfield(g_lua, -2, "name");
536
537 lua_pushunsigned(g_lua, dev.addr[index].addr);
538 lua_setfield(g_lua, -2, "addr");
539
540 for(size_t i = 0; i < dev.reg.size(); i++)
541 {
542 bool table = dev.reg[i].addr.size() > 1;
543 if(table)
544 lua_newtable(g_lua);
545 else
546 lua_pushnil(g_lua);
547
548 for(size_t k = 0; k < dev.reg[i].addr.size(); k++)
549 {
550 my_lua_create_reg(dev.addr[index].addr, k, dev.reg[i]);
551 if(table)
552 {
553 lua_pushinteger(g_lua, k);
554 lua_pushvalue(g_lua, -2);
555 lua_settable(g_lua, -4);
556 }
557 lua_setfield(g_lua, -3, dev.reg[i].addr[k].name.c_str());
558 }
559
560 if(table)
561 lua_setfield(g_lua, -2, dev.reg[i].name.c_str());
562 else
563 lua_pop(g_lua, 1);
564 }
565}
566
567bool my_lua_import_soc(const soc_t& soc)
568{
569 int oldtop = lua_gettop(g_lua);
570
571 lua_getglobal(g_lua, "hwstub");
572 lua_getfield(g_lua, -1, "soc");
573
574 lua_newtable(g_lua);
575
576 lua_pushstring(g_lua, soc.name.c_str());
577 lua_setfield(g_lua, -2, "name");
578
579 lua_pushstring(g_lua, soc.desc.c_str());
580 lua_setfield(g_lua, -2, "desc");
581
582 for(size_t i = 0; i < soc.dev.size(); i++)
583 {
584 bool table = soc.dev[i].addr.size() > 1;
585 if(table)
586 lua_newtable(g_lua);
587 else
588 lua_pushnil(g_lua);
589
590 for(size_t k = 0; k < soc.dev[i].addr.size(); k++)
591 {
592 my_lua_create_dev(k, soc.dev[i]);
593 if(table)
594 {
595 lua_pushinteger(g_lua, k + 1);
596 lua_pushvalue(g_lua, -2);
597 lua_settable(g_lua, -4);
598 }
599 lua_setfield(g_lua, -3, soc.dev[i].addr[k].name.c_str());
600 }
601
602 if(table)
603 lua_setfield(g_lua, -2, soc.dev[i].name.c_str());
604 else
605 lua_pop(g_lua, 1);
606 }
607
608 lua_setfield(g_lua, -2, soc.name.c_str());
609
610 lua_pop(g_lua, 2);
611
612 if(lua_gettop(g_lua) != oldtop)
613 {
614 printf("internal error: unbalanced my_lua_import_soc\n");
615 return false;
616 }
617 return true;
618}
619
620bool my_lua_import_soc(const std::vector< soc_t >& socs)
621{
622 for(size_t i = 0; i < socs.size(); i++)
623 {
624 if(!g_quiet)
625 printf("importing %s...\n", socs[i].name.c_str());
626 if(!my_lua_import_soc(socs[i]))
627 return false;
628 }
629 return true;
630}
631
632/**
633 * glue
634 */
635
636void usage(void)
637{
638 printf("hwstub_tool, compiled with hwstub %d.%d.%d\n",
639 HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
640 printf("\n");
641 printf("usage: hwstub_tool [options] <soc desc files>\n");
642 printf("options:\n");
643 printf(" --help/-?\tDisplay this help\n");
644 printf(" --quiet/-q\tQuiet non-command messages\n");
645 printf(" -i <init>\tSet lua init file (default is init.lua)\n");
646 exit(1);
647}
648
649int main(int argc, char **argv)
650{
651 const char *lua_init = "init.lua";
652 // parse command line
653 while(1)
654 {
655 static struct option long_options[] =
656 {
657 {"help", no_argument, 0, '?'},
658 {"quiet", no_argument, 0, 'q'},
659 {0, 0, 0, 0}
660 };
661
662 int c = getopt_long(argc, argv, "?qi:", long_options, NULL);
663 if(c == -1)
664 break;
665 switch(c)
666 {
667 case -1:
668 break;
669 case 'q':
670 g_quiet = true;
671 break;
672 case '?':
673 usage();
674 break;
675 case 'i':
676 lua_init = optarg;
677 break;
678 default:
679 abort();
680 }
681 }
682
683 // load register descriptions
684 std::vector< soc_t > socs;
685 for(int i = optind; i < argc; i++)
686 if(!soc_desc_parse_xml(argv[i], socs))
687 {
688 printf("Cannot load description '%s'\n", argv[i]);
689 return 2;
690 }
691
692 // create usb context
693 libusb_context *ctx;
694 libusb_init(&ctx);
695 libusb_set_debug(ctx, 3);
696
697 // look for device
698 if(!g_quiet)
699 printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID);
700
701 libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
702 HWSTUB_USB_VID, HWSTUB_USB_PID);
703 if(handle == NULL)
704 {
705 printf("No device found\n");
706 return 1;
707 }
708
709 // admin stuff
710 libusb_device *mydev = libusb_get_device(handle);
711 if(!g_quiet)
712 {
713 printf("device found at %d:%d\n",
714 libusb_get_bus_number(mydev),
715 libusb_get_device_address(mydev));
716 }
717 g_hwdev.handle = handle;
718 if(hwstub_probe(&g_hwdev))
719 {
720 printf("Cannot probe device!\n");
721 return 1;
722 }
723
724 // get hwstub information
725 int ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_VERSION, &g_hwdev_ver, sizeof(g_hwdev_ver));
726 if(ret != sizeof(g_hwdev_ver))
727 {
728 printf("Cannot get version!\n");
729 goto Lerr;
730 }
731 if(g_hwdev_ver.major != HWSTUB_VERSION_MAJOR || g_hwdev_ver.minor < HWSTUB_VERSION_MINOR)
732 {
733 printf("Warning: this tool is possibly incompatible with your device:\n");
734 printf("Device version: %d.%d.%d\n", g_hwdev_ver.major, g_hwdev_ver.minor, g_hwdev_ver.revision);
735 printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
736 }
737
738 // get memory layout information
739 ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_LAYOUT, &g_hwdev_layout, sizeof(g_hwdev_layout));
740 if(ret != sizeof(g_hwdev_layout))
741 {
742 printf("Cannot get layout: %d\n", ret);
743 goto Lerr;
744 }
745
746 // get features
747 ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_FEATURES, &g_hwdev_features, sizeof(g_hwdev_features));
748 if(ret != sizeof(g_hwdev_features))
749 {
750 printf("Cannot get features: %d\n", ret);
751 goto Lerr;
752 }
753
754 // get STMP specific information
755 ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_STMP, &g_hwdev_stmp, sizeof(g_hwdev_stmp));
756 if(ret != sizeof(g_hwdev_stmp))
757 {
758 printf("Cannot get stmp: %d\n", ret);
759 goto Lerr;
760 }
761
762 // dump ROM
763 if(!g_quiet)
764 {
765 void *rom = malloc(64 * 1024);
766 ret = hwstub_rw_mem(&g_hwdev, 1, 0xc0000000, rom, 64 * 1024);
767 if(ret != 64 * 1024)
768 {
769 printf("Cannot read ROM: %d\n", ret);
770 goto Lerr;
771 }
772
773 printf("ROM successfully read!\n");
774 FILE *f = fopen("rom.bin", "wb");
775 fwrite(rom, 64 * 1024, 1, f);
776 fclose(f);
777 }
778
779 // test DCP
780#if 0
781 if(!g_quiet)
782 {
783 struct
784 {
785 uint8_t iv[16];
786 uint8_t data[16];
787 } __attribute__((packed)) dcp_test;
788
789 for(int i = 0; i < 16; i++)
790 dcp_test.iv[i] = rand();
791 for(int i = 0; i < 16; i++)
792 dcp_test.data[i] = rand();
793 printf("DCP\n");
794 printf(" IN\n");
795 printf(" IV:");
796 for(int i = 0; i < 16; i++)
797 printf(" %02x", dcp_test.iv[i]);
798 printf("\n");
799 printf(" IV:");
800 for(int i = 0; i < 16; i++)
801 printf(" %02x", dcp_test.data[i]);
802 printf("\n");
803
804 if(!hwstub_aes_otp(&g_hwdev, &dcp_test, sizeof(dcp_test), HWSTUB_AES_OTP_ENCRYPT))
805 {
806 printf(" OUT\n");
807 printf(" IV:");
808 for(int i = 0; i < 16; i++)
809 printf(" %02x", dcp_test.iv[i]);
810 printf("\n");
811 printf(" IV:");
812 for(int i = 0; i < 16; i++)
813 printf(" %02x", dcp_test.data[i]);
814 printf("\n");
815 }
816 else
817 printf("DCP error!\n");
818 }
819#endif
820
821 /** Init lua */
822
823 // create lua state
824 g_lua = luaL_newstate();
825 if(g_lua == NULL)
826 {
827 printf("Cannot create lua state\n");
828 return 1;
829 }
830 // import hwstub
831 if(!my_lua_import_hwstub())
832 printf("Cannot import hwstub description into Lua context\n");
833 // open all standard libraires
834 luaL_openlibs(g_lua);
835 // import socs
836 if(!my_lua_import_soc(socs))
837 printf("Cannot import SoC descriptions into Lua context\n");
838
839 if(luaL_dofile(g_lua, lua_init))
840 printf("error in init: %s\n", lua_tostring(g_lua, -1));
841 lua_pop(g_lua, lua_gettop(g_lua));
842
843 /** start interactive mode */
844 if(!g_quiet)
845 printf("Starting interactive lua session. Type 'help()' to get some help\n");
846
847 // use readline to provide some history and completion
848 rl_bind_key('\t', rl_complete);
849 while(1)
850 {
851 char *input = readline("> ");
852 if(!input)
853 break;
854 add_history(input);
855 // evaluate string
856 if(luaL_dostring(g_lua, input))
857 printf("error: %s\n", lua_tostring(g_lua, -1));
858 // pop everything to start from a clean stack
859 lua_pop(g_lua, lua_gettop(g_lua));
860 free(input);
861 }
862
863 Lerr:
864 // display log if handled
865 if(g_hwdev_features.feature_mask & HWSTUB_FEATURE_LOG)
866 {
867 if(!g_quiet)
868 printf("Device log:\n");
869 print_log(&g_hwdev);
870 }
871 hwstub_release(&g_hwdev);
872 return 1;
873}
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 @@
1-- init code for hwstub_tools
2
3--
4-- HELP
5--
6HELP = hwstub.help
7
8function HELP:create_topic(name)
9 self[name] = { create_topic = HELP.create_topic, add = HELP.add, get_topic = HELP.get_topic }
10 return self[name]
11end
12
13function HELP:get_topic(name)
14 return self[name]
15end
16
17function HELP:add(text)
18 table.insert(self, text)
19end
20
21do
22 local h = HELP:create_topic("hwstub")
23 h:add("This tool uses a number of well-defined namespaces (tables) to organise its features.")
24 h:add("The hwstub table contains a number of information and functions related to the tool itself.")
25 h:add("Of particular interest are")
26 h:add("* hwstub.host which holds host specific information.")
27 h:add("* hwstub.dev which holds device specific information. See DEV")
28 h:add("* hwstub.help (aka HELP) which holds the help. See HELP.");
29 h:add("* hwstub.soc which holds soc specific information. See HW");
30
31 h = HELP:create_topic("HELP");
32 h:add("This variable redirects to hwstub.help and provides access to the help system.");
33 h:add("You can enhance the help using the following methods on any topic (including HELP itself).");
34 h:add("* t:create_topic(s) to create a new subtopic named s under topic t");
35 h:add("* t:add(s) to add a help line to topic t");
36 h:add("* t:get_topic(s) to get the subtopic s under topic t");
37
38 h = HELP:create_topic("DEV");
39 h:add("This variable redirects to hwstub.dev and provides direct access to the device.");
40 h:add("It contains some information about the device and the following methods.");
41 h:add("* read8/16/32(a) reads a 8/16/32-bit integer at address a");
42 h:add("* write8/16/32(a, v) writes the 8/16/32-bit integer v at address a");
43
44 h = HELP:create_topic("HW");
45 h:add("This variable redirects to the current soc under hwstub.soc and should be changed by calling hwstub:soc:select only.");
46 h:add("The complete register tree can be found under HW in a well organise fashion.");
47 h:add("* HW.dev points to device dev");
48 h:add("* HW.dev[i] points to device devi if there are several copies of the device at different addresses.");
49 h:add("* HW.dev.reg points to the register reg under dev");
50 h:add("* HW.dev.reg[i] points to the register regi if there are several copies.");
51 h:add("* HW.dev.reg.f points to the field f under register reg.");
52 h:add("* HW.dev.reg.f.v gives the value of named value v of field f.");
53 h:add("* All registers can be read using HW.dev.reg.read() and written using HW.dev.reg.write(v).");
54 h:add("* Register with a SCT variant also implement HW.dev.reg.set/clr/tog(v).");
55 h:add("* All register field can be read using HW.dev.reg.f.read() and written using HW.dev.reg.f.write(v).");
56 h:add("* Field writes can either give a integer or a named value to write(v).");
57 h:add("* Register with a SCT variant also implement HW.dev.reg.f.set/clr/tog(v) with the same properties.");
58 h:add("* All devices, registers and fields also have descriptions available such as addresses.");
59end
60
61--
62-- INFO
63--
64
65if not hwstub.options.quiet then
66 print("information")
67 print(" hwstub")
68 print(" version: " .. string.format("%d.%d.%d", hwstub.host.version.major,
69 hwstub.host.version.minor, hwstub.host.version.revision))
70 print(" device")
71 print(" version: " .. string.format("%d.%d.%d", hwstub.dev.version.major,
72 hwstub.dev.version.minor, hwstub.dev.version.revision))
73 print(" layout")
74 print(" on-chip ram")
75 print(" code: " .. string.format("%#x bytes @ %#x",
76 hwstub.dev.layout.ocram.code.size, hwstub.dev.layout.ocram.code.start))
77 print(" stack: " .. string.format("%#x bytes @ %#x",
78 hwstub.dev.layout.ocram.stack.size, hwstub.dev.layout.ocram.stack.start))
79 print(" buffer: " .. string.format("%#x bytes @ %#x",
80 hwstub.dev.layout.ocram.buffer.size, hwstub.dev.layout.ocram.buffer.start))
81 print(" features");
82 print(" log: " .. tostring(hwstub.dev.features.log))
83 print(" mem: " .. tostring(hwstub.dev.features.mem))
84 print(" call: " .. tostring(hwstub.dev.features.call))
85 print(" jump: " .. tostring(hwstub.dev.features.jump))
86 print(" aes_otp: " .. tostring(hwstub.dev.features.aes_otp))
87end
88
89--
90-- SOC
91--
92function hwstub.soc:select(soc)
93 if self[soc] == nil then return false end
94 print("Selecting soc " .. soc .. ". Redirecting HW to hwstub.soc." .. soc)
95 HW = self[soc]
96 return true
97end
98
99--
100-- DEV
101--
102DEV = hwstub.dev
103
104require "lua/load"