diff --git a/.gitignore b/.gitignore index 48ed2a0..0a21f7f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ exceptions/arm11/build *.elf *.cxi .DS_Store +*.dmp .project .cproject .settings - diff --git a/arm11/source/types.h b/arm11/source/types.h index 7b56df1..d9042cc 100644 --- a/arm11/source/types.h +++ b/arm11/source/types.h @@ -50,7 +50,7 @@ struct fb { u8 *top_left; u8 *top_right; u8 *bottom; -} __attribute__((packed)); +}; typedef enum { diff --git a/chainloader/source/types.h b/chainloader/source/types.h index c4565be..e168623 100644 --- a/chainloader/source/types.h +++ b/chainloader/source/types.h @@ -42,4 +42,4 @@ struct fb { u8 *top_left; u8 *top_right; u8 *bottom; -} __attribute__((packed)); +}; diff --git a/exceptions/arm9/Makefile b/exceptions/arm9/Makefile index 2088efe..4d5ab5b 100644 --- a/exceptions/arm9/Makefile +++ b/exceptions/arm9/Makefile @@ -13,8 +13,8 @@ dir_build := build dir_out := ../../$(dir_build) ASFLAGS := -mcpu=arm946e-s -CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -LDFLAGS := -nostdlib +CFLAGS := -Wall -Wextra -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -Os -ffast-math +LDFLAGS := -nostartfiles -Wl,--nmagic objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ diff --git a/exceptions/arm9/linker.ld b/exceptions/arm9/linker.ld index 6eb4e11..aed5a5c 100644 --- a/exceptions/arm9/linker.ld +++ b/exceptions/arm9/linker.ld @@ -4,7 +4,7 @@ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { - . = 0x01FF7FE0; + . = 0x01FF8000; .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } diff --git a/exceptions/arm9/source/handlers.h b/exceptions/arm9/source/handlers.h index 315723a..1c7fe0b 100644 --- a/exceptions/arm9/source/handlers.h +++ b/exceptions/arm9/source/handlers.h @@ -43,8 +43,9 @@ typedef struct __attribute__((packed)) u32 additionalDataSize; } ExceptionDumpHeader; -u32 readMPUConfig(u32 *regionSettings); void FIQHandler(void); void undefinedInstructionHandler(void); void dataAbortHandler(void); void prefetchAbortHandler(void); + +u32 safecpy(void *dst, const void *src, u32 len); diff --git a/exceptions/arm9/source/handlers.s b/exceptions/arm9/source/handlers.s index f8a50fe..b9f7edc 100644 --- a/exceptions/arm9/source/handlers.s +++ b/exceptions/arm9/source/handlers.s @@ -22,92 +22,131 @@ @ or requiring that modified versions of such material be marked in @ reasonable ways as different from the original version. -.macro GEN_HANDLER name - .global \name - .type \name, %function - \name: - ldr sp, =#0x02000000 @ We make the (full descending) stack point to the end of ITCM for our exception handlers. - @ It doesn't matter if we're overwriting stuff here, since we're going to reboot. +.macro GEN_USUAL_HANDLER name, index + \name\()Handler: + ldr sp, =_regs + stmia sp, {r0-r7} - stmfd sp!, {r0-r7} @ FIQ has its own r8-r14 regs - ldr r1, =\@ @ macro expansion counter + mov r0, #\index b _commonHandler - - .size \name, . - \name .endm .text .arm -.align 4 +.balign 4 .global _commonHandler .type _commonHandler, %function _commonHandler: + mov r1, r0 + mov r0, sp mrs r2, spsr - mov r6, sp mrs r3, cpsr + add r6, r0, #(8 * 4) - orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (equivalent to "cpsid aif" on arm11) + orr r3, #0xc0 @ mask interrupts msr cpsr_cx, r3 - tst r2, #0x20 - bne noSvcBreak - cmp r1, #2 - bne noSvcBreak - - sub r0, lr, #4 @ calling cannotAccessAddress cause more problems that it actually solves... (I've to save a lot of regs and that's a pain tbh) - lsr r0, #20 @ we'll just do some address checks (to see if it's in ARM9 internal memory) - cmp r0, #0x80 - bne noSvcBreak - ldr r4, [lr, #-4] - ldr r5, =#0xe12fff7f - cmp r4, r5 - bne noSvcBreak - bic r5, r3, #0xf - orr r5, #0x3 - msr cpsr_c, r5 @ switch to supervisor mode - ldmfd sp, {r8-r11}^ - ldr r2, [sp, #0x1c] @ implementation details of the official svc handler - ldr r4, [sp, #0x18] - msr cpsr_c, r3 @ restore processor mode - tst r2, #0x20 - addne lr, r4, #2 @ adjust address for later - moveq lr, r4 - - noSvcBreak: ands r4, r2, #0xf @ get the mode that triggered the exception moveq r4, #0xf @ usr => sys bic r5, r3, #0xf orr r5, r4 msr cpsr_c, r5 @ change processor mode - stmfd r6!, {r8-lr} + stmia r6!, {r8-lr} msr cpsr_c, r3 @ restore processor mode - mov sp, r6 - stmfd sp!, {r2,lr} @ it's a bit of a mess, but we will fix that later - @ order of saved regs now: cpsr, pc + (2/4/8), r8-r14, r0-r7 - - mov r0, sp + str lr, [r6], #4 + str r2, [r6] + msr cpsr_cxsf, #0xdf @ finally, switch to system mode, mask interrupts and clear flags (in case of double faults) + ldr sp, =0x02000000 b mainHandler -GEN_HANDLER FIQHandler -GEN_HANDLER undefinedInstructionHandler -GEN_HANDLER prefetchAbortHandler -GEN_HANDLER dataAbortHandler -.global readMPUConfig -.type readMPUConfig, %function -readMPUConfig: - stmfd sp!, {r4-r8, lr} - mrc p15,0,r1,c6,c0,0 - mrc p15,0,r2,c6,c1,0 - mrc p15,0,r3,c6,c2,0 - mrc p15,0,r4,c6,c3,0 - mrc p15,0,r5,c6,c4,0 - mrc p15,0,r6,c6,c5,0 - mrc p15,0,r7,c6,c6,0 - mrc p15,0,r8,c6,c7,0 - stmia r0, {r1-r8} - mrc p15,0,r0,c5,c0,2 @ read data access permission bits - ldmfd sp!, {r4-r8, pc} +.global FIQHandler +.type FIQHandler, %function +GEN_USUAL_HANDLER FIQ, 0 + +.global undefinedInstructionHandler +.type undefinedInstructionHandler, %function +GEN_USUAL_HANDLER undefinedInstruction, 1 + +.global prefetchAbortHandler +.type prefetchAbortHandler, %function +prefetchAbortHandler: + msr cpsr_cx, #0xd7 @ mask interrupts (abort mode) + mrs sp, spsr + and sp, #0x3f + cmp sp, #0x13 + bne _prefetchAbortNormalHandler + + ldr sp, =BreakPtr + ldr sp, [sp] + cmp sp, #0 + beq _prefetchAbortNormalHandler + add sp, #(1*4 + 4) + cmp lr, sp + bne _prefetchAbortNormalHandler + + mov sp, r8 + pop {r8-r11} + ldr lr, [sp, #8]! + ldr sp, [sp, #4] + msr spsr_cxsf, sp + tst sp, #0x20 + addne lr, #2 @ adjust address for later + + GEN_USUAL_HANDLER _prefetchAbortNormal, 2 + +.global dataAbortHandler +.type dataAbortHandler, %function +dataAbortHandler: + msr cpsr_cx, #0xd7 @ mask interrupts (abort mode) + mrs sp, spsr + and sp, #0x3f + cmp sp, #0x1f + bne _dataAbortNormalHandler + + sub lr, #8 + adr sp, safecpy + cmp lr, sp + blo _j_dataAbortNormalHandler + adr sp, _safecpy_end + cmp lr, sp + bhs _j_dataAbortNormalHandler + + msr spsr_f, #(1 << 30) + mov r12, #0 + adds pc, lr, #4 + + _j_dataAbortNormalHandler: + add lr, #8 + + GEN_USUAL_HANDLER _dataAbortNormal, 3 + + +.global safecpy +.type safecpy, %function +safecpy: + push {r4, lr} + mov r3, #0 + movs r12, #1 + + _safecpy_loop: + ldrb r4, [r1, r3] + cmp r12, #0 + beq _safecpy_loop_end + strb r4, [r0, r3] + add r3, #1 + cmp r3, r2 + blo _safecpy_loop + + _safecpy_loop_end: + mov r0, r3 + pop {r4, pc} + +_safecpy_end: + +.bss +.balign 4 +_regs: .skip (4 * 17) diff --git a/exceptions/arm9/source/mainHandler.c b/exceptions/arm9/source/mainHandler.c index f1e5ca0..4db047a 100644 --- a/exceptions/arm9/source/mainHandler.c +++ b/exceptions/arm9/source/mainHandler.c @@ -32,48 +32,10 @@ #define REG_DUMP_SIZE 4 * 17 #define CODE_DUMP_SIZE 48 -bool cannotAccessAddress(const void *address) -{ - u32 regionSettings[8]; - u32 addr = (u32)address; - - u32 dataAccessPermissions = readMPUConfig(regionSettings); - for(u32 i = 0; i < 8; i++) - { - if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0) - continue; //No access / region not enabled - - u32 regionAddrBase = regionSettings[i] & ~0xFFF; - u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1); - - if(addr >= regionAddrBase && addr < regionAddrBase + regionSize) - return false; - - dataAccessPermissions >>= 4; - } - - return true; -} - -static u32 __attribute__((noinline)) copyMemory(void *dst, const void *src, u32 size, u32 alignment) -{ - u8 *out = (u8 *)dst; - const u8 *in = (const u8 *)src; - - if(((u32)src & (alignment - 1)) != 0 || cannotAccessAddress(src) || (size != 0 && cannotAccessAddress((u8 *)src + size - 1))) - return 0; - - for(u32 i = 0; i < size; i++) - *out++ = *in++; - - return size; -} - -void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type) +void __attribute__((noreturn)) mainHandler(u32 *registerDump, u32 type) { ExceptionDumpHeader dumpHeader; - u32 registerDump[REG_DUMP_SIZE / 4]; u8 codeDump[CODE_DUMP_SIZE]; dumpHeader.magic[0] = 0xDEADC0DE; @@ -89,27 +51,22 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type) dumpHeader.codeDumpSize = CODE_DUMP_SIZE; dumpHeader.additionalDataSize = 0; - //Dump registers - //Current order of saved regs: cpsr, pc, r8-r14, r0-r7 - u32 cpsr = regs[0]; - u32 pc = regs[1] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8); + u32 cpsr = registerDump[16]; + u32 pc = registerDump[15] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8); registerDump[15] = pc; - registerDump[16] = cpsr; - for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[2 + i]; - for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i]; //Dump code - u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem - dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4); + u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem + dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize); - //Copy register dump and code dump + //Copy register dump and code dump u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader)); - final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1); - final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1); + final += safecpy(final, registerDump, dumpHeader.registerDumpSize); + final += safecpy(final, codeDump, dumpHeader.codeDumpSize); //Dump stack in place - dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1); + dumpHeader.stackDumpSize = safecpy(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF)); dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize; diff --git a/exceptions/arm9/source/start.s b/exceptions/arm9/source/start.s index 80f70f7..fb6ad02 100644 --- a/exceptions/arm9/source/start.s +++ b/exceptions/arm9/source/start.s @@ -26,8 +26,12 @@ .align 4 .global _start _start: - add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations + add pc, r0, #(handlers - .) @ Dummy instruction +.global BreakPtr +BreakPtr: .word 0 + +.global handlers handlers: .word FIQHandler .word undefinedInstructionHandler diff --git a/k11_extension/source/fatalExceptionHandlers.s b/k11_extension/source/fatalExceptionHandlers.s index 30a9aec..c7a3d64 100644 --- a/k11_extension/source/fatalExceptionHandlers.s +++ b/k11_extension/source/fatalExceptionHandlers.s @@ -159,7 +159,7 @@ _commonHandler: _no_L2C: - cps #0x1F + msr cpsr_cxsf, #0xdf @ finally, switch to system mode, mask interrupts and clear flags (in case of double faults) ldr sp, =exceptionStackTop ldr sp, [sp] sub sp, #0x100 @@ -221,7 +221,8 @@ prefetchAbortHandler: pop {r8-r11} ldr lr, [sp, #8]! ldr sp, [sp, #4] - msr spsr, sp + msr spsr_cxsf, sp + tst sp, #0x20 addne lr, #2 @ adjust address for later GEN_USUAL_HANDLER _prefetchAbortNormal, 2, 12 diff --git a/k11_extension/source/fatalExceptionHandlersMain.c b/k11_extension/source/fatalExceptionHandlersMain.c index 66ae07d..a7bde74 100644 --- a/k11_extension/source/fatalExceptionHandlersMain.c +++ b/k11_extension/source/fatalExceptionHandlersMain.c @@ -37,7 +37,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index) { if(CONFIG(DISABLEARM11EXCHANDLERS)) return false; - if((spsr & 0x1f) != 0x10) return true; + if((spsr & 0x1F) != 0x10) return true; KThread *thread = currentCoreContext->objectContext.currentThread; KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; @@ -65,7 +65,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index) extern u32 safecpy_sz; bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr) { - return ((spsr & 0x1F) != 0x10) && ( + return (!(spsr & 0x20) && (spsr & 0x1F) != 0x10) && ( ((u32)kernelUsrCopyFuncsStart <= addr && addr < (u32)kernelUsrCopyFuncsEnd) || ((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz) ); @@ -96,7 +96,7 @@ void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId) registerDump[15] = pc; //Dump code - u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem + u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize); //Copy register dump and code dump diff --git a/patches/reboot.s b/patches/reboot.s index 795afd2..984ce8c 100644 --- a/patches/reboot.s +++ b/patches/reboot.s @@ -116,9 +116,7 @@ fname: .ascii "FILE" .align 4 kernelcode_start: - mrs r0, cpsr ; disable interrupts - orr r0, #0xC0 - msr cpsr, r0 + msr cpsr_cxsf, #0xD3 ; disable interrupts and clear flags ldr sp, =copy_launch_stub_stack_top diff --git a/source/config.c b/source/config.c index a4a1130..f006841 100644 --- a/source/config.c +++ b/source/config.c @@ -27,6 +27,7 @@ #include "config.h" #include "memory.h" #include "fs.h" +#include "strings.h" #include "utils.h" #include "screen.h" #include "draw.h" @@ -201,12 +202,12 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) u32 enabled; bool visible; } multiOptions[] = { - { .posXs = {19, 24, 29, 34}, .visible = isSdMode }, - { .posXs = {21, 26, 31, 36}, .visible = true }, - { .posXs = {12, 22, 31, 0}, .visible = true }, - { .posXs = {19, 24, 29, 34}, .visible = true }, - { .posXs = {14, 19, 24, 29}, .visible = true }, - { .posXs = {17, 26, 32, 44}, .visible = ISN3DS }, + { .visible = isSdMode }, + { .visible = true }, + { .visible = true }, + { .visible = true }, + { .visible = true }, + { .visible = ISN3DS }, }; struct singleOption { @@ -234,7 +235,15 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) //Parse the existing options for(u32 i = 0; i < multiOptionsAmount; i++) + { + //Detect the positions where the "x" should go + u32 optionNum = 0; + for(u32 j = 0; optionNum < 4 && j < strlen(multiOptionsText[i]); j++) + if(multiOptionsText[i][j] == '(') multiOptions[i].posXs[optionNum++] = j + 1; + while(optionNum < 4) multiOptions[i].posXs[optionNum++] = 0; + multiOptions[i].enabled = MULTICONFIG(i); + } for(u32 i = 0; i < singleOptionsAmount; i++) singleOptions[i].enabled = CONFIG(i); diff --git a/source/exceptions.c b/source/exceptions.c index 32698c9..70886df 100644 --- a/source/exceptions.c +++ b/source/exceptions.c @@ -37,7 +37,7 @@ void installArm9Handlers(void) { - memcpy((void *)0x01FF8000, arm9_exceptions_bin + 32, arm9_exceptions_bin_size - 32); + memcpy((void *)0x01FF8000, arm9_exceptions_bin, arm9_exceptions_bin_size); /* IRQHandler is at 0x08000000, but we won't handle it for some reasons svcHandler is at 0x08000010, but we won't handle svc either */ @@ -47,8 +47,10 @@ void installArm9Handlers(void) for(u32 i = 0; i < 4; i++) { *(vu32 *)(0x08000000 + offsets[i]) = 0xE51FF004; - *(vu32 *)(0x08000000 + offsets[i] + 4) = *((u32 *)arm9_exceptions_bin + 1 + i); + *(vu32 *)(0x08000000 + offsets[i] + 4) = *(vu32 *)(0x01FF8008 + 4 * i); } + + *(vu32 *)0x01FF8004 = 0; //BreakPtr } void detectAndProcessExceptionDumps(void) diff --git a/source/patches.c b/source/patches.c index 55d3f55..26de128 100644 --- a/source/patches.c +++ b/source/patches.c @@ -454,7 +454,9 @@ u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) if(temp == NULL) return 1; - u32 *off = (u32 *)(temp - 0xA); + u32 *off; + + for(off = (u32 *)(temp - 2); *off != 0xE5801000; off--); //Until str r1, [r0] for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 { @@ -491,7 +493,15 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL) u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); - *addr = 0xE12FFF7F; + + /* + mov r8, sp + bkpt 0xffff + */ + addr[0] = 0xE1A0800D; + addr[1] = 0xE12FFF7F; + + *(vu32 *)0x01FF8004 = arm9SvcTable[0x3C]; //BreakPtr return 0; } diff --git a/source/screen.h b/source/screen.h index 3905739..3dc18eb 100644 --- a/source/screen.h +++ b/source/screen.h @@ -49,7 +49,7 @@ struct fb { u8 *top_left; u8 *top_right; u8 *bottom; -} __attribute__((packed)); +}; typedef enum { diff --git a/source/start.s b/source/start.s index 1ac02fc..149b1f9 100644 --- a/source/start.s +++ b/source/start.s @@ -27,9 +27,7 @@ .global _start _start: @ Disable interrupts and switch to supervisor mode (also clear flags) - mov r4, #0x13 - orr r4, #0x1C0 - msr cpsr_cxsf, r4 + msr cpsr_cxsf, #0xD3 @ Check if r0-r2 are 0 (r0-sp are supposed to be 0), and for regions 0, 5 and 7 of the MPU config @ This is not foolproof but should work well enough diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index bba67c2..9d5b8bf 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -203,7 +203,7 @@ static void menuDraw(Menu *menu, u32 selected) if(R_SUCCEEDED(mcuHwcInit())) { - if(R_FAILED(mcuHwcGetBatteryLevel(&batteryLevel))) + if(R_FAILED(MCUHWC_GetBatteryLevel(&batteryLevel))) batteryLevel = 255; mcuHwcExit(); } diff --git a/sysmodules/rosalina/source/menus/sysconfig.c b/sysmodules/rosalina/source/menus/sysconfig.c index 2ca1302..2a0a350 100644 --- a/sysmodules/rosalina/source/menus/sysconfig.c +++ b/sysmodules/rosalina/source/menus/sysconfig.c @@ -66,9 +66,9 @@ void SysConfigMenu_ToggleLEDs(void) { mcuHwcInit(); u8 result; - mcuHwcReadRegister(0x28, &result, 1); + MCUHWC_ReadRegister(0x28, &result, 1); result = ~result; - mcuHwcWriteRegister(0x28, &result, 1); + MCUHWC_WriteRegister(0x28, &result, 1); mcuHwcExit(); } else if(pressed & BUTTON_B)