diff --git a/arm9/source/arm9_exception_handlers_asm.s b/arm9/source/arm9_exception_handlers_asm.s index 458023f76..d52e10e2d 100644 --- a/arm9/source/arm9_exception_handlers_asm.s +++ b/arm9/source/arm9_exception_handlers_asm.s @@ -76,7 +76,7 @@ GEN_USUAL_HANDLER undefinedInstruction, 1 prefetchAbortHandler: msr cpsr_cx, #0xd7 @ mask interrupts (abort mode) mrs sp, spsr - and sp, #0x3f + and sp, #0x1f cmp sp, #0x13 bne _prefetchAbortNormalHandler @@ -84,7 +84,9 @@ prefetchAbortHandler: ldr sp, [sp] cmp sp, #0 beq _prefetchAbortNormalHandler - add sp, #(1*4 + 4) + tst sp, #1 + addne sp, #(1*2 + 2 + 1) + addeq sp, #(1*4 + 4) cmp lr, sp bne _prefetchAbortNormalHandler diff --git a/arm9/source/emunand.c b/arm9/source/emunand.c index fa0f3802a..35581c285 100644 --- a/arm9/source/emunand.c +++ b/arm9/source/emunand.c @@ -149,18 +149,33 @@ static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc) return 0; } +static inline u32 getTwlSdmmc(u8 *pos, u32 size, u32 *sdmmc) +{ + static const u8 pattern[] = {0xF2, 0xD0, 0x12, 0x48}, + pattern2[] = {0x3D, 0x18, 0x28, 0x79}; + + const u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); + const u16 *off2 = (u16 *)memsearch(pos, pattern2, size, sizeof(pattern2)); + + if(off == NULL || off2 == NULL) return 1; + + *sdmmc = *(off + 0x13) + *(u32 *)(off2 + (*(off2 - 1) & 0xFF) * 2); + + return 0; +} + static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset) { //Look for read/write code static const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; - u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); + u16 *readOffset = (u16 *)((u32)memsearch(pos, pattern, size, sizeof(pattern)) | 2); if(readOffset == NULL) return 1; readOffset -= 3; - u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)); + u16 *writeOffset = (u16 *)((u32)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)) | 2); if(writeOffset == NULL) return 1; @@ -187,7 +202,7 @@ static inline u32 patchMpu(u8 *pos, u32 size) return 0; } -u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion) +u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion, bool twl) { u8 *freeK9Space; @@ -201,14 +216,14 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce //Find and add the SDMMC struct u32 sdmmc; - ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc); + ret += twl ? getTwlSdmmc(process9Offset, process9Size, &sdmmc) : !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc); if(!ret) emunandPatchSdmmcStructPtr = sdmmc; //Copy EmuNAND code memcpy(freeK9Space, emunandPatch, emunandPatchSize); //Add EmuNAND hooks - u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address); + u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address) | 1; ret += patchNandRw(process9Offset, process9Size, branchOffset); //Set MPU diff --git a/arm9/source/emunand.h b/arm9/source/emunand.h index 58941caf5..687c14381 100644 --- a/arm9/source/emunand.h +++ b/arm9/source/emunand.h @@ -38,4 +38,4 @@ extern u32 emuOffset, emuHeader; void locateEmuNand(FirmwareSource *nandType); -u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion); +u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion, bool twl); diff --git a/arm9/source/exceptions.c b/arm9/source/exceptions.c index 07106840e..966d31012 100644 --- a/arm9/source/exceptions.c +++ b/arm9/source/exceptions.c @@ -105,8 +105,10 @@ void detectAndProcessExceptionDumps(void) else if((regs[16] & 0x20) != 0 && dumpHeader->codeDumpSize >= 2) { u16 instr = *(vu16 *)(stackDump - 2); - if(instr == 0xDF3C) + if(instr == 0xBEFE) posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[0]); + else if(instr == 0xDF3C) + posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[1]); else posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]); } diff --git a/arm9/source/firm.c b/arm9/source/firm.c index 6088bbe8d..dff30ac69 100755 --- a/arm9/source/firm.c +++ b/arm9/source/firm.c @@ -388,7 +388,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora ret += patchSignatureChecks(process9Offset, process9Size); //Apply EmuNAND patches - if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion); + if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion, false); //Apply FIRM0/1 writes patches on SysNAND to protect A9LH else if(isFirmProtEnabled) ret += patchFirmWrites(process9Offset, process9Size); @@ -429,7 +429,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora return ret; } -u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch) +u32 patchTwlFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool doUnitinfoPatch) { u8 *arm9Section = (u8 *)firm + firm->section[3].offset; @@ -460,9 +460,17 @@ u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch) else if(!ISN3DS && firmVersion == 0x11) ret += patchOldTwlFlashcartChecks(process9Offset, process9Size); ret += patchTwlShaHashChecks(process9Offset, process9Size); + //Apply EmuNAND patches + if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[3].address, firmVersion, true); + //Apply UNITINFO patch if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size); + //Arm9 exception handlers + ret += patchTwlArm9ExceptionHandlersInstall(arm9Section, kernel9Size); + ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[3].address); + ret += patchTwlKernel9Panic(arm9Section, kernel9Size); + if(loadFromStorage) { mergeSection0(TWL_FIRM, 0, true); diff --git a/arm9/source/firm.h b/arm9/source/firm.h index 591ec2faa..57463af54 100644 --- a/arm9/source/firm.h +++ b/arm9/source/firm.h @@ -32,7 +32,7 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode); void loadHomebrewFirm(u32 pressed); u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isFirmProtEnabled, bool needToInitSd, bool doUnitinfoPatch); -u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch); +u32 patchTwlFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool doUnitinfoPatch); u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch); u32 patch1x2xNativeAndSafeFirm(void); void launchFirm(int argc, char **argv); diff --git a/arm9/source/large_patches.s b/arm9/source/large_patches.s index 90f3ffd95..0cb13a338 100644 --- a/arm9/source/large_patches.s +++ b/arm9/source/large_patches.s @@ -1,5 +1,5 @@ .section .large_patch.emunand, "aw", %progbits -.arm +.thumb .align 4 @ Code originally by Normmatt @@ -14,40 +14,43 @@ emunandPatch: @ End @ If we're already trying to access the SD, return - ldr r2, [r0, #4] - ldr r1, emunandPatchSdmmcStructPtr - cmp r2, r1 + ldr r2, [r4, #4] + ldr r0, emunandPatchSdmmcStructPtr + cmp r2, r0 beq out - str r1, [r0, #4] @ Set object to be SD - ldr r2, [r0, #8] @ Get sector to read - cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0) + ldr r2, [r4, #8] @ Get sector to read + str r0, [r4, #4] @ Set object to be SD ldr r3, emunandPatchNandOffset add r2, r3 @ Add the offset to the NAND in the SD - ldreq r3, emunandPatchNcsdHeaderOffset - addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector + cmp r2, r3 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0) + bne skip_add - str r2, [r0, #8] @ Store sector to read + ldr r3, emunandPatchNcsdHeaderOffset + add r2, r3 @ If we're reading the ncsd header, add the offset of that sector - out: - @ Restore registers. - mov r1, r5 - mov r2, r7 - mov r3, r6 + skip_add: + str r2, [r4, #8] @ Store sector to read + out: @ Return 4 bytes behind where we got called, @ due to the offset of this function being stored there - mov r0, lr - add r0, #4 - bx r0 + mov r2, lr + add r2, #4 + + @ More original code that might have been skipped depending on alignment; + @ needs to be done at the end so CPSR is preserved + lsl r0, r1, #0x17 + bx r2 .pool .global emunandPatchSdmmcStructPtr .global emunandPatchNandOffset .global emunandPatchNcsdHeaderOffset +.balign 4 emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct emunandPatchNandOffset: .word 0 @ For rednand this should be 1 diff --git a/arm9/source/main.c b/arm9/source/main.c index 50b66668c..0d0f58f0c 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -369,7 +369,7 @@ void main(int argc, char **argv, u32 magicWord) res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isFirmProtEnabled, needToInitSd, doUnitinfoPatch); break; case TWL_FIRM: - res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch); + res = patchTwlFirm(firmVersion, nandType, loadFromStorage, doUnitinfoPatch); break; case AGB_FIRM: res = patchAgbFirm(loadFromStorage, doUnitinfoPatch); diff --git a/arm9/source/patches.c b/arm9/source/patches.c index a22e85c85..52270d088 100644 --- a/arm9/source/patches.c +++ b/arm9/source/patches.c @@ -486,9 +486,36 @@ u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) return 0; } + +u32 patchTwlArm9ExceptionHandlersInstall(u8 *pos, u32 size) +{ + //This is in thumb in TWL_FIRM + + static const u8 pattern[] = {0xC1, 0x60, 0x40, 0x21}; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) return 1; + + u16 *off; + + for(off = (u16 *)temp; *off != 0x6001; off--); //Until str r1, [r0] + + for(u32 r0 = 0x08000000; *off != 0x2140; off++) //Until mov r1, #0x40 + { + //Discard everything that's not str rX, [r0, #imm](!) + if((*off & 0xFC00) != 0x6000) continue; + + u32 addr = r0 + ((*off >> 4) & 0xFF); + if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0x4600; //nop + } + + return 0; +} + u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) { - //Stub svcBreak with "bkpt 65535" so we can debug the panic + //Stub svcBreak with "bkpt 65535" or "bkpt 255" so we can debug the panic //Look for the svc handler static const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr @@ -499,14 +526,28 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL) - u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); - - /* - mov r8, sp - bkpt 0xffff - */ - addr[0] = 0xE1A0800D; - addr[1] = 0xE12FFF7F; + if (arm9SvcTable[0x3C] & 1) //Might be thumb + { + u16 *addr = (u16 *)(pos + arm9SvcTable[0x3C] - kernel9Address - 1); + + /* + mov r8, sp + bkpt 0xff + */ + addr[0] = 0x46E8; + addr[1] = 0xBEFF; + } + else + { + u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); + + /* + mov r8, sp + bkpt 0xffff + */ + addr[0] = 0xE1A0800D; + addr[1] = 0xE12FFF7F; + } arm9ExceptionHandlerSvcBreakAddress = arm9SvcTable[0x3C]; //BreakPtr @@ -527,6 +568,20 @@ u32 patchKernel9Panic(u8 *pos, u32 size) return 0; } +u32 patchTwlKernel9Panic(u8 *pos, u32 size) +{ + static const u8 pattern[] = {0xB5, 0x13, 0x00, 0x11}; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) return 1; + + u16 *off = (u16 *)(temp - 3); + *off = 0xBEFE; + + return 0; +} + u32 patchP9AccessChecks(u8 *pos, u32 size) { static const u8 pattern[] = {0x00, 0x08, 0x49, 0x68}; @@ -651,7 +706,11 @@ u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion) if(temp == NULL) { - if(firmVersion == 0xFFFFFFFF) return patchOldTwlFlashcartChecks(pos, size); + if(firmVersion == 0xFFFFFFFF) + { + patchOldTwlFlashcartChecks(pos, size); + return 0; + } return 1; } diff --git a/arm9/source/patches.h b/arm9/source/patches.h index dae35984a..3cca65cde 100644 --- a/arm9/source/patches.h +++ b/arm9/source/patches.h @@ -52,8 +52,10 @@ u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size); u32 patchCheckForDevCommonKey(u8 *pos, u32 size); u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *startPos, u32 size); u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size); +u32 patchTwlArm9ExceptionHandlersInstall(u8 *pos, u32 size); u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address); u32 patchKernel9Panic(u8 *pos, u32 size); +u32 patchTwlKernel9Panic(u8 *pos, u32 size); u32 patchP9AccessChecks(u8 *pos, u32 size); u32 patchUnitInfoValueSet(u8 *pos, u32 size); u32 patchP9AMTicketWrapperZeroKeyIV(u8 *pos, u32 size, u32 firmVersion);