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:
parent
a5b52a2470
commit
7a3d15c48b
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
CakeHax
1
CakeHax
@ -1 +0,0 @@
|
||||
Subproject commit 5245c7b9dc232956a8578a36468f9024d8cf7001
|
29
Makefile
29
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
|
||||
|
116
diffs/1.diff
Normal file
116
diffs/1.diff
Normal 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();
|
@ -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;
|
@ -26,7 +26,8 @@ enum singleOptions
|
||||
{
|
||||
AUTOBOOTSYS = 0,
|
||||
USESYSFIRM,
|
||||
SDFIRMSANDMODULES,
|
||||
LOADSDFIRMSANDMODULES,
|
||||
USECUSTOMPATH,
|
||||
USELANGEMUANDCODE,
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
@ -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)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
@ -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);
|
@ -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++)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
29
source/pin.c
29
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
128
source/screen.c
128
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);
|
||||
}
|
@ -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);
|
@ -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();
|
||||
|
Reference in New Issue
Block a user