180 lines
3.9 KiB
C
180 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");
|
||
|
}
|