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