foboot/third_party/libbase/exception.c

212 lines
5.3 KiB
C
Raw Normal View History

#include <generated/csr.h>
#include <stdio.h>
#include <stdarg.h>
void isr(void);
#ifdef __or1k__
#include <hw/flags.h>
#define EXTERNAL_IRQ 0x8
static void emerg_printf(const char *fmt, ...)
{
char buf[512];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
char *p = buf;
while(*p) {
while(uart_txfull_read());
uart_rxtx_write(*p++);
}
}
static char emerg_getc(void)
{
while(uart_rxempty_read());
char c = uart_rxtx_read();
uart_ev_pending_write(UART_EV_RX);
return c;
}
static const char hex[] = "0123456789abcdef";
static void gdb_send(const char *txbuf)
{
unsigned char cksum = 0;
const char *p = txbuf;
while(*p) cksum += *p++;
emerg_printf("+$%s#%c%c", txbuf, hex[cksum >> 4], hex[cksum & 0xf]);
}
static void gdb_recv(char *rxbuf, size_t size)
{
size_t pos = (size_t)-1;
for(;;) {
char c = emerg_getc();
if(c == '$')
pos = 0;
else if(c == '#')
return;
else if(pos < size - 1) {
rxbuf[pos++] = c;
rxbuf[pos] = 0;
}
}
}
static void gdb_stub(unsigned long pc, unsigned long sr,
unsigned long r1, unsigned long *regs)
{
gdb_send("S05");
char buf[385];
for(;;) {
gdb_recv(buf, sizeof(buf));
switch(buf[0]) {
case '?': {
snprintf(buf, sizeof(buf), "S05");
break;
}
case 'g': {
snprintf(buf, sizeof(buf),
"%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x"
"%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x"
"%08x%08x%08x",
0, r1, regs[2], regs[3], regs[4], regs[5], regs[6], regs[7],
regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15],
regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23],
regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31],
pc-4, pc, sr);
break;
}
case 'm': {
unsigned long addr, len;
char *endptr = &buf[0];
addr = strtoul(endptr + 1, &endptr, 16);
len = strtoul(endptr + 1, &endptr, 16);
unsigned char *ptr = (unsigned char *)addr;
if(len > sizeof(buf) / 2) len = sizeof(buf) / 2;
for(size_t i = 0; i < len; i++) {
buf[i*2 ] = hex[ptr[i] >> 4];
buf[i*2+1] = hex[ptr[i] & 15];
buf[i*2+2] = 0;
}
break;
}
case 'p': {
unsigned long reg, value;
char *endptr = &buf[0];
reg = strtoul(endptr + 1, &endptr, 16);
if(reg == 0)
value = 0;
else if(reg == 1)
value = r1;
else if(reg >= 2 && reg <= 31)
value = regs[reg];
else if(reg == 33)
value = pc;
else if(reg == 34)
value = sr;
else {
snprintf(buf, sizeof(buf), "E01");
break;
}
snprintf(buf, sizeof(buf), "%08x", value);
break;
}
case 'P': {
unsigned long reg, value;
char *endptr = &buf[0];
reg = strtoul(endptr + 1, &endptr, 16);
value = strtoul(endptr + 1, &endptr, 16);
if(reg == 0)
/* ignore */;
else if(reg == 1)
r1 = value;
else if(reg >= 2 && reg <= 31)
regs[reg] = value;
else if(reg == 33)
pc = value;
else if(reg == 34)
sr = value;
else {
snprintf(buf, sizeof(buf), "E01");
break;
}
snprintf(buf, sizeof(buf), "OK");
break;
}
case 'c': {
if(buf[1] != '\0') {
snprintf(buf, sizeof(buf), "E01");
break;
}
return;
}
default:
snprintf(buf, sizeof(buf), "");
break;
}
do {
gdb_send(buf);
} while(emerg_getc() == '-');
}
}
void exception_handler(unsigned long vect, unsigned long *regs,
unsigned long pc, unsigned long ea, unsigned long sr);
void exception_handler(unsigned long vect, unsigned long *regs,
unsigned long pc, unsigned long ea, unsigned long sr)
{
if(vect == EXTERNAL_IRQ) {
isr();
} else {
emerg_printf("\n *** Unhandled exception %d *** \n", vect);
emerg_printf(" pc %08x sr %08x ea %08x\n",
pc, sr, ea);
unsigned long r1 = (unsigned long)regs + 4*32;
regs -= 2;
emerg_printf(" r0 %08x r1 %08x r2 %08x r3 %08x\n",
0, r1, regs[2], regs[3]);
emerg_printf(" r4 %08x r5 %08x r6 %08x r7 %08x\n",
regs[4], regs[5], regs[6], regs[7]);
emerg_printf(" r8 %08x r9 %08x r10 %08x r11 %08x\n",
regs[8], regs[9], regs[10], regs[11]);
emerg_printf(" r12 %08x r13 %08x r14 %08x r15 %08x\n",
regs[12], regs[13], regs[14], regs[15]);
emerg_printf(" r16 %08x r17 %08x r18 %08x r19 %08x\n",
regs[16], regs[17], regs[18], regs[19]);
emerg_printf(" r20 %08x r21 %08x r22 %08x r23 %08x\n",
regs[20], regs[21], regs[22], regs[23]);
emerg_printf(" r24 %08x r25 %08x r26 %08x r27 %08x\n",
regs[24], regs[25], regs[26], regs[27]);
emerg_printf(" r28 %08x r29 %08x r30 %08x r31 %08x\n",
regs[28], regs[29], regs[30], regs[31]);
emerg_printf(" stack:\n");
unsigned long *sp = (unsigned long *)r1;
for(unsigned long spoff = 0; spoff < 16; spoff += 4) {
emerg_printf(" %08x:", &sp[spoff]);
for(unsigned long spoff2 = 0; spoff2 < 4; spoff2++) {
emerg_printf(" %08x", sp[spoff + spoff2]);
}
emerg_printf("\n");
}
emerg_printf(" waiting for gdb... ");
gdb_stub(pc, sr, r1, regs);
}
}
#endif