diff --git a/include/arm11/debug.h b/include/arm11/debug.h
new file mode 100644
index 0000000..b8fde2c
--- /dev/null
+++ b/include/arm11/debug.h
@@ -0,0 +1,28 @@
+#pragma once
+
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "types.h"
+
+
+
+void debugHashCodeRoData();
+noreturn void panic();
+noreturn void panicMsg(const char *msg);
+void dumpMem(u8 *mem, u32 size, char *filepath);
diff --git a/include/ipc_handler.h b/include/ipc_handler.h
index 2f9cf0f..e78f4ca 100644
--- a/include/ipc_handler.h
+++ b/include/ipc_handler.h
@@ -24,7 +24,7 @@
#define IPC_MAX_PARAMS (15)
#define IPC_CMD_ID_MASK(cmd) ((cmd)>>24)
#define IPC_CMD_IN_BUFS_MASK(cmd) ((cmd)>>20 & 0xFu)
-#define IPC_CMD_OUT_BUFS_MASK(cmd) ((cmd)>>26 & 0xFu)
+#define IPC_CMD_OUT_BUFS_MASK(cmd) ((cmd)>>16 & 0xFu)
#define IPC_CMD_PARAMS_MASK(cmd) ((cmd)>>12 & 0xFu)
diff --git a/include/mem_map.h b/include/mem_map.h
index c5fd94b..8ec6c75 100644
--- a/include/mem_map.h
+++ b/include/mem_map.h
@@ -144,4 +144,6 @@
#define A11_HEAP_END (AXIWRAM_BASE + AXIWRAM_SIZE + DSP_MEM_SIZE)
#define A11_STACK_START (A11_STUB_ENTRY - 0xE00)
#define A11_STACK_END (A11_STUB_ENTRY)
+#define A11_EXC_STACK_START (VRAM_BASE + VRAM_SIZE - 0x200000)
+#define A11_EXC_STACK_END (VRAM_BASE + VRAM_SIZE - 0x100000)
#endif
diff --git a/source/arm11/debug.c b/source/arm11/debug.c
new file mode 100644
index 0000000..554eada
--- /dev/null
+++ b/source/arm11/debug.c
@@ -0,0 +1,164 @@
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include "types.h"
+#include "mem_map.h"
+#include "arm11/console.h"
+#include "arm11/fmt.h"
+#include "fs.h"
+#include "hardware/pxi.h"
+#include "hardware/gfx.h"
+#include "arm11/hardware/interrupt.h"
+
+static u32 debugHash = 0;
+
+
+void debugHashCodeRoData()
+{
+#ifndef NDEBUG
+ extern u32 __start__[];
+ extern u32 __exidx_start[];
+
+ u32 *start = __start__;
+ u32 *end = __exidx_start;
+
+ debugHash = 0;
+
+ for(u32 *ptr = start; ptr < end; ptr++)
+ debugHash += *ptr;
+#endif
+}
+
+noreturn void panic()
+{
+ register u32 lr __asm__("lr");
+
+ consoleInit(SCREEN_SUB, NULL, false);
+
+ ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr);
+
+ //fsUnmountAll();
+ //devs_close();
+
+ GX_textureCopy((u64*)RENDERBUF_TOP, (240 * 2)>>4, (u64*)GFX_getFramebuffer(SCREEN_TOP),
+ (240 * 2)>>4, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB);
+ GFX_swapFramebufs();
+
+ while(1) waitForInterrupt();
+}
+
+noreturn void panicMsg(const char *msg)
+{
+ register u32 lr __asm__("lr");
+
+ consoleInit(SCREEN_SUB, NULL, false);
+
+ ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr);
+ ee_printf("\nERROR MESSAGE:\n%s\n", msg);
+
+ //fsUnmountAll();
+ //devs_close();
+
+ GX_textureCopy((u64*)RENDERBUF_TOP, (240 * 2)>>4, (u64*)GFX_getFramebuffer(SCREEN_TOP),
+ (240 * 2)>>4, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB);
+ GFX_swapFramebufs();
+
+ while(1) waitForInterrupt();
+}
+
+// Expects the registers in the exception stack to be in the following order:
+// r0-r14, pc (unmodified), cpsr
+noreturn void guruMeditation(u8 type, const u32 *excStack)
+{
+ const char *const typeStr[3] = {"Undefined instruction", "Prefetch abort", "Data abort"};
+ u32 realPc, instSize = 4;
+ bool codeChanged = false;
+
+
+ // verify text and rodata
+ /*u32 prevHash = debugHash;
+ debugHashCodeRoData();
+ if(prevHash != debugHash)
+ codeChanged = true;*/
+
+ consoleInit(SCREEN_SUB, NULL, false);
+
+ if(excStack[16] & 0x20) instSize = 2; // Processor was in Thumb mode?
+ if(type == 2) realPc = excStack[15] - (instSize * 2); // Data abort
+ else realPc = excStack[15] - instSize; // Other
+
+ ee_printf("\x1b[41m\x1b[0J\x1b[15CGuru Meditation Error!\n\n%s:\n", typeStr[type]);
+ ee_printf("CPSR: 0x%08" PRIX32 "\n"
+ "r0 = 0x%08" PRIX32 " r6 = 0x%08" PRIX32 " r12 = 0x%08" PRIX32 "\n"
+ "r1 = 0x%08" PRIX32 " r7 = 0x%08" PRIX32 " sp = 0x%08" PRIX32 "\n"
+ "r2 = 0x%08" PRIX32 " r8 = 0x%08" PRIX32 " lr = 0x%08" PRIX32 "\n"
+ "r3 = 0x%08" PRIX32 " r9 = 0x%08" PRIX32 " pc = 0x%08" PRIX32 "\n"
+ "r4 = 0x%08" PRIX32 " r10 = 0x%08" PRIX32 "\n"
+ "r5 = 0x%08" PRIX32 " r11 = 0x%08" PRIX32 "\n\n",
+ excStack[16],
+ excStack[0], excStack[6], excStack[12],
+ excStack[1], excStack[7], excStack[13],
+ excStack[2], excStack[8], excStack[14],
+ excStack[3], excStack[9], realPc,
+ excStack[4], excStack[10],
+ excStack[5], excStack[11]);
+
+ ee_puts("Stack dump:");
+ u32 sp = excStack[13];
+ if(sp >= AXIWRAM_BASE && sp < AXIWRAM_BASE + AXIWRAM_SIZE && !(sp & 3u))
+ {
+ u32 stackWords = ((AXIWRAM_BASE + AXIWRAM_SIZE - sp) / 4 > 48 ? 48 : (AXIWRAM_BASE + AXIWRAM_SIZE - sp) / 4);
+
+ u32 newlineCounter = 0;
+ for(u32 i = 0; i < stackWords; i++)
+ {
+ if(newlineCounter == 4) {ee_printf("\n"); newlineCounter = 0;}
+ ee_printf("0x%08" PRIX32 " ", ((u32*)sp)[i]);
+ newlineCounter++;
+ }
+ }
+
+ //if(codeChanged) ee_printf("Attention: RO section data changed!!");
+
+ // avoid fs corruptions
+ //fsUnmountAll();
+ //devs_close();
+
+ GX_textureCopy((u64*)RENDERBUF_TOP, (240 * 2)>>4, (u64*)GFX_getFramebuffer(SCREEN_TOP),
+ (240 * 2)>>4, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB);
+ GFX_swapFramebufs();
+
+ while(1) waitForInterrupt();
+}
+
+/*void dumpMem(u8 *mem, u32 size, char *filepath)
+{
+ FIL file;
+ UINT bytesWritten;
+
+ if(f_open(&file, filepath, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
+ return;
+
+ f_write(&file, mem, size, &bytesWritten);
+
+ f_sync(&file);
+
+ f_close(&file);
+}*/
diff --git a/source/arm11/hardware/exception.s b/source/arm11/hardware/exception.s
index 730b3db..d24a2a7 100644
--- a/source/arm11/hardware/exception.s
+++ b/source/arm11/hardware/exception.s
@@ -23,21 +23,43 @@
.fpu vfpv2
.extern deinitCpu
+.extern guruMeditation
.extern privIrqHandlerTable
.extern irqHandlerTable
-ASM_FUNC tmpExceptionHandler
+ASM_FUNC undefInstrHandler
+ msr cpsr_f, #(0<<29) @ Abuse conditional flags in cpsr for temporary exception type storage
+ b exceptionHandler
+ASM_FUNC prefetchAbortHandler
+ msr cpsr_f, #(1<<29)
+ b exceptionHandler
+ASM_FUNC dataAbortHandler
+ msr cpsr_f, #(2<<29)
+ASM_FUNC exceptionHandler
+ sub sp, #68
+ stmia sp, {r0-r14}^ @ Save all user/system mode regs except pc
+ mrs r2, spsr @ Get saved cpsr
+ mrs r3, cpsr
+ lsr r0, r3, #29 @ Get back the exception type from cpsr
+ and r1, r2, #0x1F
+ cmp r1, #0x10 @ User mode
+ beq exceptionHandler_skip_other_mode
+ add r4, sp, #32
+ msr cpsr_c, r2
+ stmia r4!, {r8-r14} @ Some regs are written twice but we don't care
+ msr cpsr_c, r3
+exceptionHandler_skip_other_mode:
+ str lr, [sp, #60] @ Save lr (pc) on exception stack
+ str r2, [sp, #64] @ Save spsr (cpsr) on exception stack
+ mov r4, r0
+ mov r5, sp
bl deinitCpu
- ldr r0, =0x10202A04
- mov r1, #0xFF
- orr r1, #0x1000000
- str r1, [r0]
-tmpExceptionHandler_lp:
- wfi
- b tmpExceptionHandler_lp
-.pool
+ mov r0, r4
+ mov sp, r5
+ mov r1, r5
+ b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), cpsr}
ASM_FUNC irqHandler
diff --git a/source/arm11/main.c b/source/arm11/main.c
index f7c5591..e8ef697 100644
--- a/source/arm11/main.c
+++ b/source/arm11/main.c
@@ -29,7 +29,6 @@
#include "arm11/menu_fb3ds.h"
#include "arm11/console.h"
#include "arm11/fmt.h"
- #include "fs.h"
volatile bool g_poweroffAllowed = false;
@@ -42,18 +41,18 @@
hardwareInit();
GFX_init();
-
+
// init menu console
PrintConsole menu_con;
consoleInit(SCREEN_SUB, &menu_con, false);
-
+
// init description console
PrintConsole desc_con;
consoleInit(SCREEN_TOP, &desc_con, false);
// run menu
menuProcess(&menu_con, &desc_con, menu_fb3ds);
-
+
// power off
if(g_poweroffAllowed) power_off();
diff --git a/source/arm11/start.s b/source/arm11/start.s
index fd52be9..f6d3fa9 100644
--- a/source/arm11/start.s
+++ b/source/arm11/start.s
@@ -35,8 +35,10 @@
.type _init %function
.type deinitCpu %function
-.extern tmpExceptionHandler
.extern irqHandler
+.extern undefInstrHandler
+.extern prefetchAbortHandler
+.extern dataAbortHandler
.extern __bss_start__
.extern __bss_end__
.extern __end__
@@ -61,10 +63,10 @@
ldr pc, irqHandlerPtr @ Interrupt (IRQ) vector
ldr pc, fiqHandlerPtr @ Fast interrupt (FIQ) vector
resetHandlerPtr: .word _start
- undefInstrHandlerPtr: .word tmpExceptionHandler
+ undefInstrHandlerPtr: .word undefInstrHandler
svcHandlerPtr: .word (vectors + 0x08)
- prefetchAbortHandlerPtr: .word tmpExceptionHandler
- dataAbortHandlerPtr: .word tmpExceptionHandler
+ prefetchAbortHandlerPtr: .word prefetchAbortHandler
+ dataAbortHandlerPtr: .word dataAbortHandler
reservedHandlerPtr: .word (vectors + 0x14)
irqHandlerPtr: .word irqHandler
fiqHandlerPtr: .word (vectors + 0x1C)
@@ -104,9 +106,9 @@
mov sp, #0 @ SVC mode sp (unused, aborts)
cpsid aif, #23 @ Abort mode
- mov sp, #0 @ Not yet
+ ldr sp, =A11_EXC_STACK_END
cpsid aif, #27 @ Undefined mode
- mov sp, #0 @ Not yet
+ ldr sp, =A11_EXC_STACK_END
cpsid aif, #17 @ FIQ mode
mov sp, #0 @ Unused
cpsid aif, #18 @ IRQ mode