From 50a2424001694b5cdbcc2509962a77075ece56c2 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Wed, 17 Aug 2016 23:47:30 +0200 Subject: [PATCH] Implement svcGetCFWInfo in place of svc 0x2e (which is stubbed). Luma3DS now boots ca. 1.5s faster Fix bug in pin.c where the START button wasn't recognized as well. --- Makefile | 9 +++- injector/source/patcher.c | 53 ++++++++++++-------- patches/svcGetCFWInfo.s | 48 ++++++++++++++++++ source/firm.c | 2 + source/patches.c | 103 ++++++++++++++++++++++++++++++++++---- source/patches.h | 1 + source/pin.c | 7 ++- 7 files changed, 187 insertions(+), 36 deletions(-) create mode 100644 patches/svcGetCFWInfo.s diff --git a/Makefile b/Makefile index c6e7de2..f332334 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ OC := arm-none-eabi-objcopy name := Luma3DS revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i') +commit := $(shell git rev-parse --short=8 HEAD) dir_source := source dir_patches := patches @@ -32,7 +33,7 @@ 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)/injector.h $(dir_build)/loader.h +bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/injector.h $(dir_build)/loader.h .PHONY: all all: launcher a9lh ninjhax @@ -91,6 +92,11 @@ $(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s @armips $< @bin2c -o $@ -n reboot $(@D)/reboot.bin +$(dir_build)/svcGetCFWInfopatch.h: $(dir_patches)/svcGetCFWInfo.s + @mkdir -p "$(@D)" + @armips $< + @bin2c -o $@ -n svcGetCFWInfo $(@D)/svcGetCFWInfo.bin + $(dir_build)/injector.h: $(dir_injector)/Makefile @mkdir -p "$(@D)" @$(MAKE) -C $(dir_injector) @@ -102,6 +108,7 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile $(dir_build)/memory.o: CFLAGS += -O3 $(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\"" +$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)" $(dir_build)/%.o: $(dir_source)/%.c $(bundled) @mkdir -p "$(@D)" diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 531ff51..4242cd2 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -3,11 +3,39 @@ #include "patcher.h" #include "ifile.h" +typedef struct __attribute__((packed)) +{ + char magic[4]; + + u8 versionMajor; + u8 versionMinor; + u8 versionBuild; + u8 flags; /* bit 0: dev branch; bit 1: is release */ + + u32 commitHash; + + u32 config; +} CFWInfo; + +CFWInfo info = {0}; + +int __attribute__((naked)) svcGetCFWInfo(CFWInfo __attribute__((unused)) *out) +{ + __asm__ volatile("svc 0x2E; bx lr"); +} + +static void loadCFWInfo(void) +{ + static bool infoLoaded = false; + if(!infoLoaded) svcGetCFWInfo(&info); + infoLoaded = true; +} + #ifndef PATH_MAX #define PATH_MAX 255 -#define CONFIG(a) (((loadConfig() >> (a + 16)) & 1) != 0) -#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3) -#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b) +#define CONFIG(a) (((info.config >> (a + 16)) & 1) != 0) +#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3) +#define BOOTCONFIG(a, b) ((info.config >> a) & b) #endif static int memcmp(const void *buf1, const void *buf2, u32 size) @@ -107,24 +135,6 @@ static bool secureInfoExists(void) return exists; } -static u32 loadConfig(void) -{ - static u32 config = 0; - - if(!config) - { - IFile file; - if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ))) - { - u64 total; - if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4; - IFile_Close(&file); - } - } - - return config; -} - static void progIdToStr(char *strEnd, u64 progId) { while(progId) @@ -319,6 +329,7 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff void patchCode(u64 progId, u8 *code, u32 size) { + loadCFWInfo(); switch(progId) { case 0x0004003000008F02LL: // USA Menu diff --git a/patches/svcGetCFWInfo.s b/patches/svcGetCFWInfo.s new file mode 100644 index 0000000..edded7d --- /dev/null +++ b/patches/svcGetCFWInfo.s @@ -0,0 +1,48 @@ +; +; 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/svcGetCFWInfo.bin", 0 + +.arm + + adr r1, infoStart + add r2, r0, #(infoEnd - infoStart) + + loop: + ldrb r3, [r1], #1 + strbt r3, [r0], #1 + cmp r0, r2 + blo loop + + mov r0, #0 + bx lr + +.pool +infoStart: + .ascii "LUMA" ; magic + .word 0 ; version + .word 0 ; truncated commit hash + .word 0 ; config +infoEnd: +.close \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index ef35cc7..fde33b8 100755 --- a/source/firm.c +++ b/source/firm.c @@ -301,6 +301,8 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 //Restore svcBackdoor reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size); } + + implementSvcGetCFWInfo((u8 *)firm + section[1].offset, section[1].size); } static inline void patchLegacyFirm(FirmwareType firmType) diff --git a/source/patches.c b/source/patches.c index a9cb7b6..c8e2c9b 100644 --- a/source/patches.c +++ b/source/patches.c @@ -24,6 +24,49 @@ #include "memory.h" #include "config.h" #include "../build/rebootpatch.h" +#include "../build/svcGetCFWInfopatch.h" +#include "fs.h" + +static u32 *arm11ExceptionsPage = NULL; +static u32 *arm11SvcTable = NULL; +static u32 *arm11SvcHandler = NULL; + +static u8 *freeK11Space = NULL; //other than the one used for svcBackdoor + +static void findArm11ExceptionsPageAndSvcHandlerAndTable(u8 *pos, u32 size) +{ + const u8 arm11ExceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5}; + + if(arm11ExceptionsPage == NULL) arm11ExceptionsPage = (u32 *)memsearch(pos, arm11ExceptionsPagePattern, size, 4) - 0xB; + if((arm11SvcTable == NULL || arm11SvcHandler == NULL) && arm11ExceptionsPage != NULL) + { + u32 svcOffset = (-((arm11ExceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch + arm11SvcHandler = arm11SvcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address + while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) + } +} + +static void findFreeK11Space(u8 *pos, u32 size) +{ + if(freeK11Space == NULL) + { + const u8 bogus_pattern[] = { 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, + 0x2F, 0xE1, 0x00, 0x10, 0xA0, 0xE3, 0x00, 0x10, 0xC0, 0xE5, + 0x1E, 0xFF, 0x2F, 0xE1 }; + + u32 *someSpace = (u32 *)memsearch(pos, bogus_pattern, size, 24); + + // We couldn't find the place where to begin our search of an empty block + if (someSpace == NULL) + return; + + // Advance until we reach the padding area (filled with 0xFF) + u32 *freeSpace; + for(freeSpace = someSpace; *freeSpace != 0xFFFFFFFF; freeSpace++); + + freeK11Space = (u8 *)freeSpace; + } +} u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) { @@ -111,25 +154,65 @@ void reimplementSvcBackdoor(u8 *pos, u32 size) 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x11, 0xFF, 0x2F, 0xE1}; //bx r1 - const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif - - u32 *exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB; + findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size); - 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) - - if(svcTable[0x7B] == 0) + if(!arm11SvcTable[0x7B]) { u32 *freeSpace; - for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); + for(freeSpace = arm11ExceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); memcpy(freeSpace, svcBackdoor, 40); - svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage); + arm11SvcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)arm11ExceptionsPage); } } +extern u32 config; + +void implementSvcGetCFWInfo(u8 *pos, u32 size) +{ + typedef struct __attribute__((packed)) + { + char magic[4]; + + u8 versionMajor; + u8 versionMinor; + u8 versionBuild; + u8 flags; + + u32 commitHash; + + u32 config; + } CFWInfo; + + const char *rev = REVISION; + bool isRelease = false; + + findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size); + findFreeK11Space(pos, size); + + memcpy(freeK11Space, svcGetCFWInfo, svcGetCFWInfo_size); + + CFWInfo *info = (CFWInfo *)memsearch(freeK11Space, "LUMA", svcGetCFWInfo_size, 4); + + info->commitHash = COMMIT_HASH; + info->config = config; + info->versionMajor = (u8)(rev[1] - '0'); + info->versionMinor = (u8)(rev[3] - '0'); + if(rev[4] == '.') + { + info->versionBuild = (u8)(rev[5] - '0'); + isRelease = rev[6] == 0; + } + else + isRelease = rev[4] == 0; + + info->flags = 0 /* master branch */ | (((isRelease) ? 1 : 0) << 1) /* is release */; + + arm11SvcTable[0x2E] = 0xFFF00000 + freeK11Space - pos; //stubbed svc + freeK11Space += svcGetCFWInfo_size; +} + void patchTitleInstallMinVersionCheck(u8 *pos, u32 size) { const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02}; diff --git a/source/patches.h b/source/patches.h index 5f36c14..b1e038f 100644 --- a/source/patches.h +++ b/source/patches.h @@ -42,5 +42,6 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); 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); u32 getLoader(u8 *pos, u32 *loaderSize); \ No newline at end of file diff --git a/source/pin.c b/source/pin.c index 6d69e68..599fee0 100644 --- a/source/pin.c +++ b/source/pin.c @@ -131,12 +131,11 @@ void verifyPin(PINData *in) } while(!(pressed & PIN_BUTTONS)); - pressed &= PIN_BUTTONS & ~BUTTON_START; - - if(!pressed) continue; - if(pressed & BUTTON_START) mcuPowerOff(); + pressed &= PIN_BUTTONS & ~BUTTON_START; + if(!pressed) continue; + char key = PINKeyToLetter(pressed); enteredPassword[cnt++] = (u8)key; // add character to password.