diff --git a/Makefile b/Makefile index e071c65..01c263d 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 @@ -34,7 +35,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)/k11modulespatch.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)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h $(dir_build)/injector.h $(dir_build)/loader.h .PHONY: all all: launcher a9lh ninjhax @@ -100,6 +101,11 @@ $(dir_build)/k11modulespatch.h: $(dir_patches)/k11modules.s @armips $< @bin2c -o $@ -n k11modules $(@D)/k11modules.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) @@ -119,6 +125,7 @@ $(dir_build)/arm11_exceptions.h: $(dir_arm11_exceptions)/Makefile $(dir_build)/memory.o: CFLAGS += -O3 $(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) (dev) 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 32fb3d1..ce77b7f 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 82e1df5..6a0d51e 100755 --- a/source/firm.c +++ b/source/firm.c @@ -339,6 +339,8 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 patchK11ModuleChecks(arm11Section1, section[1].size); patchP9AccessChecks(arm9Section, section[2].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 a97c5b0..1736890 100644 --- a/source/patches.c +++ b/source/patches.c @@ -25,11 +25,15 @@ #include "config.h" #include "../build/rebootpatch.h" #include "../build/k11modulespatch.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}; @@ -43,6 +47,28 @@ static void findArm11ExceptionsPageAndSvcHandlerAndTable(u8 *pos, u32 size) } } +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) { u8 *off = memsearch(pos, "ess9", size, 4); @@ -233,21 +259,10 @@ void patchK11ModuleChecks(u8 *pos, u32 size) // We have to detour a function in the ARM11 kernel because builtin modules // are compressed in memory and are only decompressed at runtime. - // Find some padding space to add our code - 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 }; + findFreeK11Space(pos, size); + u8 *freeSpace = freeK11Space; + freeK11Space += k11modules_size; - 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++); - // Inject our code into the free space memcpy(freeSpace, k11modules, k11modules_size); @@ -318,6 +333,52 @@ void reimplementSvcBackdoor(u8 *pos, u32 size) } } +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 = 1 /* dev 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 a2c1c81..bf64b74 100644 --- a/source/patches.h +++ b/source/patches.h @@ -52,5 +52,6 @@ void patchK11ModuleChecks(u8 *pos, u32 size); 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); u8 *getUnitInfoValueSet(u8 *pos, u32 size); 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.