Merge branch 'master' into developer

Conflicts:
	source/firm.c
	source/patches.c
	source/patches.h
This commit is contained in:
TuxSH 2016-05-12 14:31:48 +02:00
commit 2c10b6bff2
10 changed files with 174 additions and 166 deletions

View File

@ -364,15 +364,12 @@ void patchCode(u64 progId, u8 *code, u32 size)
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
}; };
static const u8 fpdVerPatch = 0x06; static const u8 mostRecentFpdVer = 0x06;
//Allow online access to work with old friends modules u8 *fpdVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
patchMemory(code, size,
fpdVerPattern, //Allow online access to work with old friends modules, without breaking newer firmwares
sizeof(fpdVerPattern), 9, if(fpdVer != NULL && fpdVer[9] < mostRecentFpdVer) fpdVer[9] = mostRecentFpdVer;
&fpdVerPatch,
sizeof(fpdVerPatch), 1
);
break; break;
} }

View File

@ -186,7 +186,4 @@ void configureCFW(const char *configPath)
deinitScreens(); deinitScreens();
PDN_GPU_CNT = 1; PDN_GPU_CNT = 1;
} }
u64 t0 = chrono();
while(chrono() - t0 < 2 * TICKS_PER_SEC); //wait for 2s
} }

View File

@ -48,13 +48,13 @@ u32 getSDMMC(u8 *pos, u32 size)
return *(u32 *)(off + 9) + *(u32 *)(off + 0xD); return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
} }
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff) void getEmuRW(u8 *pos, u32 size, u32 *readOffset, u32 *writeOffset)
{ {
//Look for read/write code //Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
*readOff = (u32)memsearch(pos, pattern, size, 4) - 6; *readOffset = (u32)memsearch(pos, pattern, size, 4) - 6;
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6; *writeOffset = (u32)memsearch((u8 *)(*readOffset + 0xA), pattern, 0x100, 4) - 6;
} }
u32 *getMPU(u8 *pos, u32 size) u32 *getMPU(u8 *pos, u32 size)
@ -65,10 +65,10 @@ u32 *getMPU(u8 *pos, u32 size)
return (u32 *)memsearch(pos, pattern, size, 4); return (u32 *)memsearch(pos, pattern, size, 4);
} }
void *getEmuCode(u8 *proc9Offset) void *getEmuCode(u8 *pos)
{ {
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
//Looking for the last free space before Process9 //Looking for the last free space before Process9
return memsearch(proc9Offset - 0x3000, pattern, 0x3000, 6) + 0x455; return memsearch(pos + 0x13500, pattern, 0x1000, 6) + 0x455;
} }

View File

@ -10,6 +10,6 @@
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND); void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
u32 getSDMMC(u8 *pos, u32 size); u32 getSDMMC(u8 *pos, u32 size);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff); void getEmuRW(u8 *pos, u32 size, u32 *readOffset, u32 *writeOffset);
u32 *getMPU(u8 *pos, u32 size); u32 *getMPU(u8 *pos, u32 size);
void *getEmuCode(u8 *proc9Offset); void *getEmuCode(u8 *pos);

View File

