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"]
|
[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
CakeHax
1
CakeHax
@ -1 +0,0 @@
|
|||||||
Subproject commit 5245c7b9dc232956a8578a36468f9024d8cf7001
|
|
29
Makefile
29
Makefile
@ -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
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) {
|
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;
|
@ -26,7 +26,8 @@ enum singleOptions
|
|||||||
{
|
{
|
||||||
AUTOBOOTSYS = 0,
|
AUTOBOOTSYS = 0,
|
||||||
USESYSFIRM,
|
USESYSFIRM,
|
||||||
SDFIRMSANDMODULES,
|
LOADSDFIRMSANDMODULES,
|
||||||
|
USECUSTOMPATH,
|
||||||
USELANGEMUANDCODE,
|
USELANGEMUANDCODE,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
@ -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:
|
||||||
|
@ -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",
|
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
|
||||||
|
@ -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,
|
||||||
|
@ -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));
|
||||||
|
}
|
@ -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);
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
29
source/pin.c
29
source/pin.c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
126
source/screen.c
126
source/screen.c
@ -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);
|
||||||
}
|
}
|
@ -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);
|
@ -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();
|
||||||
|
Reference in New Issue
Block a user