Skip to content

Commit 035c50c

Browse files
committed
Fix support for all older versions
- Move emuNAND hook to ITCM, fixing previously untested emuNAND support for 5.0 (and possibly more versions). This was a very long-standing bug - Fix booting on versions 4.x to 8.x, and restore full support for 5.x to 8.x. All Arm11 custom sysmodules and k11ext have been disabled on 4.x because the Luma3DS v13.0 changes couldn't be ported (this means no Rosalina and no region-free and such, and while I could restore some of the functionality, you should just update *after* installing Luma, like you've been instructed to)
1 parent 5989d9d commit 035c50c

File tree

8 files changed

+89
-140
lines changed

8 files changed

+89
-140
lines changed

arm9/linker.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ SECTIONS
4646
chainloader.o(.text*)
4747
i2c.o(.text*)
4848
arm9_exception_handlers.o(.text*)
49+
KEEP (*(.emunand_patch))
4950

5051
*(.arm9_exception_handlers.rodata*)
5152
chainloader.o(.rodata*)

arm9/source/emunand.c

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -111,21 +111,6 @@ void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCt
111111
else *nandType = FIRMWARE_SYSNAND;
112112
}
113113

114-
static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
115-
{
116-
static const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
117-
118-
//Looking for the last free space before Process9
119-
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
120-
121-
if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunandPatchSize ||
122-
*(u32 *)(*freeK9Space + 0x455 + emunandPatchSize - 4) != 0xFFFFFFFF) return false;
123-
124-
*freeK9Space += 0x455;
125-
126-
return true;
127-
}
128-
129114
static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion)
130115
{
131116
switch(firmVersion)
@@ -158,7 +143,7 @@ static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
158143
return 0;
159144
}
160145

161-
static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
146+
static inline u32 patchNandRw(u8 *pos, u32 size, u32 hookAddr)
162147
{
163148
//Look for read/write code
164149
static const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
@@ -176,32 +161,13 @@ static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
176161
writeOffset -= 3;
177162
*readOffset = *writeOffset = 0x4C00;
178163
readOffset[1] = writeOffset[1] = 0x47A0;
179-
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset;
180-
181-
return 0;
182-
}
183-
184-
static inline u32 patchMpu(u8 *pos, u32 size)
185-
{
186-
//Look for MPU pattern
187-
static const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
188-
189-
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
190-
191-
if(off == NULL) return 1;
192-
193-
off[1] = 0x0036;
194-
off[0xC] = off[0x12] = 0x0603;
164+
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = hookAddr;
195165

196166
return 0;
197167
}
198168

199-
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion)
169+
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
200170
{
201-
u8 *freeK9Space;
202-
203-
if(!getFreeK9Space(arm9Section, kernel9Size, &freeK9Space)) return 1;
204-
205171
u32 ret = 0;
206172

207173
//Add the data of the found EmuNAND
@@ -213,15 +179,8 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce
213179
ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc);
214180
if(!ret) emunandPatchSdmmcStructPtr = sdmmc;
215181

216-
//Copy EmuNAND code
217-
memcpy(freeK9Space, emunandPatch, emunandPatchSize);
218-
219182
//Add EmuNAND hooks
220-
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
221-
ret += patchNandRw(process9Offset, process9Size, branchOffset);
222-
223-
//Set MPU
224-
ret += patchMpu(arm9Section, kernel9Size);
183+
ret += patchNandRw(process9Offset, process9Size, (u32)emunandPatch);
225184

226185
return ret;
227186
}

arm9/source/emunand.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ extern u32 emuOffset,
3838
emuHeader;
3939

4040
void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCtrNandParams);
41-
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion);
41+
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion);