@ -24,8 +24,6 @@ u32 config,
firmSource, firmSource,
emuOffset; emuOffset;
u64 chronoWhenSplashLoaded = 0;
static inline void patchExceptionHandlersInstall(u8 *arm9Section) static inline void patchExceptionHandlersInstall(u8 *arm9Section)
{ {
static const u8 pattern[] = { static const u8 pattern[] = {
@ -72,7 +70,7 @@ void main(void)
newConfig, newConfig,
emuHeader; emuHeader;
startChrono(0); //Start the chronometer. It shouldn't be reset. u64 chronoStarted = 0;
//Detect the console being used //Detect the console being used
console = PDN_MPCORE_CFG == 7; console = PDN_MPCORE_CFG == 7;
@ -106,13 +104,17 @@ void main(void)
u32 pressed = HID_PAD; u32 pressed = HID_PAD;
//If no configuration file exists or SELECT is held, load configuration menu //If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || (pressed & BUTTON_SELECT)) if(needConfig == 2 || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)))
{ {
configureCFW(configPath); configureCFW(configPath);
//Zero the last booted FIRM flag //Zero the last booted FIRM flag
CFG_BOOTENV = 0; CFG_BOOTENV = 0;
chronoStarted = chrono();
while(chrono() - chronoStarted < 2 * TICKS_PER_SEC); //Wait for 2s
chronoStarted = 1;
//Update pressed buttons //Update pressed buttons
pressed = HID_PAD; pressed = HID_PAD;
} }
@ -193,8 +195,8 @@ void main(void)
loadPayload(pressed); loadPayload(pressed);
//If screens are inited or the corresponding option is set, load splash screen //If screens are inited or the corresponding option is set, load splash screen
if(PDN_GPU_CNT != 1 || CONFIG(8)) chronoWhenSplashLoaded = (u64) loadSplash(); if((PDN_GPU_CNT != 1 || CONFIG(8)) && loadSplash())
if(chronoWhenSplashLoaded) chronoWhenSplashLoaded = chrono(); chronoStarted = chrono();
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
if(pressed & BUTTON_R1) if(pressed & BUTTON_R1)
@ -260,6 +262,12 @@ void main(void)
break; break;
} }
if(chronoStarted)
{
while(chronoStarted > 1 && chrono() - chronoStarted < 3 * TICKS_PER_SEC);
stopChrono();
}
launchFirm(!firmType, bootType); launchFirm(!firmType, bootType);
} }
@ -301,7 +309,6 @@ static inline void patchKernelFCRAMAndVRAMMappingPermissions(u8* arm11Section1)
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode) static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
{ {
u8 *arm9Section = (u8 *)firm + section[2].offset; u8 *arm9Section = (u8 *)firm + section[2].offset;
u8 *arm11Section1 = (u8 *)firm + section[1].offset;
u32 nativeFirmType; u32 nativeFirmType;
@ -332,29 +339,32 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
nativeFirmType = memcmp(section[2].hash, firm90Hash, 0x10) != 0; nativeFirmType = memcmp(section[2].hash, firm90Hash, 0x10) != 0;
} }
if(nativeFirmType || nandType || a9lhMode == 2) u32 process9Size,
{ process9MemAddr;
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches //Find the Process9 NCCH location
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader); u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax //Apply emuNAND patches
if(nativeFirmType || a9lhMode == 2) patchReboots(arm9Section, proc9Offset); if(nandType) patchEmuNAND(arm9Section, process9Offset, process9Size, emuHeader);
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH //Apply FIRM0/1 writes patches on sysNAND to protect A9LH
if(a9lhMode && !nandType) patchFirmWrites(arm9Section, 1); else if(a9lhMode) patchFirmWrites(process9Offset, process9Size, 1);
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(nativeFirmType || a9lhMode == 2) patchReboots(process9Offset, process9Size, process9MemAddr);
//Apply signature checks patches //Apply signature checks patches
u32 sigOffset, u16 *sigOffset,
sigOffset2; *sigOffset2;
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2); getSigChecks(process9Offset, process9Size, &sigOffset, &sigOffset2);
*(u16 *)sigOffset = sigPatch[0]; *sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0]; sigOffset2[0] = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1]; sigOffset2[1] = sigPatch[1];
//Does nothing if svcBackdoor is still there
reimplementSvcBackdoor();
if(CONFIG(5)) if(CONFIG(5))
{ {
@ -365,16 +375,14 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
//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); patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1);
} }
reimplementSvcBackdoor(arm11Section1); //Does nothing if svcBackdoor is still there
//Replace the FIRM loader with the injector while copying section0 //Replace the FIRM loader with the injector while copying section0
copySection0AndInjectLoader(); copySection0AndInjectLoader();
} }
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader) static inline void patchEmuNAND(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader)
{ {
//Copy emuNAND code //Copy emuNAND code
void *emuCodeOffset = getEmuCode(proc9Offset); void *emuCodeOffset = getEmuCode(arm9Section);
memcpy(emuCodeOffset, emunand, emunand_size); memcpy(emuCodeOffset, emunand, emunand_size);
//Add the data of the found emuNAND //Add the data of the found emuNAND
@ -385,7 +393,7 @@ static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
//Find and add the SDMMC struct //Find and add the SDMMC struct
u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4); u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4);
*pos_sdmmc = getSDMMC(arm9Section, section[2].size); *pos_sdmmc = getSDMMC(process9Offset, process9Size);
//Calculate offset for the hooks //Calculate offset for the hooks
u32 branchOffset = (u32)emuCodeOffset - (u32)firm - u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
@ -395,7 +403,7 @@ static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
u32 emuRead, u32 emuRead,
emuWrite; emuWrite;
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite); getEmuRW(process9Offset, process9Size, &emuRead, &emuWrite);
*(u16 *)emuRead = nandRedir[0]; *(u16 *)emuRead = nandRedir[0];
*((u16 *)emuRead + 1) = nandRedir[1]; *((u16 *)emuRead + 1) = nandRedir[1];
*((u32 *)emuRead + 1) = branchOffset; *((u32 *)emuRead + 1) = branchOffset;
@ -410,13 +418,12 @@ static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset) static inline void patchReboots(u8 *process9Offset, u32 process9Size, u32 process9MemAddr)
{ {
//Calculate offset for the firmlaunch code u32 fOpenOffset;
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function //Calculate offset for the firmlaunch code
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset); void *rebootOffset = getReboot(process9Offset, process9Size, process9MemAddr, &fOpenOffset);
//Copy firmlaunch code //Copy firmlaunch code
memcpy(rebootOffset, reboot, reboot_size); memcpy(rebootOffset, reboot, reboot_size);
@ -426,39 +433,24 @@ static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
*pos_fopen = fOpenOffset; *pos_fopen = fOpenOffset;
} }
static inline void reimplementSvcBackdoor(u8 *arm11Section1) static inline void reimplementSvcBackdoor(void)
{ {
u32 *exceptionsPage = getExceptionVectorsPage(arm11Section1, section[1].size); u8 *arm11Section1 = (u8 *)firm + section[1].offset;
if(exceptionsPage == NULL) return;
u32 low24 = (exceptionsPage[2] & 0x00FFFFFF) << 2; u32 *exceptionsPage;
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
int offset = (int)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
u32* svcTable = (u32 *)(arm11Section1 + *(u32 *)(arm11Section1 + 0xFFFF0008 + offset - 0xFFF00000 + 8) - 0xFFF00000); //svc handler address u32 *svcTable = getSvcAndExceptions(arm11Section1, section[1].size, &exceptionsPage);
while(*svcTable != 0) svcTable++; //svc0 = NULL
if(svcTable[0x7B] != 0) return; if(!svcTable[0x7B])
{
u32 *freeSpace;
u32 *freeSpace = exceptionsPage; for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
while(freeSpace < exceptionsPage + 0x400 - 0xA && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF))
freeSpace++;
if(freeSpace >= exceptionsPage + 0x400 - 0xA) return; memcpy(freeSpace, svcBackdoor, 40);
//Official implementation of svcBackdoor svcTable[0x7B] = 0xFFFF0000 + (u32)((u8 *)freeSpace - (u8 *)exceptionsPage);
freeSpace[0] = 0xE3CD10FF; //bic r1, sp, #0xff }
freeSpace[1] = 0xE3811C0F; //orr r1, r1, #0xf00
freeSpace[2] = 0xE2811028; //add r1, r1, #0x28
freeSpace[3] = 0xE5912000; //ldr r2, [r1]
freeSpace[4] = 0xE9226000; //stmdb r2!, {sp, lr}
freeSpace[5] = 0xE1A0D002; //mov sp, r2
freeSpace[6] = 0xE12FFF30; //blx r0
freeSpace[7] = 0xE8BD0003; //pop {r0, r1}
freeSpace[8] = 0xE1A0D000; //mov sp, r0
freeSpace[9] = 0xE12FFF11; //bx r1
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *) exceptionsPage);
} }
static inline void copySection0AndInjectLoader(void) static inline void copySection0AndInjectLoader(void)
@ -472,6 +464,37 @@ static inline void copySection0AndInjectLoader(void)
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize)); memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize));
} }
static inline void patchSafeFirm(void)
{
u8 *arm9Section = (u8 *)firm + section[2].offset;
if(console)
{
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, 0);
firm->arm9Entry = (u8 *)0x801B01C;
}
//Apply FIRM0/1 writes patches to protect A9LH
patchFirmWrites(arm9Section, section[2].size, console);
}
static void patchFirmWrites(u8 *offset, u32 size, u32 mode)
{
if(mode)
{
u16 *writeOffset = getFirmWrite(offset, size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
else
{
u16 *writeOffset = getFirmWriteSafe(offset, size);
*writeOffset = writeBlockSafe[0];
*(writeOffset + 1) = writeBlockSafe[1];
}
}
static inline void patchLegacyFirm(u32 firmType) static inline void patchLegacyFirm(u32 firmType)
{ {
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
@ -520,45 +543,11 @@ static inline void patchLegacyFirm(u32 firmType)
} }
} }
static inline void patchSafeFirm(void) static inline void launchFirm(u32 sectionNum, u32 bootType)
{
u8 *arm9Section = (u8 *)firm + section[2].offset;
if(console)
{
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, 0);
firm->arm9Entry = (u8 *)0x801B01C;
}
//Apply FIRM0/1 writes patches to protect A9LH
patchFirmWrites(arm9Section, console);
}
static void patchFirmWrites(u8 *arm9Section, u32 mode)
{
if(mode)
{
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
else
{
u16 *writeOffset = getFirmWriteSafe(arm9Section, section[2].size);
*writeOffset = writeBlockSafe[0];
*(writeOffset + 1) = writeBlockSafe[1];
}
}
static inline void launchFirm(u32 firstSectionToCopy, u32 bootType)
{ {
//Copy FIRM sections to respective memory locations //Copy FIRM sections to respective memory locations
for(u32 i = firstSectionToCopy; i < 4 && section[i].size; i++) for(; sectionNum < 4 && section[sectionNum].size; sectionNum++)
memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size); memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size);
while(chronoWhenSplashLoaded && chrono() - chronoWhenSplashLoaded < 3 * TICKS_PER_SEC);
stopChrono();
//Determine the ARM11 entry to use //Determine the ARM11 entry to use
vu32 *arm11; vu32 *arm11;

View File

@ -39,11 +39,11 @@ typedef struct patchData {
static inline void loadFirm(u32 firmType, u32 externalFirm); static inline void loadFirm(u32 firmType, u32 externalFirm);
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode); static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode);
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader); static inline void patchEmuNAND(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader);
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset); static inline void patchReboots(u8 *process9Offset, u32 process9Size, u32 process9MemAddr);
static inline void reimplementSvcBackdoor(u8 *arm11Section1); static inline void reimplementSvcBackdoor(void);
static inline void copySection0AndInjectLoader(void); static inline void copySection0AndInjectLoader(void);
static inline void patchLegacyFirm(u32 firmType);
static inline void patchSafeFirm(void); static inline void patchSafeFirm(void);
static void patchFirmWrites(u8 *arm9Section, u32 mode); static void patchFirmWrites(u8 *offset, u32 size, u32 mode);
static inline void launchFirm(u32 firstSectionToCopy, u32 bootType); static inline void patchLegacyFirm(u32 firmType);
static inline void launchFirm(u32 sectionNum, u32 bootType);

