Got rid of CakeHax, patched CakeBrah to load arm9loaderhax.bin directly (lifting size restrictions in the process), got rid of the pathchanger (to have a custom path you can now enable the option and write it in a /luma/path.txt file, it must start with a / (this path is also picked up by the patched CakeBrah loader), fixed loading SafeA9LHInstaller and other payloads which need the OTP hash if having a PIN, fixed writing a file smaller than the existing one not removing the extra size, slightly changed the PIN format, added support for the alternate framebuffer and made the splash screen use it (it is now displayed all at once), fixed screen issues from CakeBrah

This commit is contained in:
Aurora 2016-09-22 14:48:28 +02:00
parent a5b52a2470
commit 7a3d15c48b
26 changed files with 318 additions and 283 deletions

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "CakeBrah"] [submodule "CakeBrah"]
path = CakeBrah path = CakeBrah
url = https://github.com/mid-kid/CakeBrah url = https://github.com/mid-kid/CakeBrah
[submodule "CakeHax"]
path = CakeHax
url = https://github.com/mid-kid/CakeHax

@ -1 +0,0 @@
Subproject commit 5245c7b9dc232956a8578a36468f9024d8cf7001

View File

@ -22,10 +22,8 @@ dir_injector := injector
dir_exceptions := exceptions dir_exceptions := exceptions
dir_arm9_exceptions := $(dir_exceptions)/arm9 dir_arm9_exceptions := $(dir_exceptions)/arm9
dir_arm11_exceptions := $(dir_exceptions)/arm11 dir_arm11_exceptions := $(dir_exceptions)/arm11
dir_mset := CakeHax
dir_ninjhax := CakeBrah dir_ninjhax := CakeBrah
dir_menuhax := menuhax dir_diffs := diffs
dir_pathchanger := pathchanger
dir_build := build dir_build := build
dir_out := out 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 $(dir_build)/k11modulespatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h
.PHONY: all .PHONY: all
all: launcher a9lh ninjhax menuhax all: a9lh ninjhax menuhax
.PHONY: launcher
launcher: $(dir_out)/$(name).dat
.PHONY: a9lh .PHONY: a9lh
a9lh: $(dir_out)/arm9loaderhax.bin a9lh: $(dir_out)/arm9loaderhax.bin
@ -61,7 +56,6 @@ release: $(dir_out)/$(name)$(revision).7z
.PHONY: clean .PHONY: clean
clean: clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_arm9_exceptions) clean @$(MAKE) -C $(dir_arm9_exceptions) clean
@ -72,30 +66,21 @@ clean:
$(dir_out): $(dir_out):
@mkdir -p "$(dir_out)" @mkdir -p "$(dir_out)"
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out) $(dir_out)/menuhax/boot.3dsx: $(dir_diffs) $(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)
@mkdir -p "$(@D)" @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 $@ @mv $(dir_out)/$(name).3dsx $@
@rm $(dir_out)/$(name).smdh @rm $(dir_out)/$(name).smdh
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out) $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -a $(dir_build)/main.bin $@ @cp -a $(dir_build)/main.bin $@
$(dir_out)/3ds/$(name): $(dir_out) $(dir_out)/3ds/$(name): $(dir_diffs) $(dir_out)
@mkdir -p "$@" @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 $@ @mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
$(dir_out)/pathchanger: $(dir_pathchanger)/pathchanger.py $(dir_pathchanger)/prebuilt $(dir_out) $(dir_out)/$(name)$(revision).7z: all
@mkdir -p "$@"
@cp $(dir_pathchanger)/pathchanger.py $@
@cp -rfT $(dir_pathchanger)/prebuilt $@
$(dir_out)/$(name)$(revision).7z: all $(dir_out)/pathchanger
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py @7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
$(dir_build)/main.bin: $(dir_build)/main.elf $(dir_build)/main.bin: $(dir_build)/main.elf

116
diffs/1.diff Normal file
View File

@ -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();

View File

