2021-01-16 15:45:10 +00:00
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
2021-01-30 06:14:38 +00:00
|
|
|
#include "exception.h"
|
2021-01-16 15:45:10 +00:00
|
|
|
#include "uart.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
extern char _vectors_start[0];
|
|
|
|
|
2021-01-30 06:14:38 +00:00
|
|
|
volatile enum exc_guard_t exc_guard = GUARD_OFF;
|
|
|
|
volatile int exc_count = 0;
|
|
|
|
|
|
|
|
#define SYS_L2C_ERR_STS sys_reg(3, 3, 15, 8, 0)
|
|
|
|
#define SYS_L2C_ERR_ADR sys_reg(3, 3, 15, 9, 0)
|
|
|
|
#define SYS_L2C_ERR_INF sys_reg(3, 3, 15, 10, 0)
|
|
|
|
#define SYS_LSU_ERR_STS sys_reg(3, 3, 15, 0, 0)
|
|
|
|
#define SYS_FED_ERR_STS sys_reg(3, 4, 15, 0, 0)
|
|
|
|
#define SYS_MMU_ERR_STS sys_reg(3, 6, 15, 0, 0)
|
|
|
|
#define SYS_E_LSU_ERR_STS sys_reg(3, 3, 15, 2, 0)
|
|
|
|
#define SYS_E_FED_ERR_STS sys_reg(3, 4, 15, 0, 2)
|
|
|
|
#define SYS_E_MMU_ERR_STS sys_reg(3, 6, 15, 2, 0)
|
|
|
|
|
2021-01-16 15:45:10 +00:00
|
|
|
void exception_initialize(void)
|
|
|
|
{
|
|
|
|
msr(vbar_el2, _vectors_start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_regs(u64 *regs)
|
|
|
|
{
|
2021-01-17 16:57:16 +00:00
|
|
|
u64 sp = ((u64)(regs)) + 256;
|
2021-01-16 15:45:10 +00:00
|
|
|
|
|
|
|
printf("Running in EL%d\n", mrs(CurrentEL) >> 2);
|
2021-01-30 06:14:38 +00:00
|
|
|
printf("MPIDR: 0x%x\n", mrs(MPIDR_EL1));
|
2021-01-16 15:45:10 +00:00
|
|
|
printf("Registers: (@%p)\n", regs);
|
2021-01-28 06:27:35 +00:00
|
|
|
printf(" x0-x3: %016lx %016lx %016lx %016lx\n", regs[0], regs[1], regs[2], regs[3]);
|
|
|
|
printf(" x4-x7: %016lx %016lx %016lx %016lx\n", regs[4], regs[5], regs[6], regs[7]);
|
|
|
|
printf(" x8-x11: %016lx %016lx %016lx %016lx\n", regs[8], regs[9], regs[10], regs[11]);
|
|
|
|
printf("x12-x15: %016lx %016lx %016lx %016lx\n", regs[12], regs[13], regs[14], regs[15]);
|
|
|
|
printf("x16-x19: %016lx %016lx %016lx %016lx\n", regs[16], regs[17], regs[18], regs[19]);
|
|
|
|
printf("x20-x23: %016lx %016lx %016lx %016lx\n", regs[20], regs[21], regs[22], regs[23]);
|
|
|
|
printf("x24-x27: %016lx %016lx %016lx %016lx\n", regs[24], regs[25], regs[26], regs[27]);
|
2021-01-16 15:45:10 +00:00
|
|
|
printf("x28-x30: %016lx %016lx %016lx\n", regs[28], regs[29], regs[30]);
|
|
|
|
|
|
|
|
u64 elr = mrs(elr_el2);
|
|
|
|
|
|
|
|
printf("PC: 0x%lx (rel: 0x%lx)\n", elr, elr - (u64)_base);
|
2021-01-30 06:14:38 +00:00
|
|
|
printf("SPSEL: 0x%lx\n", mrs(SPSEL));
|
2021-01-16 15:45:10 +00:00
|
|
|
printf("SP: 0x%lx\n", sp);
|
2021-01-30 06:14:38 +00:00
|
|
|
printf("SPSR_EL2: 0x%x\n", mrs(SPSR_EL2));
|
|
|
|
printf("ESR_EL2: 0x%x\n", mrs(ESR_EL2));
|
|
|
|
|
|
|
|
printf("L2C_ERR_STS: 0x%lx\n", mrs(SYS_L2C_ERR_STS));
|
|
|
|
printf("L2C_ERR_ADR: 0x%lx\n", mrs(SYS_L2C_ERR_ADR));
|
|
|
|
printf("L2C_ERR_INF: 0x%lx\n", mrs(SYS_L2C_ERR_INF));
|
|
|
|
|
|
|
|
if (is_ecore()) {
|
|
|
|
printf("SYS_E_LSU_ERR_STS: 0x%lx\n", mrs(SYS_E_LSU_ERR_STS));
|
|
|
|
printf("SYS_E_FED_ERR_STS: 0x%lx\n", mrs(SYS_E_FED_ERR_STS));
|
|
|
|
printf("SYS_E_MMU_ERR_STS: 0x%lx\n", mrs(SYS_E_MMU_ERR_STS));
|
|
|
|
} else {
|
|
|
|
printf("SYS_LSU_ERR_STS: 0x%lx\n", mrs(SYS_LSU_ERR_STS));
|
|
|
|
printf("SYS_FED_ERR_STS: 0x%lx\n", mrs(SYS_FED_ERR_STS));
|
|
|
|
printf("SYS_MMU_ERR_STS: 0x%lx\n", mrs(SYS_MMU_ERR_STS));
|
|
|
|
}
|
2021-01-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void exc_sync(u64 *regs)
|
|
|
|
{
|
2021-01-30 06:14:38 +00:00
|
|
|
u64 elr;
|
|
|
|
u32 insn;
|
|
|
|
|
2021-01-16 15:45:10 +00:00
|
|
|
uart_puts("Exception: SYNC");
|
|
|
|
|
|
|
|
print_regs(regs);
|
2021-01-30 06:14:38 +00:00
|
|
|
|
|
|
|
switch (exc_guard) {
|
|
|
|
case GUARD_SKIP:
|
|
|
|
elr = mrs(ELR_EL2) + 4;
|
|
|
|
break;
|
|
|
|
case GUARD_MARK:
|
|
|
|
// Assuming this is a load or store, dest reg is in low bits
|
|
|
|
insn = read32(mrs(ELR_EL2));
|
|
|
|
regs[insn & 0x1f] = 0xacce5515abad1dea;
|
|
|
|
elr = mrs(ELR_EL2) + 4;
|
|
|
|
break;
|
|
|
|
case GUARD_RETURN:
|
|
|
|
regs[0] = 0xacce5515abad1dea;
|
|
|
|
elr = regs[30];
|
|
|
|
exc_guard = GUARD_OFF;
|
|
|
|
break;
|
|
|
|
case GUARD_OFF:
|
|
|
|
default:
|
|
|
|
reboot();
|
|
|
|
}
|
|
|
|
|
|
|
|
exc_count++;
|
|
|
|
|
|
|
|
printf("Recovering from exception (ELR=0x%lx)\n", elr);
|
|
|
|
msr(ELR_EL2, elr);
|
2021-01-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void exc_irq(u64 *regs)
|
|
|
|
{
|
2021-01-23 13:32:35 +00:00
|
|
|
#ifdef DEBUG_UART_IRQS
|
|
|
|
u32 ucon, utrstat, uerstat, ufstat;
|
|
|
|
ucon = read32(0x235200004);
|
|
|
|
utrstat = read32(0x235200010);
|
|
|
|
uerstat = read32(0x235200014);
|
|
|
|
ufstat = read32(0x235200018);
|
|
|
|
#endif
|
|
|
|
|
2021-01-16 15:45:10 +00:00
|
|
|
uart_puts("Exception: IRQ");
|
|
|
|
|
|
|
|
u32 reason = read32(0x23b102004);
|
|
|
|
|
|
|
|
printf(" type: %d num: %d\n", reason >> 16, reason & 0xffff);
|
|
|
|
|
2021-01-23 13:32:35 +00:00
|
|
|
#ifdef DEBUG_UART_IRQS
|
|
|
|
printf(" UCON: 0x%x\n", ucon);
|
|
|
|
printf(" UTRSTAT: 0x%x\n", utrstat);
|
|
|
|
printf(" UERSTAT: 0x%x\n", uerstat);
|
|
|
|
printf(" UFSTAT: 0x%x\n", ufstat);
|
|
|
|
#endif
|
2021-01-16 20:57:43 +00:00
|
|
|
UNUSED(regs);
|
2021-01-16 15:45:10 +00:00
|
|
|
// print_regs(regs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void exc_fiq(u64 *regs)
|
|
|
|
{
|
|
|
|
uart_puts("Exception: FIQ");
|
|
|
|
|
|
|
|
u32 timer_ctl = mrs(CNTP_CTL_EL0);
|
|
|
|
|
|
|
|
if (timer_ctl == 0x5) {
|
|
|
|
uart_puts(" timer IRQ, masking");
|
2021-01-16 19:44:44 +00:00
|
|
|
msr(CNTP_CTL_EL0, 7L);
|
2021-01-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
2021-01-16 20:57:43 +00:00
|
|
|
UNUSED(regs);
|
2021-01-16 15:45:10 +00:00
|
|
|
// print_regs(regs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void exc_serr(u64 *regs)
|
|
|
|
{
|
|
|
|
printf("Exception: SError\n");
|
|
|
|
|
|
|
|
print_regs(regs);
|
|
|
|
reboot();
|
|
|
|
}
|