Fix derps (thanks to @Mrrraou), general cleaup, rewrite of the modules copying function
This commit is contained in:
parent
cb9576b10e
commit
e8b9e49f57
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#define FINAL_BUFFER 0xE5000000 //0x25000000
|
#define FINAL_BUFFER 0xE5000000 //0x25000000
|
||||||
|
|
||||||
#define REG_DUMP_SIZE (4*23)
|
#define REG_DUMP_SIZE 4 * 23
|
||||||
#define CODE_DUMP_SIZE 48
|
#define CODE_DUMP_SIZE 48
|
||||||
|
|
||||||
#define CODESET_OFFSET 0xBEEFBEEF
|
#define CODESET_OFFSET 0xBEEFBEEF
|
||||||
@ -69,7 +69,7 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
//Dump registers
|
//Dump registers
|
||||||
//Current order of saved regs: dfsr, ifsr, far, fpexc, fpinst, fpinst2, cpsr, pc, r8-r12, sp, lr, r0-r7
|
//Current order of saved regs: dfsr, ifsr, far, fpexc, fpinst, fpinst2, cpsr, pc, r8-r12, sp, lr, r0-r7
|
||||||
u32 cpsr = regs[6];
|
u32 cpsr = regs[6];
|
||||||
u32 pc = regs[7] - ((type < 3) ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
u32 pc = regs[7] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
||||||
|
|
||||||
registerDump[15] = pc;
|
registerDump[15] = pc;
|
||||||
registerDump[16] = cpsr;
|
registerDump[16] = cpsr;
|
||||||
@ -90,8 +90,8 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||||
final += dumpHeader.stackDumpSize;
|
final += dumpHeader.stackDumpSize;
|
||||||
|
|
||||||
vu8 *currentKProcess = (cannotAccessVA((u8 *)0xFFFF9004)) ? NULL : *(vu8 **)0xFFFF9004;
|
vu8 *currentKProcess = cannotAccessVA((u8 *)0xFFFF9004) ? NULL : *(vu8 **)0xFFFF9004;
|
||||||
vu8 *currentKCodeSet = (currentKProcess != NULL) ? *(vu8 **)(currentKProcess + CODESET_OFFSET) : NULL;
|
vu8 *currentKCodeSet = currentKProcess != NULL ? *(vu8 **)(currentKProcess + CODESET_OFFSET) : NULL;
|
||||||
|
|
||||||
if(currentKCodeSet != NULL)
|
if(currentKCodeSet != NULL)
|
||||||
{
|
{
|
||||||
@ -101,8 +101,7 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
additionalData[0] = *(vu64 *)(currentKCodeSet + 0x50); //Process name
|
additionalData[0] = *(vu64 *)(currentKCodeSet + 0x50); //Process name
|
||||||
additionalData[1] = *(vu64 *)(currentKCodeSet + 0x5C); //Title ID
|
additionalData[1] = *(vu64 *)(currentKCodeSet + 0x5C); //Title ID
|
||||||
}
|
}
|
||||||
else
|
else dumpHeader.additionalDataSize = 0;
|
||||||
dumpHeader.additionalDataSize = 0;
|
|
||||||
|
|
||||||
//Copy header (actually optimized by the compiler)
|
//Copy header (actually optimized by the compiler)
|
||||||
final = (u8 *)FINAL_BUFFER;
|
final = (u8 *)FINAL_BUFFER;
|
||||||
|
@ -23,12 +23,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Common data types
|
//Common data types
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#define FINAL_BUFFER 0x25000000
|
#define FINAL_BUFFER 0x25000000
|
||||||
|
|
||||||
#define REG_DUMP_SIZE (4*17)
|
#define REG_DUMP_SIZE 4 * 17
|
||||||
#define CODE_DUMP_SIZE 48
|
#define CODE_DUMP_SIZE 48
|
||||||
|
|
||||||
bool cannotAccessAddress(const void *address)
|
bool cannotAccessAddress(const void *address)
|
||||||
@ -37,7 +37,7 @@ bool cannotAccessAddress(const void *address)
|
|||||||
for(u32 i = 0; i < 8; i++)
|
for(u32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0)
|
if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0)
|
||||||
continue; //no access / region not enabled
|
continue; //No access / region not enabled
|
||||||
|
|
||||||
u32 regionAddrBase = regionSettings[i] & ~0xFFF;
|
u32 regionAddrBase = regionSettings[i] & ~0xFFF;
|
||||||
u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1);
|
u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1);
|
||||||
@ -88,7 +88,7 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
//Dump registers
|
//Dump registers
|
||||||
//Current order of saved regs: cpsr, pc, r8-r14, r0-r7
|
//Current order of saved regs: cpsr, pc, r8-r14, r0-r7
|
||||||
u32 cpsr = regs[0];
|
u32 cpsr = regs[0];
|
||||||
u32 pc = regs[1] - ((type < 3) ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
u32 pc = regs[1] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
||||||
|
|
||||||
registerDump[15] = pc;
|
registerDump[15] = pc;
|
||||||
registerDump[16] = cpsr;
|
registerDump[16] = cpsr;
|
||||||
|
@ -23,12 +23,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Common data types
|
//Common data types
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
|
@ -30,27 +30,11 @@
|
|||||||
#include "../build/arm9_exceptions.h"
|
#include "../build/arm9_exceptions.h"
|
||||||
#include "../build/arm11_exceptions.h"
|
#include "../build/arm11_exceptions.h"
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
|
||||||
{
|
|
||||||
u32 magic[2];
|
|
||||||
u16 versionMinor, versionMajor;
|
|
||||||
|
|
||||||
u16 processor, core;
|
|
||||||
u32 type;
|
|
||||||
|
|
||||||
u32 totalSize;
|
|
||||||
u32 registerDumpSize;
|
|
||||||
u32 codeDumpSize;
|
|
||||||
u32 stackDumpSize;
|
|
||||||
u32 additionalDataSize;
|
|
||||||
} ExceptionDumpHeader;
|
|
||||||
|
|
||||||
void installArm9Handlers(void)
|
void installArm9Handlers(void)
|
||||||
{
|
{
|
||||||
void *payloadAddress = (void *)0x01FF8000;
|
|
||||||
const u32 offsets[] = {0x08, 0x18, 0x20, 0x28};
|
const u32 offsets[] = {0x08, 0x18, 0x20, 0x28};
|
||||||
|
|
||||||
memcpy(payloadAddress, arm9_exceptions + 32, arm9_exceptions_size - 32);
|
memcpy((void *)0x01FF8000, arm9_exceptions + 32, arm9_exceptions_size - 32);
|
||||||
|
|
||||||
//IRQHandler is at 0x08000000, but we won't handle it for some reasons
|
//IRQHandler is at 0x08000000, but we won't handle it for some reasons
|
||||||
//svcHandler is at 0x08000010, but we won't handle svc either
|
//svcHandler is at 0x08000010, but we won't handle svc either
|
||||||
@ -62,20 +46,18 @@ void installArm9Handlers(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
|
||||||
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
|
||||||
|
|
||||||
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr, u32 codeSetOffset)
|
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr, u32 codeSetOffset)
|
||||||
{
|
{
|
||||||
u32 *initFPU;
|
u32 *initFPU;
|
||||||
for(initFPU = exceptionsPage; initFPU < (exceptionsPage + 0x400) && (initFPU[0] != 0xE59F0008 || initFPU[1] != 0xE5900000); initFPU += 1);
|
for(initFPU = exceptionsPage; initFPU < (exceptionsPage + 0x400) && (initFPU[0] != 0xE59F0008 || initFPU[1] != 0xE5900000); initFPU++);
|
||||||
|
|
||||||
u32 *mcuReboot;
|
u32 *mcuReboot;
|
||||||
for(mcuReboot = exceptionsPage; mcuReboot < (exceptionsPage + 0x400) && (mcuReboot[0] != 0xE59F4104 || mcuReboot[1] != 0xE3A0A0C2); mcuReboot += 1);
|
for(mcuReboot = exceptionsPage; mcuReboot < (exceptionsPage + 0x400) && (mcuReboot[0] != 0xE59F4104 || mcuReboot[1] != 0xE3A0A0C2); mcuReboot++);
|
||||||
mcuReboot--;
|
mcuReboot--;
|
||||||
|
|
||||||
u32 *freeSpace;
|
u32 *freeSpace;
|
||||||
for(freeSpace = initFPU; freeSpace < (exceptionsPage + 0x400) && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF); freeSpace += 1);
|
for(freeSpace = initFPU; freeSpace < (exceptionsPage + 0x400) && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF); freeSpace++);
|
||||||
|
|
||||||
memcpy(freeSpace, arm11_exceptions + 32, arm11_exceptions_size - 32);
|
memcpy(freeSpace, arm11_exceptions + 32, arm11_exceptions_size - 32);
|
||||||
|
|
||||||
exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 8) - 32); //Undefined Instruction
|
exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 8) - 32); //Undefined Instruction
|
||||||
@ -91,7 +73,7 @@ void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr, u32 codeSetOffset)
|
|||||||
case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break;
|
case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break;
|
||||||
case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break;
|
case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break;
|
||||||
case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler)
|
case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler)
|
||||||
case 0xBEEFBEEF: *pos = codeSetOffset;
|
case 0xBEEFBEEF: *pos = codeSetOffset; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,6 +95,43 @@ static void hexItoa(u32 n, char *out)
|
|||||||
|
|
||||||
void detectAndProcessExceptionDumps(void)
|
void detectAndProcessExceptionDumps(void)
|
||||||
{
|
{
|
||||||
|
volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000;
|
||||||
|
|
||||||
|
if(dumpHeader->magic[0] == 0xDEADC0DE && dumpHeader->magic[1] == 0xDEADCAFE && (dumpHeader->processor == 9 || dumpHeader->processor == 11))
|
||||||
|
{
|
||||||
|
char path[42];
|
||||||
|
char fileName[] = "crash_dump_00000000.dmp";
|
||||||
|
u32 size = dumpHeader->totalSize;
|
||||||
|
|
||||||
|
char *pathFolder;
|
||||||
|
u32 fileNameSpot;
|
||||||
|
if(dumpHeader->processor == 9)
|
||||||
|
{
|
||||||
|
pathFolder = "/luma/dumps/arm9";
|
||||||
|
fileNameSpot = 16;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathFolder = "/luma/dumps/arm11";
|
||||||
|
fileNameSpot = 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
findDumpFile(pathFolder, fileName);
|
||||||
|
memcpy(path, pathFolder, 17);
|
||||||
|
path[fileNameSpot] = '/';
|
||||||
|
memcpy(&path[fileNameSpot + 1], fileName, sizeof(fileName));
|
||||||
|
|
||||||
|
if(!fileWrite((void *)dumpHeader, path, size))
|
||||||
|
{
|
||||||
|
createDirectory("/luma");
|
||||||
|
createDirectory("/luma/dumps");
|
||||||
|
createDirectory(pathFolder);
|
||||||
|
fileWrite((void *)dumpHeader, path, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader));
|
||||||
|
vu8 *additionalData = (vu8 *)dumpHeader + dumpHeader->totalSize - dumpHeader->additionalDataSize;
|
||||||
|
|
||||||
const char *handledExceptionNames[] = {
|
const char *handledExceptionNames[] = {
|
||||||
"FIQ", "undefined instruction", "prefetch abort", "data abort"
|
"FIQ", "undefined instruction", "prefetch abort", "data abort"
|
||||||
};
|
};
|
||||||
@ -124,53 +143,13 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
|
|
||||||
char hexstring[] = "00000000";
|
char hexstring[] = "00000000";
|
||||||
|
|
||||||
volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000;
|
|
||||||
vu32 *dump = (vu32 *)dumpHeader;
|
|
||||||
vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader));
|
|
||||||
vu8 *additionalData = (vu8 *)dumpHeader + dumpHeader->totalSize - dumpHeader->additionalDataSize;
|
|
||||||
|
|
||||||
if(dumpHeader->magic[0] == 0xDEADC0DE && dumpHeader->magic[1] == 0xDEADCAFE && (dumpHeader->processor == 9 || dumpHeader->processor == 11))
|
|
||||||
{
|
|
||||||
char path9[41] = "/luma/dumps/arm9";
|
|
||||||
char path11[42] = "/luma/dumps/arm11";
|
|
||||||
char fileName[] = "crash_dump_00000000.dmp";
|
|
||||||
u32 size = dumpHeader->totalSize;
|
|
||||||
|
|
||||||
if(dumpHeader->processor == 9)
|
|
||||||
{
|
|
||||||
findDumpFile(path9, fileName);
|
|
||||||
path9[16] = '/';
|
|
||||||
memcpy(&path9[17], fileName, sizeof(fileName));
|
|
||||||
if(!fileWrite((void *)dump, path9, size))
|
|
||||||
{
|
|
||||||
createDirectory("/luma");
|
|
||||||
createDirectory("/luma/dumps");
|
|
||||||
createDirectory("/luma/dumps/arm9");
|
|
||||||
fileWrite((void *)dump, path9, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
findDumpFile(path11, fileName);
|
|
||||||
path11[17] = '/';
|
|
||||||
memcpy(&path11[18], fileName, sizeof(fileName));
|
|
||||||
if(!fileWrite((void *)dump, path11, size))
|
|
||||||
{
|
|
||||||
createDirectory("/luma");
|
|
||||||
createDirectory("/luma/dumps");
|
|
||||||
createDirectory("/luma/dumps/arm11");
|
|
||||||
fileWrite((void *)dump, path11, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char arm11Str[] = "Processor: ARM11 (core X)";
|
char arm11Str[] = "Processor: ARM11 (core X)";
|
||||||
if(dumpHeader->processor == 11) arm11Str[29] = '0' + (char)(dumpHeader->core);
|
if(dumpHeader->processor == 11) arm11Str[29] = '0' + (char)(dumpHeader->core);
|
||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("An exception occurred", 10, 10, COLOR_RED);
|
drawString("An exception occurred", 10, 10, COLOR_RED);
|
||||||
int posY = drawString((dumpHeader->processor == 11) ? arm11Str : "Processor: ARM9", 10, 30, COLOR_WHITE) + SPACING_Y;
|
int posY = drawString(dumpHeader->processor == 11 ? arm11Str : "Processor: ARM9", 10, 30, COLOR_WHITE) + SPACING_Y;
|
||||||
|
|
||||||
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);
|
||||||
@ -202,6 +181,7 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
posY += 3 * SPACING_Y;
|
posY += 3 * SPACING_Y;
|
||||||
|
|
||||||
for(u32 i = 0; i < 17; i += 2)
|
for(u32 i = 0; i < 17; i += 2)
|
||||||
{
|
{
|
||||||
posY = drawString(registerNames[i], 10, posY, COLOR_WHITE);
|
posY = drawString(registerNames[i], 10, posY, COLOR_WHITE);
|
||||||
@ -211,7 +191,7 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
if(dumpHeader->processor != 9 || i != 16)
|
if(dumpHeader->processor != 9 || i != 16)
|
||||||
{
|
{
|
||||||
posY = drawString(registerNames[i + 1], 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
posY = drawString(registerNames[i + 1], 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
||||||
hexItoa((i == 16) ? regs[20] : regs[i + 1], hexstring);
|
hexItoa(i == 16 ? regs[20] : regs[i + 1], hexstring);
|
||||||
posY = drawString(hexstring, 10 + 29 * SPACING_X, posY, COLOR_WHITE);
|
posY = drawString(hexstring, 10 + 29 * SPACING_X, posY, COLOR_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,19 +203,18 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
u32 mode = regs[16] & 0xF;
|
u32 mode = regs[16] & 0xF;
|
||||||
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
||||||
{
|
{
|
||||||
posY = drawString("Incorrect dump: failed to dump code and/or stack", 10, posY, 0x00FFFF) + 2 * SPACING_Y; //in yellow
|
posY = drawString("Incorrect dump: failed to dump code and/or stack", 10, posY, 0x00FFFF) + 2 * SPACING_Y; //In yellow
|
||||||
if(dumpHeader->processor != 9) posY -= SPACING_Y;
|
if(dumpHeader->processor != 9) posY -= SPACING_Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
posY = drawString("You can find a dump in the following file:", 10, posY, COLOR_WHITE) + SPACING_Y;
|
posY = drawString("You can find a dump in the following file:", 10, posY, COLOR_WHITE) + SPACING_Y;
|
||||||
posY = drawString((dumpHeader->processor == 9) ? path9 : path11, 10, posY, COLOR_WHITE) + 2 * SPACING_Y;
|
posY = drawString(path, 10, posY, COLOR_WHITE) + 2 * SPACING_Y;
|
||||||
drawString("Press any button to shutdown", 10, posY, COLOR_WHITE);
|
drawString("Press any button to shutdown", 10, posY, COLOR_WHITE);
|
||||||
|
|
||||||
waitInput();
|
waitInput();
|
||||||
|
|
||||||
for(u32 i = 0; i < size / 4; i++) dump[i] = 0;
|
memset32((void *)dumpHeader, 0, size);
|
||||||
|
|
||||||
clearScreens();
|
|
||||||
mcuPowerOff();
|
mcuPowerOff();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,6 +24,24 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||||
|
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
u32 magic[2];
|
||||||
|
u16 versionMinor, versionMajor;
|
||||||
|
|
||||||
|
u16 processor, core;
|
||||||
|
u32 type;
|
||||||
|
|
||||||
|
u32 totalSize;
|
||||||
|
u32 registerDumpSize;
|
||||||
|
u32 codeDumpSize;
|
||||||
|
u32 stackDumpSize;
|
||||||
|
u32 additionalDataSize;
|
||||||
|
} ExceptionDumpHeader;
|
||||||
|
|
||||||
void installArm9Handlers(void);
|
void installArm9Handlers(void);
|
||||||
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr, u32 codeSetOffset);
|
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr, u32 codeSetOffset);
|
||||||
void detectAndProcessExceptionDumps(void);
|
void detectAndProcessExceptionDumps(void);
|
103
source/firm.c
103
source/firm.c
@ -43,7 +43,9 @@ static const firmSectionHeader *section;
|
|||||||
|
|
||||||
u32 emuOffset;
|
u32 emuOffset;
|
||||||
|
|
||||||
bool isN3DS, isDevUnit, isFirmlaunch;
|
bool isN3DS,
|
||||||
|
isDevUnit,
|
||||||
|
isFirmlaunch;
|
||||||
|
|
||||||
cfgData configData;
|
cfgData configData;
|
||||||
FirmwareSource firmSource;
|
FirmwareSource firmSource;
|
||||||
@ -239,6 +241,7 @@ void main(void)
|
|||||||
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
|
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
|
||||||
{
|
{
|
||||||
section = firm->section;
|
section = firm->section;
|
||||||
|
|
||||||
const char *firmwareFiles[4] = {
|
const char *firmwareFiles[4] = {
|
||||||
"/luma/firmware.bin",
|
"/luma/firmware.bin",
|
||||||
"/luma/firmware_twl.bin",
|
"/luma/firmware_twl.bin",
|
||||||
@ -248,13 +251,10 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
|
|||||||
|
|
||||||
u32 firmVersion;
|
u32 firmVersion;
|
||||||
|
|
||||||
if(fileRead(firm, firmwareFiles[(u32)firmType]))
|
if(fileRead(firm, firmwareFiles[(u32)*firmType])) firmVersion = 0xFFFFFFFF;
|
||||||
{
|
|
||||||
firmVersion = 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
firmVersion = firmRead(firm, (u32)firmType);
|
firmVersion = firmRead(firm, (u32)*firmType);
|
||||||
|
|
||||||
if(!isN3DS && *firmType == NATIVE_FIRM)
|
if(!isN3DS && *firmType == NATIVE_FIRM)
|
||||||
{
|
{
|
||||||
@ -279,9 +279,9 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
|
|||||||
firmVersion = 0xFFFFFFFF;
|
firmVersion = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(firmVersion != 0xFFFFFFFF) decryptExeFs((u8 *)firm);
|
decryptExeFs((u8 *)firm);
|
||||||
|
}
|
||||||
|
|
||||||
return firmVersion;
|
return firmVersion;
|
||||||
}
|
}
|
||||||
@ -347,13 +347,14 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
|
|||||||
if(DEV_OPTIONS != 2)
|
if(DEV_OPTIONS != 2)
|
||||||
{
|
{
|
||||||
//Install arm11 exception handlers
|
//Install arm11 exception handlers
|
||||||
u32 stackAddress, codeSetOffset;
|
u32 stackAddress,
|
||||||
|
codeSetOffset;
|
||||||
getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &stackAddress, &codeSetOffset);
|
getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &stackAddress, &codeSetOffset);
|
||||||
installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset);
|
installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset);
|
||||||
|
|
||||||
//Kernel9/Process9 debugging
|
//Kernel9/Process9 debugging
|
||||||
patchArm9ExceptionHandlersInstall(arm9Section, section[2].size);
|
patchArm9ExceptionHandlersInstall(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, NATIVE_FIRM);
|
patchKernel9Panic(arm9Section, section[2].size, NATIVE_FIRM);
|
||||||
|
|
||||||
//Stub svcBreak11 with "bkpt 65535"
|
//Stub svcBreak11 with "bkpt 65535"
|
||||||
@ -389,7 +390,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
|||||||
{
|
{
|
||||||
//Kernel9/Process9 debugging
|
//Kernel9/Process9 debugging
|
||||||
patchArm9ExceptionHandlersInstall(arm9Section, section[3].size);
|
patchArm9ExceptionHandlersInstall(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, firmType);
|
patchKernel9Panic(arm9Section, section[3].size, firmType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,70 +417,48 @@ static inline void patch2xNativeAndSafeFirm(void)
|
|||||||
{
|
{
|
||||||
//Kernel9/Process9 debugging
|
//Kernel9/Process9 debugging
|
||||||
patchArm9ExceptionHandlersInstall(arm9Section, section[2].size);
|
patchArm9ExceptionHandlersInstall(arm9Section, section[2].size);
|
||||||
patchSvcBreak9(arm9Section, section[2].size, (u32)(section[2].address));
|
patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
|
static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
u32 srcModuleSize,
|
||||||
char fileName[] = "/luma/sysmodules/--------.cxi";
|
dstModuleSize;
|
||||||
|
|
||||||
|
for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address;
|
||||||
|
src < srcEnd; src += srcModuleSize, dst += dstModuleSize)
|
||||||
|
{
|
||||||
|
srcModuleSize = *(u32 *)(src + 0x104) * 0x200;
|
||||||
|
char *moduleName = (char *)(src + 0x200);
|
||||||
|
|
||||||
|
char fileName[30] = "/luma/sysmodules/";
|
||||||
const char *ext = ".cxi";
|
const char *ext = ".cxi";
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u32 size;
|
|
||||||
char name[8];
|
|
||||||
const u8 *addr;
|
|
||||||
} modules[5];
|
|
||||||
|
|
||||||
u8 *pos = arm11Section0;
|
|
||||||
u32 n = 0;
|
|
||||||
|
|
||||||
u32 loaderIndex = 0;
|
|
||||||
|
|
||||||
for(u8 *end = pos + section[0].size; pos < end; pos += modules[n++].size)
|
|
||||||
{
|
|
||||||
modules[n].addr = pos;
|
|
||||||
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
|
||||||
|
|
||||||
memcpy(modules[n].name, pos + 0x200, 8);
|
|
||||||
|
|
||||||
//Read modules from files if they exist
|
//Read modules from files if they exist
|
||||||
u32 nameOff;
|
u32 nameOff;
|
||||||
for(nameOff = 0; nameOff < 8 && modules[n].name[nameOff] != 0; nameOff++);
|
for(nameOff = 0; nameOff < 8 && moduleName[nameOff] != 0; nameOff++);
|
||||||
memcpy(fileName + 17, modules[n].name, nameOff);
|
memcpy(fileName + 17, moduleName, nameOff);
|
||||||
memcpy(fileName + 17 + nameOff, ext, 5);
|
memcpy(fileName + 17 + nameOff, ext, 5);
|
||||||
|
|
||||||
u32 fileSize = getFileSize(fileName);
|
u32 fileSize = fileRead(dst, fileName);
|
||||||
if(fileSize != 0)
|
if(fileSize) dstModuleSize = fileSize;
|
||||||
{
|
|
||||||
modules[n].addr = NULL;
|
|
||||||
modules[n].size = fileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(firmType == NATIVE_FIRM && memcmp(modules[n].name, "loader", 7) == 0) loaderIndex = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 < n; pos += modules[i++].size)
|
|
||||||
{
|
|
||||||
if(modules[i].addr != NULL)
|
|
||||||
memcpy(pos, modules[i].addr, modules[i].size);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Read modules from files if they exist
|
void *module;
|
||||||
u32 nameOff;
|
|
||||||
for(nameOff = 0; nameOff < 8 && modules[i].name[nameOff] != 0; nameOff++);
|
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
||||||
memcpy(fileName + 17, modules[i].name, nameOff);
|
{
|
||||||
memcpy(fileName + 17 + nameOff, ext, 5);
|
module = (void *)injector;
|
||||||
fileRead(pos, fileName);
|
dstModuleSize = injector_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
module = src;
|
||||||
|
dstModuleSize = srcModuleSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, module, dstModuleSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,9 +265,7 @@ void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
|
|||||||
if(off == NULL) return;
|
if(off == NULL) return;
|
||||||
off += sizeof(pattern)/4;
|
off += sizeof(pattern)/4;
|
||||||
|
|
||||||
u32 r0 = 0x08000000;
|
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
|
||||||
|
|
||||||
for(; *off != 0xE3A01040; off++) //Until mov r1, #0x40
|
|
||||||
{
|
{
|
||||||
if((*off >> 26) != 0x39 || ((*off >> 16) & 0xF) != 0 || ((*off >> 25) & 1) != 0 || ((*off >> 20) & 5) != 0)
|
if((*off >> 26) != 0x39 || ((*off >> 16) & 0xF) != 0 || ((*off >> 25) & 1) != 0 || ((*off >> 20) & 5) != 0)
|
||||||
continue; //Discard everything that's not str rX, [r0, #imm](!)
|
continue; //Discard everything that's not str rX, [r0, #imm](!)
|
||||||
@ -288,7 +286,7 @@ void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr)
|
void patchSvcBreak9(u8 *pos, u32 size, u32 k9Address)
|
||||||
{
|
{
|
||||||
//Stub svcBreak with "bkpt 65535" so we can debug the panic.
|
//Stub svcBreak with "bkpt 65535" so we can debug the panic.
|
||||||
//Thanks @yellows8 and others for mentioning this idea on #3dsdev.
|
//Thanks @yellows8 and others for mentioning this idea on #3dsdev.
|
||||||
@ -296,14 +294,14 @@ 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 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - k9addr);
|
|
||||||
|
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - k9Address);
|
||||||
*addr = 0xE12FFF7F;
|
*addr = 0xE12FFF7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable)
|
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable)
|
||||||
{
|
{
|
||||||
//Same as above, for NFIRM arm11
|
//Same as above, for NFIRM arm11
|
||||||
|
|
||||||
u32 *addr = (u32 *)(pos + arm11SvcTable[0x3C] - 0xFFF00000);
|
u32 *addr = (u32 *)(pos + arm11SvcTable[0x3C] - 0xFFF00000);
|
||||||
*addr = 0xE12FFF7F;
|
*addr = 0xE12FFF7F;
|
||||||
}
|
}
|
||||||
@ -312,12 +310,11 @@ void patchKernel9Panic(u8 *pos, u32 size, FirmwareType firmType)
|
|||||||
{
|
{
|
||||||
if(firmType == TWL_FIRM || firmType == AGB_FIRM)
|
if(firmType == TWL_FIRM || firmType == AGB_FIRM)
|
||||||
{
|
{
|
||||||
u8 *off = pos + ((isN3DS) ? 0x723C : 0x69A8);
|
u8 *off = pos + (isN3DS ? 0x723C : 0x69A8);
|
||||||
*(u16 *)off = 0x4778; //bx pc
|
*(u16 *)off = 0x4778; //bx pc
|
||||||
*(u16 *)(off + 2) = 0x46C0; //nop
|
*(u16 *)(off + 2) = 0x46C0; //nop
|
||||||
*(u32 *)(off + 4) = 0xE12FFF7E; //bkpt 65534
|
*(u32 *)(off + 4) = 0xE12FFF7E; //bkpt 65534
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const u8 pattern[] = {0x00, 0x20, 0xA0, 0xE3, 0x02, 0x30, 0xA0, 0xE1, 0x02, 0x10, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE3};
|
const u8 pattern[] = {0x00, 0x20, 0xA0, 0xE3, 0x02, 0x30, 0xA0, 0xE1, 0x02, 0x10, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE3};
|
||||||
@ -337,10 +334,8 @@ void patchKernel11Panic(u8 *pos, u32 size)
|
|||||||
|
|
||||||
void patchArm11SvcAccessChecks(u32 *arm11SvcHandler)
|
void patchArm11SvcAccessChecks(u32 *arm11SvcHandler)
|
||||||
{
|
{
|
||||||
u32 *off = arm11SvcHandler;
|
while(*arm11SvcHandler != 0xE11A0E1B) arm11SvcHandler++; //TST R10, R11,LSL LR
|
||||||
while(*off != 0xE11A0E1B) off++; //TST R10, R11,LSL LR
|
*arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1
|
||||||
|
|
||||||
*off = 0xE3B0A001; //MOVS R10, #1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//It's mainly Subv's code here:
|
//It's mainly Subv's code here:
|
||||||
@ -349,29 +344,24 @@ void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
|
|||||||
//We have to detour a function in the ARM11 kernel because builtin modules
|
//We have to detour a function in the ARM11 kernel because builtin modules
|
||||||
//are compressed in memory and are only decompressed at runtime.
|
//are compressed in memory and are only decompressed at runtime.
|
||||||
|
|
||||||
u8 *freeSpace = *freeK11Space;
|
|
||||||
*freeK11Space += k11modules_size;
|
|
||||||
|
|
||||||
//Inject our code into the free space
|
//Inject our code into the free space
|
||||||
memcpy(freeSpace, k11modules, k11modules_size);
|
memcpy(*freeK11Space, k11modules, k11modules_size);
|
||||||
|
(*freeK11Space) += k11modules_size;
|
||||||
|
|
||||||
//Find the code that decompresses the .code section of the builtin modules and detour it with a jump to our code
|
//Find the code that decompresses the .code section of the builtin modules and detour it with a jump to our code
|
||||||
const u8 pattern[] = { 0x00, 0x00, 0x94, 0xE5, 0x18, 0x10, 0x90, 0xE5, 0x28, 0x20,
|
const u8 pattern[] = { 0x00, 0x00, 0x94, 0xE5, 0x18, 0x10, 0x90, 0xE5, 0x28, 0x20,
|
||||||
0x90, 0xE5, 0x48, 0x00, 0x9D, 0xE5 };
|
0x90, 0xE5, 0x48, 0x00, 0x9D, 0xE5 };
|
||||||
|
|
||||||
u8 *off = memsearch(pos, pattern, size, 16);
|
u32 *off = (u32 *)memsearch(pos, pattern, size, 16);
|
||||||
|
|
||||||
//We couldn't find the code that decompresses the module
|
//We couldn't find the code that decompresses the module
|
||||||
if (off == NULL)
|
if(off == NULL) return;
|
||||||
return;
|
|
||||||
|
|
||||||
//Inject a jump instruction to our code at the offset we found
|
//Inject a jump instruction to our code at the offset we found
|
||||||
//Construct a jump (BL) instruction to our code
|
//Construct a jump (BL) instruction to our code
|
||||||
u32 offset = ((((u32)freeSpace) - ((u32)off + 8)) >> 2) & 0xFFFFFF;
|
u32 offset = ((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF;
|
||||||
u32 instruction = offset | (1 << 24) | (0x5 << 25) | (0xE << 28);
|
|
||||||
|
|
||||||
// Write our jump
|
*off = offset | (1 << 24) | (0x5 << 25) | (0xE << 28);
|
||||||
memcpy(off, &instruction, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchP9AccessChecks(u8 *pos, u32 size)
|
void patchP9AccessChecks(u8 *pos, u32 size)
|
||||||
@ -384,7 +374,6 @@ void patchP9AccessChecks(u8 *pos, u32 size)
|
|||||||
off[1] = 0x4770; //bx lr
|
off[1] = 0x4770; //bx lr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void patchUnitInfoValueSet(u8 *pos, u32 size)
|
void patchUnitInfoValueSet(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
//Look for UNITINFO value being set during kernel sync
|
//Look for UNITINFO value being set during kernel sync
|
||||||
@ -392,6 +381,6 @@ void patchUnitInfoValueSet(u8 *pos, u32 size)
|
|||||||
|
|
||||||
u8 *off = memsearch(pos, pattern, size, 4);
|
u8 *off = memsearch(pos, pattern, size, 4);
|
||||||
|
|
||||||
off[0] = (isDevUnit) ? 0 : 1;
|
off[0] = isDevUnit ? 0 : 1;
|
||||||
off[3] = 0xE3;
|
off[3] = 0xE3;
|
||||||
}
|
}
|
@ -63,7 +63,7 @@ void patchTwlBg(u8 *pos);
|
|||||||
|
|
||||||
void getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr, u32 *codeSetOffset);
|
void getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr, u32 *codeSetOffset);
|
||||||
void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
||||||
void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr);
|
void patchSvcBreak9(u8 *pos, u32 size, u32 k9Address);
|
||||||
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable);
|
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable);
|
||||||
void patchKernel9Panic(u8 *pos, u32 size, FirmwareType firmType);
|
void patchKernel9Panic(u8 *pos, u32 size, FirmwareType firmType);
|
||||||
void patchKernel11Panic(u8 *pos, u32 size);
|
void patchKernel11Panic(u8 *pos, u32 size);
|
||||||
|
Reference in New Issue
Block a user