Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EmuNAND support for TWL_FIRM, other related fixes #1696

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions arm9/source/arm9_exception_handlers_asm.s
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,17 @@ 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

ldr sp, =arm9ExceptionHandlerSvcBreakAddress
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

Expand Down
25 changes: 20 additions & 5 deletions arm9/source/emunand.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arm9/source/emunand.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
4 changes: 3 additions & 1 deletion arm9/source/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
Expand Down
12 changes: 10 additions & 2 deletions arm9/source/firm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion arm9/source/firm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
39 changes: 21 additions & 18 deletions arm9/source/large_patches.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.section .large_patch.emunand, "aw", %progbits
.arm
.thumb
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the rationale behind this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned this in the commit message for 6ffef91 but I guess I should've explained more prominently: the free space region in kernel9 used for the emunand patch is too small in the TWL_FIRM kernel9s from firmware versions 3.0 and 3.1 to fit the old patch, so I ported the patch to thumb mode to make it fit.

I don't remember exactly how small the free space is in those versions or by how much the old arm-mode patch didn't fit, but I remember trying to cut down the size of the patch while keeping it in arm mode, and I was almost able to get it small enough, but I had to resort to some pretty ugly-looking hacks at that point, and it was still 4 or 8 bytes to big. I didn't see a strong reason to not just use thumb, so I just used thumb.

If you'd like me to go find the exact numbers for all this I can do so, it'll just take a little while for me to find it.

.align 4

@ Code originally by Normmatt
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arm9/source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
79 changes: 69 additions & 10 deletions arm9/source/patches.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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};
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions arm9/source/patches.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down