@ -7,5 +7,5 @@ diff -uNr a/source/main.c b/source/main.c
int main (void) { int main (void) {
+ svcSleepThread(2500 * 1000000ULL); + svcSleepThread(2500 * 1000000ULL);
if (brahma_init()) { if (brahma_init()) {
if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1) if (load_arm9_payload_offset() != 1)
goto error; goto error;

View File

@ -26,7 +26,8 @@ enum singleOptions
{ {
AUTOBOOTSYS = 0, AUTOBOOTSYS = 0,
USESYSFIRM, USESYSFIRM,
SDFIRMSANDMODULES, LOADSDFIRMSANDMODULES,
USECUSTOMPATH,
USELANGEMUANDCODE, USELANGEMUANDCODE,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,

View File

@ -1,7 +1,7 @@
.arm.little .arm.little
payload_addr equ 0x23F00000 ; Brahma payload address. 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 .create "build/reboot.bin", 0
.arm .arm
@ -25,38 +25,22 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB
cmp r0, r2 cmp r0, r2
bne pxi_wait_recv bne pxi_wait_recv
mov r4, #0 ; Open file
adr r1, bin_fname add r0, r7, #8
b open_payload adr r1, fname
mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6
fallback: ; Read file
mov r4, #1 mov r0, r7
adr r1, dat_fname adr r1, bytes_read
ldr r2, =payload_addr
open_payload: mov r3, payload_maxsize
; Open file ldr r6, [r7]
add r0, r7, #8 ldr r6, [r6, #0x28]
mov r2, #1 blx r6
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.
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload ; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
add r0, r8, 0x1A add r0, r8, 0x1A
@ -87,10 +71,8 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB
bytes_read: .word 0 bytes_read: .word 0
fopen: .ascii "OPEN" fopen: .ascii "OPEN"
.pool .pool
bin_fname: .dcw "sdmc:/arm9loaderhax.bin" fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dat_fname: .dcw "sdmc:/Luma3DS.dat"
.word 0
.align 4 .align 4
kernelcode_start: kernelcode_start:

View File

@ -1,97 +0,0 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 <Luma3DS payload path>\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);
}

View File

@ -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)

View File

@ -77,6 +77,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
const char *singleOptionsText[] = { "( ) Autoboot SysNAND", const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) Use SysNAND FIRM if booting with R (A9LH)", "( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Enable FIRMs and modules loading from SD", "( ) Enable FIRMs and modules loading from SD",
"( ) Use custom path",
"( ) Enable region/language emu. and ext. .code", "( ) Enable region/language emu. and ext. .code",
"( ) Show NAND or user string in System Settings", "( ) Show NAND or user string in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) 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" "system modules from the SD card.\n\n"
"This isn't needed in most cases.", "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" "Enable overriding the region and\n"
"language configuration and the usage\n" "language configuration and the usage\n"
"of patched code binaries for specific\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); 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); drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
} }
else else

View File

@ -30,7 +30,7 @@
#define CONFIG_PATH "/luma/config.bin" #define CONFIG_PATH "/luma/config.bin"
#define CONFIG_VERSIONMAJOR 1 #define CONFIG_VERSIONMAJOR 1
#define CONFIG_VERSIONMINOR 5 #define CONFIG_VERSIONMINOR 6
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
@ -52,7 +52,8 @@ enum singleOptions
{ {
AUTOBOOTSYS = 0, AUTOBOOTSYS = 0,
USESYSFIRM, USESYSFIRM,
SDFIRMSANDMODULES, LOADSDFIRMSANDMODULES,
USECUSTOMPATH,
USELANGEMUANDCODE, USELANGEMUANDCODE,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,

View File

@ -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 __attribute__((aligned(4))) nandCtr[AES_BLOCK_SIZE];
static u8 nandSlot; static u8 nandSlot;
static u32 fatStart; static u32 fatStart;
static bool didShaHashBackup = false;
static u8 __attribute__((aligned(4))) shaHashBackup[SHA_256_HASH_SIZE];
void ctrNandInit(void) 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))) cid[AES_BLOCK_SIZE];
u8 __attribute__((aligned(4))) cipherText[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); sdmmc_get_cid(1, (u32 *)cid);
aes_use_keyslot(4); //Console-unique keyslot whose keys are set by the ARM9 bootROM 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); aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE); sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE);
} }
void restoreShaHashBackup(void)
{
if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup));
}

View File

