From d2f53626aece4e35ec09f29dbd7cd771ab218587 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 10 May 2016 01:27:58 +0200 Subject: [PATCH 1/6] Add precise and reliable time measurement (with a resolution of 67MHz). Splash screens now last 3 seconds after they have been loaded. The delay after pressing START in the configuration menu is now 2s long. --- source/config.c | 5 +++-- source/draw.c | 5 +++-- source/draw.h | 2 +- source/firm.c | 12 ++++++++++-- source/utils.c | 31 ++++++++++++++++++++++++++----- source/utils.h | 9 +++++++-- 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/source/config.c b/source/config.c index 969bb333..0e2e4270 100644 --- a/source/config.c +++ b/source/config.c @@ -185,6 +185,7 @@ void configureCFW(const char *configPath) deinitScreens(); PDN_GPU_CNT = 1; } - - delay(0x1400000); + + u64 t0 = chrono(); + while(chrono() - t0 < 2 * TICKS_PER_SEC); //wait for 1.5s } \ No newline at end of file diff --git a/source/draw.c b/source/draw.c index c8f1fab6..1f13e9dd 100644 --- a/source/draw.c +++ b/source/draw.c @@ -33,14 +33,15 @@ void clearScreens(void) memset32(fb->bottom, 0, 0x38400); } -void loadSplash(void) +u32 loadSplash(void) { initScreens(); //Don't delay boot if no splash image is on the SD if(fileRead(fb->top_left, "/luma/splash.bin") + fileRead(fb->bottom, "/luma/splashbottom.bin")) - delay(0x1400000); + return 1; + return 0; } void drawCharacter(char character, int posX, int posY, u32 color) diff --git a/source/draw.h b/source/draw.h index a8959bfa..18b46d02 100644 --- a/source/draw.h +++ b/source/draw.h @@ -19,7 +19,7 @@ #define COLOR_RED 0x0000FF #define COLOR_BLACK 0x000000 -void loadSplash(void); +u32 loadSplash(void); void clearScreens(void); void drawCharacter(char character, int posX, int posY, u32 color); int drawString(const char *string, int posX, int posY, u32 color); \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index 4a01557a..82dcb04d 100755 --- a/source/firm.c +++ b/source/firm.c @@ -23,6 +23,8 @@ u32 config, firmSource, emuOffset; +u64 chronoWhenSplashLoaded = 0; + void main(void) { u32 bootType, @@ -33,6 +35,8 @@ void main(void) needConfig, newConfig, emuHeader; + + startChrono(0); //Start the chronometer. It shouldn't be reset. //Detect the console being used console = PDN_MPCORE_CFG == 7; @@ -145,8 +149,9 @@ void main(void) loadPayload(pressed); //If screens are inited or the corresponding option is set, load splash screen - if(PDN_GPU_CNT != 1 || CONFIG(7)) loadSplash(); - + if(PDN_GPU_CNT != 1 || CONFIG(7)) chronoWhenSplashLoaded = (u64) loadSplash(); + if(chronoWhenSplashLoaded) chronoWhenSplashLoaded = chrono(); + //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one if(pressed & BUTTON_R1) { @@ -446,6 +451,9 @@ static inline void launchFirm(u32 firstSectionToCopy, u32 bootType) for(u32 i = firstSectionToCopy; i < 4 && section[i].size; i++) memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size); + while(chronoWhenSplashLoaded && chrono() - chronoWhenSplashLoaded < 3 * TICKS_PER_SEC); + stopChrono(); + //Determine the ARM11 entry to use vu32 *arm11; if(bootType) arm11 = (u32 *)0x1FFFFFFC; diff --git a/source/utils.c b/source/utils.c index ba0f8053..5c10112d 100644 --- a/source/utils.c +++ b/source/utils.c @@ -33,13 +33,34 @@ u32 waitInput(void) return key; } -void delay(u64 length) -{ - while(length--) __asm("mov r0, r0"); -} - void mcuReboot(void) { i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); while(1); +} + +//TODO: add support for TIMER IRQ +void startChrono(u64 initialTicks) +{ + //Based on a NATIVE_FIRM disassembly + + *(vu16 *)(0x10003002 + 4 * 0) = 0; //67MHz + 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)); + + *(vu16 *)(0x10003002 + 4 * 0) = 0x80; //67MHz; enabled + for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 0x84; //Count-up; enabled +} + +u64 chrono(void) +{ + u64 res = 0; + for(u32 i = 0; i < 4; i++) res |= *(vu16 *)(0x10003000 + 4 * i) << (16 * i); + return res; +} + +void stopChrono(void) +{ + for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) &= ~0x80; } \ No newline at end of file diff --git a/source/utils.h b/source/utils.h index c95778e2..e2ef8ffb 100644 --- a/source/utils.h +++ b/source/utils.h @@ -7,5 +7,10 @@ #include "types.h" u32 waitInput(void); -void delay(u64 length); -void mcuReboot(void); \ No newline at end of file +void mcuReboot(void); + +#define TICKS_PER_SEC 67027964ULL + +void startChrono(u64 initialTicks); +u64 chrono(void); +void stopChrono(void); \ No newline at end of file From 4483b65b25dabae7a18f580a7be525d0b137f885 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 10 May 2016 01:38:08 +0200 Subject: [PATCH 2/6] Update config.c --- source/config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/config.c b/source/config.c index 0e2e4270..cb595810 100644 --- a/source/config.c +++ b/source/config.c @@ -187,5 +187,5 @@ void configureCFW(const char *configPath) } u64 t0 = chrono(); - while(chrono() - t0 < 2 * TICKS_PER_SEC); //wait for 1.5s -} \ No newline at end of file + while(chrono() - t0 < 2 * TICKS_PER_SEC); //wait for 2s +} From f7552f7c3292aaa8147ba4b64a871653661284ba Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 10 May 2016 02:12:44 +0200 Subject: [PATCH 3/6] Update patcher.c --- injector/source/patcher.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/injector/source/patcher.c b/injector/source/patcher.c index dafa7d40..d001b784 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -364,7 +364,7 @@ void patchCode(u64 progId, u8 *code, u32 size) 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01 }; - static const u8 fpdVerPatch = 0x05; + static const u8 fpdVerPatch = 0x06; //Allow online access to work with old friends modules patchMemory(code, size, @@ -504,4 +504,4 @@ void patchCode(u64 progId, u8 *code, u32 size) break; } -} \ No newline at end of file +} From edb5a82a8904d876c4957ae4c6171c64689d3d96 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 10 May 2016 23:06:32 +0200 Subject: [PATCH 4/6] Restore svcBackdoor (on ARM11, for 11.0 and higher) --- source/firm.c | 39 ++++++++++++++++++++++++++++++++++++++- source/firm.h | 1 + source/patches.c | 9 ++++++++- source/patches.h | 4 +++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/source/firm.c b/source/firm.c index 82dcb04d..b77877da 100755 --- a/source/firm.c +++ b/source/firm.c @@ -242,7 +242,8 @@ static inline void loadFirm(u32 firmType, u32 externalFirm) static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode) { u8 *arm9Section = (u8 *)firm + section[2].offset; - + u8 *arm11Section1 = (u8 *)firm + section[1].offset; + u32 nativeFirmType; if(console) @@ -296,6 +297,7 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode) *(u16 *)sigOffset2 = sigPatch[0]; *((u16 *)sigOffset2 + 1) = sigPatch[1]; + reimplementSvcBackdoor(arm11Section1); //Does nothing if svcBackdoor is still there //Replace the FIRM loader with the injector while copying section0 copySection0AndInjectLoader(); } @@ -355,6 +357,41 @@ static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset) *pos_fopen = fOpenOffset; } +static inline void reimplementSvcBackdoor(u8 *arm11Section1) +{ + u32 *exceptionsPage = getExceptionVectorsPage(arm11Section1, section[1].size); + if(exceptionsPage == NULL) return; + + u32 low24 = (exceptionsPage[2] & 0x00FFFFFF) << 2; + 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 + while(*svcTable != 0) svcTable++; //svc0 = NULL + + if(svcTable[0x7B] != 0) return; + + u32 *freeSpace = exceptionsPage; + while(freeSpace < exceptionsPage + 0x400 && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF)) + freeSpace++; + + if(freeSpace >= exceptionsPage + 0x400) return; + + //Official implementation of svcBackdoor + freeSpace[0] = 0xE3CD10FF; + freeSpace[1] = 0xE3811C0F; + freeSpace[2] = 0xE2811028; + freeSpace[3] = 0xE5912000; + freeSpace[4] = 0xE9226000; + freeSpace[5] = 0xE1A0D002; + freeSpace[6] = 0xE12FFF30; + freeSpace[7] = 0xE8BD0003; + freeSpace[8] = 0xE1A0D000; + freeSpace[9] = 0xE12FFF11; + + svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *) exceptionsPage); +} + static inline void copySection0AndInjectLoader(void) { u8 *arm11Section0 = (u8 *)firm + section[0].offset; diff --git a/source/firm.h b/source/firm.h index 8a88b231..5ef25497 100644 --- a/source/firm.h +++ b/source/firm.h @@ -41,6 +41,7 @@ static inline void loadFirm(u32 firmType, u32 externalFirm); static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode); static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader); static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset); +static inline void reimplementSvcBackdoor(u8 *arm11Section1); static inline void copySection0AndInjectLoader(void); static inline void patchLegacyFirm(u32 firmType); static inline void patchSafeFirm(void); diff --git a/source/patches.c b/source/patches.c index 62d4e67c..40b9929c 100644 --- a/source/patches.c +++ b/source/patches.c @@ -87,4 +87,11 @@ u32 getLoader(u8 *pos, u32 *loaderSize) *loaderSize = size; return (u32)(off - pos); -} \ No newline at end of file +} + +u32* getExceptionVectorsPage(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x00,0xB0,0x9C,0xE5,0x0A,0xB0,0x0B,0xE0,0x0A,0x00,0x5B,0xE1,0xFB,0xFF,0xFF,0x1A}; + + return (u32 *)(memsearch(pos, pattern, size, 16) - 0x2C); +} diff --git a/source/patches.h b/source/patches.h index 78de1fc8..31736daa 100644 --- a/source/patches.h +++ b/source/patches.h @@ -24,4 +24,6 @@ void *getReboot(u8 *pos, u32 size); u32 getfOpen(u8 *proc9Offset, void *rebootOffset); u16 *getFirmWrite(u8 *pos, u32 size); u16 *getFirmWriteSafe(u8 *pos, u32 size); -u32 getLoader(u8 *pos, u32 *loaderSize); \ No newline at end of file + +u32 getLoader(u8 *pos, u32 *loaderSize); +u32* getExceptionVectorsPage(u8 *pos, u32 size); //Multi-purpose, don't change From d00d82ac8972dfe1de60ba7aae978c83031d8c90 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 10 May 2016 23:27:54 +0200 Subject: [PATCH 5/6] Update firm.c --- source/firm.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/firm.c b/source/firm.c index b77877da..09945919 100755 --- a/source/firm.c +++ b/source/firm.c @@ -378,16 +378,16 @@ static inline void reimplementSvcBackdoor(u8 *arm11Section1) if(freeSpace >= exceptionsPage + 0x400) return; //Official implementation of svcBackdoor - freeSpace[0] = 0xE3CD10FF; - freeSpace[1] = 0xE3811C0F; - freeSpace[2] = 0xE2811028; - freeSpace[3] = 0xE5912000; - freeSpace[4] = 0xE9226000; - freeSpace[5] = 0xE1A0D002; - freeSpace[6] = 0xE12FFF30; - freeSpace[7] = 0xE8BD0003; - freeSpace[8] = 0xE1A0D000; - freeSpace[9] = 0xE12FFF11; + 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); } @@ -505,4 +505,4 @@ static inline void launchFirm(u32 firstSectionToCopy, u32 bootType) //Final jump to ARM9 kernel ((void (*)())firm->arm9Entry)(); -} \ No newline at end of file +} From 1750b256ebaad1ba3444954ce9b231db2cd15387 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Wed, 11 May 2016 01:08:54 +0200 Subject: [PATCH 6/6] Do things right --- source/firm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/firm.c b/source/firm.c index 09945919..fc269000 100755 --- a/source/firm.c +++ b/source/firm.c @@ -372,10 +372,10 @@ static inline void reimplementSvcBackdoor(u8 *arm11Section1) if(svcTable[0x7B] != 0) return; u32 *freeSpace = exceptionsPage; - while(freeSpace < exceptionsPage + 0x400 && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF)) + while(freeSpace < exceptionsPage + 0x400 - 0xA && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF)) freeSpace++; - if(freeSpace >= exceptionsPage + 0x400) return; + if(freeSpace >= exceptionsPage + 0x400 - 0xA) return; //Official implementation of svcBackdoor freeSpace[0] = 0xE3CD10FF; //bic r1, sp, #0xff