ardix/arch/at91sam3x8e/handle_fault.c

168 lines
3.8 KiB
C

/* See the end of this file for copyright, license, and warranty information. */
#include <arch-generic/hardware.h>
#include <arch/hardware.h>
#include <arch/interrupt.h>
#include <toolchain.h>
/** Setup UART to manual byte-by-byte control */
static inline void uart_emergency_setup(void)
{
REG_UART_PDC_PTCR = REG_UART_PDC_PTCR_RXTDIS_MASK | REG_UART_PDC_PTCR_TXTDIS_MASK;
REG_UART_CR = REG_UART_CR_RXDIS_MASK | REG_UART_CR_RSTRX_MASK
| REG_UART_CR_TXDIS_MASK | REG_UART_CR_RSTTX_MASK;
REG_UART_IDR = 0xffffffff;
REG_UART_CR = REG_UART_CR_RXEN_MASK | REG_UART_CR_TXEN_MASK;
}
static void uart_write_sync(const char *s)
{
char c;
while ((c = *s++) != '\0') {
mom_are_we_there_yet(REG_UART_SR & REG_UART_SR_TXRDY_MASK);
REG_UART_THR = c;
}
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
static inline void print_err_msg(enum irqno irqno)
{
switch (irqno) {
case IRQNO_HARD_FAULT:
uart_write_sync("Hard");
break;
case IRQNO_MM_FAULT:
uart_write_sync("Memory Management");
break;
case IRQNO_BUS_FAULT:
uart_write_sync("Bus");
break;
case IRQNO_USAGE_FAULT:
uart_write_sync("Usage");
break;
}
uart_write_sync(" Fault encountered, system halted.\n\n");
}
#pragma GCC diagnostic pop /* -Wswitch */
static void reg_to_str(char *dest, uint32_t val)
{
for (int i = 28; i >= 0; i -= 4) {
uint8_t digit = (val >> i) & 0x0f;
if (digit < 0x0a)
digit += '0';
else
digit += 'a';
*dest++ = digit;
}
}
static void print_regs(struct reg_snapshot *regs)
{
static char reg_line[] = "r0 = 0x????????\n";
char *reg_val = &reg_line[8]; /* first question mark */
reg_to_str(reg_val, regs->hw.r0);
uart_write_sync(reg_line);
reg_line[1] = '1';
reg_to_str(reg_val, regs->hw.r1);
uart_write_sync(reg_line);
reg_line[1] = '2';
reg_to_str(reg_val, regs->hw.r2);
uart_write_sync(reg_line);
reg_line[1] = '3';
reg_to_str(reg_val, regs->hw.r3);
uart_write_sync(reg_line);
reg_line[1] = '4';
reg_to_str(reg_val, regs->sw.r4);
uart_write_sync(reg_line);
reg_line[1] = '5';
reg_to_str(reg_val, regs->sw.r5);
uart_write_sync(reg_line);
reg_line[1] = '6';
reg_to_str(reg_val, regs->sw.r6);
uart_write_sync(reg_line);
reg_line[1] = '7';
reg_to_str(reg_val, regs->sw.r7);
uart_write_sync(reg_line);
reg_line[1] = '8';
reg_to_str(reg_val, regs->sw.r8);
uart_write_sync(reg_line);
reg_line[1] = '9';
reg_to_str(reg_val, regs->sw.r9);
uart_write_sync(reg_line);
reg_line[1] = '1';
reg_line[2] = '0';
reg_to_str(reg_val, regs->sw.r10);
uart_write_sync(reg_line);
reg_line[2] = '1';
reg_to_str(reg_val, regs->sw.r11);
uart_write_sync(reg_line);
reg_line[2] = '2';
reg_to_str(reg_val, regs->hw.r12);
uart_write_sync(reg_line);
reg_line[0] = 's';
reg_line[1] = 'p';
reg_line[2] = ' ';
reg_to_str(reg_val, (uint32_t)(regs + 1)); /* where SP was before reg save */
uart_write_sync(reg_line);
reg_line[0] = 'l';
reg_line[1] = 'r';
reg_to_str(reg_val, (uint32_t)regs->hw.lr);
uart_write_sync(reg_line);
reg_line[0] = 'p';
reg_line[1] = 'c';
reg_to_str(reg_val, (uint32_t)regs->hw.pc);
uart_write_sync(reg_line);
}
#include <arch/debug.h>
__naked __noreturn void arch_handle_fault(struct reg_snapshot *regs, enum irqno irqno)
{
uart_emergency_setup();
print_err_msg(irqno);
print_regs(regs);
/* give developers a chance to inspect the system */
__breakpoint;
/* but never leave this function */
while (1);
}
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/