/* See the end of this file for copyright, license, and warranty information. */ #include #include #include #include /** 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 = ®_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 __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 . * * 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 * . * * Ardix comes with ABSOLUTELY NO WARRANTY, to the extent * permitted by applicable law. See the CNPLv6+ for details. */