diff --git a/arm9/linker.ld b/arm9/linker.ld index 4365b8c38..aa5ac8288 100644 --- a/arm9/linker.ld +++ b/arm9/linker.ld @@ -46,6 +46,7 @@ SECTIONS chainloader.o(.text*) i2c.o(.text*) arm9_exception_handlers.o(.text*) + KEEP (*(.emunand_patch)) *(.arm9_exception_handlers.rodata*) chainloader.o(.rodata*) diff --git a/arm9/source/emunand.c b/arm9/source/emunand.c index 003242494..147fe8a38 100644 --- a/arm9/source/emunand.c +++ b/arm9/source/emunand.c @@ -111,21 +111,6 @@ void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCt else *nandType = FIRMWARE_SYSNAND; } -static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space) -{ - static const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; - - //Looking for the last free space before Process9 - *freeK9Space = memsearch(pos, pattern, size, sizeof(pattern)); - - if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunandPatchSize || - *(u32 *)(*freeK9Space + 0x455 + emunandPatchSize - 4) != 0xFFFFFFFF) return false; - - *freeK9Space += 0x455; - - return true; -} - static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion) { switch(firmVersion) @@ -158,7 +143,7 @@ static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc) return 0; } -static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset) +static inline u32 patchNandRw(u8 *pos, u32 size, u32 hookAddr) { //Look for read/write code static const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; @@ -176,32 +161,13 @@ static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset) writeOffset -= 3; *readOffset = *writeOffset = 0x4C00; readOffset[1] = writeOffset[1] = 0x47A0; - ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset; - - return 0; -} - -static inline u32 patchMpu(u8 *pos, u32 size) -{ - //Look for MPU pattern - static const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; - - u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - - if(off == NULL) return 1; - - off[1] = 0x0036; - off[0xC] = off[0x12] = 0x0603; + ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = hookAddr; return 0; } -u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion) +u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion) { - u8 *freeK9Space; - - if(!getFreeK9Space(arm9Section, kernel9Size, &freeK9Space)) return 1; - u32 ret = 0; //Add the data of the found EmuNAND @@ -213,15 +179,8 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce ret += !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); - ret += patchNandRw(process9Offset, process9Size, branchOffset); - - //Set MPU - ret += patchMpu(arm9Section, kernel9Size); + ret += patchNandRw(process9Offset, process9Size, (u32)emunandPatch); return ret; } diff --git a/arm9/source/emunand.h b/arm9/source/emunand.h index 369baab89..60623a1b9 100644 --- a/arm9/source/emunand.h +++ b/arm9/source/emunand.h @@ -38,4 +38,4 @@ extern u32 emuOffset, emuHeader; void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCtrNandParams); -u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion); +u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion); diff --git a/arm9/source/emunand_patch.s b/arm9/source/emunand_patch.s new file mode 100644 index 000000000..6cbab55c3 --- /dev/null +++ b/arm9/source/emunand_patch.s @@ -0,0 +1,63 @@ +.section .emunand_patch, "aw", %progbits +.arm +.align 4 + +@ Code originally by Normmatt + +.global emunandPatch +emunandPatch: + @ Original code that still needs to be executed + mov r4, r0 + mov r5, r1 + mov r7, r2 + mov r6, r3 + @ End + + @ If we're already trying to access the SD, return + ldr r2, [r0, #4] + ldr r1, emunandPatchSdmmcStructPtr + cmp r2, r1 + 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 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 + + str r2, [r0, #8] @ Store sector to read + + out: + @ Restore registers. + mov r1, r5 + mov r2, r7 + mov r3, r6 + + @ 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 + +.pool + +.global emunandPatchSdmmcStructPtr +.global emunandPatchNandOffset +.global emunandPatchNcsdHeaderOffset + +emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct +emunandPatchNandOffset: .word 0 @ For rednand this should be 1 +emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED) + +.pool +.balign 4 + +_emunandPatchEnd: + +.global emunandPatchSize +emunandPatchSize: + .word _emunandPatchEnd - emunandPatch diff --git a/arm9/source/firm.c b/arm9/source/firm.c index 0554a3fef..811e20366 100755 --- a/arm9/source/firm.c +++ b/arm9/source/firm.c @@ -422,7 +422,7 @@ static void mergeSection0(FirmwareType firmType, u32 firmVersion, bool loadFromS } // SAFE_FIRM only for N3DS and only if ENABLESAFEFIRMROSALINA is on - if((firmType == NATIVE_FIRM || firmType == SAFE_FIRM) && (ISN3DS || firmVersion >= 0x1D)) + if((firmType == NATIVE_FIRM || firmType == SAFE_FIRM) && (ISN3DS || firmVersion >= 0x25)) { //2) Merge that info with our own modules' for(u8 *src = (u8 *)0x18180000; memcmp(((Cxi *)src)->ncch.magic, "NCCH", 4) == 0; src += srcModuleSize) @@ -528,8 +528,8 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora ret = 0; #ifndef BUILD_FOR_EXPLOIT_DEV - //Skip on FIRMs < 4.0 - if(ISN3DS || firmVersion >= 0x1D) + //Skip on FIRMs < 5.0 + if(ISN3DS || firmVersion >= 0x25) { //Find the Kernel11 SVC table and handler, exceptions page and free space locations u8 *arm11Section1 = (u8 *)firm + firm->section[1].offset; @@ -550,7 +550,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(process9Offset, process9Size, firmVersion); //Apply FIRM0/1 writes patches on SysNAND to protect A9LH else if(isFirmProtEnabled) ret += patchFirmWrites(process9Offset, process9Size); diff --git a/arm9/source/large_patches.s b/arm9/source/large_patches.s index 90f3ffd95..c66f63b5f 100644 --- a/arm9/source/large_patches.s +++ b/arm9/source/large_patches.s @@ -1,67 +1,3 @@ -.section .large_patch.emunand, "aw", %progbits -.arm -.align 4 - -@ Code originally by Normmatt - -.global emunandPatch -emunandPatch: - @ Original code that still needs to be executed - mov r4, r0 - mov r5, r1 - mov r7, r2 - mov r6, r3 - @ End - - @ If we're already trying to access the SD, return - ldr r2, [r0, #4] - ldr r1, emunandPatchSdmmcStructPtr - cmp r2, r1 - 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 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 - - str r2, [r0, #8] @ Store sector to read - - out: - @ Restore registers. - mov r1, r5 - mov r2, r7 - mov r3, r6 - - @ 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 - -.pool - -.global emunandPatchSdmmcStructPtr -.global emunandPatchNandOffset -.global emunandPatchNcsdHeaderOffset - -emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct -emunandPatchNandOffset: .word 0 @ For rednand this should be 1 -emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED) - -.pool -.balign 4 - -_emunandPatchEnd: - -.global emunandPatchSize -emunandPatchSize: - .word _emunandPatchEnd - emunandPatch - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ Code originally from delebile and mid-kid diff --git a/k11_extension/source/main.c b/k11_extension/source/main.c index 0ff4e68e1..8210be6db 100644 --- a/k11_extension/source/main.c +++ b/k11_extension/source/main.c @@ -135,33 +135,17 @@ void KProcessHwInfo__MapL2Section_Hook(void); static void installMmuHooks(void) { - u32 *mapL1Section = NULL; - u32 *mapL2Section = NULL; + // Older versions of k11 had different VA memory mappings + u32 k11TextStartVa = (u32)originalHandlers[2] & ~0xFFFF; u32 *off; - for(off = (u32 *)officialSVCs[0x1F]; *off != 0xE1CD60F0; ++off); - off = decodeArmBranch(off + 1); + for (off = (u32 *)k11TextStartVa; off[0] != 0xE3A05801 || off[1] != 0xE2010EE3; off++); + for (; (off[0] >> 16) != 0xE92D; off--); + u32 *mapL2Section = PA_FROM_VA_PTR(off); // fragile, might break due to cache - for (; *off != 0xE58D5000; ++off); - off = decodeArmBranch(off + 1); - - for (; *off != 0xE58DC000; ++off); - off = decodeArmBranch(off + 1); - for (; *off != 0xE1A0000B; ++off); - off = decodeArmBranch(off + 1); - for (; *off != 0xE59D2030; ++off); - off = decodeArmBranch(off + 1); - - for (; *off != 0xE88D1100; ++off); - mapL2Section = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(off + 1)); - - do - { - for (; *off != 0xE58D8000; ++off); - u32 *loc = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(++off)); - if (loc != mapL2Section) - mapL1Section = loc; - } while (mapL1Section == NULL); + for (off = (u32 *)k11TextStartVa; off[0] != 0x13A0A401 || off[1] != 0x03A0A601; off++); + for (; (off[0] >> 16) != 0xE92D; off--); + u32 *mapL1Section = PA_FROM_VA_PTR(off); mapL1Section[1] = 0xE28FE004; // add lr, pc, #4 mapL1Section[2] = 0xE51FF004; // ldr pc, [pc, #-4] @@ -176,8 +160,10 @@ static void findUsefulSymbols(void) { u32 *off; + // Older versions of k11 had different VA memory mappings + u32 k11TextStartVa = (u32)originalHandlers[2] & ~0xFFFF; // Get fcramDescriptor - for (off = (u32 *)0xFFF00000; ; ++off) + for (off = (u32 *)k11TextStartVa; ; ++off) { if ( (off[0] >> 16) == 0xE59F && (off[1] >> 16) == 0xE3A0 diff --git a/sysmodules/loader/source/main.c b/sysmodules/loader/source/main.c index f349286e7..a039b5bab 100644 --- a/sysmodules/loader/source/main.c +++ b/sysmodules/loader/source/main.c @@ -59,7 +59,11 @@ static inline void loadCFWInfo(void) if (numKips >= 6) panic(0xDEADCAFE); - config = 0; // all options 0 +#ifndef BUILD_FOR_EXPLOIT_DEV + config = 1u << PATCHVERSTRING; // all options 0, except maybe the MSET version display patch +#else + config = 0; +#endif multiConfig = 0; bootConfig = 0; isN3DS = OS_KernelConfig->app_memtype >= 6;