888 lines
18 KiB
C
888 lines
18 KiB
C
#include <string.h>
|
|
#include "serial.h"
|
|
#include "utils.h"
|
|
#include "bionic.h"
|
|
|
|
#define AUTOMATED
|
|
|
|
#if defined(AUTOMATED)
|
|
#define PROMPT "fernly> \n"
|
|
#else
|
|
#define PROMPT "fernly> "
|
|
#endif
|
|
|
|
/* memcpy utils, from extbl */
|
|
const char iram_utils_0[] =
|
|
"\x02\x00\x51\xe1\x04\x30\x90\x34\x04\x30\x81\x34\xfb\xff\xff\x3a"
|
|
"\x0e\xf0\xa0\xe1\x01\x00\x50\xe1\xf8\xff\xff\x8a\x0e\xf0\xa0\x01"
|
|
"\x01\x30\x42\xe0\x04\x30\x43\xe2\x01\x20\xa0\xe1\x03\x00\x80\xe0"
|
|
"\x03\x10\x81\xe0\x02\x00\x51\xe1\x04\x30\x10\xa4\x04\x30\x01\xa4"
|
|
"\xfb\xff\xff\xaa\x0e\xf0\xa0\xe1\x00\x20\xa0\xe3\x01\x00\x50\xe1"
|
|
"\x04\x20\x80\x34\xfb\xff"
|
|
;
|
|
const int iram_utils_0_size = 86;
|
|
|
|
const char iram_utils_1[] =
|
|
"\xf8\xb5\x00\x10\xd0\x73\x00\x70\xe8\x00\x00\x00\xb4\x10\x00\x00"
|
|
"\xb8\x74\x00\x70\x28\x92\x00\x10\x00\x50\x00\x70\x74\x23\x00\x00"
|
|
"\x00\x00\x00\x00\x74\x73\x00\x70\x50\x91\x00\x10\x00\x20\x01\x00"
|
|
"\xd8\x00\x00\x00\x8c\x0d\x00\x00\xd8\x20\x01\x00\x9c\xb5\x00\x10"
|
|
"\x74\x73\x00\x70\x5c\x00\x00\x00\x30\xb5\x08\x00\x80\x30\xc2\x6a"
|
|
"\x01\x24\x02\x23\x14\x70\x53\x70\x80\x23\x93\x70\x3c\x25\xd3\x70"
|
|
"\x15\x71\x53\x71\x03\x6b\x9f\x22\x9a\x72\x03\x6b\x35\x22\xda\x73"
|
|
"\x03\x6b\xc0\x31\x5a\x73\x03\x6b\x05\x22\xda\x72\x02\x6b\x14\x73"
|
|
"\x03\x6b\x75\x22\x9a\x70\x00\x6b\x7a\x22\xc2\x70\x16\x20\x08\x70"
|
|
"\x9e\x48\x48\x61\x00\x20\x30\xbd\x00\x20\x70\x47\x30\xb5\x0d\x00"
|
|
"\x80\x31\xcc\x6a\x29\x00\xff\xf7\xcf\xff\x00\x20\xa0\x70\xe0\x70"
|
|
"\x02\x20\xc0\x35\x28\x70\x00\x20\x30\xbd\x02\x00\xc0\x32\x10\xb5"
|
|
"\x00\x29\x02\xd1\x51\x69\x88\x47\x0c\xe0\x01\x29\x0a\xd1\x51\x78"
|
|
"\xc2\x29\x07\xd1\x41\x69\x01\x20\x09\x68\x80\x04\x81\x42\x01\xd1"
|
|
"\xc2\x20\x10\xbd\x00\x20\x10\xbd"
|
|
;
|
|
|
|
extern void ram_memcpy(const void *src, int dest_start, int dest_end);
|
|
extern void ram_bzero(int dest_start, int dest_end);
|
|
#define RAM_MEMCPY_OFFSET ((void *)0x70007374)
|
|
|
|
static int serial_get_line(uint8_t *bfr, int len)
|
|
{
|
|
int cur = 0;
|
|
|
|
while (cur < len) {
|
|
bfr[cur] = serial_getc();
|
|
#if !defined(AUTOMATED)
|
|
serial_putc(bfr[cur]);
|
|
#endif
|
|
|
|
/* 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;
|
|
}
|
|
|
|
static void writeb(uint8_t value, uint32_t addr)
|
|
{
|
|
*((volatile uint8_t *)addr) = value;
|
|
}
|
|
|
|
static uint8_t readb(uint32_t addr)
|
|
{
|
|
return *(volatile uint8_t *)addr;
|
|
}
|
|
|
|
static void writew(uint16_t value, uint32_t addr)
|
|
{
|
|
*((volatile uint16_t *)addr) = value;
|
|
}
|
|
|
|
static uint16_t readw(uint32_t addr)
|
|
{
|
|
return *(volatile uint16_t *)addr;
|
|
}
|
|
|
|
static void writel(uint32_t value, uint32_t addr)
|
|
{
|
|
*((volatile uint32_t *)addr) = value;
|
|
}
|
|
|
|
static uint32_t readl(uint32_t addr)
|
|
{
|
|
return *(volatile uint32_t *)addr;
|
|
}
|
|
|
|
static int memory_test(uint32_t start, uint32_t length)
|
|
{
|
|
int addr;
|
|
register uint32_t val = 0xdeadbeef;
|
|
register uint32_t test;
|
|
uint32_t end = start + length;
|
|
|
|
printf("Testing memory from %08x to %08x", start, end);
|
|
|
|
for (addr = start; addr < end; addr += 4) {
|
|
if (! (addr & 0xffff))
|
|
printf("\nAddress %08x...", addr);
|
|
|
|
writel(val, addr);
|
|
test = readl(addr);
|
|
if (test != val)
|
|
printf("Address %08x appears to be invalid! "
|
|
"Expected 0xdeadbeef, got 0x%08x\n",
|
|
addr, test);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wdt_kick(void)
|
|
{
|
|
writel(0x1971, 0xa0030008);
|
|
return 0;
|
|
}
|
|
|
|
static int wdt_reboot(void)
|
|
{
|
|
writel(0x1209, 0xa003001c);
|
|
return 0;
|
|
}
|
|
|
|
int memory_search(uint32_t start, uint32_t length, uint32_t nonce, uint32_t mask)
|
|
{
|
|
int addr;
|
|
register uint32_t test;
|
|
uint32_t end = start + length;
|
|
|
|
printf("Looking in memory from %08x to %08x for nonce %08x\n",
|
|
start, end, nonce);
|
|
|
|
for (addr = start; addr < end; addr += 0x800) {
|
|
// if (! (addr & 0xffff)) {
|
|
printf("\rAddress %08x...", addr);
|
|
wdt_kick();
|
|
// }
|
|
|
|
test = readw(addr);
|
|
if ((test & mask) == nonce)
|
|
printf(" %08x matches nonce\n", addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int list_registers(void)
|
|
{
|
|
int var;
|
|
|
|
printf("Registers:\n");
|
|
|
|
printf("CPSR: ");
|
|
asm volatile ("mrs %0, cpsr":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("SPSR: ");
|
|
asm volatile ("mrs %0, spsr":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R0: ");
|
|
asm volatile ("mov %0, r0":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R1: ");
|
|
asm volatile ("mov %0, r1":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R2: ");
|
|
asm volatile ("mov %0, r2":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R3: ");
|
|
asm volatile ("mov %0, r3":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R4: ");
|
|
asm volatile ("mov %0, r4":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R5: ");
|
|
asm volatile ("mov %0, r5":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R6: ");
|
|
asm volatile ("mov %0, r6":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R7: ");
|
|
asm volatile ("mov %0, r7":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R8: ");
|
|
asm volatile ("mov %0, r8":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R9: ");
|
|
asm volatile ("mov %0, r9":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R10: ");
|
|
asm volatile ("mov %0, r10":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("FP: ");
|
|
asm volatile ("mov %0, r11":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("IP: ");
|
|
asm volatile ("mov %0, r12":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("SP: ");
|
|
asm volatile ("mov %0, r13":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R14: ");
|
|
asm volatile ("mov %0, r14":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("R15: ");
|
|
asm volatile ("mov %0, r15":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
printf("LR: ");
|
|
asm volatile ("mov %0, lr":"=r" (var));
|
|
serial_puth(var, 8);
|
|
printf("\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int read_address(uint8_t *arg)
|
|
{
|
|
int bytes = 4;
|
|
uint32_t addr;
|
|
|
|
/* If the address begins with 'o', read one byte, 't' two, 'f' four */
|
|
if (*arg == 't') {
|
|
bytes = 2;
|
|
arg++;
|
|
}
|
|
else if (*arg == 'o') {
|
|
bytes = 1;
|
|
arg++;
|
|
}
|
|
else if (*arg == 'f') {
|
|
bytes = 4;
|
|
arg++;
|
|
}
|
|
|
|
addr = _strtoul(arg, 0, 16);
|
|
|
|
if (bytes == 1)
|
|
printf("%08x: %02x\n", addr, readb(addr));
|
|
else if (bytes == 2)
|
|
printf("%08x: %04x\n", addr, readw(addr));
|
|
else
|
|
printf("%08x: %08x\n", addr, readl(addr));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int write_address(uint8_t *arg)
|
|
{
|
|
uint8_t *valpos;
|
|
uint32_t val;
|
|
uint32_t addr;
|
|
int bytes = 4;
|
|
|
|
/* If the address begins with 'o', read one byte, 't' two, 'f' four */
|
|
if (*arg == 't') {
|
|
bytes = 2;
|
|
arg++;
|
|
}
|
|
else if (*arg == 'o') {
|
|
bytes = 1;
|
|
arg++;
|
|
}
|
|
else if (*arg == 'f') {
|
|
bytes = 4;
|
|
arg++;
|
|
}
|
|
|
|
addr = _strtoul(arg, (void **)&valpos, 16);
|
|
val = _strtoul(valpos, 0, 16);
|
|
|
|
if (bytes == 1) {
|
|
printf("%08x: %02x\n", addr, val);
|
|
writeb(val, addr);
|
|
}
|
|
else if (bytes == 2) {
|
|
printf("%08x: %04x\n", addr, val);
|
|
writew(val, addr);
|
|
}
|
|
else if (bytes == 4) {
|
|
printf("%08x: %08x\n", addr, val);
|
|
writel(val, addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hex_print(uint8_t *arg)
|
|
{
|
|
uint8_t *valpos;
|
|
uint32_t *addr = (uint32_t *)_strtoul(arg, (void **)&valpos, 16);
|
|
uint32_t count = 0;
|
|
int i;
|
|
|
|
if (valpos)
|
|
count = _strtoul(valpos, 0, 16);
|
|
if (!count)
|
|
count = 256;
|
|
|
|
uint32_t data[count / 4];
|
|
for (i = 0; i < ((sizeof(data) / sizeof(*data))); i++)
|
|
data[i] = addr[i];
|
|
|
|
printf("%08x:\n", (uint32_t)addr);
|
|
serial_print_hex(data, sizeof(data));
|
|
printf("\n");
|
|
return 0;
|
|
}
|
|
|
|
#define IRQ_BASE 0xa0060180
|
|
|
|
#define IRQ_MASK_SET_LOW 0x20
|
|
#define IRQ_MASK_SET_HIGH 0x24
|
|
|
|
#define IRQ_MASK_CLEAR_LOW 0x40
|
|
#define IRQ_MASK_CLEAR_HIGH 0x44
|
|
|
|
#define IRQ_SCAN_DEPTH 0x1000
|
|
#define IRQ_SCAN_START 0x020
|
|
static int find_irqs(void)
|
|
{
|
|
/* There should be a mask register, a mask-clear register, and a
|
|
mask-set register. Look through memory for a register containing
|
|
the value 0xffffffff. Then, try setting it to 0x00000000. If
|
|
that fails, try another address.
|
|
|
|
If that succeeds, mark it as a candidate for the IRQ Mask
|
|
Register.
|
|
|
|
Then, begin writing 0xffffffff to other registers, trying to make
|
|
the candidate go from 0x00000000 to 0xffffffff. If no candidate
|
|
is found, continue.
|
|
|
|
If you find this, then you have a good candidate for the IRQ Mask
|
|
Set register. Begin looking again for a register that, when
|
|
written to, sets the mask register to 0x00000000 again.
|
|
*/
|
|
|
|
//int base_num;
|
|
uint32_t base = 0xa0050000;
|
|
|
|
printf("Trying to look for IRQ tables...\n");
|
|
|
|
writel(0, 0xa0180820);
|
|
//for (base = 0xa0180850; base < 0xa0180a00; base += 4) {
|
|
for (base = 0xa0010410; base < 0xa0030500; base += 4) {
|
|
printf("Investigating addr 0x%08x...\n", base);
|
|
writel(1, base);
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
uint32_t mask_offset;
|
|
uint32_t set_offset;
|
|
uint32_t clear_offset;
|
|
|
|
//if (!(base & 0x7ffff))
|
|
printf("Investigating base 0x%08x...\n", base);
|
|
wdt_kick();
|
|
/* Look for mask register */
|
|
for (mask_offset = IRQ_SCAN_START;
|
|
mask_offset < IRQ_SCAN_DEPTH;
|
|
mask_offset += 4) {
|
|
|
|
/* In our little world, offset registers can be set
|
|
* to 0xffffffff */
|
|
|
|
/* Try setting the register, make sure it sets */
|
|
writel(0xffffffff, mask_offset + base);
|
|
if (readl(mask_offset + base) == 0)
|
|
continue;
|
|
|
|
/* Try clearing the register, make sure it clears */
|
|
writel(0x00000000, mask_offset + base);
|
|
if (readl(mask_offset + base) != 0x00000000)
|
|
continue;
|
|
|
|
writel(0x00000000, mask_offset + base);
|
|
if (readl(mask_offset + base) != 0x00000000)
|
|
continue;
|
|
|
|
writel(0xffffffff, mask_offset + base);
|
|
if (readl(mask_offset + base) == 0)
|
|
continue;
|
|
|
|
writel(0xffffffff, mask_offset + base);
|
|
if (readl(mask_offset + base) == 0)
|
|
continue;
|
|
|
|
printf(" Candidate mask register at 0x%08x\n",
|
|
base + mask_offset);
|
|
|
|
/* Candidate mask offset. Look for clear
|
|
* register */
|
|
wdt_kick();
|
|
for (clear_offset = (mask_offset - 0x20);
|
|
clear_offset < (mask_offset + 0x20);
|
|
clear_offset += 4) {
|
|
uint32_t old_mask;
|
|
|
|
if (clear_offset == mask_offset)
|
|
continue;
|
|
|
|
writel(0xffffffff, mask_offset + base);
|
|
old_mask = readl(mask_offset + base);
|
|
writel(0xffffffff, clear_offset + base);
|
|
if (readl(mask_offset + base) == old_mask)
|
|
continue;
|
|
|
|
printf(" Candidate clear register at 0x%08x\n",
|
|
base + clear_offset);
|
|
|
|
/* Candidate for mask and clear offsets,
|
|
* look for set offset
|
|
*/
|
|
wdt_kick();
|
|
for (set_offset = (mask_offset - 0x20);
|
|
set_offset < (mask_offset + 0x20);
|
|
set_offset += 4) {
|
|
|
|
if (set_offset == mask_offset)
|
|
continue;
|
|
|
|
if (set_offset == clear_offset)
|
|
continue;
|
|
|
|
/* If we write and the mask changes, we
|
|
* might have a set register */
|
|
writel(0x00000000, mask_offset + base);
|
|
old_mask = readl(mask_offset + base);
|
|
writel(0xffffffff, set_offset + base);
|
|
if (readl(mask_offset + base) == old_mask)
|
|
continue;
|
|
|
|
|
|
|
|
printf("Candidate for IRQ mask/set/clear:\n");
|
|
printf(" Base: 0x%08x\n", base);
|
|
printf(" Mask: 0x%08x\n", mask_offset);
|
|
printf(" Set: 0x%08x\n", set_offset);
|
|
printf(" Clear: 0x%08x\n", clear_offset);
|
|
while(1)
|
|
wdt_kick();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int enable_irq(void)
|
|
{
|
|
int var;
|
|
asm volatile ("mrs %0, cpsr":"=r" (var));
|
|
if (!(var & 0x80)) {
|
|
printf("Interrupts already enabled\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("Interrupts were disabled. Re-enabling...\n");
|
|
var &= ~0x80;
|
|
var &= ~0x1f;
|
|
var |= 0x10;
|
|
asm volatile ("msr cpsr, %0":"=r" (var));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int enable_fiq(void)
|
|
{
|
|
int var;
|
|
asm volatile ("mrs %0, cpsr":"=r" (var));
|
|
if (!(var & 0x40)) {
|
|
printf("FIQ already enabled\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("FIQ was disabled. Re-enabling...\n");
|
|
var &= ~0x40;
|
|
asm volatile ("msr cpsr, %0":"=r" (var));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void gpio_set(unsigned int gpio, int value)
|
|
{
|
|
uint32_t gpio_dr_reg;
|
|
uint32_t gpio_dr_mask;
|
|
uint32_t gpio_dr_val;
|
|
|
|
uint32_t gpio_dout_reg;
|
|
uint32_t gpio_dout_mask;
|
|
uint32_t gpio_dout_val;
|
|
|
|
uint32_t val;
|
|
|
|
if (gpio < 16) {
|
|
gpio_dr_reg = 0xa0020000;
|
|
gpio_dout_reg = 0xa0020300;
|
|
}
|
|
else if (gpio < 32) {
|
|
gpio_dr_reg = 0xa0020010;
|
|
gpio_dout_reg = 0xa0020310;
|
|
}
|
|
else if (gpio < 48) {
|
|
gpio_dr_reg = 0xa0020020;
|
|
gpio_dout_reg = 0xa0020320;
|
|
}
|
|
else if (gpio < 64) {
|
|
gpio_dr_reg = 0xa0020030;
|
|
gpio_dout_reg = 0xa0020330;
|
|
}
|
|
else if (gpio < 73) {
|
|
gpio_dr_reg = 0xa0020040;
|
|
gpio_dout_reg = 0xa0020340;
|
|
}
|
|
else {
|
|
printf("Invalid GPIO selected: %d\n", gpio);
|
|
return;
|
|
}
|
|
|
|
gpio_dr_mask = ~(1 << (gpio & 15));
|
|
gpio_dout_mask = ~(1 << (gpio & 15));
|
|
|
|
/* Values less than 0 indicate input */
|
|
if (value < 0) {
|
|
gpio_dr_val = 0;
|
|
gpio_dout_val = 0; /* Value doesn't matter */
|
|
}
|
|
else {
|
|
gpio_dr_val = 1 << (gpio & 15);
|
|
if (value > 0)
|
|
gpio_dout_val = 1 << (gpio & 15);
|
|
else
|
|
gpio_dout_val = 0;
|
|
}
|
|
|
|
// printf("Setting GPIO%d -> %d\n", gpio, value);
|
|
|
|
val = (readw(gpio_dout_reg) & gpio_dout_mask) | gpio_dout_val;
|
|
// printf(" DOUT 0x%04x: 0x%04x -> 0x%04x\n",
|
|
// gpio_dout_reg, readw(gpio_dout_reg), val);
|
|
writew(val, gpio_dout_reg);
|
|
|
|
val = (readw(gpio_dr_reg) & gpio_dr_mask) | gpio_dr_val;
|
|
// printf(" DR 0x%04x: 0x%04x -> 0x%04x\n",
|
|
// gpio_dr_reg, readw(gpio_dr_reg), val);
|
|
writew(val, gpio_dr_reg);
|
|
}
|
|
|
|
static const uint8_t gpio_step_vals[] = {
|
|
50, 27, 26, 10, 3, 4, 25,
|
|
};
|
|
|
|
/* Connector pinout:
|
|
1 -
|
|
2 -
|
|
3 - GPIO27 / MCCM0 / JTDO
|
|
4 - (pwr?)
|
|
5 - GPIO25 / MCCK / JTRCK
|
|
6 - GND
|
|
7 - GPIO26 / MCDA0 / JTRSTB
|
|
8 -
|
|
*/
|
|
static int step_gpio(int step)
|
|
{
|
|
gpio_set(gpio_step_vals[step], 0);
|
|
step++;
|
|
if (step > 6)
|
|
step = 0;
|
|
|
|
if (step == 0)
|
|
printf("Step %d GPIO%d - MC2CM (JRTCK)\n",
|
|
step, gpio_step_vals[step]);
|
|
else if (step == 1) // Pin 3
|
|
printf("Step %d GPIO%d - MCCM0 (JTDO), pin 3\n",
|
|
step, gpio_step_vals[step]);
|
|
else if (step == 2) // Pin 7
|
|
printf("Step %d GPIO%d - MCDA0 (JTRSTB)\n",
|
|
step, gpio_step_vals[step]);
|
|
else if (step == 3)
|
|
printf("Step %d GPIO%d - MCDA3 (JTCK)\n",
|
|
step, gpio_step_vals[step]);
|
|
else if (step == 4)
|
|
printf("Step %d GPIO%d - MCDA1 (JTDI)\n",
|
|
step, gpio_step_vals[step]);
|
|
else if (step == 5)
|
|
printf("Step %d GPIO%d - MCDA2 (NONE)\n",
|
|
step, gpio_step_vals[step]);
|
|
else if (step == 6)
|
|
printf("Step %d GPIO%d - MCCK (JTRCK)\n",
|
|
step, gpio_step_vals[step]);
|
|
|
|
gpio_set(gpio_step_vals[step], 1);
|
|
|
|
return step;
|
|
}
|
|
|
|
#define set_gpio_mode(addr, offset, value) \
|
|
writel((readl(addr) & ~(0xf << offset)) | (value << offset), addr)
|
|
static int enable_jtag(void)
|
|
{
|
|
int mode;
|
|
|
|
mode = 0;
|
|
|
|
if (mode == 0) {
|
|
printf("Setting up JTAG using SD connector\n");
|
|
|
|
printf("\tGPIO50 (MC2CM) -> JRTCK\n");
|
|
set_gpio_mode(0xa0020c60, 8, 5);
|
|
|
|
printf("\tGPIO27 (MCCM0) -> JTDO\n");
|
|
set_gpio_mode(0xa0020c30, 12, 5);
|
|
|
|
printf("\tGPIO26 (MCDA0) -> JTRSTB\n");
|
|
set_gpio_mode(0xa0020c30, 8, 5);
|
|
|
|
printf("\tGPIO25 (MCCK) -> JTRCK\n");
|
|
set_gpio_mode(0xa0020c30, 4, 5);
|
|
|
|
printf("\tGPIO10 (MCDA3) -> JTCK\n");
|
|
set_gpio_mode(0xa0020c10, 8, 5);
|
|
|
|
printf("\tGPIO3 (MCDA1) -> JTDI\n");
|
|
set_gpio_mode(0xa0020c00, 12, 5);
|
|
}
|
|
else {
|
|
printf("Setting up JTAG using camera module\n");
|
|
|
|
printf("\tGPIO48 CMDAT1 -> JTMS\n");
|
|
printf("\tGPIO49 CMDAT2 -> JTCK\n");
|
|
printf("\tGPIO50 CMDAT3 -> JRTCK\n");
|
|
printf("\tGPIO51 CMDAT4 -> JTRST_B\n");
|
|
printf("\tGPIO52 CMDAT5 -> JTDO\n");
|
|
|
|
writel(0x00055555, 0xa0020c60);
|
|
}
|
|
|
|
printf("\tDone.\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int setup_priorities(void)
|
|
{
|
|
writel(0x43415453, 0xf0244a88);
|
|
writel(0x444e454b, 0xf0244a8c);
|
|
|
|
writel(0x43415453, 0x7000a5d8);
|
|
writel(0x444e454b, 0x7000a5dc);
|
|
|
|
writel(0x43415453, 0xf0244a08);
|
|
writel(0x444e454b, 0xf0244a0c);
|
|
|
|
writel(0x43415453, 0xf0244908);
|
|
writel(0x444e454b, 0xf024490c);
|
|
|
|
writel(0x43415453, 0xf0244988);
|
|
writel(0x444e454b, 0xf0244988);
|
|
|
|
writel(0x43415453, 0xf0244988);
|
|
writel(0x444e454b, 0xf024498c);
|
|
|
|
writel(0x43415453, 0x7000a680);
|
|
writel(0x444e454b, 0x7000a684);
|
|
return 0;
|
|
}
|
|
|
|
static int do_init(void)
|
|
{
|
|
void *rv_start = (void *)0x10003460;
|
|
void *rv_end = (void *)0x100034e0;
|
|
int i;
|
|
|
|
serial_init();
|
|
//setup_priorities();
|
|
|
|
/* Kick WDT */
|
|
writel(0x1971, 0xa0030008);
|
|
|
|
/* Disable WDT */
|
|
writel(0x2200, 0xa0030000);
|
|
|
|
printf("\n\nFernly shell\n");
|
|
|
|
/* Copy some utils to iram */
|
|
printf("Installing iram utils memcpy");
|
|
_memcpy(RAM_MEMCPY_OFFSET, iram_utils_0, iram_utils_0_size);
|
|
|
|
printf(" ram_memcpy(0)");
|
|
ram_memcpy(0, 0, 0);
|
|
|
|
printf(" ram_bzero(0)");
|
|
ram_bzero(0, 0);
|
|
|
|
printf(" ram_memcpy(0x700073d0)");
|
|
ram_memcpy(iram_utils_1, 0x700073d0, 0x700074b8);
|
|
|
|
printf(" ram_bzero(0x700074b8)");
|
|
ram_bzero(0x700074b8, 0x7000856c);
|
|
|
|
printf(" ok.\n");
|
|
|
|
/* Copy exception vectors to address 0 */
|
|
printf("Copying vectors");
|
|
printf(" Src: %p", rv_start);
|
|
printf(" Src end: %p", rv_end);
|
|
printf(" Size: %d\n", rv_end - rv_start);
|
|
printf("(%d bytes from %p to 0)...\n", rv_end - rv_start, rv_start);
|
|
_memcpy((void *)0, rv_start, rv_end - rv_start);
|
|
enable_irq();
|
|
enable_fiq();
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int step = 0;
|
|
list_registers();
|
|
do_init();
|
|
|
|
while (1) {
|
|
uint8_t line[256];
|
|
printf(PROMPT);
|
|
serial_get_line(line, sizeof(line));
|
|
#if !defined(AUTOMATED)
|
|
printf("\n");
|
|
#endif
|
|
|
|
switch(*line) {
|
|
case ' ':
|
|
case '\0':
|
|
break;
|
|
|
|
case 'm':
|
|
/* 0x70000000 - 0x7000ffff -> Stack, OCRAM? */
|
|
memory_test(0x0ffe0000, 0x40000000);
|
|
break;
|
|
|
|
case 'h':
|
|
hex_print(line + 1);
|
|
break;
|
|
|
|
case 'l':
|
|
list_registers();
|
|
break;
|
|
|
|
case 'i':
|
|
find_irqs();
|
|
break;
|
|
|
|
case 'j':
|
|
enable_jtag();
|
|
break;
|
|
|
|
case 'r':
|
|
read_address(line + 1);
|
|
break;
|
|
|
|
case 'w':
|
|
write_address(line + 1);
|
|
break;
|
|
|
|
case 'd':
|
|
printf("Kicking WDT...\n");
|
|
wdt_kick();
|
|
break;
|
|
|
|
case 'b':
|
|
printf("Rebooting (using WDT)...\n");
|
|
wdt_reboot();
|
|
break;
|
|
|
|
case 'c':
|
|
asm volatile ("swi 3");
|
|
break;
|
|
|
|
case 's':
|
|
step = step_gpio(step);
|
|
break;
|
|
|
|
default:
|
|
printf("Unknown command\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|