#include #include "bionic.h" #include "memio.h" #include "printf.h" #include "serial.h" #include "utils.h" //#define AUTOMATED #if !defined(AUTOMATED) #define PROMPT "fernly> " static int serial_get_line(char *bfr, int len) { int cur = 0; while (cur < len) { bfr[cur] = serial_getc(); serial_putc(bfr[cur]); /* Carriage Return */ if (bfr[cur] == '\n') { bfr[cur] = '\0'; return 0; } /* Linefeed */ else if (bfr[cur] == '\r') { bfr[cur] = '\0'; return 0; } /* Backspace */ else if (bfr[cur] == 0x7f) { bfr[cur] = '\0'; if (cur > 0) { serial_putc('\b'); serial_putc(' '); serial_putc('\b'); cur--; } } /* Ctrl-U */ else if (bfr[cur] == 0x15) { while (cur > 0) { serial_putc('\b'); serial_putc(' '); serial_putc('\b'); bfr[cur] = '\0'; cur--; } } /* Ctrl-W */ else if (bfr[cur] == 0x17) { while (cur > 0 && bfr[cur] != ' ') { serial_putc('\b'); serial_putc(' '); serial_putc('\b'); bfr[cur] = '\0'; cur--; } } /* Escape code */ else if (bfr[cur] == 0x1b) { /* Next two characters are escape codes */ uint8_t next = serial_getc(); /* Sanity check: next should be '[' */ next = serial_getc(); } else cur++; } bfr[len - 1] = '\0'; return -1; } #endif /* static int wdt_kick(void) { writel(0x1971, 0xa0030008); return 0; } */ static int wdt_reboot(void) { writel(0x1209, 0xa003001c); return 0; } static int list_registers(void) { int var; serial_puts("Registers:\n"); serial_puts("CPSR: "); asm volatile ("mrs %0, cpsr":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("SPSR: "); asm volatile ("mrs %0, spsr":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R0: "); asm volatile ("mov %0, r0":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R1: "); asm volatile ("mov %0, r1":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R2: "); asm volatile ("mov %0, r2":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R3: "); asm volatile ("mov %0, r3":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R4: "); asm volatile ("mov %0, r4":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R5: "); asm volatile ("mov %0, r5":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R6: "); asm volatile ("mov %0, r6":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R7: "); asm volatile ("mov %0, r7":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R8: "); asm volatile ("mov %0, r8":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R9: "); asm volatile ("mov %0, r9":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("R10: "); asm volatile ("mov %0, r10":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("FP: "); asm volatile ("mov %0, r11":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("IP: "); asm volatile ("mov %0, r12":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("SP: "); asm volatile ("mov %0, r13":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("LR: "); asm volatile ("mov %0, r14":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); serial_puts("PC: "); asm volatile ("mov %0, r15":"=r" (var)); serial_puth(var, 8); serial_puts("\n"); return 0; } static int do_init(void) { list_registers(); /* Kick WDT */ writel(0x1971, 0xa0030008); /* Disable WDT */ writel(0x2200, 0xa0030000); serial_puts("\n\nFernly shell\n"); return 0; } static inline int get_hex(int bytes) { uint32_t word = 0; uint8_t buf; int i; if (bytes == 4) i = 28; else if (bytes == 2) i = 12; else i = 4; while (i >= 0) { buf = serial_getc(); if (buf > 96) buf -= 87; else if (buf > 64) buf -= 55; else buf -= 48; word |= (buf << i); i -= 4; } return word; } #ifdef AUTOMATED /* Protocol: * Stream is byte-oriented. The following commands are known: * * r - read an address * w - write to an address * z - zero-fill a region * * Responses: * * k - Ready for command * ? - Unknown command */ static int loop(void) { int buf; int size; uint32_t offset; uint32_t value; serial_putc('k'); buf = serial_getc(); switch (buf) { /* Read. Format: r[otf]aaaaaaaa otf -> read One, Two, or Four bytes a.. -> address to read */ case 'r': size = serial_getc(); if (size == 'o') { offset = get_hex(4); value = readb(offset); serial_puth(value, 2); } else if (size == 't') { offset = get_hex(4); value = readw(offset); serial_puth(value, 4); } else { offset = get_hex(4); value = readl(offset); serial_puth(value, 8); } break; case 'f': size = get_hex(4); break; /* Write. Format: w[otf]aaaaaaaavvvvvvvv otf -> write One, Two, or Four bytes a.. -> address to write v.. -> value to write */ case 'w': size = serial_getc(); if (size == 'o') { offset = get_hex(4); value = get_hex(1); writeb(value, offset); serial_puth(value, 2); } else if (size == 't') { offset = get_hex(4); value = get_hex(2); writew(value, offset); serial_puth(value, 4); } else { offset = get_hex(4); value = get_hex(4); writel(value, offset); serial_puth(value, 8); } break; case 'z': { uint32_t start; uint32_t end; start = get_hex(4); end = get_hex(4); while (start < end) { *((uint32_t *)start) = 0; start += 4; } } break; default: serial_putc('?'); break; } return 0; } #else /* AUTOMATED */ static int cmd_help(int argc, char **argv); static int cmd_hex(int argc, char **argv); static int cmd_peek(int argc, char **argv); static int cmd_poke(int argc, char **argv); static int cmd_swi(int argc, char **argv); static int cmd_reboot(int argc, char **argv); static int cmd_args(int argc, char **argv); int cmd_irq(int argc, char **argv); static const struct { int (*func)(int argc, char **argv); const char *name; const char *help; } commands[] = { { .func = cmd_help, .name = "help", .help = "Print help about available commands", }, { .func = cmd_reboot, .name = "reboot", .help = "Reboot Fernvale", }, { .func = cmd_hex, .name = "hex", .help = "Print area of memory as hex", }, { .func = cmd_peek, .name = "peek", .help = "Look at one area of memory", }, { .func = cmd_poke, .name = "poke", .help = "Write a value to an area of memory", }, { .func = cmd_irq, .name = "irq", .help = "Manipulate IRQs", }, { .func = cmd_args, .name = "args", .help = "Print contents of arc and argv", }, { .func = cmd_swi, .name = "swi", .help = "Generate software interrupt", }, }; int cmd_help(int argc, char **argv) { int i; printf("Fernly shell help. Available commands:\n"); for (i = 0; i < sizeof(commands) / sizeof(*commands); i++) { serial_putc('\t'); serial_puts(commands[i].name); serial_putc('\t'); serial_puts(commands[i].help); serial_puts("\n"); } return 0; } int cmd_args(int argc, char **argv) { int i; printf("argc: %d\n", argc); for (i = 0; i < argc; i++) { printf("argv[%d]: ", i); serial_puts(argv[i]); serial_puts("\n"); } return 0; } int cmd_hex(int argc, char **argv) { uint32_t offset; int count = 0x200; if (argc < 1) { printf("Usage: hex [offset] [[count]]\n"); return -1; } offset = _strtoul(argv[0], NULL, 0); if (argc > 1) count = _strtoul(argv[1], NULL, 0); serial_print_hex((const void *)offset, count); return 0; } int cmd_peek(int argc, char **argv) { uint32_t offset; if (argc < 1) { printf("Usage: peek [offset]\n"); return -1; } offset = _strtoul(argv[0], NULL, 0); printf("Value at 0x%08x: ", offset); printf("0x%08x\n", *((volatile uint32_t *)offset)); return 0; } int cmd_poke(int argc, char **argv) { uint32_t offset; uint32_t val; if (argc < 2) { printf("Usage: poke [offset] [val]\n"); return -1; } offset = _strtoul(argv[0], NULL, 0); val = _strtoul(argv[1], NULL, 0); printf("Setting value at 0x%08x to 0x%08x: ", offset, val); writel(val, offset); printf("Ok\n"); return 0; } int cmd_swi(int argc, char **argv) { printf("Generating SWI...\n"); asm volatile ("swi #0\n"); printf("Returned from SWI\n"); return 0; } int cmd_reboot(int argc, char **argv) { printf("Rebooting...\n"); wdt_reboot(); while(1); return 0; } static int shell_run_command(char *line) { char *lp, *cmd, *tokp; char *args[8]; int i, n; lp = _strtok(line, " \t", &tokp); cmd = lp; n = 0; while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) { if (n >= 7) { printf("too many arguments\r\n"); cmd = NULL; break; } args[n++] = lp; } args[n] = NULL; if (cmd == NULL) return -1; for (i = 0; i < sizeof(commands) / sizeof(*commands); i++) if (!_strcasecmp(commands[i].name, cmd)) return commands[i].func(n, args); printf("Unknown command: %s\n", args[0]); return 0; } static int loop(void) { char line[256]; serial_puts(PROMPT); serial_get_line(line, sizeof(line)); printf("\n"); return shell_run_command(line); } #endif int main(void) { do_init(); while (1) loop(); return 0; }