fernly: Act as a shim for qemu
We're using bigger tools now. Now we just act as a shim for qemu.
This commit is contained in:
parent
70c8695eee
commit
11a84110f1
2 changed files with 115 additions and 670 deletions
767
main.c
767
main.c
|
@ -3,172 +3,37 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "bionic.h"
|
#include "bionic.h"
|
||||||
|
|
||||||
#define AUTOMATED
|
static inline void writeb(uint8_t value, uint32_t addr)
|
||||||
|
|
||||||
#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;
|
*((volatile uint8_t *)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t readb(uint32_t addr)
|
static inline uint8_t readb(uint32_t addr)
|
||||||
{
|
{
|
||||||
return *(volatile uint8_t *)addr;
|
return *(volatile uint8_t *)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writew(uint16_t value, uint32_t addr)
|
static inline void writew(uint16_t value, uint32_t addr)
|
||||||
{
|
{
|
||||||
*((volatile uint16_t *)addr) = value;
|
*((volatile uint16_t *)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t readw(uint32_t addr)
|
static inline uint16_t readw(uint32_t addr)
|
||||||
{
|
{
|
||||||
return *(volatile uint16_t *)addr;
|
return *(volatile uint16_t *)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writel(uint32_t value, uint32_t addr)
|
static inline void writel(uint32_t value, uint32_t addr)
|
||||||
{
|
{
|
||||||
*((volatile uint32_t *)addr) = value;
|
*((volatile uint32_t *)addr) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t readl(uint32_t addr)
|
static inline uint32_t readl(uint32_t addr)
|
||||||
{
|
{
|
||||||
return *(volatile 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)
|
static int wdt_kick(void)
|
||||||
{
|
{
|
||||||
writel(0x1971, 0xa0030008);
|
writel(0x1971, 0xa0030008);
|
||||||
|
@ -180,29 +45,7 @@ static int wdt_reboot(void)
|
||||||
writel(0x1209, 0xa003001c);
|
writel(0x1209, 0xa003001c);
|
||||||
return 0;
|
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)
|
static int list_registers(void)
|
||||||
{
|
{
|
||||||
|
@ -308,242 +151,6 @@ static int list_registers(void)
|
||||||
return 0;
|
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)
|
static int enable_irq(void)
|
||||||
{
|
{
|
||||||
int var;
|
int var;
|
||||||
|
@ -578,199 +185,14 @@ static int enable_fiq(void)
|
||||||
return 0;
|
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)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
void *rv_start = (void *)0x10003460;
|
void *rv_start = (void *)0x10003460;
|
||||||
void *rv_end = (void *)0x100034e0;
|
void *rv_end = (void *)0x100034e0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
list_registers();
|
||||||
serial_init();
|
serial_init();
|
||||||
//setup_priorities();
|
|
||||||
|
|
||||||
/* Kick WDT */
|
/* Kick WDT */
|
||||||
writel(0x1971, 0xa0030008);
|
writel(0x1971, 0xa0030008);
|
||||||
|
@ -779,24 +201,7 @@ static int do_init(void)
|
||||||
writel(0x2200, 0xa0030000);
|
writel(0x2200, 0xa0030000);
|
||||||
|
|
||||||
printf("\n\nFernly shell\n");
|
printf("\n\nFernly shell\n");
|
||||||
|
#if 0
|
||||||
/* 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 */
|
/* Copy exception vectors to address 0 */
|
||||||
printf("Copying vectors");
|
printf("Copying vectors");
|
||||||
|
@ -807,79 +212,119 @@ static int do_init(void)
|
||||||
_memcpy((void *)0, rv_start, rv_end - rv_start);
|
_memcpy((void *)0, rv_start, rv_end - rv_start);
|
||||||
enable_irq();
|
enable_irq();
|
||||||
enable_fiq();
|
enable_fiq();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int step = 0;
|
int buf;
|
||||||
list_registers();
|
int cmd;
|
||||||
|
int size;
|
||||||
|
int i;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t value;
|
||||||
do_init();
|
do_init();
|
||||||
|
|
||||||
|
/* Protocol:
|
||||||
|
Stream is byte-oriented. The following commands are known:
|
||||||
|
|
||||||
|
r - read an address
|
||||||
|
w - write to an address
|
||||||
|
|
||||||
|
Responses:
|
||||||
|
|
||||||
|
k - Ready for command
|
||||||
|
? - Unknown command
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
uint8_t line[256];
|
serial_putc('k');
|
||||||
printf(PROMPT);
|
buf = serial_getc();
|
||||||
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;
|
|
||||||
|
|
||||||
|
switch (buf) {
|
||||||
|
/* Read. Format: r[otf]aaaaaaaa
|
||||||
|
otf -> read One, Two, or Four bytes
|
||||||
|
a.. -> address to read
|
||||||
|
*/
|
||||||
case 'r':
|
case 'r':
|
||||||
read_address(line + 1);
|
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;
|
break;
|
||||||
|
|
||||||
|
/* Write. Format: w[otf]aaaaaaaavvvvvvvv
|
||||||
|
otf -> write One, Two, or Four bytes
|
||||||
|
a.. -> address to write
|
||||||
|
v.. -> value to write
|
||||||
|
*/
|
||||||
case 'w':
|
case 'w':
|
||||||
write_address(line + 1);
|
size = serial_getc();
|
||||||
break;
|
if (size == 'o') {
|
||||||
|
offset = get_hex(4);
|
||||||
case 'd':
|
value = get_hex(1);
|
||||||
printf("Kicking WDT...\n");
|
writeb(value, offset);
|
||||||
wdt_kick();
|
serial_puth(value, 2);
|
||||||
break;
|
}
|
||||||
|
else if (size == 't') {
|
||||||
case 'b':
|
offset = get_hex(4);
|
||||||
printf("Rebooting (using WDT)...\n");
|
value = get_hex(2);
|
||||||
wdt_reboot();
|
writew(value, offset);
|
||||||
break;
|
serial_puth(value, 4);
|
||||||
|
}
|
||||||
case 'c':
|
else {
|
||||||
asm volatile ("swi 3");
|
offset = get_hex(4);
|
||||||
break;
|
value = get_hex(4);
|
||||||
|
writel(value, offset);
|
||||||
case 's':
|
serial_puth(value, 8);
|
||||||
step = step_gpio(step);
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("Unknown command\n");
|
serial_putc('?');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
/* Reset handler calls main() directly */
|
|
||||||
/*
|
|
||||||
void reset_handler(void) {
|
void reset_handler(void) {
|
||||||
extern int main(int argc, char **argv);
|
extern int main(int argc, char **argv);
|
||||||
|
serial_putc('<');
|
||||||
|
printf("Reset exception\n");
|
||||||
|
serial_putc('>');
|
||||||
main(1, 0);
|
main(1, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
void undef_handler(void) {
|
void undef_handler(void) {
|
||||||
printf("Undefined instruction exception\n");
|
printf("Undefined instruction exception\n");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue