/* ** Copyright 2001, Brian Swetland ** All Rights Reserved. Please read the provided LICENSE file. */ #include #include #include #include "xtypes.h" #include "xproto.h" extern XIO *xio; void bytedump(u1 *ptr, int count) { u1 *x = ptr - count; int c; while(count < 16) { msg(" "); count++; } while(x < ptr){ c = *x++; if((c < ' ') || (c > 127)) { msg("."); } else { msg("%c",c); } } } void hexdump(u4 addr, u1 *ptr, u4 len) { int i, c = 0; for(i = 0; i < len; i++){ if((i & 15)) { msg("%02x ", *ptr++); } else { if(i > 0) { bytedump(ptr, 16); msg("\n"); } msg("%08x: %02x ",addr, *ptr++); addr += 16; } } bytedump(ptr, len % 16 ? len % 16 : 16); msg("\n"); } void hexdump16(u4 addr, u2 *ptr, u4 len) { int i, c = 0; for(i = 0; i < len; i+=2){ if((i & 15)) { msg("%04x ", *ptr++); } else { if(i > 0) msg("\n"); msg("%08x: %04x ",addr, *ptr++); addr += 16; } } msg("\n"); } void hexdump32(u4 addr, u4 *ptr, u4 len) { int i, c = 0; for(i = 0; i < len; i+=4){ if((i & 15)) { msg("%08x ", *ptr++); } else { if(i > 0) msg("\n"); msg("%08x: %08x ",addr, *ptr++); addr += 16; } } msg("\n"); } int number(char *text) { if(text[0] == '/') { return strtoul(text + 1, 0, 10); } else { return strtoul(text, 0, 16); } } void ADDR(int argc, char **argv, u4 *addr, u4 *len) { if(argc > 0) { *addr = number(argv[0]); argc--; argv++; } else { *addr = 0; } if(argc > 0) { *len = number(argv[0]); argc--; argv++; } else { *len = 128; } } void cmd_db(int argc, char **argv) { u4 addr, len; xframe f; ADDR(argc, argv, &addr, &len); f.cmd = XCMD_READ8; f.len = 16; f.u.w[0] = addr; f.u.w[1] = len; if(xio_rpc(xio, &f) > 0){ hexdump(addr, f.u.b, f.len - 8); } } void cmd_sb(int argc, char **argv) { xframe f; if(argc < 2) return; f.cmd = XCMD_WRITE8; f.len = 17; f.u.w[0] = number(argv[0]); f.u.w[1] = 1; f.u.b[8] = number(argv[1]); xio_rpc(xio, &f); } void cmd_sw(int argc, char **argv) { xframe f; if(argc < 2) return; f.cmd = XCMD_WRITE32; f.len = 20; f.u.w[0] = number(argv[0]); f.u.w[1] = 4; f.u.w[2] = number(argv[1]); xio_rpc(xio, &f); } void cmd_sh(int argc, char **argv) { xframe f; if(argc < 2) return; f.cmd = XCMD_WRITE16; f.len = 18; f.u.w[0] = number(argv[0]); f.u.w[1] = 2; f.u.h[4] = number(argv[1]); xio_rpc(xio, &f); } void cmd_dw(int argc, char **argv) { u4 addr, len; xframe f; ADDR(argc, argv, &addr, &len); f.cmd = XCMD_READ32; f.len = 16; f.u.w[0] = addr; f.u.w[1] = len; if(xio_rpc(xio, &f) > 0){ hexdump32(addr, f.u.w, f.len - 8); } } void cmd_dh(int argc, char **argv) { u4 addr, len; xframe f; ADDR(argc, argv, &addr, &len); f.cmd = XCMD_READ16; f.len = 16; f.u.w[0] = addr; f.u.w[1] = len; if(xio_rpc(xio, &f) > 0){ hexdump16(addr, f.u.h, f.len - 8); } } void cmd_ping(int argc, char **argv) { xframe f; f.cmd = XCMD_PING; f.len = 12; f.u.w[0] = 0xaead4222; if(xio_rpc(xio, &f) > 0) msg("PONG\n"); } void *load_file(const char *file, u4 *_size) { u1 *data; FILE *fp; u4 size,r; if((fp = fopen(file,"rb")) == 0) return 0; fseek(fp, 0, SEEK_END); size = ftell(fp); rewind(fp); if((data = (u1*) malloc(size)) == 0){ fclose(fp); return 0; } if((r = fread(data, size, 1, fp)) != 1) { fclose(fp); free(data); return 0; } fclose(fp); *_size = size; return data; } int upload(u4 addr, void *data, int len) { int retry, xmit; u1 *ptr; xframe f; int total = len + 1; int info = 3; ptr = (u1*) data; retry = 0; while(len > 0){ if(++info == 4) { status("loading %2d%%", 100 - ((len * 100) / total)); info = 0; } xmit = len > 1024 ? 1024 : len; memcpy(f.u.b + 8, ptr, xmit); f.u.w[0] = addr; f.u.w[1] = xmit; f.len = 16 + xmit; if((addr & 3) || (xmit & 3)) { f.cmd = XCMD_WRITE8; } else { f.cmd = XCMD_WRITE32; } if(xio_rpc(xio, &f) > 0) { retry = 0; len -= xmit; addr += xmit; ptr += xmit; } else { retry++; if(retry == 5) return -1; continue; } } return 0; } void cmd_load(int argc, char **argv) { void *data; u4 sz,addr; if(argc < 1) return; if(argc > 1) { addr = number(argv[1]); } else { addr = 0x02000000; } if((data = load_file(argv[0], &sz)) == 0) { msg("cannot load file '%s'\n",argv[0]); return; } if(upload(addr, data, sz)){ msg("load FAILED\n"); } else { msg("load OK\n"); } free(data); return; } void cmd_run(int argc, char **argv) { void *data; char *name; u4 sz; xframe f; u4 ADDR; if(argc < 1) { name = "boot.bin"; } else { name = argv[0]; } if(argc < 2) { ADDR = 0x02000000; } else { ADDR = number(argv[1]); } if((data = load_file(name, &sz)) == 0) { msg("cannot load file '%s'\n",name); return; } if(upload(ADDR, data, sz)){ msg("load FAILED\n"); } else { msg("load OK\n"); f.cmd = XCMD_CALL; f.len = 12; f.u.w[0] = ADDR; msg("CALL 0x%08x\n",ADDR); xio_rpc_nowait(xio, &f); } free(data); return; } void cmd_call(int argc, char **argv) { xframe f; if(argc != 1) return; f.cmd = XCMD_CALL; f.len = 12; f.u.w[0] = number(argv[0]); msg("CALL 0x%08x\n", f.u.w[0]); xio_rpc_nowait(xio, &f); } void cmd_reboot(int argc, char **argv) { xframe f; f.cmd = XCMD_REBOOT; f.len = 8; xio_rpc_nowait(xio, &f); } void cmd_flash(int argc, char **argv) { xframe f; if(argc != 2) return; f.cmd = XCMD_FLASH; f.len = 20; f.u.w[0] = FLASH_WRITE; f.u.w[1] = number(argv[0]); f.u.w[2] = number(argv[1]); xio_rpc(xio, &f); } void cmd_erase(int argc, char **argv) { xframe f; if(argc != 1) return; f.cmd = XCMD_FLASH; f.len = 20; f.u.w[0] = FLASH_ERASE; f.u.w[1] = number(argv[0]); f.u.w[2] = 0x00040000; xio_rpc(xio, &f); } void cmd_visoly_ram(int argc, char **argv) { xframe f; if(argc != 1) return; f.cmd = XCMD_VISOLY; f.len = 16; f.u.w[0] = 0x0942468a; f.u.w[1] = number(argv[0]); xio_rpc(xio, &f); } void cmd_visoly_rom(int argc, char **argv) { xframe f; if(argc != 1) return; f.cmd = XCMD_VISOLY; f.len = 16; f.u.w[0] = 0x096b592e; f.u.w[1] = number(argv[0]); xio_rpc(xio, &f); } void cmd_help(int, char**); static struct { const char *name; void (*func)(int, char **); const char *descr; } cmds[] = { { "help", cmd_help, 0 }, { "?", cmd_help, 0 }, { "ping", cmd_ping, "see if remote is alive" }, { "load", cmd_load, " [=0x02000000]" }, { "run", cmd_run, " [=0x02000000]" }, { "x", cmd_run, " [=0x02000000]" }, { "call", cmd_call, "" }, { "reboot", cmd_reboot, "reboot the gba" }, { "!", cmd_reboot, "reboot the gba" }, { "db", cmd_db, " -- dump bytes" }, { "dw", cmd_dw, " -- dump words" }, { "dh", cmd_dh, " -- dump halfwords" }, { "sb", cmd_sb, " -- set byte" }, { "sw", cmd_sw, " -- set word" }, { "sh", cmd_sh, " -- set halfword" }, { "erase", cmd_erase, " 256k flash @ addr" }, { "flash", cmd_flash, " (from 0x02000000)" }, { "farom", cmd_visoly_rom, " set FA rom offset register" }, { "faram", cmd_visoly_ram, " set FA ram offset register" }, { 0, 0 } }; void cmd_help(int argc, char **argv) { int i; for(i = 0; cmds[i].name != 0; i++) { if(cmds[i].descr == 0) continue; msg("%10s - %s\n",cmds[i].name,cmds[i].descr); } } static void tokenize( char *buf, int *argc, char **argv ) { *argc = 0; while( *buf == ' ' ) /* skip leading spaces */ buf++; if( *buf != 0 ) { /* empty string? */ argv[0] = buf; /* at least 1 arg */ (*argc)++; while( *buf != 0 ) { if( *buf == ' ' ) { *buf++ = 0; while( *buf == ' ' ) /* skip multiple spaces between args */ buf++; if (*buf != 0) { argv[*argc] = buf; (*argc)++; } } buf++; } } } void execute_command(char *cmd) { int i, argc; char *argv[128]; tokenize(cmd, &argc, argv); if(argc < 1) return; for (i = 0; cmds[i].name; i++) { if (!strcmp(argv[0], cmds[i].name)) { cmds[i].func(argc - 1, &argv[1]); return; } } msg("unknown command '%s' - use 'help' to get a list\n",argv[0]); }