imxtools/hwemul: add readline support
[maemo-rb.git] / utils / imxtools / hwemul / tools / hwemul_tool.c
blobd75cd7a95779145aafbb76677e6a9e2f5621aa8b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2012 by Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
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>
30 bool g_quiet = false;
31 struct hwemul_device_t hwdev;
32 struct hwemul_soc_t *cur_soc = NULL;
34 void print_log(struct hwemul_device_t *hwdev)
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);
47 int print_help()
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;
64 int syntax_error(char *str)
66 printf("Syntax error at '%s'. Type 'help' to get some help.\n", str);
67 return 1;
70 int parse_uint32(char *str, uint32_t *u)
72 char *end;
73 *u = strtoul(str, &end, 0);
74 return *end == 0;
77 int do_call(uint32_t a)
79 hwemul_call(&hwdev, a);
80 return 1;
83 int parse_call()
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);
93 int do_read32(uint32_t a)
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;
103 int parse_read32()
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);
113 int do_write32(uint32_t val, uint32_t a)
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;
122 int parse_write32()
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);
136 struct hwemul_soc_t *find_soc_by_name(const char *soc)
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;
145 struct hwemul_soc_reg_t *find_reg_by_name(struct hwemul_soc_t *soc, const char *reg)
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;
153 struct hwemul_soc_reg_field_t *find_field_by_name(struct hwemul_soc_reg_t *reg, const char *field)
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;
162 int do_read(char *regname)
164 char *dot = strchr(regname, '.');
165 if(dot != NULL)
166 *dot++ = 0;
167 if(cur_soc == NULL)
169 printf("No soc selected!\n");
170 return 1;
172 struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname);
173 if(reg == NULL)
175 printf("no reg '%s' found\n", regname);
176 return 1;
178 uint32_t val;
179 if(hwemul_rw_mem(&hwdev, 1, reg->addr, &val, sizeof(val)) != sizeof(val))
181 printf("read error at %#x\n", reg->addr);
182 return 1;
184 if(dot)
186 struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot);
187 if(field == NULL)
189 printf("no field '%s' found\n", dot);
190 return 1;
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);
196 else
197 printf("%s = %#x\n", regname, val);
198 return 1;
201 int parse_read()
203 char *arg = strtok(NULL, " ");
204 if(arg)
205 return do_read(arg);
206 else
207 return syntax_error(arg);
210 int do_soc(char *soc)
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;
220 int parse_soc()
222 char *arg = strtok(NULL, " ");
223 if(arg)
224 return do_soc(arg);
225 else
226 return syntax_error(arg);
229 int do_write(uint32_t val, char *regname)
231 char *dot = strchr(regname, '.');
232 if(dot != NULL)
233 *dot++ = 0;
234 if(cur_soc == NULL)
236 printf("No soc selected!\n");
237 return 1;
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)
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
254 printf("no reg '%s' found\n", regname);
255 return 1;
257 is_sct = 1;
258 regname[len - 4] = 0;
259 reg = find_reg_by_name(cur_soc, regname);
260 if(reg == NULL)
262 printf("no reg '%s' found\n", regname);
263 return 1;
266 if(dot)
268 struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot);
269 if(field == NULL)
271 printf("no field '%s' found\n", dot);
272 return 1;
274 uint32_t actual_val = 0;
275 if(!is_sct)
277 if(hwemul_rw_mem(&hwdev, 1, reg->addr, &actual_val, sizeof(actual_val)) != sizeof(actual_val))
279 printf("read error at %#x\n", reg->addr);
280 return 1;
282 printf("read %#x at %#x\n", actual_val, reg->addr);
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);
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))
291 printf("write error at %#x\n", reg->addr);
292 return 1;
294 return 1;
297 int parse_write()
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);
310 int parse_command(char *cmd)
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);
331 void interactive_mode(void)
333 rl_bind_key('\t', rl_complete);
334 while(1)
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;
347 void usage(void)
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);
362 int main(int argc, char **argv)
364 while(1)
366 static struct option long_options[] =
368 {"help", no_argument, 0, '?'},
369 {"quiet", no_argument, 0, 'q'},
370 {0, 0, 0, 0}
373 int c = getopt_long(argc, argv, "?q", long_options, NULL);
374 if(c == -1)
375 break;
376 switch(c)
378 case -1:
379 break;
380 case 'q':
381 g_quiet = true;
382 break;
383 case '?':
384 usage();
385 break;
386 default:
387 abort();
391 if(argc - optind != 0)
393 usage();
394 return 1;
397 libusb_context *ctx;
398 libusb_init(&ctx);
399 libusb_set_debug(ctx, 3);
401 if(!g_quiet)
402 printf("Looking for device %#04x:%#04x...\n", HWEMUL_USB_VID, HWEMUL_USB_PID);
404 libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
405 HWEMUL_USB_VID, HWEMUL_USB_PID);
406 if(handle == NULL)
408 printf("No device found\n");
409 return 1;
412 libusb_device *mydev = libusb_get_device(handle);
413 if(!g_quiet)
415 printf("device found at %d:%d\n",
416 libusb_get_bus_number(mydev),
417 libusb_get_device_address(mydev));
419 hwdev.handle = handle;
420 if(hwemul_probe(&hwdev))
422 printf("Cannot probe device!\n");
423 return 1;
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))
430 printf("Cannot get version!\n");
431 goto Lerr;
433 if(!g_quiet)
434 printf("Device version: %d.%d.%d\n", ver.major, ver.minor, ver.revision);
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))
440 printf("Cannot get layout: %d\n", ret);
441 goto Lerr;
443 if(!g_quiet)
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);
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))
455 printf("Cannot get features: %d\n", ret);
456 goto Lerr;
458 if(!g_quiet)
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");
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))
478 printf("Cannot get stmp: %d\n", ret);
479 goto Lerr;
481 if(!g_quiet)
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);
489 if(!g_quiet)
491 void *rom = malloc(64 * 1024);
492 ret = hwemul_rw_mem(&hwdev, 1, 0xc0000000, rom, 64 * 1024);
493 if(ret != 64 * 1024)
495 printf("Cannot read ROM: %d\n", ret);
496 goto Lerr;
499 printf("ROM successfully read!\n");
500 FILE *f = fopen("rom.bin", "wb");
501 fwrite(rom, 64 * 1024, 1, f);
502 fclose(f);
505 if(!g_quiet)
507 struct
509 uint8_t iv[16];
510 uint8_t data[16];
511 } __attribute__((packed)) dcp_test;
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");
528 if(!hwemul_aes_otp(&hwdev, &dcp_test, sizeof(dcp_test), HWEMUL_AES_OTP_ENCRYPT))
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");
540 else
541 printf("DCP error!\n");
544 if(!g_quiet)
545 printf("Starting interactive session. Type 'help' to get help.\n");
547 interactive_mode();
549 Lerr:
550 if(features.feature_mask & HWEMUL_FEATURE_LOG)
552 if(!g_quiet)
553 printf("Device log:\n");
554 print_log(&hwdev);
556 hwemul_release(&hwdev);
557 return 1;