diff --git a/Makefile b/Makefile
index 01c263d..5959325 100644
--- a/Makefile
+++ b/Makefile
@@ -35,8 +35,8 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
-bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/k11modulespatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h $(dir_build)/injector.h $(dir_build)/loader.h
-
+bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/k11modulespatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/twl_k11modulespatch.h \
+ $(dir_build)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h $(dir_build)/injector.h $(dir_build)/loader.h
.PHONY: all
all: launcher a9lh ninjhax
@@ -106,6 +106,11 @@ $(dir_build)/svcGetCFWInfopatch.h: $(dir_patches)/svcGetCFWInfo.s
@armips $<
@bin2c -o $@ -n svcGetCFWInfo $(@D)/svcGetCFWInfo.bin
+$(dir_build)/twl_k11modulespatch.h: $(dir_patches)/twl_k11modules.s
+ @mkdir -p "$(@D)"
+ @armips $<
+ @bin2c -o $@ -n twl_k11modules $(@D)/twl_k11modules.bin
+
$(dir_build)/injector.h: $(dir_injector)/Makefile
@mkdir -p "$(@D)"
@$(MAKE) -C $(dir_injector)
diff --git a/patches/twl_k11modules.s b/patches/twl_k11modules.s
new file mode 100644
index 0000000..dcda791
--- /dev/null
+++ b/patches/twl_k11modules.s
@@ -0,0 +1,144 @@
+;
+; This file is part of Luma3DS
+; Copyright (C) 2016 Aurora Wright, TuxSH
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see .
+;
+; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
+; reasonable legal notices or author attributions in that material or in the Appropriate Legal
+; Notices displayed by works containing it.
+;
+
+.arm.little
+
+.create "build/twl_k11modules.bin", 0
+
+.align 4
+.arm
+
+patch:
+ ; r4: Pointer to a pointer to the exheader of the current NCCH
+ ; sp + 0xb0 - 0xa4: Pointer to the memory location where the NCCH text was loaded
+
+ add r3, sp, #(0xb0 - 0xa4)
+ add r1, sp, #(0xb0 - 0xac)
+
+ push {r0-r11, lr}
+
+ ldr r9, [r3] ; load the address of the code section
+ ldr r8, [r4] ; load the address of the exheader
+
+ ldr r7, [r8, #0x200] ; low titleID
+ ldr r6, =#0x000001ff
+ cmp r7, r6
+ bne end
+
+ ldr r7, =#0xabcdabcd ; offset of the dev launcher (will be replaced later)
+ add r7, r9
+
+ adr r5, patchesStart
+ add r6, r5, #(patchesEnd - patchesStart)
+
+ patchLoop:
+ ldrh r0, [r5, #4]
+ cmp r0, #0
+ moveq r4, r9
+ movne r4, r7
+
+ ldrh r2, [r5, #6]
+ add r1, r5, #8
+ ldr r0, [r5]
+ add r0, r4
+ blx memcmp
+ cmp r0, #0
+ bne skipPatch
+
+ ldrh r2, [r5, #6]
+ add r1, r5, #0x08
+ add r1, r2
+ ldr r0, [r5]
+ add r0, r4
+ blx memcpy
+
+ skipPatch:
+
+ ldrh r0, [r5, #6]
+ add r5, r5, #0x08
+ add r5, r0,lsl#1
+ cmp r5, r6
+ blo patchLoop
+
+ end:
+
+ pop {r0-r11, pc}
+
+.align 2
+.thumb
+
+memcmp:
+ push {r4-r7, lr}
+ mov r4, #0
+ cmp_loop:
+ cmp r4, r2
+ bhs cmp_loop_end
+ ldrb r6, [r0, r4]
+ ldrb r7, [r1, r4]
+ add r4, #1
+ sub r6, r7
+ cmp r6, #0
+ beq cmp_loop
+
+ cmp_loop_end:
+ mov r0, r6
+ pop {r4-r7, pc}
+
+memcpy:
+ push {r4-r5, lr}
+ mov r4, #0
+
+ copy_loop:
+ cmp r4, r2
+ bhs copy_loop_end
+ ldrb r5, [r1, r4]
+ strb r5, [r0, r4]
+ add r4, #1
+ b copy_loop
+
+ copy_loop_end:
+ pop {r4-r5, pc}
+
+.align 4
+
+; Available space for patches: 152 bytes on N3DS, 666 on O3DS
+
+patchesStart:
+ ; SCFG_EXT bit31 patches, based on https://github.com/ahezard/twl_firm_patcher (credits where they're due)
+
+ .word 0x07368 ; offset
+ .halfword 1 ; type (0: relative to the start of TwlBg's code; 1: relative to the start of the dev SRL launcher)
+ .halfword 4 ; size (must be a multiple of 4)
+ .byte 0x94, 0x09, 0xfc, 0xed ; expected data (decrypted = 0x08, 0x60, 0x87, 0x05)
+ .byte 0x24, 0x09, 0xbc, 0xe9 ; patched data (decrypted = 0xb8, 0x60, 0xc7, 0x01)
+
+ .word 0xa5888
+ .halfword 1
+ .halfword 8
+ .byte 0x83, 0x30, 0x2e, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x01, 0x1a, 0xe3, 0x08, 0x60, 0x87, 0x05)
+ .byte 0x89, 0x53, 0xb2, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x08, 0x62, 0x86, 0xe3, 0x08, 0x60, 0x87, 0xe5)
+
+patchesEnd:
+
+.pool
+
+.close
\ No newline at end of file
diff --git a/source/firm.c b/source/firm.c
index 466a5c7..be22917 100755
--- a/source/firm.c
+++ b/source/firm.c
@@ -44,7 +44,7 @@ static const firmSectionHeader *section;
u32 config,
emuOffset;
-bool isN3DS, isDevUnit;
+bool isN3DS, isDevUnit, isFirmlaunch;
FirmwareSource firmSource;
@@ -101,7 +101,7 @@ void main(void)
isFirmlaunch = false;
firmType = NATIVE_FIRM;
-
+
//Determine if booting with A9LH
isA9lh = !PDN_SPI_CNT;
@@ -226,7 +226,7 @@ void main(void)
}
u32 firmVersion = loadFirm(firmType);
-
+
switch(firmType)
{
case NATIVE_FIRM:
@@ -241,7 +241,7 @@ void main(void)
break;
}
- launchFirm(firmType, isFirmlaunch);
+ launchFirm(firmType);
}
static inline u32 loadFirm(FirmwareType firmType)
@@ -346,7 +346,7 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
patchP9AccessChecks(process9Offset, process9Size);
}
- implementSvcGetCFWInfo((u8 *)firm + section[1].offset, section[1].size);
+ implementSvcGetCFWInfo(arm11Section1, section[1].size);
}
static inline void patchLegacyFirm(FirmwareType firmType)
@@ -372,8 +372,9 @@ static inline void patchLegacyFirm(FirmwareType firmType)
}
applyLegacyFirmPatches((u8 *)firm, firmType);
- fileWrite(arm9Section, "/luma/twl_arm9sec.bin", section[3].size);
+ if(firmType == TWL_FIRM)
+ patchTwlBg((u8 *)firm + section[1].offset);
}
static inline void patchSafeFirm(void)
@@ -414,7 +415,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
u8 *pos = arm11Section0, *end = pos + section[0].size;
u32 n = 0;
- u32 loaderIndex = 0, twlBgIndex = 0;
+ u32 loaderIndex = 0;
while(pos < end)
{
@@ -438,35 +439,20 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
}
if(firmType == NATIVE_FIRM && memcmp(modules[n].name, "loader", 7) == 0) loaderIndex = n;
- else if(firmType == TWL_FIRM && memcmp(modules[n].name, "TwlBg", 6) == 0) twlBgIndex = n;
n++;
}
- u32 twlBgSize = 0;
-
if(firmType == NATIVE_FIRM && modules[loaderIndex].addr != NULL)
{
modules[loaderIndex].size = injector_size;
modules[loaderIndex].addr = injector;
}
- else if(firmType == TWL_FIRM)
- {
- twlBgSize = getFileSize("/luma/TwlBg.cxi");
- if(twlBgSize != 0)
- {
- modules[twlBgIndex].size = twlBgSize;
- modules[twlBgIndex].addr = NULL;
- }
- }
-
pos = section[0].address;
for(u32 i = 0; i < n; i++)
{
- if(firmType == TWL_FIRM && i == twlBgIndex && twlBgSize != 0)
- fileRead(pos, "/luma/TwlBg.cxi");
- else if(modules[i].addr != NULL)
+ if(modules[i].addr != NULL)
memcpy(pos, modules[i].addr, modules[i].size);
else
{
@@ -482,7 +468,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
}
}
-static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
+static inline void launchFirm(FirmwareType firmType)
{
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
u32 sectionNum;
diff --git a/source/firm.h b/source/firm.h
index 7437b3e..84c74ed 100644
--- a/source/firm.h
+++ b/source/firm.h
@@ -24,11 +24,6 @@
#include "types.h"
-#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
-#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
-#define CFG_BOOTENV (*(vu32 *)0x10010000)
-#define CFG_UNITINFO (*(vu8 *)0x10010010)
-
//FIRM Header layout
typedef struct firmSectionHeader {
u32 offset;
@@ -59,4 +54,4 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
static inline void patchLegacyFirm(FirmwareType firmType);
static inline void patchSafeFirm(void);
static inline void copySection0AndInjectSystemModules(FirmwareType firmType);
-static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch);
\ No newline at end of file
+static inline void launchFirm(FirmwareType firmType);
\ No newline at end of file
diff --git a/source/patches.c b/source/patches.c
index 8f527ed..eab35ec 100644
--- a/source/patches.c
+++ b/source/patches.c
@@ -26,6 +26,7 @@
#include "../build/rebootpatch.h"
#include "../build/svcGetCFWInfopatch.h"
#include "../build/k11modulespatch.h"
+#include "../build/twl_k11modulespatch.h"
static u32 *arm11ExceptionsPage = NULL;
static u32 *arm11SvcTable = NULL;
@@ -302,7 +303,7 @@ void patchUnitInfoValueSet(u8 *pos, u32 size)
u8 *off = memsearch(pos, pattern, size, 4);
- off[0] = (*(vu8 *)0x10010010 == 0) ? 1 : 0;
+ off[0] = (CFG_UNITINFO == 0) ? 1 : 0;
off[3] = 0xE3;
}
@@ -428,3 +429,21 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
}
}
}
+
+void patchTwlBg(u8 *pos)
+{
+ u8 *dst = pos + ((isN3DS) ? 0xFEA4 : 0xFCA0);
+ u16 *src1 = (u16 *)(pos + ((isN3DS) ? 0xE38 : 0xE3C)), *src2 = (u16 *)(pos + ((isN3DS) ? 0xE54 : 0xE58));
+ memcpy(dst, twl_k11modules, twl_k11modules_size); //install k11 hook
+
+ u32 *off;
+ for(off = (u32 *)dst; *off != 0xABCDABCD; off++);
+ *off = (isN3DS) ? 0xCDE88 : 0xCD5F8; //dev SRL launcher offset
+
+ //Construct BLX instructions:
+ src1[0] = 0xF000 | ((((u32)dst - (u32)src1 - 4) & (0xFFF << 11)) >> 12);
+ src1[1] = 0xE800 | ((((u32)dst - (u32)src1 - 4) & 0xFFF) >> 1);
+
+ src2[0] = 0xF000 | ((((u32)dst - (u32)src2 - 4) & (0xFFF << 11)) >> 12);
+ src2[1] = 0xE800 | ((((u32)dst - (u32)src2 - 4) & 0xFFF) >> 1);
+}
\ No newline at end of file
diff --git a/source/patches.h b/source/patches.h
index ee3b54a..52b1c38 100644
--- a/source/patches.h
+++ b/source/patches.h
@@ -53,4 +53,5 @@ void patchP9AccessChecks(u8 *pos, u32 size);
void patchUnitInfoValueSet(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 size);
void implementSvcGetCFWInfo(u8 *pos, u32 size);
-void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
\ No newline at end of file
+void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
+void patchTwlBg(u8 *pos);
diff --git a/source/screen.h b/source/screen.h
index a7af345..1e86289 100644
--- a/source/screen.h
+++ b/source/screen.h
@@ -29,7 +29,6 @@
#include "types.h"
-#define PDN_GPU_CNT (*(vu8 *)0x10141200)
#define ARM11_STUB_ADDRESS (0x25000000 - 0x30) //It's currently only 0x28 bytes large. We're putting 0x30 just to be sure here
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
diff --git a/source/types.h b/source/types.h
index 979db43..0aa6fc5 100644
--- a/source/types.h
+++ b/source/types.h
@@ -26,6 +26,13 @@
#include
#include
+#define CFG_BOOTENV (*(vu32 *)0x10010000)
+#define CFG_UNITINFO (*(vu8 *)0x10010010)
+
+#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
+#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
+#define PDN_GPU_CNT (*(vu8 *)0x10141200)
+
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
diff --git a/source/utils.c b/source/utils.c
index a7d3989..3a931f9 100644
--- a/source/utils.c
+++ b/source/utils.c
@@ -27,6 +27,8 @@
#include "draw.h"
#include "cache.h"
+extern bool isFirmlaunch;
+
u32 waitInput(void)
{
u32 pressedKey = 0,
@@ -56,7 +58,7 @@ u32 waitInput(void)
void mcuReboot(void)
{
- if(PDN_GPU_CNT != 1) clearScreens();
+ if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
@@ -66,7 +68,7 @@ void mcuReboot(void)
void mcuPowerOff(void)
{
- if(PDN_GPU_CNT != 1) clearScreens();
+ if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed