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
|
mov r6, sp
|
||||||
mrs r3, cpsr
|
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
|
cmp r1, #1
|
||||||
bne noFPUInit
|
bne noFPUInit
|
||||||
tst r2, #0x20
|
|
||||||
bne noFPUInit
|
|
||||||
|
|
||||||
ldr r4, [lr, #-4]
|
|
||||||
lsl r4, #4
|
lsl r4, #4
|
||||||
sub r4, #0xc0000000
|
sub r4, #0xc0000000
|
||||||
cmp r4, #0x30000000
|
cmp r4, #0x30000000
|
||||||
bcs noFPUInit
|
bcs noFPUInitNorSvcBreak
|
||||||
fmrx r3, fpexc
|
fmrx r0, fpexc
|
||||||
tst r3, #0x40000000
|
tst r0, #0x40000000
|
||||||
bne noFPUInit
|
bne noFPUInitNorSvcBreak
|
||||||
|
|
||||||
sub lr, #4
|
sub lr, #4
|
||||||
srsfd sp!, #0x13
|
srsfd sp!, #0x13
|
||||||
ldmfd sp!, {r0-r7} @ restore context
|
ldmfd sp!, {r0-r7} @ restore context
|
||||||
cps #0x13 @ FPU init
|
cps #0x13 @ FPU init
|
||||||
stmfd sp, {r0-r3, r11-lr}^
|
stmfd sp, {r0-r3, r11-lr}^
|
||||||
sub sp, #0x20
|
sub sp, #0x20
|
||||||
bl . @ will be replaced
|
bl . @ will be replaced
|
||||||
ldmfd sp, {r0-r3, r11-lr}^
|
ldmfd sp, {r0-r3, r11-lr}^
|
||||||
add sp, #0x20
|
add sp, #0x20
|
||||||
rfefd sp!
|
rfefd sp!
|
||||||
|
|
||||||
noFPUInit:
|
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
|
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||||
moveq r4, #0xf @ usr => sys
|
moveq r4, #0xf @ usr => sys
|
||||||
bic r5, r3, #0xf
|
bic r5, r3, #0xf
|
||||||
|
@ -29,20 +29,34 @@
|
|||||||
|
|
||||||
#define CODESET_OFFSET 0xBEEFBEEF
|
#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)
|
void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type, u32 cpuId)
|
||||||
{
|
{
|
||||||
ExceptionDumpHeader dumpHeader;
|
ExceptionDumpHeader dumpHeader;
|
||||||
|
|
||||||
u32 registerDump[REG_DUMP_SIZE / 4];
|
u32 registerDump[REG_DUMP_SIZE / 4];
|
||||||
u8 codeDump[CODE_DUMP_SIZE];
|
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[0] = 0xDEADC0DE;
|
||||||
dumpHeader.magic[1] = 0xDEADCAFE;
|
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||||
dumpHeader.versionMajor = 1;
|
dumpHeader.versionMajor = 1;
|
||||||
dumpHeader.versionMinor = 1;
|
dumpHeader.versionMinor = 2;
|
||||||
|
|
||||||
dumpHeader.processor = 11;
|
dumpHeader.processor = 11;
|
||||||
dumpHeader.core = cpuId & 0xF;
|
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);
|
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
||||||
|
|
||||||
//Dump code
|
//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
|
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
|
||||||
if(cannotAccessVA((u8 *)instr) || cannotAccessVA((u8 *)instr + dumpHeader.codeDumpSize))
|
dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4);
|
||||||
dumpHeader.codeDumpSize = 0;
|
|
||||||
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
|
||||||
codeDump[i] = instr[i];
|
|
||||||
|
|
||||||
//Copy register dump and code dump
|
//Copy register dump and code dump
|
||||||
final = (vu32 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||||
|
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1);
|
||||||
for(u32 i = 0; i < dumpHeader.registerDumpSize / 4; i++)
|
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1);
|
||||||
*final++ = registerDump[i];
|
|
||||||
|
|
||||||
for(u32 i = 0; i < dumpHeader.codeDumpSize / 4; i++)
|
|
||||||
*final++ = *((u32 *)codeDump + i);
|
|
||||||
|
|
||||||
//Dump stack in place
|
//Dump stack in place
|
||||||
vu32 *sp = (vu32 *)registerDump[13];
|
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||||
if(cannotAccessVA((u8 *)sp))
|
|
||||||
dumpHeader.stackDumpSize = 0;
|
|
||||||
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
|
||||||
*final++ = sp[i];
|
|
||||||
|
|
||||||
|
|
||||||
vu8 *currentKProcess = (cannotAccessVA((u8 *)0xFFFF9004)) ? NULL : *(vu8 **)0xFFFF9004;
|
vu8 *currentKProcess = (cannotAccessVA((u8 *)0xFFFF9004)) ? NULL : *(vu8 **)0xFFFF9004;
|
||||||
vu8 *currentKCodeSet = (currentKProcess != NULL && ((u32)currentKProcess & 3) == 0 && !cannotAccessVA((u8 *)currentKProcess + CODESET_OFFSET))
|
vu8 *currentKCodeSet = (currentKProcess != NULL) ? *(vu8 **)(currentKProcess + CODESET_OFFSET) : 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;
|
dumpHeader.additionalDataSize = 16;
|
||||||
|
|
||||||
additionalData[0] = *(vu32 *)(currentKCodeSet + 0x50); //Process name
|
additionalData[0] = *(vu64 *)(currentKCodeSet + 0x50); //Process name
|
||||||
additionalData[1] = *(vu32 *)(currentKCodeSet + 0x54);
|
additionalData[1] = *(vu64 *)(currentKCodeSet + 0x5C); //Title ID
|
||||||
|
|
||||||
additionalData[2] = *(vu32 *)(currentKCodeSet + 0x5C); //Title ID
|
|
||||||
additionalData[3] = *(vu32 *)(currentKCodeSet + 0x60);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dumpHeader.additionalDataSize = 0;
|
dumpHeader.additionalDataSize = 0;
|
||||||
|
|
||||||
//Copy header (actually optimized by the compiler)
|
//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;
|
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
|
||||||
*(ExceptionDumpHeader *)final = dumpHeader;
|
*(ExceptionDumpHeader *)final = dumpHeader;
|
||||||
|
|
||||||
|
|
||||||
cleanInvalidateDCacheAndDMB();
|
cleanInvalidateDCacheAndDMB();
|
||||||
mcuReboot(); //Also contains DCache-cleaning code
|
mcuReboot(); //Also contains DCache-cleaning code
|
||||||
}
|
}
|
||||||
|
@ -42,20 +42,48 @@ _commonHandler:
|
|||||||
mrs r2, spsr
|
mrs r2, spsr
|
||||||
mov r6, sp
|
mov r6, sp
|
||||||
mrs r3, cpsr
|
mrs r3, cpsr
|
||||||
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (AIF)
|
|
||||||
ands r4, r2, #0xf @ get the mode that triggered the exception
|
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (equivalent to "cpsid aif" on arm11)
|
||||||
moveq r4, #0xf @ usr => sys
|
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
|
bic r5, r3, #0xf
|
||||||
orr r5, r4
|
orr r5, r4
|
||||||
msr cpsr_c, r5 @ change processor mode
|
msr cpsr_c, r5 @ change processor mode
|
||||||
stmfd r6!, {r8-lr}
|
stmfd r6!, {r8-lr}
|
||||||
msr cpsr_cx, r3 @ restore processor mode
|
msr cpsr_c, r3 @ restore processor mode
|
||||||
mov sp, r6
|
mov sp, r6
|
||||||
|
|
||||||
stmfd sp!, {r2,lr} @ it's a bit of a mess, but we will fix that later
|
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
|
@ order of saved regs now: cpsr, pc + (2/4/8), r8-r14, r0-r7
|
||||||
|
|
||||||
mov r0, sp
|
mov r0, sp
|
||||||
|
|
||||||
b mainHandler
|
b mainHandler
|
||||||
|
|
||||||
GEN_HANDLER FIQHandler
|
GEN_HANDLER FIQHandler
|
||||||
@ -66,7 +94,7 @@ GEN_HANDLER dataAbortHandler
|
|||||||
.global readMPUConfig
|
.global readMPUConfig
|
||||||
.type readMPUConfig, %function
|
.type readMPUConfig, %function
|
||||||
readMPUConfig:
|
readMPUConfig:
|
||||||
stmfd sp!, {r4-r8}
|
stmfd sp!, {r4-r8, lr}
|
||||||
mrc p15,0,r1,c6,c0,0
|
mrc p15,0,r1,c6,c0,0
|
||||||
mrc p15,0,r2,c6,c1,0
|
mrc p15,0,r2,c6,c1,0
|
||||||
mrc p15,0,r3,c6,c2,0
|
mrc p15,0,r3,c6,c2,0
|
||||||
@ -76,6 +104,5 @@ readMPUConfig:
|
|||||||
mrc p15,0,r7,c6,c6,0
|
mrc p15,0,r7,c6,c6,0
|
||||||
mrc p15,0,r8,c6,c7,0
|
mrc p15,0,r8,c6,c7,0
|
||||||
stmia r0, {r1-r8}
|
stmia r0, {r1-r8}
|
||||||
mrc p15,0,r0,c5,c0,2 @ read data access permission bits
|
mrc p15,0,r0,c5,c0,2 @ read data access permission bits
|
||||||
ldmfd sp!, {r4-r8}
|
ldmfd sp!, {r4-r8, pc}
|
||||||
bx lr
|
|
||||||
|
@ -51,6 +51,20 @@ bool cannotAccessAddress(const void *address)
|
|||||||
return true;
|
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)
|
void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type)
|
||||||
{
|
{
|
||||||
ExceptionDumpHeader dumpHeader;
|
ExceptionDumpHeader dumpHeader;
|
||||||
@ -61,7 +75,7 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
dumpHeader.magic[0] = 0xDEADC0DE;
|
dumpHeader.magic[0] = 0xDEADC0DE;
|
||||||
dumpHeader.magic[1] = 0xDEADCAFE;
|
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||||
dumpHeader.versionMajor = 1;
|
dumpHeader.versionMajor = 1;
|
||||||
dumpHeader.versionMinor = 1;
|
dumpHeader.versionMinor = 2;
|
||||||
|
|
||||||
dumpHeader.processor = 9;
|
dumpHeader.processor = 9;
|
||||||
dumpHeader.core = 0;
|
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];
|
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
|
||||||
|
|
||||||
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
||||||
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize;
|
|
||||||
|
|
||||||
//Dump code
|
//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
|
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
|
||||||
if(cannotAccessAddress((u8 *)instr) || cannotAccessAddress((u8 *)instr + dumpHeader.codeDumpSize))
|
dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4);
|
||||||
dumpHeader.codeDumpSize = 0;
|
|
||||||
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
|
||||||
codeDump[i] = instr[i];
|
|
||||||
|
|
||||||
//Copy header (actually optimized by the compiler), register dump and code dump
|
//Copy register dump and code dump
|
||||||
vu32 *final = (vu32 *)FINAL_BUFFER;
|
u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||||
*(ExceptionDumpHeader *)final = dumpHeader;
|
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1);
|
||||||
final += sizeof(ExceptionDumpHeader) / 4;
|
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
//Dump stack in place
|
//Dump stack in place
|
||||||
vu32 *sp = (vu32 *)registerDump[13];
|
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||||
if(cannotAccessAddress((u8 *)sp))
|
|
||||||
dumpHeader.stackDumpSize = 0;
|
//Copy header (actually optimized by the compiler)
|
||||||
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
final = (u8 *)FINAL_BUFFER;
|
||||||
*final++ = sp[i];
|
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
|
((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
|
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)
|
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
|
||||||
nbRegisters //= 4
|
nbRegisters //= 4
|
||||||
|
|
||||||
if version < (1 << 16) | 1:
|
if version < (1 << 16) | 2:
|
||||||
raise SystemExit("Incompatible format version, please use the appropriate parser.")
|
raise SystemExit("Incompatible format version, please use the appropriate parser.")
|
||||||
|
|
||||||
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
|
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))
|
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
||||||
|
|
||||||
typeDetailsStr = ""
|
typeDetailsStr = ""
|
||||||
if exceptionType == 2 and (registers[16] & 0x20) == 0 and codeDumpSize >= 4 and unpack_from("<I", codeDump[-4:])[0] == 0xe12fff7f:
|
if exceptionType == 2:
|
||||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
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:
|
elif processor != 9 and (registers[20] & 0x80000000) != 0:
|
||||||
typeDetailsStr = " (VFP exception)"
|
typeDetailsStr = " (VFP exception)"
|
||||||
|
|
||||||
|
@ -162,9 +162,24 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
|
|
||||||
posY = drawString("Exception type: ", 10, posY, COLOR_WHITE);
|
posY = drawString("Exception type: ", 10, posY, COLOR_WHITE);
|
||||||
posY = drawString(handledExceptionNames[dumpHeader->type], 10 + 17 * SPACING_X, 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)
|
if(dumpHeader->type == 2)
|
||||||
posY = drawString("(svcBreak)", 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
{
|
||||||
|
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)
|
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||||
{
|
{
|
||||||
|
@ -358,9 +358,12 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
|
|||||||
//Kernel9/Process9 debugging
|
//Kernel9/Process9 debugging
|
||||||
patchExceptionHandlersInstall(arm9Section, section[2].size);
|
patchExceptionHandlersInstall(arm9Section, section[2].size);
|
||||||
patchSvcBreak9(arm9Section, section[2].size, (u32)(section[2].address));
|
patchSvcBreak9(arm9Section, section[2].size, (u32)(section[2].address));
|
||||||
|
patchKernel9Panic(arm9Section, section[2].size);
|
||||||
|
|
||||||
//Stub svcBreak11 with "bkpt 65535"
|
//Stub svcBreak11 with "bkpt 65535"
|
||||||
patchSvcBreak11(arm11Section1, section[1].size);
|
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
|
//Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
|
||||||
patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size);
|
patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size);
|
||||||
@ -390,6 +393,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
|||||||
//Kernel9/Process9 debugging
|
//Kernel9/Process9 debugging
|
||||||
patchExceptionHandlersInstall(arm9Section, section[3].size);
|
patchExceptionHandlersInstall(arm9Section, section[3].size);
|
||||||
patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address));
|
patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address));
|
||||||
|
patchKernel9Panic(arm9Section, section[3].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyLegacyFirmPatches((u8 *)firm, firmType);
|
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||||
@ -414,10 +418,11 @@ static inline void patchSafeFirm(void)
|
|||||||
//Kernel9/Process9 debugging
|
//Kernel9/Process9 debugging
|
||||||
patchExceptionHandlersInstall(arm9Section, section[2].size);
|
patchExceptionHandlersInstall(arm9Section, section[2].size);
|
||||||
patchSvcBreak9(arm9Section, section[2].size, (u32)(section[2].address));
|
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;
|
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
||||||
char fileName[] = "/luma/sysmodules/--------.cxi";
|
char fileName[] = "/luma/sysmodules/--------.cxi";
|
||||||
@ -430,40 +435,45 @@ static inline void copySection0AndInjectSystemModules(void)
|
|||||||
const u8 *addr;
|
const u8 *addr;
|
||||||
} modules[5] = {{0}};
|
} modules[5] = {{0}};
|
||||||
|
|
||||||
u8 *pos = arm11Section0;
|
u8 *pos = arm11Section0, *end = pos + section[0].size;
|
||||||
u32 loaderIndex = 0;
|
u32 n = 0;
|
||||||
for(u32 i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
modules[i].addr = pos;
|
|
||||||
modules[i].size = *(u32 *)(pos + 0x104) * 0x200;
|
|
||||||
|
|
||||||
memcpy(modules[i].name, pos + 0x200, 8);
|
u32 loaderIndex = 0;
|
||||||
pos += modules[i].size;
|
|
||||||
|
while(pos < end)
|
||||||
|
{
|
||||||
|
modules[n].addr = pos;
|
||||||
|
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
||||||
|
|
||||||
|
memcpy(modules[n].name, pos + 0x200, 8);
|
||||||
|
pos += modules[n].size;
|
||||||
|
|
||||||
//Read modules from files if they exist
|
//Read modules from files if they exist
|
||||||
u32 nameOff;
|
u32 nameOff;
|
||||||
for(nameOff = 0; nameOff < 8 && modules[i].name[nameOff] != 0; nameOff++);
|
for(nameOff = 0; nameOff < 8 && modules[n].name[nameOff] != 0; nameOff++);
|
||||||
memcpy(fileName + 17, modules[i].name, nameOff);
|
memcpy(fileName + 17, modules[n].name, nameOff);
|
||||||
memcpy(fileName + 17 + nameOff, ext, 5);
|
memcpy(fileName + 17 + nameOff, ext, 5);
|
||||||
|
|
||||||
u32 fileSize = getFileSize(fileName);
|
u32 fileSize = getFileSize(fileName);
|
||||||
if(fileSize != 0)
|
if(fileSize != 0)
|
||||||
{
|
{
|
||||||
modules[i].addr = NULL;
|
modules[n].addr = NULL;
|
||||||
modules[i].size = fileSize;
|
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].size = injector_size;
|
||||||
modules[loaderIndex].addr = injector;
|
modules[loaderIndex].addr = injector;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = section[0].address;
|
pos = section[0].address;
|
||||||
for(u32 i = 0; i < 5; i++)
|
for(u32 i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
if(modules[i].addr != NULL)
|
if(modules[i].addr != NULL)
|
||||||
memcpy(pos, modules[i].addr, modules[i].size);
|
memcpy(pos, modules[i].addr, modules[i].size);
|
||||||
@ -487,7 +497,7 @@ static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
|
|||||||
u32 sectionNum;
|
u32 sectionNum;
|
||||||
if(firmType != SAFE_FIRM)
|
if(firmType != SAFE_FIRM)
|
||||||
{
|
{
|
||||||
copySection0AndInjectSystemModules();
|
copySection0AndInjectSystemModules(firmType);
|
||||||
sectionNum = 1;
|
sectionNum = 1;
|
||||||
}
|
}
|
||||||
else sectionNum = 0;
|
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 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
||||||
static inline void patchLegacyFirm(FirmwareType firmType);
|
static inline void patchLegacyFirm(FirmwareType firmType);
|
||||||
static inline void patchSafeFirm(void);
|
static inline void patchSafeFirm(void);
|
||||||
static inline void copySection0AndInjectSystemModules(void);
|
static inline void copySection0AndInjectSystemModules(FirmwareType firmType);
|
||||||
static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch);
|
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);
|
u32 *arm9SvcTable = (u32 *)memsearch(pos, svcHandlerPattern, size, 4);
|
||||||
while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL)
|
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)
|
void patchSvcBreak11(u8 *pos, u32 size)
|
||||||
@ -185,7 +186,24 @@ void patchSvcBreak11(u8 *pos, u32 size)
|
|||||||
//Same as above, for NFIRM arm11
|
//Same as above, for NFIRM arm11
|
||||||
|
|
||||||
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
|
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)
|
void patchArm11SvcAccessChecks(u8 *pos, u32 size)
|
||||||
|
@ -45,6 +45,8 @@ void patchFirmWriteSafe(u8 *pos, u32 size);
|
|||||||
void patchExceptionHandlersInstall(u8 *pos, u32 size);
|
void patchExceptionHandlersInstall(u8 *pos, u32 size);
|
||||||
void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr);
|
void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr);
|
||||||
void patchSvcBreak11(u8 *pos, u32 size);
|
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 patchArm11SvcAccessChecks(u8 *pos, u32 size);
|
||||||
void patchK11ModuleChecks(u8 *pos, u32 size);
|
void patchK11ModuleChecks(u8 *pos, u32 size);
|
||||||
void patchP9AccessChecks(u8 *pos, u32 size);
|
void patchP9AccessChecks(u8 *pos, u32 size);
|
||||||
|
Reference in New Issue
Block a user