@ -112,3 +112,4 @@ void decryptExeFs(u8 *inbuf);
void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize); void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize);
void kernel9Loader(u8 *arm9Section); void kernel9Loader(u8 *arm9Section);
void computePinHash(u8 *outbuf, const u8 *inbuf); void computePinHash(u8 *outbuf, const u8 *inbuf);
void restoreShaHashBackup(void);

View File

@ -45,9 +45,12 @@ bool loadSplash(void)
return false; return false;
initScreens(); initScreens();
clearScreens(true, true, true);
if(isTopSplashValid) fileRead(fb->top_left, topSplashPath, 0); if(isTopSplashValid) fileRead(fbs[1].top_left, topSplashPath, 0);
if(isBottomSplashValid) fileRead(fb->bottom, bottomSplashPath, 0); if(isBottomSplashValid) fileRead(fbs[1].bottom, bottomSplashPath, 0);
swapFramebuffers(true);
chrono(3); chrono(3);
@ -56,7 +59,7 @@ bool loadSplash(void)
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color) 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++) for(u32 y = 0; y < 8; y++)
{ {

View File

@ -29,12 +29,6 @@
#include "types.h" #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_Y 10
#define SPACING_X 8 #define SPACING_X 8

View File

@ -247,7 +247,7 @@ void main(void)
writeConfig(needConfig, configTemp); writeConfig(needConfig, configTemp);
} }
bool loadFromSd = CONFIG(SDFIRMSANDMODULES); bool loadFromSd = CONFIG(LOADSDFIRMSANDMODULES);
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromSd); u32 firmVersion = loadFirm(&firmType, firmSource, loadFromSd);
switch(firmType) switch(firmType)
@ -316,7 +316,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo
{ {
u8 cetk[0xA50]; 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); decryptNusFirm(cetk, (u8 *)firm, firmSize);
} }

View File