View File

@ -18,43 +18,54 @@ const u16 nandRedir[2] = {0x4C00, 0x47A0},
const u8 unitInfoPatch = 0xE3; const u8 unitInfoPatch = 0xE3;
//Official implementation of svcBackdoor
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00
0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28
0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1]
0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr}
0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2
0x30, 0xFF, 0x2F, 0xE1, //blx r0
0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1}
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
/************************************************** /**************************************************
* Functions * Functions
**************************************************/ **************************************************/
u8 *getProc9(u8 *pos, u32 size) u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{ {
return memsearch(pos, "ess9", size, 4); u8 *off = memsearch(pos, "ess9", size, 4);
*process9Size = *(u32 *)(off - 0x60) * 0x200;
*process9MemAddr = *(u32 *)(off + 0xC);
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
} }
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2) void getSigChecks(u8 *pos, u32 size, u16 **off, u16 **off2)
{ {
//Look for signature checks //Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
*off = (u32)memsearch(pos, pattern, size, 4); *off = (u16 *)memsearch(pos, pattern, size, 4);
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1; *off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1);
} }
void *getReboot(u8 *pos, u32 size) void *getReboot(u8 *pos, u32 size, u32 process9MemAddr, u32 *fOpenOffset)
{ {
//Look for FIRM reboot code //Look for FIRM reboot code
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
return memsearch(pos, pattern, size, 4) - 0x10; u8 *off = memsearch(pos, pattern, size, 4) - 0x10;
}
u32 getfOpen(u8 *proc9Offset, void *rebootOffset)
{
//Offset Process9 code gets loaded to in memory (defined in ExHeader)
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr; *fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
return off;
} }
u16 *getFirmWrite(u8 *pos, u32 size) u16 *getFirmWrite(u8 *pos, u32 size)
@ -99,9 +110,15 @@ u32 getLoader(u8 *pos, u32 *loaderSize)
return (u32)(off - pos); return (u32)(off - pos);
} }
u32* getExceptionVectorsPage(u8 *pos, u32 size) u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage)
{ {
const u8 pattern[] = {0x00,0xB0,0x9C,0xE5,0x0A,0xB0,0x0B,0xE0,0x0A,0x00,0x5B,0xE1,0xFB,0xFF,0xFF,0x1A}; const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
return (u32 *)(memsearch(pos, pattern, size, 16) - 0x2C); *exceptionsPage = (u32 *)(memsearch(pos, pattern, size, 4) - 0x2C);
u32 svcOffset = (-(((*exceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
return svcTable;
} }

View File

@ -15,17 +15,16 @@ const u16 nandRedir[2],
writeBlock[2], writeBlock[2],
writeBlockSafe[2]; writeBlockSafe[2];
const u8 unitInfoPatch; const u8 unitInfoPatch;
const u8 svcBackdoor[40];
/************************************************** /**************************************************
* Functions * Functions
**************************************************/ **************************************************/
u8 *getProc9(u8 *pos, u32 size); u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2); void getSigChecks(u8 *pos, u32 size, u16 **off, u16 **off2);
void *getReboot(u8 *pos, u32 size); void *getReboot(u8 *pos, u32 size, u32 process9MemAddr, u32 *fOpenOffset);
u32 getfOpen(u8 *proc9Offset, void *rebootOffset);
u16 *getFirmWrite(u8 *pos, u32 size); u16 *getFirmWrite(u8 *pos, u32 size);
u16 *getFirmWriteSafe(u8 *pos, u32 size); u16 *getFirmWriteSafe(u8 *pos, u32 size);
u8 *getUnitInfoValueSet(u8 *pos, u32 size); u8 *getUnitInfoValueSet(u8 *pos, u32 size);
u32 getLoader(u8 *pos, u32 *loaderSize); u32 getLoader(u8 *pos, u32 *loaderSize);
u32* getExceptionVectorsPage(u8 *pos, u32 size); //Multi-purpose, don't change u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage);

View File

@ -40,23 +40,33 @@ void mcuReboot(void)
} }
//TODO: add support for TIMER IRQ //TODO: add support for TIMER IRQ
void startChrono(u64 initialTicks) static void startChrono(u64 initialTicks)
{ {
//Based on a NATIVE_FIRM disassembly //Based on a NATIVE_FIRM disassembly
*(vu16 *)(0x10003002 + 4 * 0) = 0; //67MHz *(vu16 *)0x10003002 = 0; //67MHz
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 4; //Count-up for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 4; //Count-up
for(u32 i = 0; i < 4; i++) *(vu16 *)(0x10003000 + 4 * i) = (u16)(initialTicks >> (16 * i)); for(u32 i = 0; i < 4; i++) *(vu16 *)(0x10003000 + 4 * i) = (u16)(initialTicks >> (16 * i));
*(vu16 *)(0x10003002 + 4 * 0) = 0x80; //67MHz; enabled *(vu16 *)0x10003002 = 0x80; //67MHz; enabled
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 0x84; //Count-up; enabled for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 0x84; //Count-up; enabled
} }
u64 chrono(void) u64 chrono(void)
{ {
static u32 chronoStarted = 0;
if(!chronoStarted)
{
startChrono(0);
chronoStarted++;
}
u64 res = 0; u64 res = 0;
for(u32 i = 0; i < 4; i++) res |= *(vu16 *)(0x10003000 + 4 * i) << (16 * i); for(u32 i = 0; i < 4; i++) res |= *(vu16 *)(0x10003000 + 4 * i) << (16 * i);
return res; return res;
} }

View File

@ -11,6 +11,5 @@ void mcuReboot(void);
#define TICKS_PER_SEC 67027964ULL #define TICKS_PER_SEC 67027964ULL
void startChrono(u64 initialTicks);
u64 chrono(void); u64 chrono(void);
void stopChrono(void); void stopChrono(void);