arm9/source/emunand_patch.s

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
.section .emunand_patch, "aw", %progbits
2+
.arm
3+
.align 4
4+
5+
@ Code originally by Normmatt
6+
7+
.global emunandPatch
8+
emunandPatch:
9+
@ Original code that still needs to be executed
10+
mov r4, r0
11+
mov r5, r1
12+
mov r7, r2
13+
mov r6, r3
14+
@ End
15+
16+
@ If we're already trying to access the SD, return
17+
ldr r2, [r0, #4]
18+
ldr r1, emunandPatchSdmmcStructPtr
19+
cmp r2, r1
20+
beq out
21+
22+
str r1, [r0, #4] @ Set object to be SD
23+
ldr r2, [r0, #8] @ Get sector to read
24+
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
25+
26+
ldr r3, emunandPatchNandOffset
27+
add r2, r3 @ Add the offset to the NAND in the SD
28+
29+
ldreq r3, emunandPatchNcsdHeaderOffset
30+
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
31+
32+
str r2, [r0, #8] @ Store sector to read
33+
34+
out:
35+
@ Restore registers.
36+
mov r1, r5
37+
mov r2, r7
38+
mov r3, r6
39+
40+
@ Return 4 bytes behind where we got called,
41+
@ due to the offset of this function being stored there
42+
mov r0, lr
43+
add r0, #4
44+
bx r0
45+
46+
.pool
47+
48+
.global emunandPatchSdmmcStructPtr
49+
.global emunandPatchNandOffset
50+
.global emunandPatchNcsdHeaderOffset
51+
52+
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
53+
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
54+
emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED)
55+
56+
.pool
57+
.balign 4
58+
59+
_emunandPatchEnd:
60+
61+
.global emunandPatchSize
62+
emunandPatchSize:
63+
.word _emunandPatchEnd - emunandPatch

arm9/source/firm.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ static void mergeSection0(FirmwareType firmType, u32 firmVersion, bool loadFromS
422422
}
423423

424424
// SAFE_FIRM only for N3DS and only if ENABLESAFEFIRMROSALINA is on
425-
if((firmType == NATIVE_FIRM || firmType == SAFE_FIRM) && (ISN3DS || firmVersion >= 0x1D))
425+
if((firmType == NATIVE_FIRM || firmType == SAFE_FIRM) && (ISN3DS || firmVersion >= 0x25))
426426
{
427427
//2) Merge that info with our own modules'
428428
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
528528
ret = 0;
529529

530530
#ifndef BUILD_FOR_EXPLOIT_DEV
531-
//Skip on FIRMs < 4.0
532-
if(ISN3DS || firmVersion >= 0x1D)
531+
//Skip on FIRMs < 5.0
532+
if(ISN3DS || firmVersion >= 0x25)
533533
{
534534
//Find the Kernel11 SVC table and handler, exceptions page and free space locations
535535
u8 *arm11Section1 = (u8 *)firm + firm->section[1].offset;
@@ -550,7 +550,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
550550
ret += patchSignatureChecks(process9Offset, process9Size);
551551

552552
//Apply EmuNAND patches
553-
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion);
553+
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(process9Offset, process9Size, firmVersion);
554554

555555
//Apply FIRM0/1 writes patches on SysNAND to protect A9LH
556556
else if(isFirmProtEnabled) ret += patchFirmWrites(process9Offset, process9Size);

arm9/source/large_patches.s

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,3 @@
1-
.section .large_patch.emunand, "aw", %progbits
2-
.arm
3-
.align 4
4-
5-
@ Code originally by Normmatt
6-
7-
.global emunandPatch
8-
emunandPatch:
9-
@ Original code that still needs to be executed
10-
mov r4, r0
11-
mov r5, r1
12-
mov r7, r2
13-
mov r6, r3
14-
@ End
15-
16-
@ If we're already trying to access the SD, return
17-
ldr r2, [r0, #4]
18-
ldr r1, emunandPatchSdmmcStructPtr
19-
cmp r2, r1
20-
beq out
21-
22-
str r1, [r0, #4] @ Set object to be SD
23-
ldr r2, [r0, #8] @ Get sector to read
24-
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
25-
26-
ldr r3, emunandPatchNandOffset
27-
add r2, r3 @ Add the offset to the NAND in the SD
28-
29-
ldreq r3, emunandPatchNcsdHeaderOffset
30-
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
31-
32-
str r2, [r0, #8] @ Store sector to read
33-
34-
out:
35-
@ Restore registers.
36-
mov r1, r5
37-
mov r2, r7
38-
mov r3, r6
39-
40-
@ Return 4 bytes behind where we got called,
41-
@ due to the offset of this function being stored there
42-
mov r0, lr
43-
add r0, #4
44-
bx r0
45-
46-
.pool
47-
48-
.global emunandPatchSdmmcStructPtr
49-
.global emunandPatchNandOffset
50-
.global emunandPatchNcsdHeaderOffset
51-
52-
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
53-
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
54-
emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED)
55-
56-
.pool
57-
.balign 4
58-
59-
_emunandPatchEnd:
60-
61-
.global emunandPatchSize
62-
emunandPatchSize:
63-
.word _emunandPatchEnd - emunandPatch
64-
651
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
662

673
@ Code originally from delebile and mid-kid

k11_extension/source/main.c

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -135,33 +135,17 @@ void KProcessHwInfo__MapL2Section_Hook(void);
135135

136136
static void installMmuHooks(void)
137137
{
138-
u32 *mapL1Section = NULL;
139-
u32 *mapL2Section = NULL;
138+
// Older versions of k11 had different VA memory mappings
139+
u32 k11TextStartVa = (u32)originalHandlers[2] & ~0xFFFF;
140140
u32 *off;
141141

142-
for(off = (u32 *)officialSVCs[0x1F]; *off != 0xE1CD60F0; ++off);
143-
off = decodeArmBranch(off + 1);
142+
for (off = (u32 *)k11TextStartVa; off[0] != 0xE3A05801 || off[1] != 0xE2010EE3; off++);
143+
for (; (off[0] >> 16) != 0xE92D; off--);
144+
u32 *mapL2Section = PA_FROM_VA_PTR(off); // fragile, might break due to cache
144145

145-
for (; *off != 0xE58D5000; ++off);
146-
off = decodeArmBranch(off + 1);
147-
148-
for (; *off != 0xE58DC000; ++off);
149-
off = decodeArmBranch(off + 1);
150-
for (; *off != 0xE1A0000B; ++off);
151-
off = decodeArmBranch(off + 1);
152-
for (; *off != 0xE59D2030; ++off);
153-
off = decodeArmBranch(off + 1);
154-
155-
for (; *off != 0xE88D1100; ++off);
156-
mapL2Section = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(off + 1));
157-
158-
do
159-
{
160-
for (; *off != 0xE58D8000; ++off);
161-
u32 *loc = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(++off));
162-
if (loc != mapL2Section)
163-
mapL1Section = loc;
164-
} while (mapL1Section == NULL);
146+
for (off = (u32 *)k11TextStartVa; off[0] != 0x13A0A401 || off[1] != 0x03A0A601; off++);
147+
for (; (off[0] >> 16) != 0xE92D; off--);
148+
u32 *mapL1Section = PA_FROM_VA_PTR(off);
165149

166150
mapL1Section[1] = 0xE28FE004; // add lr, pc, #4
167151
mapL1Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
@@ -176,8 +160,10 @@ static void findUsefulSymbols(void)
176160
{
177161
u32 *off;
178162

163+
// Older versions of k11 had different VA memory mappings
164+
u32 k11TextStartVa = (u32)originalHandlers[2] & ~0xFFFF;
179165
// Get fcramDescriptor
180-
for (off = (u32 *)0xFFF00000; ; ++off)
166+
for (off = (u32 *)k11TextStartVa; ; ++off)
181167
{
182168
if ( (off[0] >> 16) == 0xE59F
183169
&& (off[1] >> 16) == 0xE3A0

sysmodules/loader/source/main.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ static inline void loadCFWInfo(void)
5959
if (numKips >= 6)
6060
panic(0xDEADCAFE);
6161

62-
config = 0; // all options 0
62+
#ifndef BUILD_FOR_EXPLOIT_DEV
63+
config = 1u << PATCHVERSTRING; // all options 0, except maybe the MSET version display patch
64+
#else
65+
config = 0;
66+
#endif
6367
multiConfig = 0;
6468
bootConfig = 0;
6569
isN3DS = OS_KernelConfig->app_memtype >= 6;

0 commit comments

Comments
 (0)