From 384dd2ad810623aeb5e712d3b5718f3409f74bd3 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Thu, 25 Aug 2016 00:13:43 +0200 Subject: [PATCH 1/2] Implement on-the-fly patching of TwlBg (and port the patches from https://github.com/ahezard/twl_firm_patcher; big thanks to ahezard and people mentioned in this page; also to Subv for the original patching idea (for NATIVE_FIRM)) --- Makefile | 8 ++- patches/twl_k11modules.s | 144 +++++++++++++++++++++++++++++++++++++++ source/firm.c | 8 ++- source/firm.h | 5 -- source/patches.c | 19 ++++++ source/patches.h | 3 +- source/types.h | 5 ++ 7 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 patches/twl_k11modules.s diff --git a/Makefile b/Makefile index f332334..e964dd7 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,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)/svcGetCFWInfopatch.h $(dir_build)/injector.h $(dir_build)/loader.h +bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/twl_k11modulespatch.h \ + $(dir_build)/injector.h $(dir_build)/loader.h .PHONY: all all: launcher a9lh ninjhax @@ -97,6 +98,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 44d23ee..937e522 100755 --- a/source/firm.c +++ b/source/firm.c @@ -260,6 +260,7 @@ static inline u32 loadFirm(FirmwareType firmType) static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh) { u8 *arm9Section = (u8 *)firm + section[2].offset; + u8 *arm11Section1 = (u8 *)firm + section[1].offset; if(isN3DS) { @@ -299,10 +300,10 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 patchTitleInstallMinVersionCheck(process9Offset, process9Size); //Restore svcBackdoor - reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size); + reimplementSvcBackdoor(arm11Section1, section[1].size); } - implementSvcGetCFWInfo((u8 *)firm + section[1].offset, section[1].size); + implementSvcGetCFWInfo(arm11Section1, section[1].size); } static inline void patchLegacyFirm(FirmwareType firmType) @@ -315,6 +316,9 @@ static inline void patchLegacyFirm(FirmwareType firmType) } applyLegacyFirmPatches((u8 *)firm, firmType); + + if(firmType == TWL_FIRM) + patchTwlBg((u8 *)firm + section[1].offset); } static inline void patchSafeFirm(void) diff --git a/source/firm.h b/source/firm.h index 7437b3e..78c1f1f 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; diff --git a/source/patches.c b/source/patches.c index 94bd77c..e86f50f 100644 --- a/source/patches.c +++ b/source/patches.c @@ -25,6 +25,7 @@ #include "config.h" #include "../build/rebootpatch.h" #include "../build/svcGetCFWInfopatch.h" +#include "../build/twl_k11modulespatch.h" static u32 *arm11ExceptionsPage = NULL; static u32 *arm11SvcTable = NULL; @@ -260,4 +261,22 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType) break; } } +} + +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 b2629af..e1f203d 100644 --- a/source/patches.h +++ b/source/patches.h @@ -43,4 +43,5 @@ void patchFirmWrites(u8 *pos, u32 size); void patchFirmWriteSafe(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); \ No newline at end of file diff --git a/source/types.h b/source/types.h index 979db43..b50d215 100644 --- a/source/types.h +++ b/source/types.h @@ -26,6 +26,11 @@ #include #include +#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) +#define PDN_SPI_CNT (*(vu32 *)0x101401C0) +#define CFG_BOOTENV (*(vu32 *)0x10010000) +#define CFG_UNITINFO (*(vu8 *)0x10010010) + //Common data types typedef uint8_t u8; typedef uint16_t u16; From 33238cee54e41ff8e7130e2de577be017eedf312 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Thu, 25 Aug 2016 16:39:43 +0200 Subject: [PATCH 2/2] Remove loading of /luma/TwlBg.cxi, fix bugs. --- source/firm.c | 29 ++++++----------------------- source/firm.h | 2 +- source/screen.h | 1 - source/types.h | 6 ++++-- source/utils.c | 6 ++++-- 5 files changed, 15 insertions(+), 29 deletions(-) diff --git a/source/firm.c b/source/firm.c index 937e522..a4600c3 100755 --- a/source/firm.c +++ b/source/firm.c @@ -43,7 +43,7 @@ static const firmSectionHeader *section; u32 config, emuOffset; -bool isN3DS, isDevUnit; +bool isN3DS, isDevUnit, isFirmlaunch; FirmwareSource firmSource; @@ -234,7 +234,7 @@ void main(void) break; } - launchFirm(firmType, isFirmlaunch); + launchFirm(firmType); } static inline u32 loadFirm(FirmwareType firmType) @@ -350,7 +350,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) { @@ -361,42 +361,25 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType) pos += modules[n].size; 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].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) - memcpy(pos, modules[i].addr, modules[i].size); - + memcpy(pos, modules[i].addr, modules[i].size); pos += modules[i].size; } + } -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 78c1f1f..84c74ed 100644 --- a/source/firm.h +++ b/source/firm.h @@ -54,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/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 b50d215..0aa6fc5 100644 --- a/source/types.h +++ b/source/types.h @@ -26,11 +26,13 @@ #include #include -#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) -#define PDN_SPI_CNT (*(vu32 *)0x101401C0) #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