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"]
path = 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_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

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) {
+ svcSleepThread(2500 * 1000000ULL);
if (brahma_init()) {
if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1)
if (load_arm9_payload_offset() != 1)
goto error;

View File

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

View File

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

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",
"( ) 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

View File

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

View File

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

View File

@ -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);
void computePinHash(u8 *outbuf, const u8 *inbuf);
void restoreShaHashBackup(void);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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