119 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <cstdint>
 | |
| 
 | |
| #include "gpio.h"
 | |
| #include "itoa.h"
 | |
| #include "sleep.h"
 | |
| #include "trace.h"
 | |
| #include "uart.h"
 | |
| 
 | |
| extern "C" uint32_t _initial_stack_pointer, _text_begin, _text_end;
 | |
| 
 | |
| namespace crash {
 | |
| namespace {
 | |
| [[maybe_unused]] void CrashHexDump(uint32_t* begin, uint32_t* end,
 | |
|                                    int direction = 1) {
 | |
|     char number[] = "00000000 ";
 | |
|     char addr[] = "00000000: ";
 | |
|     int i = 0;
 | |
|     itoa(reinterpret_cast<uint32_t>(begin), addr);
 | |
|     UartWriteCrash(addr);
 | |
|     for (uint32_t* ptr = begin; direction > 0 ? ptr < end : ptr > end;
 | |
|          ptr += direction, i++) {
 | |
|         itoa(*ptr, number);
 | |
|         UartWriteCrash(number);
 | |
|         if (i % 4 == 3) {
 | |
|             UartWriteCrash("\r\n");
 | |
|             itoa(reinterpret_cast<uint32_t>(ptr + 1), addr);
 | |
|             UartWriteCrash(addr);
 | |
|         }
 | |
|     }
 | |
|     if (i % 4 != 3) {
 | |
|         UartWriteCrash("\r\n");
 | |
|     }
 | |
| }
 | |
| 
 | |
| void StackTrace(uint32_t* sp) {
 | |
|     char number[] = "00000000\r\n";
 | |
|     for (uint32_t* ptr = sp; ptr < &_initial_stack_pointer; ptr++) {
 | |
|         auto addr = reinterpret_cast<uint32_t*>(*ptr);
 | |
|         if (addr < &_text_begin || addr >= &_text_end || (*ptr & 0x1) == 0) {
 | |
|             continue;
 | |
|         }
 | |
|         itoa(*ptr, number);
 | |
|         UartWriteCrash(number);
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct Armv6mRegs {
 | |
|     uintptr_t r4;
 | |
|     uintptr_t r5;
 | |
|     uintptr_t r6;
 | |
|     uintptr_t r7;
 | |
|     uintptr_t r8;
 | |
|     uintptr_t r9;
 | |
|     uintptr_t r10;
 | |
|     uintptr_t r11;
 | |
|     uintptr_t sp;
 | |
| 
 | |
|     // saved by the CPU
 | |
|     uintptr_t r0;
 | |
|     uintptr_t r1;
 | |
|     uintptr_t r2;
 | |
|     uintptr_t r3;
 | |
|     uintptr_t r12;
 | |
|     uintptr_t lr;
 | |
|     uintptr_t pc;
 | |
|     uintptr_t xpsr;
 | |
| };
 | |
| 
 | |
| void CrashHandler(Armv6mRegs* regs) {
 | |
|     char number[] = "00000000\r\n";
 | |
| 
 | |
|     UartWriteCrash("\r\n\r\nCra$h!!\r\n- xpsr: 0x");
 | |
|     itoa(regs->xpsr, number);
 | |
|     UartWriteCrash(number);
 | |
|     UartWriteCrash("- pc: 0x");
 | |
|     itoa(regs->pc, number);
 | |
|     UartWriteCrash(number);
 | |
|     UartWriteCrash("- lr: 0x");
 | |
|     itoa(regs->lr, number);
 | |
|     UartWriteCrash(number);
 | |
|     UartWriteCrash("- Stack trace:\r\n");
 | |
|     StackTrace(reinterpret_cast<uint32_t*>(regs->sp));
 | |
| 
 | |
|     tracing::dump();
 | |
| 
 | |
|     while (1) {
 | |
|         gpio0->data = 0x55;
 | |
|         sleep(100);
 | |
|         gpio0->data = 0xaa;
 | |
|         sleep(100);
 | |
|     }
 | |
| }
 | |
| }  // namespace
 | |
| 
 | |
| __attribute__((naked)) void HardFaultHandler() {
 | |
|     asm volatile(
 | |
|         // set those leds first
 | |
|         "mov r0, %0            \n"
 | |
|         "mov r1, #0xa5         \n"
 | |
|         "str r1, [r0]          \n"
 | |
| 
 | |
|         "mov r0, r8            \n"
 | |
|         "mov r1, r9            \n"
 | |
|         "mov r2, r10           \n"
 | |
|         "mov r3, r11           \n"
 | |
|         "mrs lr, msp           \n"
 | |
|         "push {r0-r3, lr}      \n"
 | |
|         "push {r4-r7}          \n"
 | |
|         :
 | |
|         : "r"(gpio0));
 | |
|     asm volatile(
 | |
|         "mrs r0, msp           \n"
 | |
|         "mov r1, %0            \n"
 | |
|         "blx r1                \n"
 | |
|         :
 | |
|         : "r"(CrashHandler));
 | |
| }
 | |
| }  // namespace crash
 |