diff --git a/.gitmodules b/.gitmodules index 41f0849..154c12f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "CakeBrah"] path = CakeBrah url = https://github.com/mid-kid/CakeBrah -[submodule "CakeHax"] - path = CakeHax - url = https://github.com/mid-kid/CakeHax diff --git a/CakeHax b/CakeHax deleted file mode 160000 index 5245c7b..0000000 --- a/CakeHax +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5245c7b9dc232956a8578a36468f9024d8cf7001 diff --git a/Makefile b/Makefile index 9e56076..4ff4dba 100644 --- a/Makefile +++ b/Makefile @@ -22,10 +22,8 @@ dir_injector := injector dir_exceptions := exceptions dir_arm9_exceptions := $(dir_exceptions)/arm9 dir_arm11_exceptions := $(dir_exceptions)/arm11 -dir_mset := CakeHax dir_ninjhax := CakeBrah -dir_menuhax := menuhax -dir_pathchanger := pathchanger +dir_diffs := diffs dir_build := build dir_out := out @@ -42,10 +40,7 @@ bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/sv $(dir_build)/k11modulespatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h .PHONY: all -all: launcher a9lh ninjhax menuhax - -.PHONY: launcher -launcher: $(dir_out)/$(name).dat +all: a9lh ninjhax menuhax .PHONY: a9lh a9lh: $(dir_out)/arm9loaderhax.bin @@ -61,7 +56,6 @@ release: $(dir_out)/$(name)$(revision).7z .PHONY: clean clean: - @$(MAKE) $(FLAGS) -C $(dir_mset) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_arm9_exceptions) clean @@ -72,30 +66,21 @@ clean: $(dir_out): @mkdir -p "$(dir_out)" -$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out) - @$(MAKE) $(FLAGS) -C $(dir_mset) launcher - @dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144 - -$(dir_out)/menuhax/boot.3dsx: $(dir_menuhax)/menuhax.diff $(dir_out) +$(dir_out)/menuhax/boot.3dsx: $(dir_diffs) $(dir_out) @mkdir -p "$(@D)" - @cd $(dir_ninjhax); patch -p1 < ../$(dir_menuhax)/menuhax.diff; $(MAKE) $(FLAGS); git reset --hard + @cd $(dir_ninjhax); patch -p1 < ../$(dir_diffs)/1.diff; patch -p1 < ../$(dir_diffs)/2.diff; $(MAKE) $(FLAGS); git reset --hard @mv $(dir_out)/$(name).3dsx $@ @rm $(dir_out)/$(name).smdh $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out) @cp -a $(dir_build)/main.bin $@ -$(dir_out)/3ds/$(name): $(dir_out) +$(dir_out)/3ds/$(name): $(dir_diffs) $(dir_out) @mkdir -p "$@" - @$(MAKE) $(FLAGS) -C $(dir_ninjhax) + @cd $(dir_ninjhax); patch -p1 < ../$(dir_diffs)/1.diff; $(MAKE) $(FLAGS); git reset --hard @mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@ -$(dir_out)/pathchanger: $(dir_pathchanger)/pathchanger.py $(dir_pathchanger)/prebuilt $(dir_out) - @mkdir -p "$@" - @cp $(dir_pathchanger)/pathchanger.py $@ - @cp -rfT $(dir_pathchanger)/prebuilt $@ - -$(dir_out)/$(name)$(revision).7z: all $(dir_out)/pathchanger +$(dir_out)/$(name)$(revision).7z: all @7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py $(dir_build)/main.bin: $(dir_build)/main.elf diff --git a/diffs/1.diff b/diffs/1.diff new file mode 100644 index 0000000..7326b25 --- /dev/null +++ b/diffs/1.diff @@ -0,0 +1,116 @@ +diff -uNr a/include/brahma.h b/include/brahma.h +--- a/include/brahma.h 2016-09-21 16:18:56.246840000 +0200 ++++ b/include/brahma.h 2016-09-21 16:20:28.975957322 +0200 +@@ -4,7 +4,7 @@ + + u32 brahma_init (void); + u32 brahma_exit (void); +-s32 load_arm9_payload_offset (char *filename, u32 offset, u32 max_psize); ++s32 load_arm9_payload_offset (void); + s32 load_arm9_payload_from_mem (u8* data, u32 dsize); + void redirect_codeflow (u32 *dst_addr, u32 *src_addr); + s32 map_arm9_payload (void); +@@ -13,8 +13,6 @@ + s32 get_exploit_data (struct exploit_data *data); + s32 firm_reboot (); + +-#define load_arm9_payload(filename) load_arm9_payload_offset(filename, 0, 0) +- + #define BRAHMA_NETWORK_PORT 80 + + #define ARM_JUMPOUT 0xE51FF004 // LDR PC, [PC, -#04] +diff -uNr a/source/brahma.c b/source/brahma.c +--- a/source/brahma.c 2016-09-21 16:18:56.246840000 +0200 ++++ b/source/brahma.c 2016-09-21 16:21:33.240730777 +0200 +@@ -179,39 +179,56 @@ + return g_ext_arm9_loaded; + } + +-/* reads ARM9 payload from a given path. +- filename: full path of payload +- offset: offset of the payload in the file +- max_psize: the maximum size of the payload that should be loaded (if 0, ARM9_MAX_PAYLOAD_SIZE. Should be smaller than ARM9_MAX_PAYLOAD_SIZE) ++/* reads Luma payload + returns: 0 on failure, 1 on success */ +-s32 load_arm9_payload_offset (char *filename, u32 offset, u32 max_psize) { ++s32 load_arm9_payload_offset (void) { + s32 result = 0; + u32 fsize = 0; + u32 psize = 0; ++ bool use_default = true; ++ FILE *f; + +- if (max_psize == 0 || max_psize > ARM9_PAYLOAD_MAX_SIZE) +- max_psize = ARM9_PAYLOAD_MAX_SIZE; ++ FILE *p = fopen("/luma/path.txt", "r"); + +- if (!filename) +- return result; ++ if (p) { ++ fseek(p , 0, SEEK_END); ++ psize = ftell(p); ++ if (psize < 39 && psize > 5) { ++ char path[psize + 1]; ++ ++ fseek(p, 0, SEEK_SET); ++ u32 bytes_read = fread(path, 1, psize, p); ++ ++ if (bytes_read == psize) { ++ if (path[psize - 1] == 0xA) psize--; ++ if (path[psize - 1] == 0xD) psize--; ++ if (psize > 5 && path[0] == '/' && memcmp(&path[psize - 4], ".bin", 4)) { ++ path[psize] = 0; ++ f = fopen(path, "rb"); ++ use_default = false; ++ } ++ } ++ } ++ fclose(p); ++ } ++ ++ if (use_default) f = fopen("/arm9loaderhax.bin", "rb"); ++ ++ u32 max_size = ARM9_PAYLOAD_MAX_SIZE; + +- FILE *f = fopen(filename, "rb"); + if (f) { +- fseek(f , 0, SEEK_END); ++ fseek(f, 0, SEEK_END); + fsize = ftell(f); + +- if (offset < fsize) { +- psize = fsize - offset; +- if (psize > max_psize) +- psize = max_psize; +- +- g_ext_arm9_size = psize; +- +- fseek(f, offset, SEEK_SET); +- if (psize >= 8) { +- u32 bytes_read = fread(g_ext_arm9_buf, 1, psize, f); +- result = (g_ext_arm9_loaded = (bytes_read == psize)); +- } ++ if (fsize > max_size) ++ fsize = max_size; ++ ++ g_ext_arm9_size = fsize; ++ ++ fseek(f, 0, SEEK_SET); ++ if (fsize >= 8) { ++ u32 bytes_read = fread(g_ext_arm9_buf, 1, fsize, f); ++ result = (g_ext_arm9_loaded = (bytes_read == fsize)); + } + fclose(f); + } +diff -uNr a/source/main.c b/source/main.c +--- a/source/main.c 2016-09-21 16:18:56.246840000 +0200 ++++ b/source/main.c 2016-09-21 16:20:28.979957377 +0200 +@@ -10,7 +10,7 @@ + + int main (void) { + if (brahma_init()) { +- if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1) ++ if (load_arm9_payload_offset() != 1) + goto error; + firm_reboot(); + brahma_exit(); diff --git a/menuhax/menuhax.diff b/diffs/2.diff similarity index 78% rename from menuhax/menuhax.diff rename to diffs/2.diff index af9f93c..47ffe5f 100644 --- a/menuhax/menuhax.diff +++ b/diffs/2.diff @@ -7,5 +7,5 @@ diff -uNr a/source/main.c b/source/main.c int main (void) { + svcSleepThread(2500 * 1000000ULL); if (brahma_init()) { - if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1) + if (load_arm9_payload_offset() != 1) goto error; diff --git a/injector/source/patcher.h b/injector/source/patcher.h index 498c7aa..3520ed7 100644 --- a/injector/source/patcher.h +++ b/injector/source/patcher.h @@ -26,7 +26,8 @@ enum singleOptions { AUTOBOOTSYS = 0, USESYSFIRM, - SDFIRMSANDMODULES, + LOADSDFIRMSANDMODULES, + USECUSTOMPATH, USELANGEMUANDCODE, PATCHVERSTRING, SHOWGBABOOT, diff --git a/patches/reboot.s b/patches/reboot.s index 9174a23..75756e6 100644 --- a/patches/reboot.s +++ b/patches/reboot.s @@ -1,7 +1,7 @@ .arm.little payload_addr equ 0x23F00000 ; Brahma payload address. -payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeBrah supports). +payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeBrah supports). .create "build/reboot.bin", 0 .arm @@ -25,38 +25,22 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB cmp r0, r2 bne pxi_wait_recv - mov r4, #0 - adr r1, bin_fname - b open_payload + ; Open file + add r0, r7, #8 + adr r1, fname + mov r2, #1 + ldr r6, [fopen] + orr r6, 1 + blx r6 - fallback: - mov r4, #1 - adr r1, dat_fname - - open_payload: - ; Open file - add r0, r7, #8 - mov r2, #1 - ldr r6, [fopen] - orr r6, 1 - blx r6 - cmp r0, #0 - bne fallback ; If the .bin is not found, try the .dat. - - read_payload: - ; Read file - mov r0, r7 - adr r1, bytes_read - ldr r2, =payload_addr - cmp r4, #0 - movne r3, #0x12000 ; Skip the first 0x12000 bytes. - moveq r3, payload_maxsize - ldr r6, [r7] - ldr r6, [r6, #0x28] - blx r6 - cmp r4, #0 - movne r4, #0 - bne read_payload ; Go read the real payload. + ; Read file + mov r0, r7 + adr r1, bytes_read + ldr r2, =payload_addr + mov r3, payload_maxsize + ldr r6, [r7] + ldr r6, [r6, #0x28] + blx r6 ; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload add r0, r8, 0x1A @@ -87,10 +71,8 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB bytes_read: .word 0 fopen: .ascii "OPEN" .pool -bin_fname: .dcw "sdmc:/arm9loaderhax.bin" - .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -dat_fname: .dcw "sdmc:/Luma3DS.dat" - .word 0 +fname: .dcw "sdmc:/arm9loaderhax.bin" + .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .align 4 kernelcode_start: diff --git a/pathchanger/pathchanger.c b/pathchanger/pathchanger.c deleted file mode 100644 index 3a3a9b9..0000000 --- a/pathchanger/pathchanger.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include - -typedef uint8_t u8; - -static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize) -{ - const u8 *patternc = (const u8 *)pattern; - int table[256]; - - //Preprocessing - int i; - for(i = 0; i < 256; i++) - table[i] = patternSize; - for(i = 0; i < patternSize - 1; i++) - table[patternc[i]] = patternSize - i - 1; - - //Searching - int j = 0; - while(j <= size - patternSize) - { - u8 c = startPos[j + patternSize - 1]; - if(patternc[patternSize - 1] == c && memcmp(pattern, startPos + j, patternSize - 1) == 0) - return startPos + j; - j += table[c]; - } - - return NULL; -} - -static int fsize(FILE *fp) -{ - fseek(fp, 0, SEEK_END); - int size = ftell(fp); - rewind(fp); - - return size; -} - -static void error(FILE *payload, const char *message) -{ - fclose(payload); - printf("%s, are you sure you're using a Luma3DS payload?\n", message); - exit(0); -} - -int main(int argc, char **argv) -{ - if(argc == 1) - { - printf("Usage: %s \n", argv[0]); - exit(0); - } - - FILE *payload; - size_t size; - - payload = fopen(argv[1], "rb+"); - size = fsize(payload); - if(size > 0x20000) - error(payload, "The input file is too large"); - - u8 *buffer = (u8 *)malloc(size); - fread(buffer, 1, size, payload); - - u8 pattern[] = {'s', 0, 'd', 0, 'm', 0, 'c', 0, ':', 0, '/', 0}; - - u8 *found = memsearch(buffer, pattern, size, sizeof(pattern)); - - if(found == NULL) - { - free(buffer); - error(payload, "Pattern not found"); - } - - u8 input[38] = {0}; - u8 payloadname[2 * (sizeof(input) - 1)] = {0}; - - printf("Enter the payload's path (37 characters max): "); - scanf("%37s", input); - - unsigned int i; - for (i = 0; i < sizeof(input) - 1; i++) - payloadname[2 * i] = input[i]; - - memcpy(found + 12, payloadname, sizeof(payloadname)); - - rewind(payload); - fwrite(buffer, 1, size, payload); - - free(buffer); - fclose(payload); - - exit(0); -} \ No newline at end of file diff --git a/pathchanger/pathchanger.py b/pathchanger/pathchanger.py deleted file mode 100644 index cd4ea6c..0000000 --- a/pathchanger/pathchanger.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# Requires Python >= 3.2 or >= 2.7 - -# This is part of Luma3DS - -__author__ = "TuxSH" -__copyright__ = "Copyright (c) 2016 TuxSH" -__license__ = "GPLv3" -__version__ = "v1.0" - -import argparse - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Changes the path to Luma3DS for reboot patches") - parser.add_argument("payload", help="Path to the Luma3DS payload") - parser.add_argument("new_path", help="New Luma3DS payload path") - args = parser.parse_args() - data = b"" - - if len(args.new_path) > 37: - raise SystemExit("The new payload path is too large (37 characters max.)") - - with open(args.payload, "rb") as f: data = bytearray(f.read()) - - if len(data) == 0: raise SystemExit("Could not read {0}".format(args.payload)) - - if len(data) > 0x20000: - raise SystemExit("The input file is too large, are you sure you're using a Luma3DS payload?") - - found_index = data.find("sdmc:/".encode("utf-16-le")) - - if found_index == -1: - raise SystemExit("The pattern was not found, are you sure you're usinga a Luma3DS payload?") - - namebuf = args.new_path.encode("utf-16-le") - namebuf += b'\x00' * (74 - len(namebuf)) - - data[found_index + 12 : found_index + 12 + 74] = namebuf - - with open(args.payload, "wb+") as f: f.write(data) diff --git a/pathchanger/prebuilt/Linux/pathchanger b/pathchanger/prebuilt/Linux/pathchanger deleted file mode 100755 index 10f3e65..0000000 Binary files a/pathchanger/prebuilt/Linux/pathchanger and /dev/null differ diff --git a/pathchanger/prebuilt/Mac OS X/pathchanger b/pathchanger/prebuilt/Mac OS X/pathchanger deleted file mode 100755 index 9d6ee99..0000000 Binary files a/pathchanger/prebuilt/Mac OS X/pathchanger and /dev/null differ diff --git a/pathchanger/prebuilt/Windows/pathchanger.exe b/pathchanger/prebuilt/Windows/pathchanger.exe deleted file mode 100755 index 232a81d..0000000 Binary files a/pathchanger/prebuilt/Windows/pathchanger.exe and /dev/null differ diff --git a/source/config.c b/source/config.c index 6a6bd1e..eae8907 100644 --- a/source/config.c +++ b/source/config.c @@ -77,6 +77,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) const char *singleOptionsText[] = { "( ) Autoboot SysNAND", "( ) Use SysNAND FIRM if booting with R (A9LH)", "( ) Enable FIRMs and modules loading from SD", + "( ) Use custom path", "( ) Enable region/language emu. and ext. .code", "( ) Show NAND or user string in System Settings", "( ) Show GBA boot screen in patched AGB_FIRM", @@ -144,6 +145,10 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) "system modules from the SD card.\n\n" "This isn't needed in most cases.", + "Use a custom path for the\n" + "Luma3DS payload.\n\n" + "Refer to the wiki for instructions.", + "Enable overriding the region and\n" "language configuration and the usage\n" "of patched code binaries for specific\n" @@ -299,7 +304,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED); } - clearScreens(false, true); + clearScreens(false, true, false); drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); } else diff --git a/source/config.h b/source/config.h index c32bf0f..3aa814b 100644 --- a/source/config.h +++ b/source/config.h @@ -30,7 +30,7 @@ #define CONFIG_PATH "/luma/config.bin" #define CONFIG_VERSIONMAJOR 1 -#define CONFIG_VERSIONMINOR 5 +#define CONFIG_VERSIONMINOR 6 #define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7) @@ -52,7 +52,8 @@ enum singleOptions { AUTOBOOTSYS = 0, USESYSFIRM, - SDFIRMSANDMODULES, + LOADSDFIRMSANDMODULES, + USECUSTOMPATH, USELANGEMUANDCODE, PATCHVERSTRING, SHOWGBABOOT, diff --git a/source/crypto.c b/source/crypto.c index 7262078..7ad5957 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -282,7 +282,7 @@ static void sha(void *res, const void *src, u32 size, u32 mode) while(*REG_SHA_CNT & SHA_FINAL_ROUND); sha_wait_idle(); - + u32 hashSize = SHA_256_HASH_SIZE; if(mode == SHA_224_MODE) hashSize = SHA_224_HASH_SIZE; @@ -297,6 +297,8 @@ static void sha(void *res, const void *src, u32 size, u32 mode) static u8 __attribute__((aligned(4))) nandCtr[AES_BLOCK_SIZE]; static u8 nandSlot; static u32 fatStart; +static bool didShaHashBackup = false; +static u8 __attribute__((aligned(4))) shaHashBackup[SHA_256_HASH_SIZE]; void ctrNandInit(void) { @@ -482,8 +484,19 @@ void computePinHash(u8 *outbuf, const u8 *inbuf) u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) cipherText[AES_BLOCK_SIZE]; + if(!didShaHashBackup) + { + didShaHashBackup = true; + memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup)); + } + sdmmc_get_cid(1, (u32 *)cid); aes_use_keyslot(4); //Console-unique keyslot whose keys are set by the ARM9 bootROM aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE); +} + +void restoreShaHashBackup(void) +{ + if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup)); } \ No newline at end of file diff --git a/source/crypto.h b/source/crypto.h index 7ea191a..133d6bc 100755 --- a/source/crypto.h +++ b/source/crypto.h @@ -111,4 +111,5 @@ void set6x7xKeys(void); void decryptExeFs(u8 *inbuf); void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize); void kernel9Loader(u8 *arm9Section); -void computePinHash(u8 *outbuf, const u8 *inbuf); \ No newline at end of file +void computePinHash(u8 *outbuf, const u8 *inbuf); +void restoreShaHashBackup(void); \ No newline at end of file diff --git a/source/draw.c b/source/draw.c index 6f000f0..568a4b4 100644 --- a/source/draw.c +++ b/source/draw.c @@ -45,9 +45,12 @@ bool loadSplash(void) return false; initScreens(); + clearScreens(true, true, true); - if(isTopSplashValid) fileRead(fb->top_left, topSplashPath, 0); - if(isBottomSplashValid) fileRead(fb->bottom, bottomSplashPath, 0); + if(isTopSplashValid) fileRead(fbs[1].top_left, topSplashPath, 0); + if(isBottomSplashValid) fileRead(fbs[1].bottom, bottomSplashPath, 0); + + swapFramebuffers(true); chrono(3); @@ -56,7 +59,7 @@ bool loadSplash(void) void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color) { - u8 *select = isTopScreen ? fb->top_left : fb->bottom; + u8 *select = isTopScreen ? fbs[0].top_left : fbs[0].bottom; for(u32 y = 0; y < 8; y++) { diff --git a/source/draw.h b/source/draw.h index 7199060..9929f78 100644 --- a/source/draw.h +++ b/source/draw.h @@ -29,12 +29,6 @@ #include "types.h" -#define SCREEN_TOP_WIDTH 400 -#define SCREEN_BOTTOM_WIDTH 320 -#define SCREEN_HEIGHT 240 -#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT) -#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT) - #define SPACING_Y 10 #define SPACING_X 8 diff --git a/source/firm.c b/source/firm.c index 60c159d..e106ac9 100755 --- a/source/firm.c +++ b/source/firm.c @@ -247,7 +247,7 @@ void main(void) writeConfig(needConfig, configTemp); } - bool loadFromSd = CONFIG(SDFIRMSANDMODULES); + bool loadFromSd = CONFIG(LOADSDFIRMSANDMODULES); u32 firmVersion = loadFirm(&firmType, firmSource, loadFromSd); switch(firmType) @@ -316,7 +316,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo { u8 cetk[0xA50]; - if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk))) + if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) == sizeof(cetk)) decryptNusFirm(cetk, (u8 *)firm, firmSize); } diff --git a/source/fs.c b/source/fs.c index 21e8fb7..bb4fcf2 100644 --- a/source/fs.c +++ b/source/fs.c @@ -23,6 +23,7 @@ #include "fs.h" #include "memory.h" #include "strings.h" +#include "crypto.h" #include "cache.h" #include "screen.h" #include "fatfs/ff.h" @@ -70,6 +71,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size) { unsigned int written; f_write(&file, buffer, size, &written); + f_truncate(&file); f_close(&file); return true; @@ -137,6 +139,7 @@ void loadPayload(u32 pressed) { loaderAddress[1] = payloadSize; + restoreShaHashBackup(); initScreens(); flushDCacheRange(loaderAddress, loader_size); diff --git a/source/patches.c b/source/patches.c index 81e768f..cf00192 100644 --- a/source/patches.c +++ b/source/patches.c @@ -25,6 +25,7 @@ */ #include "patches.h" +#include "fs.h" #include "memory.h" #include "config.h" #include "../build/rebootpatch.h" @@ -94,6 +95,32 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) //Put the fOpen offset in the right location u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_size, 4); *pos_fopen = fOpenOffset; + + if(CONFIG(USECUSTOMPATH)) + { + const char pathPath[] = "/luma/path.txt"; + + u32 pathSize = getFileSize(pathPath); + + if(pathSize > 5 && pathSize < 39) + { + u8 path[pathSize]; + fileRead(path, pathPath, 0); + if(path[pathSize - 1] == 0xA) pathSize--; + if(path[pathSize - 1] == 0xD) pathSize--; + + if(pathSize > 5 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0) + { + u16 finalPath[pathSize + 1]; + for(u32 i = 0; i < pathSize; i++) + finalPath[i] = (u16)path[i]; + finalPath[pathSize] = 0; + + u8 *pos_path = memsearch(off, u"sd", reboot_size, 4) + 0xA; + memcpy(pos_path, finalPath, pathSize); + } + } + } } void patchFirmWrites(u8 *pos, u32 size) diff --git a/source/pin.c b/source/pin.c index 1e6c3ab..36f5fe5 100644 --- a/source/pin.c +++ b/source/pin.c @@ -46,7 +46,7 @@ static char pinKeyToLetter(u32 pressed) void newPin(bool allowSkipping, u32 pinMode) { - clearScreens(true, true); + clearScreens(true, true, false); u8 length = 4 + 2 * (pinMode - 1); @@ -89,13 +89,13 @@ void newPin(bool allowSkipping, u32 pinMode) memcpy(pin.magic, "PINF", 4); pin.formatVersionMajor = PIN_VERSIONMAJOR; pin.formatVersionMinor = PIN_VERSIONMINOR; - pin.length = length; u8 __attribute__((aligned(4))) tmp[SHA_256_HASH_SIZE]; - u8 __attribute__((aligned(4))) zeroes[AES_BLOCK_SIZE] = {0}; + u8 __attribute__((aligned(4))) lengthBlock[AES_BLOCK_SIZE] = {0}; + lengthBlock[0] = length; - computePinHash(tmp, zeroes); - memcpy(pin.testHash, tmp, sizeof(tmp)); + computePinHash(tmp, lengthBlock); + memcpy(pin.lengthHash, tmp, sizeof(tmp)); computePinHash(tmp, enteredPassword); memcpy(pin.hash, tmp, sizeof(tmp)); @@ -111,17 +111,17 @@ bool verifyPin(u32 pinMode) if(fileRead(&pin, PIN_PATH, sizeof(PinData)) != sizeof(PinData) || memcmp(pin.magic, "PINF", 4) != 0 || pin.formatVersionMajor != PIN_VERSIONMAJOR || - pin.formatVersionMinor != PIN_VERSIONMINOR || - pin.length != 4 + 2 * (pinMode - 1)) + pin.formatVersionMinor != PIN_VERSIONMINOR) return false; - u8 __attribute__((aligned(4))) zeroes[AES_BLOCK_SIZE] = {0}; u8 __attribute__((aligned(4))) tmp[SHA_256_HASH_SIZE]; + u8 __attribute__((aligned(4))) lengthBlock[AES_BLOCK_SIZE] = {0}; + lengthBlock[0] = 4 + 2 * (pinMode - 1); - computePinHash(tmp, zeroes); + computePinHash(tmp, lengthBlock); - //Test vector verification (SD card has, or hasn't been used on another console) - if(memcmp(pin.testHash, tmp, sizeof(tmp)) != 0) return false; + //Test vector verification (check if SD card has been used on another console or PIN length changed) + if(memcmp(pin.lengthHash, tmp, sizeof(tmp)) != 0) return false; initScreens(); @@ -135,6 +135,7 @@ bool verifyPin(u32 pinMode) const char messagePath[] = "/luma/pinmessage.txt"; u32 messageSize = getFileSize(messagePath); + if(messageSize > 0 && messageSize <= 800) { char message[messageSize + 1]; @@ -147,7 +148,7 @@ bool verifyPin(u32 pinMode) { drawString("Press START to shutdown or enter PIN to proceed", true, 10, 10, COLOR_TITLE); drawString("PIN ( digits): ", true, 10, 10 + 2 * SPACING_Y, COLOR_WHITE); - drawCharacter('0' + pin.length, true, 10 + 5 * SPACING_X, 10 + 2 * SPACING_Y, COLOR_WHITE); + drawCharacter('0' + lengthBlock[0], true, 10 + 5 * SPACING_X, 10 + 2 * SPACING_Y, COLOR_WHITE); u32 pressed; do @@ -169,7 +170,7 @@ bool verifyPin(u32 pinMode) drawCharacter(key, true, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE); charDrawPos += 2 * SPACING_X; - if(cnt >= pin.length) + if(cnt >= lengthBlock[0]) { computePinHash(tmp, enteredPassword); unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0; @@ -179,7 +180,7 @@ bool verifyPin(u32 pinMode) charDrawPos = 16 * SPACING_X; cnt = 0; - clearScreens(true, false); + clearScreens(true, false, false); drawString("Wrong PIN, try again", true, 10, 10 + 4 * SPACING_Y, COLOR_RED); } diff --git a/source/pin.h b/source/pin.h index 69390f8..f323452 100644 --- a/source/pin.h +++ b/source/pin.h @@ -30,15 +30,14 @@ #define PIN_PATH "/luma/pin.bin" #define PIN_VERSIONMAJOR 1 -#define PIN_VERSIONMINOR 2 +#define PIN_VERSIONMINOR 3 typedef struct __attribute__((packed)) { char magic[4]; u16 formatVersionMajor, formatVersionMinor; - u8 length; - u8 testHash[32]; + u8 lengthHash[32]; u8 hash[32]; } PinData; diff --git a/source/screen.c b/source/screen.c index 52eec27..09716b9 100644 --- a/source/screen.c +++ b/source/screen.c @@ -25,11 +25,20 @@ * Screen deinit code by tiniVi */ +/* +* About cache coherency: +* +* Flushing the data cache for all memory regions read from/written to by both processors is mandatory on the ARM9 processor. +* Thus, we make sure there'll be a cache miss on the ARM9 next time it's read. +* Otherwise the ARM9 won't see the changes made and things will break. +* +* On the ARM11, in the environment we're in, the MMU isn't enabled and nothing is cached. +*/ + #include "screen.h" #include "config.h" #include "memory.h" #include "cache.h" -#include "draw.h" #include "i2c.h" vu32 *const arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY; @@ -46,16 +55,6 @@ void __attribute__((naked)) arm11Stub(void) //Jump to it ((void (*)())*arm11Entry)(); } - -/* -About cache coherency: - - Flushing the data cache for **ALL** memory regions read from/written to by _both_ processors is mandatory on the arm9 processor. - Thus, we make sure there'll be a cache miss on the arm9 next time it's read. - Otherwise the arm9 won't see the changes made and things will break. - - On the arm11, in the environment we're in, the MMU isn't enabled and nothing is cached. -*/ static void invokeArm11Function(void (*func)()) { @@ -111,12 +110,34 @@ void updateBrightness(u32 brightnessIndex) invokeArm11Function(ARM11); } -void clearScreens(bool clearTop, bool clearBottom) +void swapFramebuffers(bool isAlternate) +{ + static u32 isAlternateTmp; + isAlternateTmp = isAlternate ? 1 : 0; + + void __attribute__((naked)) ARM11(void) + { + //Disable interrupts + __asm(".word 0xF10C01C0"); + + *(vu32 *)0x10400478 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp; + *(vu32 *)0x10400578 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp; + + WAIT_FOR_ARM9(); + } + + flushDCacheRange(&isAlternateTmp, 4); + invokeArm11Function(ARM11); +} + +void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate) { static bool clearTopTmp, clearBottomTmp; + static volatile struct fb *fbTmp; clearTopTmp = clearTop; clearBottomTmp = clearBottom; + fbTmp = clearAlternate ? &fbs[1] : &fbs[0]; void __attribute__((naked)) ARM11(void) { @@ -130,26 +151,26 @@ void clearScreens(bool clearTop, bool clearBottom) if(clearTopTmp) { - REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address - REGs_PSC0[1] = (u32)(fb->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address + REGs_PSC0[0] = (u32)fbTmp->top_left >> 3; //Start address + REGs_PSC0[1] = (u32)(fbTmp->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address REGs_PSC0[2] = 0; //Fill value REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start } if(clearBottomTmp) { - REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address - REGs_PSC1[1] = (u32)(fb->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address + REGs_PSC1[0] = (u32)fbTmp->bottom >> 3; //Start address + REGs_PSC1[1] = (u32)(fbTmp->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address REGs_PSC1[2] = 0; //Fill value REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start } while(!((!clearTopTmp || (REGs_PSC0[3] & 2)) && (!clearBottomTmp || (REGs_PSC1[3] & 2)))); - if(fb->top_right != fb->top_left && clearTopTmp) + if(fbTmp->top_right != fbTmp->top_left && clearTopTmp) { - REGs_PSC0[0] = (u32)fb->top_right >> 3; //Start address - REGs_PSC0[1] = (u32)(fb->top_right + SCREEN_TOP_FBSIZE) >> 3; //End address + REGs_PSC0[0] = (u32)fbTmp->top_right >> 3; //Start address + REGs_PSC0[1] = (u32)(fbTmp->top_right + SCREEN_TOP_FBSIZE) >> 3; //End address REGs_PSC0[2] = 0; //Fill value REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start @@ -161,13 +182,14 @@ void clearScreens(bool clearTop, bool clearBottom) flushDCacheRange(&clearTopTmp, 1); flushDCacheRange(&clearBottomTmp, 1); - flushDCacheRange((void *)fb, sizeof(struct fb)); + flushDCacheRange((void *)fbTmp, sizeof(struct fb)); + flushDCacheRange(&fbTmp, 4); invokeArm11Function(ARM11); } void initScreens(void) { - void __attribute__((naked)) ARM11(void) + void __attribute__((naked)) initSequence(void) { //Disable interrupts __asm(".word 0xF10C01C0"); @@ -250,35 +272,51 @@ void initScreens(void) for(u32 i = 0; i < 256; i++) *(vu32 *)0x10400584 = 0x10101 * i; - *(vu32 *)0x10400468 = 0x18300000; - *(vu32 *)0x1040046c = 0x18300000; - *(vu32 *)0x10400494 = 0x18300000; - *(vu32 *)0x10400498 = 0x18300000; - *(vu32 *)0x10400568 = 0x18346500; - *(vu32 *)0x1040056c = 0x18346500; + WAIT_FOR_ARM9(); + } - //Set CakeBrah framebuffers - fb->top_left = (u8 *)0x18300000; - fb->top_right = (u8 *)0x18300000; - fb->bottom = (u8 *)0x18346500; + //Set CakeBrah framebuffers + void __attribute__((naked)) setupFramebuffers(void) + { + //Disable interrupts + __asm(".word 0xF10C01C0"); + + fbs[0].top_left = (u8 *)0x18300000; + fbs[1].top_left = (u8 *)0x18400000; + fbs[0].top_right = (u8 *)0x18300000; + fbs[1].top_right = (u8 *)0x18400000; + fbs[0].bottom = (u8 *)0x18346500; + fbs[1].bottom = (u8 *)0x18446500; + + *(vu32 *)0x10400468 = (u32)fbs[0].top_left; + *(vu32 *)0x1040046c = (u32)fbs[1].top_left; + *(vu32 *)0x10400494 = (u32)fbs[0].top_right; + *(vu32 *)0x10400498 = (u32)fbs[1].top_right; + *(vu32 *)0x10400568 = (u32)fbs[0].bottom; + *(vu32 *)0x1040056c = (u32)fbs[1].bottom; WAIT_FOR_ARM9(); } - if(PDN_GPU_CNT == 1) - { - flushDCacheRange(&configData, sizeof(CfgData)); - flushDCacheRange((void *)fb, sizeof(struct fb)); - invokeArm11Function(ARM11); + static bool needToSetup = true; - clearScreens(true, true); - - //Turn on backlight - i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); - } - else + if(needToSetup) { - clearScreens(true, true); - updateBrightness(MULTICONFIG(BRIGHTNESS)); + if(PDN_GPU_CNT == 1) + { + flushDCacheRange(&configData, sizeof(CfgData)); + invokeArm11Function(initSequence); + + //Turn on backlight + i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); + } + else updateBrightness(MULTICONFIG(BRIGHTNESS)); + + flushDCacheRange((void *)fbs, 2 * sizeof(struct fb)); + invokeArm11Function(setupFramebuffers); + needToSetup = false; } -} + + swapFramebuffers(false); + clearScreens(true, true, false); +} \ No newline at end of file diff --git a/source/screen.h b/source/screen.h index 9e78d62..d7e5818 100644 --- a/source/screen.h +++ b/source/screen.h @@ -34,13 +34,20 @@ #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)(); +#define SCREEN_TOP_WIDTH 400 +#define SCREEN_BOTTOM_WIDTH 320 +#define SCREEN_HEIGHT 240 +#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT) +#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT) + static volatile struct fb { u8 *top_left; u8 *top_right; u8 *bottom; -} *const fb = (volatile struct fb *)0x23FFFE00; +} *const fbs = (volatile struct fb *)0x23FFFE00; void deinitScreens(void); +void swapFramebuffers(bool isAlternate); void updateBrightness(u32 brightnessIndex); -void clearScreens(bool clearTop, bool clearBottom); +void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate); void initScreens(void); \ No newline at end of file diff --git a/source/utils.c b/source/utils.c index 3addfc8..017fc82 100644 --- a/source/utils.c +++ b/source/utils.c @@ -56,7 +56,7 @@ u32 waitInput(void) void mcuReboot(void) { - if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens(true, true); + if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens(true, true, false); //Ensure that all memory transfers have completed and that the data cache has been flushed flushEntireDCache(); @@ -67,7 +67,7 @@ void mcuReboot(void) void mcuPowerOff(void) { - if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens(true, true); + if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens(true, true, false); //Ensure that all memory transfers have completed and that the data cache has been flushed flushEntireDCache();