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:
Sean Cross 2014-07-18 18:43:47 +08:00
parent 70c8695eee
commit 11a84110f1
2 changed files with 115 additions and 670 deletions

779
main.c
View file

@ -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,80 +212,120 @@ 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) { switch (buf) {
case ' ': /* Read. Format: r[otf]aaaaaaaa
case '\0': otf -> read One, Two, or Four bytes
break; 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 'm': /* Write. Format: w[otf]aaaaaaaavvvvvvvv
/* 0x70000000 - 0x7000ffff -> Stack, OCRAM? */ otf -> write One, Two, or Four bytes
memory_test(0x0ffe0000, 0x40000000); a.. -> address to write
break; 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 'h': default:
hex_print(line + 1); serial_putc('?');
break; 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;
} }
} }

View file

@ -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");