pi1541/exception.c
2018-05-20 14:53:34 +10:00

179 lines
3.9 KiB
C

#include "rpi-base.h"
#include "rpi-aux.h"
#include "rpi-gpio.h"
#include "rpi-interrupts.h"
#include "defs.h"
#include "startup.h"
// From here: https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=53862
void reboot_now(void)
{
const int PM_PASSWORD = 0x5a000000;
const int PM_RSTC_WRCFG_FULL_RESET = 0x00000020;
unsigned int *PM_WDOG = (unsigned int *) (PERIPHERAL_BASE + 0x00100024);
unsigned int *PM_RSTC = (unsigned int *) (PERIPHERAL_BASE + 0x0010001c);
// timeout = 1/16th of a second? (whatever)
*PM_WDOG = PM_PASSWORD | 1;
*PM_RSTC = PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
while(1);
}
void dump_digit(unsigned int c) {
c &= 15;
if (c < 10) {
c = '0' + c;
} else {
c = 'A' + c - 10;
}
RPI_AuxMiniUartWrite(c);
}
void dump_hex(unsigned int value) {
int i;
for (i = 0; i < 8; i++) {
int c = value >> 28;
if (c < 10) {
c = '0' + c;
} else {
c = 'A' + c - 10;
}
RPI_AuxMiniUartWrite(c);
value <<= 4;
}
}
void dump_binary(unsigned int value) {
int i;
for (i = 0; i < 32; i++) {
int c = '0' + (value >> 31);
RPI_AuxMiniUartWrite(c);
value <<= 1;
}
}
void dump_string(char *string) {
char c;
while ((c = *string++) != 0) {
RPI_AuxMiniUartWrite(c);
}
}
// For some reason printf generally doesn't work here
void dump_info(unsigned int *context, int offset, char *type) {
unsigned int *addr;
unsigned int *reg;
unsigned int flags;
int i, j;
//int rstlow;
//int led;
// Make sure we avoid unaligned accesses
context = (unsigned int *)(((unsigned int) context) & ~3);
// context point into the exception stack, at flags, followed by registers 0 .. 13
reg = context + 1;
dump_string(type);
dump_string(" at ");
// The stacked LR points one or two words afer the exception address
addr = (unsigned int *)((reg[13] & ~3) - offset);
dump_hex((unsigned int)addr);
#ifdef HAS_MULTICORE
//dump_string(" on core ");
//dump_digit(_get_core());
#endif
dump_string("\r\n");
dump_string("Registers:\r\n");
for (i = 0; i <= 13; i++) {
j = (i < 13) ? i : 14; // slot 13 actually holds the link register
dump_string(" r[");
RPI_AuxMiniUartWrite('0' + (j / 10));
RPI_AuxMiniUartWrite('0' + (j % 10));
dump_string("]=");
dump_hex(reg[i]);
dump_string("\r\n");
}
dump_string("Memory:\r\n");
for (i = -4; i <= 4; i++) {
dump_string(" ");
dump_hex((unsigned int) (addr + i));
RPI_AuxMiniUartWrite('=');
dump_hex(*(addr + i));
if (i == 0) {
dump_string(" <<<<<< \r\n");
} else {
dump_string("\r\n");
}
}
// The flags are pointed to by context, before the registers
flags = *context;
dump_string("Flags: \r\n NZCV--------------------IFTMMMMM\r\n ");
dump_binary(flags);
dump_string(" (");
// The last 5 bits of the flags are the mode
switch (flags & 0x1f) {
case 0x10:
dump_string("User");
break;
case 0x11:
dump_string("FIQ");
break;
case 0x12:
dump_string("IRQ");
break;
case 0x13:
dump_string("Supervisor");
break;
case 0x17:
dump_string("Abort");
break;
case 0x1B:
dump_string("Undefined");
break;
case 0x1F:
dump_string("System");
break;
default:
dump_string("Illegal");
break;
};
dump_string(" Mode)\r\n");
dump_string("Halted waiting for reset\r\n");
//rstlow = 0;
//led = 0;
// while (1) {
//for (i = 0; i < 1000000; i++) {
// // look for reset being low
// if (tube_is_rst_active()) {
// rstlow = 1;
// }
// // then reset on the next rising edge
// if (rstlow && (!tube_is_rst_active())) {
// reboot_now();
// }
//}
//if (led) {
// LED_OFF();
//} else {
// LED_ON();
//}
//led = ~led;
// }
}
void undefined_instruction_handler(unsigned int *context) {
dump_info(context, 4, "Undefined Instruction");
}
void prefetch_abort_handler(unsigned int *context) {
dump_info(context, 4, "Prefetch Abort");
}
void data_abort_handler(unsigned int *context) {
dump_info(context, 8, "Data Abort");
}
void swi_handler(unsigned int *context) {
dump_info(context, 4, "SWI");
}