The user-mode context is now dumped (instead of the supervisor-mode context) on a svcBreak call.
Kernel panics are now handled by the exception handlers as well.
This commit is contained in:
parent
39b2aff627
commit
f81c92e35b
@ -43,33 +43,52 @@ _commonHandler:
|
||||
mov r6, sp
|
||||
mrs r3, cpsr
|
||||
|
||||
tst r2, #0x20
|
||||
bne noFPUInitNorSvcBreak
|
||||
sub r0, lr, #4
|
||||
stmfd sp!, {lr}
|
||||
bl cannotAccessVA
|
||||
ldmfd sp!, {lr}
|
||||
cmp r0, #0
|
||||
bne noFPUInitNorSvcBreak
|
||||
ldr r4, [lr, #-4]
|
||||
cmp r1, #1
|
||||
bne noFPUInit
|
||||
tst r2, #0x20
|
||||
bne noFPUInit
|
||||
|
||||
ldr r4, [lr, #-4]
|
||||
lsl r4, #4
|
||||
sub r4, #0xc0000000
|
||||
cmp r4, #0x30000000
|
||||
bcs noFPUInit
|
||||
fmrx r3, fpexc
|
||||
tst r3, #0x40000000
|
||||
bne noFPUInit
|
||||
bcs noFPUInitNorSvcBreak
|
||||
fmrx r0, fpexc
|
||||
tst r0, #0x40000000
|
||||
bne noFPUInitNorSvcBreak
|
||||
|
||||
sub lr, #4
|
||||
srsfd sp!, #0x13
|
||||
ldmfd sp!, {r0-r7} @ restore context
|
||||
cps #0x13 @ FPU init
|
||||
ldmfd sp!, {r0-r7} @ restore context
|
||||
cps #0x13 @ FPU init
|
||||
stmfd sp, {r0-r3, r11-lr}^
|
||||
sub sp, #0x20
|
||||
bl . @ will be replaced
|
||||
bl . @ will be replaced
|
||||
ldmfd sp, {r0-r3, r11-lr}^
|
||||
add sp, #0x20
|
||||
rfefd sp!
|
||||
|
||||
noFPUInit:
|
||||
cmp r1, #2
|
||||
bne noFPUInitNorSvcBreak
|
||||
ldr r5, =#0xe12fff7f
|
||||
cmp r4, r5
|
||||
bne noFPUInitNorSvcBreak
|
||||
cps #0x13 @ switch to supervisor mode
|
||||
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
|
||||
|
||||
noFPUInitNorSvcBreak:
|
||||
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||
moveq r4, #0xf @ usr => sys
|
||||
bic r5, r3, #0xf
|
||||
|
@ -29,20 +29,34 @@
|
||||
|
||||
#define CODESET_OFFSET 0xBEEFBEEF
|
||||
|
||||
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 || cannotAccessVA(src) || cannotAccessVA((u8 *)src + size))
|
||||
return 0;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
*out++ = *in++;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type, u32 cpuId)
|
||||
{
|
||||
ExceptionDumpHeader dumpHeader;
|
||||
|
||||
u32 registerDump[REG_DUMP_SIZE / 4];
|
||||
u8 codeDump[CODE_DUMP_SIZE];
|
||||
vu32 *final = (vu32 *)FINAL_BUFFER;
|
||||
u8 *final = (u8 *)FINAL_BUFFER;
|
||||
|
||||
while(final[0] == 0xDEADC0DE && final[1] == 0xDEADCAFE && (final[3] == 9 || (final[3] & 0xFFFF) == 11));
|
||||
while(*(vu32 *)final == 0xDEADC0DE && *((vu32 *)final + 1) == 0xDEADCAFE);
|
||||
|
||||
dumpHeader.magic[0] = 0xDEADC0DE;
|
||||
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||
dumpHeader.versionMajor = 1;
|
||||
dumpHeader.versionMinor = 1;
|
||||
dumpHeader.versionMinor = 2;
|
||||
|
||||
dumpHeader.processor = 11;
|
||||
dumpHeader.core = cpuId & 0xF;
|
||||
@ -66,53 +80,36 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
||||
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
||||
|
||||
//Dump code
|
||||
vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||
if(cannotAccessVA((u8 *)instr) || cannotAccessVA((u8 *)instr + dumpHeader.codeDumpSize))
|
||||
dumpHeader.codeDumpSize = 0;
|
||||
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
||||
codeDump[i] = instr[i];
|
||||
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);
|
||||
|
||||
//Copy register dump and code dump
|
||||
final = (vu32 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||
|
||||
for(u32 i = 0; i < dumpHeader.registerDumpSize / 4; i++)
|
||||
*final++ = registerDump[i];
|
||||
|
||||
for(u32 i = 0; i < dumpHeader.codeDumpSize / 4; i++)
|
||||
*final++ = *((u32 *)codeDump + i);
|
||||
final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1);
|
||||
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1);
|
||||
|
||||
//Dump stack in place
|
||||
vu32 *sp = (vu32 *)registerDump[13];
|
||||
if(cannotAccessVA((u8 *)sp))
|
||||
dumpHeader.stackDumpSize = 0;
|
||||
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
||||
*final++ = sp[i];
|
||||
|
||||
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||
|
||||
vu8 *currentKProcess = (cannotAccessVA((u8 *)0xFFFF9004)) ? NULL : *(vu8 **)0xFFFF9004;
|
||||
vu8 *currentKCodeSet = (currentKProcess != NULL && ((u32)currentKProcess & 3) == 0 && !cannotAccessVA((u8 *)currentKProcess + CODESET_OFFSET))
|
||||
? *(vu8 **)(currentKProcess + CODESET_OFFSET) : NULL;
|
||||
vu8 *currentKCodeSet = (currentKProcess != NULL) ? *(vu8 **)(currentKProcess + CODESET_OFFSET) : NULL;
|
||||
|
||||
if(currentKCodeSet != NULL && ((u32)currentKCodeSet & 3) == 0 && !cannotAccessVA((u8 *)currentKCodeSet))
|
||||
if(currentKCodeSet != NULL)
|
||||
{
|
||||
vu32 *additionalData = final;
|
||||
vu64 *additionalData = (vu64 *)final;
|
||||
dumpHeader.additionalDataSize = 16;
|
||||
|
||||
additionalData[0] = *(vu32 *)(currentKCodeSet + 0x50); //Process name
|
||||
additionalData[1] = *(vu32 *)(currentKCodeSet + 0x54);
|
||||
|
||||
additionalData[2] = *(vu32 *)(currentKCodeSet + 0x5C); //Title ID
|
||||
additionalData[3] = *(vu32 *)(currentKCodeSet + 0x60);
|
||||
additionalData[0] = *(vu64 *)(currentKCodeSet + 0x50); //Process name
|
||||
additionalData[1] = *(vu64 *)(currentKCodeSet + 0x5C); //Title ID
|
||||
}
|
||||
else
|
||||
dumpHeader.additionalDataSize = 0;
|
||||
|
||||
//Copy header (actually optimized by the compiler)
|
||||
final = (vu32 *)FINAL_BUFFER;
|
||||
final = (u8 *)FINAL_BUFFER;
|
||||
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
|
||||
*(ExceptionDumpHeader *)final = dumpHeader;
|
||||
|
||||
|
||||
cleanInvalidateDCacheAndDMB();
|
||||
mcuReboot(); //Also contains DCache-cleaning code
|
||||
}
|
||||
|
@ -42,20 +42,48 @@ _commonHandler:
|
||||
mrs r2, spsr
|
||||
mov r6, sp
|
||||
mrs r3, cpsr
|
||||
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (AIF)
|
||||
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||
moveq r4, #0xf @ usr => sys
|
||||
|
||||
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (equivalent to "cpsid aif" on arm11)
|
||||
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
|
||||
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
|
||||
msr cpsr_c, r5 @ change processor mode
|
||||
stmfd r6!, {r8-lr}
|
||||
msr cpsr_cx, r3 @ restore processor mode
|
||||
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
|
||||
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
|
||||
|
||||
b mainHandler
|
||||
|
||||
GEN_HANDLER FIQHandler
|
||||
@ -66,7 +94,7 @@ GEN_HANDLER dataAbortHandler
|
||||
.global readMPUConfig
|
||||
.type readMPUConfig, %function
|
||||
readMPUConfig:
|
||||
stmfd sp!, {r4-r8}
|
||||
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
|
||||
@ -76,6 +104,5 @@ readMPUConfig:
|
||||
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}
|
||||
bx lr
|
||||
mrc p15,0,r0,c5,c0,2 @ read data access permission bits
|
||||
ldmfd sp!, {r4-r8, pc}
|
||||
|
@ -51,6 +51,20 @@ bool cannotAccessAddress(const void *address)
|
||||
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) || cannotAccessAddress((u8 *)src + size))
|
||||
return 0;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
*out++ = *in++;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type)
|
||||
{
|
||||
ExceptionDumpHeader dumpHeader;
|
||||
@ -61,7 +75,7 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
||||
dumpHeader.magic[0] = 0xDEADC0DE;
|
||||
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||
dumpHeader.versionMajor = 1;
|
||||
dumpHeader.versionMinor = 1;
|
||||
dumpHeader.versionMinor = 2;
|
||||
|
||||
dumpHeader.processor = 9;
|
||||
dumpHeader.core = 0;
|
||||
@ -82,34 +96,25 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
||||
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
|
||||
|
||||
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
||||
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize;
|
||||
|
||||
//Dump code
|
||||
vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||
if(cannotAccessAddress((u8 *)instr) || cannotAccessAddress((u8 *)instr + dumpHeader.codeDumpSize))
|
||||
dumpHeader.codeDumpSize = 0;
|
||||
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
||||
codeDump[i] = instr[i];
|
||||
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);
|
||||
|
||||
//Copy header (actually optimized by the compiler), register dump and code dump
|
||||
vu32 *final = (vu32 *)FINAL_BUFFER;
|
||||
*(ExceptionDumpHeader *)final = dumpHeader;
|
||||
final += sizeof(ExceptionDumpHeader) / 4;
|
||||
|
||||
for(u32 i = 0; i < dumpHeader.registerDumpSize / 4; i++)
|
||||
*final++ = registerDump[i];
|
||||
|
||||
for(u32 i = 0; i < dumpHeader.codeDumpSize / 4; i++)
|
||||
*final++ = *((u32 *)codeDump + i);
|
||||
//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);
|
||||
|
||||
//Dump stack in place
|
||||
vu32 *sp = (vu32 *)registerDump[13];
|
||||
if(cannotAccessAddress((u8 *)sp))
|
||||
dumpHeader.stackDumpSize = 0;
|
||||
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
||||
*final++ = sp[i];
|
||||
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||
|
||||
//Copy header (actually optimized by the compiler)
|
||||
final = (u8 *)FINAL_BUFFER;
|
||||
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
|
||||
*(ExceptionDumpHeader *)final = dumpHeader;
|
||||
|
||||
((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
|
||||
while(1);
|
||||
while(true);
|
||||
}
|
@ -100,7 +100,7 @@ if __name__ == "__main__":
|
||||
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
|
||||
nbRegisters //= 4
|
||||
|
||||
if version < (1 << 16) | 1:
|
||||
if version < (1 << 16) | 2:
|
||||
raise SystemExit("Incompatible format version, please use the appropriate parser.")
|
||||
|
||||
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
|
||||
@ -114,8 +114,18 @@ if __name__ == "__main__":
|
||||
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
||||
|
||||
typeDetailsStr = ""
|
||||
if exceptionType == 2 and (registers[16] & 0x20) == 0 and codeDumpSize >= 4 and unpack_from("<I", codeDump[-4:])[0] == 0xe12fff7f:
|
||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||
if exceptionType == 2:
|
||||
if (registers[16] & 0x20) == 0 and codeDumpSize >= 4:
|
||||
instr = unpack_from("<I", codeDump[-4:])[0]
|
||||
if instr == 0xe12fff7e:
|
||||
typeDetailsStr = " (kernel panic)"
|
||||
elif instr == 0xef00003c:
|
||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||
elif (registers[16] & 0x20) == 1 and codeDumpSize >= 2:
|
||||
instr = unpack_from("<I", codeDump[-4:])[0]
|
||||
if instr == 0xdf3c:
|
||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||
|
||||
elif processor != 9 and (registers[20] & 0x80000000) != 0:
|
||||
typeDetailsStr = " (VFP exception)"
|
||||
|
||||
|
@ -162,10 +162,25 @@ void detectAndProcessExceptionDumps(void)
|
||||
|
||||
posY = drawString("Exception type: ", 10, posY, COLOR_WHITE);
|
||||
posY = drawString(handledExceptionNames[dumpHeader->type], 10 + 17 * SPACING_X, posY, COLOR_WHITE);
|
||||
if(dumpHeader->type == 2 && dumpHeader->registerDumpSize >= 4 && (regs[16] & 0x20) == 0
|
||||
&& *(vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader) + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize - 4) == 0xE12FFF7F)
|
||||
posY = drawString("(svcBreak)", 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
|
||||
if(dumpHeader->type == 2)
|
||||
{
|
||||
if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4)
|
||||
{
|
||||
u32 instr = *(vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader) + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize - 4);
|
||||
if(instr == 0xE12FFF7E)
|
||||
posY = drawString("(kernel panic)", 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
else if(instr == 0xEF00003C)
|
||||
posY = drawString("(svcBreak)", 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
else if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 2)
|
||||
{
|
||||
u16 instr = *(vu16 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader) + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize - 2);
|
||||
if(instr == 0xDF3C)
|
||||
posY = drawString("(svcBreak)", 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||
{
|
||||
posY += SPACING_Y;
|
||||
|
@ -358,9 +358,12 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
|
||||
//Kernel9/Process9 debugging
|
||||
patchExceptionHandlersInstall(arm9Section, section[2].size);
|
||||
patchSvcBreak9(arm9Section, section[2].size, (u32)(section[2].address));
|
||||
patchKernel9Panic(arm9Section, section[2].size);
|
||||
|
||||
//Stub svcBreak11 with "bkpt 65535"
|
||||
patchSvcBreak11(arm11Section1, section[1].size);
|
||||
//Stub kernel11panic with "bkpt 65534"
|
||||
patchKernel11Panic(arm11Section1, section[1].size);
|
||||
|
||||
//Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
|
||||
patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size);
|
||||
@ -390,6 +393,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
||||
//Kernel9/Process9 debugging
|
||||
patchExceptionHandlersInstall(arm9Section, section[3].size);
|
||||
patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address));
|
||||
patchKernel9Panic(arm9Section, section[3].size);
|
||||
}
|
||||
|
||||
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||
@ -414,10 +418,11 @@ static inline void patchSafeFirm(void)
|
||||
//Kernel9/Process9 debugging
|
||||
patchExceptionHandlersInstall(arm9Section, section[2].size);
|
||||
patchSvcBreak9(arm9Section, section[2].size, (u32)(section[2].address));
|
||||
patchKernel9Panic(arm9Section, section[2].size);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void copySection0AndInjectSystemModules(void)
|
||||
static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
|
||||
{
|
||||
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
||||
char fileName[] = "/luma/sysmodules/--------.cxi";
|
||||
@ -430,40 +435,45 @@ static inline void copySection0AndInjectSystemModules(void)
|
||||
const u8 *addr;
|
||||
} modules[5] = {{0}};
|
||||
|
||||
u8 *pos = arm11Section0;
|
||||
u8 *pos = arm11Section0, *end = pos + section[0].size;
|
||||
u32 n = 0;
|
||||
|
||||
u32 loaderIndex = 0;
|
||||
for(u32 i = 0; i < 5; i++)
|
||||
|
||||
while(pos < end)
|
||||
{
|
||||
modules[i].addr = pos;
|
||||
modules[i].size = *(u32 *)(pos + 0x104) * 0x200;
|
||||
modules[n].addr = pos;
|
||||
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
||||
|
||||
memcpy(modules[i].name, pos + 0x200, 8);
|
||||
pos += modules[i].size;
|
||||
memcpy(modules[n].name, pos + 0x200, 8);
|
||||
pos += modules[n].size;
|
||||
|
||||
//Read modules from files if they exist
|
||||
u32 nameOff;
|
||||
for(nameOff = 0; nameOff < 8 && modules[i].name[nameOff] != 0; nameOff++);
|
||||
memcpy(fileName + 17, modules[i].name, nameOff);
|
||||
for(nameOff = 0; nameOff < 8 && modules[n].name[nameOff] != 0; nameOff++);
|
||||
memcpy(fileName + 17, modules[n].name, nameOff);
|
||||
memcpy(fileName + 17 + nameOff, ext, 5);
|
||||
|
||||
u32 fileSize = getFileSize(fileName);
|
||||
if(fileSize != 0)
|
||||
{
|
||||
modules[i].addr = NULL;
|
||||
modules[i].size = fileSize;
|
||||
modules[n].addr = NULL;
|
||||
modules[n].size = fileSize;
|
||||
}
|
||||
|
||||
if(memcmp(modules[i].name, "loader", 7) == 0) loaderIndex = i;
|
||||
if(firmType == NATIVE_FIRM && memcmp(modules[n].name, "loader", 7) == 0) loaderIndex = n;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
if(modules[loaderIndex].addr != NULL)
|
||||
if(firmType == NATIVE_FIRM && modules[loaderIndex].addr != NULL)
|
||||
{
|
||||
modules[loaderIndex].size = injector_size;
|
||||
modules[loaderIndex].addr = injector;
|
||||
}
|
||||
|
||||
pos = section[0].address;
|
||||
for(u32 i = 0; i < 5; i++)
|
||||
for(u32 i = 0; i < n; i++)
|
||||
{
|
||||
if(modules[i].addr != NULL)
|
||||
memcpy(pos, modules[i].addr, modules[i].size);
|
||||
@ -487,7 +497,7 @@ static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
|
||||
u32 sectionNum;
|
||||
if(firmType != SAFE_FIRM)
|
||||
{
|
||||
copySection0AndInjectSystemModules();
|
||||
copySection0AndInjectSystemModules(firmType);
|
||||
sectionNum = 1;
|
||||
}
|
||||
else sectionNum = 0;
|
||||
|
@ -58,5 +58,5 @@ static inline u32 loadFirm(FirmwareType firmType);
|
||||
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
||||
static inline void patchLegacyFirm(FirmwareType firmType);
|
||||
static inline void patchSafeFirm(void);
|
||||
static inline void copySection0AndInjectSystemModules(void);
|
||||
static inline void copySection0AndInjectSystemModules(FirmwareType firmType);
|
||||
static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch);
|
@ -177,7 +177,8 @@ void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr)
|
||||
|
||||
u32 *arm9SvcTable = (u32 *)memsearch(pos, svcHandlerPattern, size, 4);
|
||||
while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL)
|
||||
*(u32 *)(pos + arm9SvcTable[0x3C] - k9addr) = 0xE12FFF7F;
|
||||
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - k9addr);
|
||||
*addr = 0xE12FFF7F;
|
||||
}
|
||||
|
||||
void patchSvcBreak11(u8 *pos, u32 size)
|
||||
@ -185,7 +186,24 @@ void patchSvcBreak11(u8 *pos, u32 size)
|
||||
//Same as above, for NFIRM arm11
|
||||
|
||||
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
|
||||
*(u32 *)(pos + arm11SvcTable[0x3C] - 0xFFF00000) = 0xE12FFF7F;
|
||||
u32 *addr = (u32 *)(pos + arm11SvcTable[0x3C] - 0xFFF00000);
|
||||
*addr = 0xE12FFF7F;
|
||||
}
|
||||
|
||||
void patchKernel9Panic(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x20, 0xA0, 0xE3, 0x02, 0x30, 0xA0, 0xE1, 0x02, 0x10, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE3};
|
||||
|
||||
u32 *off = (u32 *)memsearch(pos, pattern, size, 16);
|
||||
*off = 0xE12FFF7E;
|
||||
}
|
||||
|
||||
void patchKernel11Panic(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2, 0x00, 0x10, 0x90, 0xE5};
|
||||
|
||||
u32 *off = (u32 *)memsearch(pos, pattern, size, 8);
|
||||
*off = 0xE12FFF7E;
|
||||
}
|
||||
|
||||
void patchArm11SvcAccessChecks(u8 *pos, u32 size)
|
||||
|
@ -45,6 +45,8 @@ void patchFirmWriteSafe(u8 *pos, u32 size);
|
||||
void patchExceptionHandlersInstall(u8 *pos, u32 size);
|
||||
void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr);
|
||||
void patchSvcBreak11(u8 *pos, u32 size);
|
||||
void patchKernel9Panic(u8 *pos, u32 size);
|
||||
void patchKernel11Panic(u8 *pos, u32 size);
|
||||
void patchArm11SvcAccessChecks(u8 *pos, u32 size);
|
||||
void patchK11ModuleChecks(u8 *pos, u32 size);
|
||||
void patchP9AccessChecks(u8 *pos, u32 size);
|
||||
|
Reference in New Issue
Block a user