@ -23,6 +23,7 @@
#include "fs.h" #include "fs.h"
#include "memory.h" #include "memory.h"
#include "strings.h" #include "strings.h"
#include "crypto.h"
#include "cache.h" #include "cache.h"
#include "screen.h" #include "screen.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
@ -70,6 +71,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
{ {
unsigned int written; unsigned int written;
f_write(&file, buffer, size, &written); f_write(&file, buffer, size, &written);
f_truncate(&file);
f_close(&file); f_close(&file);
return true; return true;
@ -137,6 +139,7 @@ void loadPayload(u32 pressed)
{ {
loaderAddress[1] = payloadSize; loaderAddress[1] = payloadSize;
restoreShaHashBackup();
initScreens(); initScreens();
flushDCacheRange(loaderAddress, loader_size); flushDCacheRange(loaderAddress, loader_size);

View File

@ -25,6 +25,7 @@
*/ */
#include "patches.h" #include "patches.h"
#include "fs.h"
#include "memory.h" #include "memory.h"
#include "config.h" #include "config.h"
#include "../build/rebootpatch.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 //Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_size, 4); u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset; *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) void patchFirmWrites(u8 *pos, u32 size)

View File

@ -46,7 +46,7 @@ static char pinKeyToLetter(u32 pressed)
void newPin(bool allowSkipping, u32 pinMode) void newPin(bool allowSkipping, u32 pinMode)
{ {
clearScreens(true, true); clearScreens(true, true, false);
u8 length = 4 + 2 * (pinMode - 1); u8 length = 4 + 2 * (pinMode - 1);
@ -89,13 +89,13 @@ void newPin(bool allowSkipping, u32 pinMode)
memcpy(pin.magic, "PINF", 4); memcpy(pin.magic, "PINF", 4);
pin.formatVersionMajor = PIN_VERSIONMAJOR; pin.formatVersionMajor = PIN_VERSIONMAJOR;
pin.formatVersionMinor = PIN_VERSIONMINOR; pin.formatVersionMinor = PIN_VERSIONMINOR;
pin.length = length;
u8 __attribute__((aligned(4))) tmp[SHA_256_HASH_SIZE]; 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); computePinHash(tmp, lengthBlock);
memcpy(pin.testHash, tmp, sizeof(tmp)); memcpy(pin.lengthHash, tmp, sizeof(tmp));
computePinHash(tmp, enteredPassword); computePinHash(tmp, enteredPassword);
memcpy(pin.hash, tmp, sizeof(tmp)); memcpy(pin.hash, tmp, sizeof(tmp));
@ -111,17 +111,17 @@ bool verifyPin(u32 pinMode)
if(fileRead(&pin, PIN_PATH, sizeof(PinData)) != sizeof(PinData) || if(fileRead(&pin, PIN_PATH, sizeof(PinData)) != sizeof(PinData) ||
memcmp(pin.magic, "PINF", 4) != 0 || memcmp(pin.magic, "PINF", 4) != 0 ||
pin.formatVersionMajor != PIN_VERSIONMAJOR || pin.formatVersionMajor != PIN_VERSIONMAJOR ||
pin.formatVersionMinor != PIN_VERSIONMINOR || pin.formatVersionMinor != PIN_VERSIONMINOR)
pin.length != 4 + 2 * (pinMode - 1))
return false; return false;
u8 __attribute__((aligned(4))) zeroes[AES_BLOCK_SIZE] = {0};
u8 __attribute__((aligned(4))) tmp[SHA_256_HASH_SIZE]; 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) //Test vector verification (check if SD card has been used on another console or PIN length changed)
if(memcmp(pin.testHash, tmp, sizeof(tmp)) != 0) return false; if(memcmp(pin.lengthHash, tmp, sizeof(tmp)) != 0) return false;
initScreens(); initScreens();
@ -135,6 +135,7 @@ bool verifyPin(u32 pinMode)
const char messagePath[] = "/luma/pinmessage.txt"; const char messagePath[] = "/luma/pinmessage.txt";
u32 messageSize = getFileSize(messagePath); u32 messageSize = getFileSize(messagePath);
if(messageSize > 0 && messageSize <= 800) if(messageSize > 0 && messageSize <= 800)
{ {
char message[messageSize + 1]; 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("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); 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; u32 pressed;
do do
@ -169,7 +170,7 @@ bool verifyPin(u32 pinMode)
drawCharacter(key, true, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE); drawCharacter(key, true, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
charDrawPos += 2 * SPACING_X; charDrawPos += 2 * SPACING_X;
if(cnt >= pin.length) if(cnt >= lengthBlock[0])
{ {
computePinHash(tmp, enteredPassword); computePinHash(tmp, enteredPassword);
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0; unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
@ -179,7 +180,7 @@ bool verifyPin(u32 pinMode)
charDrawPos = 16 * SPACING_X; charDrawPos = 16 * SPACING_X;
cnt = 0; cnt = 0;
clearScreens(true, false); clearScreens(true, false, false);
drawString("Wrong PIN, try again", true, 10, 10 + 4 * SPACING_Y, COLOR_RED); drawString("Wrong PIN, try again", true, 10, 10 + 4 * SPACING_Y, COLOR_RED);
} }

View File

@ -30,15 +30,14 @@
#define PIN_PATH "/luma/pin.bin" #define PIN_PATH "/luma/pin.bin"
#define PIN_VERSIONMAJOR 1 #define PIN_VERSIONMAJOR 1
#define PIN_VERSIONMINOR 2 #define PIN_VERSIONMINOR 3
typedef struct __attribute__((packed)) typedef struct __attribute__((packed))
{ {
char magic[4]; char magic[4];
u16 formatVersionMajor, formatVersionMinor; u16 formatVersionMajor, formatVersionMinor;
u8 length; u8 lengthHash[32];
u8 testHash[32];
u8 hash[32]; u8 hash[32];
} PinData; } PinData;

View File

@ -25,11 +25,20 @@
* Screen deinit code by tiniVi * 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 "screen.h"
#include "config.h" #include "config.h"
#include "memory.h" #include "memory.h"
#include "cache.h" #include "cache.h"
#include "draw.h"
#include "i2c.h" #include "i2c.h"
vu32 *const arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY; vu32 *const arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
@ -47,16 +56,6 @@ void __attribute__((naked)) arm11Stub(void)
((void (*)())*arm11Entry)(); ((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)()) static void invokeArm11Function(void (*func)())
{ {
static bool hasCopiedStub = false; static bool hasCopiedStub = false;
@ -111,12 +110,34 @@ void updateBrightness(u32 brightnessIndex)
invokeArm11Function(ARM11); 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, static bool clearTopTmp,
clearBottomTmp; clearBottomTmp;
static volatile struct fb *fbTmp;
clearTopTmp = clearTop; clearTopTmp = clearTop;
clearBottomTmp = clearBottom; clearBottomTmp = clearBottom;
fbTmp = clearAlternate ? &fbs[1] : &fbs[0];
void __attribute__((naked)) ARM11(void) void __attribute__((naked)) ARM11(void)
{ {
@ -130,26 +151,26 @@ void clearScreens(bool clearTop, bool clearBottom)
if(clearTopTmp) if(clearTopTmp)
{ {
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address REGs_PSC0[0] = (u32)fbTmp->top_left >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address REGs_PSC0[1] = (u32)(fbTmp->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
} }
if(clearBottomTmp) if(clearBottomTmp)
{ {
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address REGs_PSC1[0] = (u32)fbTmp->bottom >> 3; //Start address
REGs_PSC1[1] = (u32)(fb->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address REGs_PSC1[1] = (u32)(fbTmp->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
REGs_PSC1[2] = 0; //Fill value REGs_PSC1[2] = 0; //Fill value
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
} }
while(!((!clearTopTmp || (REGs_PSC0[3] & 2)) && (!clearBottomTmp || (REGs_PSC1[3] & 2)))); 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[0] = (u32)fbTmp->top_right >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_right + SCREEN_TOP_FBSIZE) >> 3; //End address REGs_PSC0[1] = (u32)(fbTmp->top_right + SCREEN_TOP_FBSIZE) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
@ -161,13 +182,14 @@ void clearScreens(bool clearTop, bool clearBottom)
flushDCacheRange(&clearTopTmp, 1); flushDCacheRange(&clearTopTmp, 1);
flushDCacheRange(&clearBottomTmp, 1); flushDCacheRange(&clearBottomTmp, 1);
flushDCacheRange((void *)fb, sizeof(struct fb)); flushDCacheRange((void *)fbTmp, sizeof(struct fb));
flushDCacheRange(&fbTmp, 4);
invokeArm11Function(ARM11); invokeArm11Function(ARM11);
} }
void initScreens(void) void initScreens(void)
{ {
void __attribute__((naked)) ARM11(void) void __attribute__((naked)) initSequence(void)
{ {
//Disable interrupts //Disable interrupts
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
@ -250,35 +272,51 @@ void initScreens(void)
for(u32 i = 0; i < 256; i++) for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i; *(vu32 *)0x10400584 = 0x10101 * i;
*(vu32 *)0x10400468 = 0x18300000; WAIT_FOR_ARM9();
*(vu32 *)0x1040046c = 0x18300000; }
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;
//Set CakeBrah framebuffers //Set CakeBrah framebuffers
fb->top_left = (u8 *)0x18300000; void __attribute__((naked)) setupFramebuffers(void)
fb->top_right = (u8 *)0x18300000; {
fb->bottom = (u8 *)0x18346500; //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(); WAIT_FOR_ARM9();
} }
if(PDN_GPU_CNT == 1) static bool needToSetup = true;
{
flushDCacheRange(&configData, sizeof(CfgData));
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
clearScreens(true, true); if(needToSetup)
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
else
{ {
clearScreens(true, true); if(PDN_GPU_CNT == 1)
updateBrightness(MULTICONFIG(BRIGHTNESS)); {
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);
} }

View File

@ -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 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 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 { static volatile struct fb {
u8 *top_left; u8 *top_left;
u8 *top_right; u8 *top_right;
u8 *bottom; u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00; } *const fbs = (volatile struct fb *)0x23FFFE00;
void deinitScreens(void); void deinitScreens(void);
void swapFramebuffers(bool isAlternate);
void updateBrightness(u32 brightnessIndex); void updateBrightness(u32 brightnessIndex);
void clearScreens(bool clearTop, bool clearBottom); void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate);
void initScreens(void); void initScreens(void);

View File

@ -56,7 +56,7 @@ u32 waitInput(void)
void mcuReboot(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 //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireDCache(); flushEntireDCache();
@ -67,7 +67,7 @@ void mcuReboot(void)
void mcuPowerOff(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 //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireDCache(); flushEntireDCache();