Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c711ed6253 | ||
|
|
356268eae5 | ||
|
|
2dd64b8a92 | ||
|
|
b5cddedb7d | ||
|
|
7afdc2b3b5 | ||
|
|
60c4956290 | ||
|
|
7331a919e4 | ||
|
|
33238cee54 | ||
|
|
384dd2ad81 | ||
|
|
74ac76ba84 | ||
|
|
253e031f83 | ||
|
|
ef1ecf859c | ||
|
|
a302ad3bea | ||
|
|
b87dadbb72 | ||
|
|
50a2424001 |
15
Makefile
15
Makefile
@@ -13,6 +13,7 @@ OC := arm-none-eabi-objcopy
|
|||||||
|
|
||||||
name := Luma3DS
|
name := Luma3DS
|
||||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||||
|
commit := $(shell git rev-parse --short=8 HEAD)
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_patches := patches
|
dir_patches := patches
|
||||||
@@ -32,7 +33,8 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/injector.h $(dir_build)/loader.h
|
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/twl_k11modulespatch.h \
|
||||||
|
$(dir_build)/injector.h $(dir_build)/loader.h
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: launcher a9lh ninjhax
|
all: launcher a9lh ninjhax
|
||||||
@@ -91,6 +93,16 @@ $(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s
|
|||||||
@armips $<
|
@armips $<
|
||||||
@bin2c -o $@ -n reboot $(@D)/reboot.bin
|
@bin2c -o $@ -n reboot $(@D)/reboot.bin
|
||||||
|
|
||||||
|
$(dir_build)/svcGetCFWInfopatch.h: $(dir_patches)/svcGetCFWInfo.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@armips $<
|
||||||
|
@bin2c -o $@ -n svcGetCFWInfo $(@D)/svcGetCFWInfo.bin
|
||||||
|
|
||||||
|
$(dir_build)/twl_k11modulespatch.h: $(dir_patches)/twl_k11modules.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@armips $<
|
||||||
|
@bin2c -o $@ -n twl_k11modules $(@D)/twl_k11modules.bin
|
||||||
|
|
||||||
$(dir_build)/injector.h: $(dir_injector)/Makefile
|
$(dir_build)/injector.h: $(dir_injector)/Makefile
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@$(MAKE) -C $(dir_injector)
|
@$(MAKE) -C $(dir_injector)
|
||||||
@@ -102,6 +114,7 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
|
|||||||
|
|
||||||
$(dir_build)/memory.o: CFLAGS += -O3
|
$(dir_build)/memory.o: CFLAGS += -O3
|
||||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||||
|
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
|
|||||||
@@ -3,12 +3,7 @@
|
|||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
static CFWInfo info = {0};
|
||||||
#define PATH_MAX 255
|
|
||||||
#define CONFIG(a) (((loadConfig() >> (a + 16)) & 1) != 0)
|
|
||||||
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
|
|
||||||
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||||
{
|
{
|
||||||
@@ -90,6 +85,28 @@ static int fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int f
|
|||||||
return IFile_Open(file, archiveId, archivePath, filePath, flags);
|
return IFile_Open(file, archiveId, archivePath, filePath, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __attribute__((naked)) svcGetCFWInfo(CFWInfo __attribute__((unused)) *out)
|
||||||
|
{
|
||||||
|
__asm__ volatile("svc 0x2E; bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadCFWInfo(void)
|
||||||
|
{
|
||||||
|
static bool infoLoaded = false;
|
||||||
|
|
||||||
|
if(!infoLoaded)
|
||||||
|
{
|
||||||
|
svcGetCFWInfo(&info);
|
||||||
|
IFile file;
|
||||||
|
if(BOOTCONFIG(5, 1) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
|
||||||
|
{
|
||||||
|
IFile_Close(&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
infoLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool secureInfoExists(void)
|
static bool secureInfoExists(void)
|
||||||
{
|
{
|
||||||
static bool exists = false;
|
static bool exists = false;
|
||||||
@@ -107,24 +124,6 @@ static bool secureInfoExists(void)
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 loadConfig(void)
|
|
||||||
{
|
|
||||||
static u32 config = 0;
|
|
||||||
|
|
||||||
if(!config)
|
|
||||||
{
|
|
||||||
IFile file;
|
|
||||||
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ)))
|
|
||||||
{
|
|
||||||
u64 total;
|
|
||||||
if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4;
|
|
||||||
IFile_Close(&file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void progIdToStr(char *strEnd, u64 progId)
|
static void progIdToStr(char *strEnd, u64 progId)
|
||||||
{
|
{
|
||||||
while(progId)
|
while(progId)
|
||||||
@@ -319,6 +318,8 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
|
|||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size)
|
void patchCode(u64 progId, u8 *code, u32 size)
|
||||||
{
|
{
|
||||||
|
loadCFWInfo();
|
||||||
|
|
||||||
switch(progId)
|
switch(progId)
|
||||||
{
|
{
|
||||||
case 0x0004003000008F02LL: // USA Menu
|
case 0x0004003000008F02LL: // USA Menu
|
||||||
|
|||||||
@@ -2,4 +2,24 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
#define PATH_MAX 255
|
||||||
|
|
||||||
|
#define CONFIG(a) (((info.config >> (a + 16)) & 1) != 0)
|
||||||
|
#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
u8 versionMajor;
|
||||||
|
u8 versionMinor;
|
||||||
|
u8 versionBuild;
|
||||||
|
u8 flags; /* bit 0: dev branch; bit 1: is release */
|
||||||
|
|
||||||
|
u32 commitHash;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CFWInfo;
|
||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size);
|
void patchCode(u64 progId, u8 *code, u32 size);
|
||||||
48
patches/svcGetCFWInfo.s
Normal file
48
patches/svcGetCFWInfo.s
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
;
|
||||||
|
; This file is part of Luma3DS
|
||||||
|
; Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
;
|
||||||
|
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
; Notices displayed by works containing it.
|
||||||
|
;
|
||||||
|
|
||||||
|
.arm.little
|
||||||
|
|
||||||
|
.create "build/svcGetCFWInfo.bin", 0
|
||||||
|
|
||||||
|
.arm
|
||||||
|
|
||||||
|
adr r1, infoStart
|
||||||
|
add r2, r0, #(infoEnd - infoStart)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
ldrb r3, [r1], #1
|
||||||
|
strbt r3, [r0], #1
|
||||||
|
cmp r0, r2
|
||||||
|
blo loop
|
||||||
|
|
||||||
|
mov r0, #0
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.pool
|
||||||
|
infoStart:
|
||||||
|
.ascii "LUMA" ; magic
|
||||||
|
.word 0 ; version
|
||||||
|
.word 0 ; truncated commit hash
|
||||||
|
.word 0 ; config
|
||||||
|
infoEnd:
|
||||||
|
.close
|
||||||
144
patches/twl_k11modules.s
Normal file
144
patches/twl_k11modules.s
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
;
|
||||||
|
; This file is part of Luma3DS
|
||||||
|
; Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
;
|
||||||
|
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
; Notices displayed by works containing it.
|
||||||
|
;
|
||||||
|
|
||||||
|
.arm.little
|
||||||
|
|
||||||
|
.create "build/twl_k11modules.bin", 0
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.arm
|
||||||
|
|
||||||
|
patch:
|
||||||
|
; r4: Pointer to a pointer to the exheader of the current NCCH
|
||||||
|
; sp + 0xb0 - 0xa4: Pointer to the memory location where the NCCH text was loaded
|
||||||
|
|
||||||
|
add r3, sp, #(0xb0 - 0xa4)
|
||||||
|
add r1, sp, #(0xb0 - 0xac)
|
||||||
|
|
||||||
|
push {r0-r11, lr}
|
||||||
|
|
||||||
|
ldr r9, [r3] ; load the address of the code section
|
||||||
|
ldr r8, [r4] ; load the address of the exheader
|
||||||
|
|
||||||
|
ldr r7, [r8, #0x200] ; low titleID
|
||||||
|
ldr r6, =#0x000001ff
|
||||||
|
cmp r7, r6
|
||||||
|
bne end
|
||||||
|
|
||||||
|
ldr r7, =#0xabcdabcd ; offset of the dev launcher (will be replaced later)
|
||||||
|
add r7, r9
|
||||||
|
|
||||||
|
adr r5, patchesStart
|
||||||
|
add r6, r5, #(patchesEnd - patchesStart)
|
||||||
|
|
||||||
|
patchLoop:
|
||||||
|
ldrh r0, [r5, #4]
|
||||||
|
cmp r0, #0
|
||||||
|
moveq r4, r9
|
||||||
|
movne r4, r7
|
||||||
|
|
||||||
|
ldrh r2, [r5, #6]
|
||||||
|
add r1, r5, #8
|
||||||
|
ldr r0, [r5]
|
||||||
|
add r0, r4
|
||||||
|
blx memcmp
|
||||||
|
cmp r0, #0
|
||||||
|
bne skipPatch
|
||||||
|
|
||||||
|
ldrh r2, [r5, #6]
|
||||||
|
add r1, r5, #0x08
|
||||||
|
add r1, r2
|
||||||
|
ldr r0, [r5]
|
||||||
|
add r0, r4
|
||||||
|
blx memcpy
|
||||||
|
|
||||||
|
skipPatch:
|
||||||
|
|
||||||
|
ldrh r0, [r5, #6]
|
||||||
|
add r5, r5, #0x08
|
||||||
|
add r5, r0,lsl#1
|
||||||
|
cmp r5, r6
|
||||||
|
blo patchLoop
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
pop {r0-r11, pc}
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
memcmp:
|
||||||
|
push {r4-r7, lr}
|
||||||
|
mov r4, #0
|
||||||
|
cmp_loop:
|
||||||
|
cmp r4, r2
|
||||||
|
bhs cmp_loop_end
|
||||||
|
ldrb r6, [r0, r4]
|
||||||
|
ldrb r7, [r1, r4]
|
||||||
|
add r4, #1
|
||||||
|
sub r6, r7
|
||||||
|
cmp r6, #0
|
||||||
|
beq cmp_loop
|
||||||
|
|
||||||
|
cmp_loop_end:
|
||||||
|
mov r0, r6
|
||||||
|
pop {r4-r7, pc}
|
||||||
|
|
||||||
|
memcpy:
|
||||||
|
push {r4-r5, lr}
|
||||||
|
mov r4, #0
|
||||||
|
|
||||||
|
copy_loop:
|
||||||
|
cmp r4, r2
|
||||||
|
bhs copy_loop_end
|
||||||
|
ldrb r5, [r1, r4]
|
||||||
|
strb r5, [r0, r4]
|
||||||
|
add r4, #1
|
||||||
|
b copy_loop
|
||||||
|
|
||||||
|
copy_loop_end:
|
||||||
|
pop {r4-r5, pc}
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
; Available space for patches: 152 bytes on N3DS, 666 on O3DS
|
||||||
|
|
||||||
|
patchesStart:
|
||||||
|
; SCFG_EXT bit31 patches, based on https://github.com/ahezard/twl_firm_patcher (credits where they're due)
|
||||||
|
|
||||||
|
.word 0x07368 ; offset
|
||||||
|
.halfword 1 ; type (0: relative to the start of TwlBg's code; 1: relative to the start of the dev SRL launcher)
|
||||||
|
.halfword 4 ; size (must be a multiple of 4)
|
||||||
|
.byte 0x94, 0x09, 0xfc, 0xed ; expected data (decrypted = 0x08, 0x60, 0x87, 0x05)
|
||||||
|
.byte 0x24, 0x09, 0xbc, 0xe9 ; patched data (decrypted = 0xb8, 0x60, 0xc7, 0x01)
|
||||||
|
|
||||||
|
.word 0xa5888
|
||||||
|
.halfword 1
|
||||||
|
.halfword 8
|
||||||
|
.byte 0x83, 0x30, 0x2e, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x01, 0x1a, 0xe3, 0x08, 0x60, 0x87, 0x05)
|
||||||
|
.byte 0x83, 0x50, 0xf2, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x61, 0xc6, 0xe3, 0x08, 0x60, 0x87, 0xe5)
|
||||||
|
|
||||||
|
patchesEnd:
|
||||||
|
|
||||||
|
.pool
|
||||||
|
|
||||||
|
.close
|
||||||
@@ -24,10 +24,9 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
|
||||||
void configureCFW(const char *configPath)
|
void configureCFW(void)
|
||||||
{
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
@@ -44,7 +43,8 @@ void configureCFW(const char *configPath)
|
|||||||
"( ) Show current NAND in System Settings",
|
"( ) Show current NAND in System Settings",
|
||||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
"( ) Display splash screen before payloads",
|
"( ) Display splash screen before payloads",
|
||||||
"( ) Use a PIN" };
|
"( ) Use a PIN",
|
||||||
|
"( ) Enable experimental TwlBg patches" };
|
||||||
|
|
||||||
struct multiOption {
|
struct multiOption {
|
||||||
int posXs[4];
|
int posXs[4];
|
||||||
@@ -193,13 +193,6 @@ void configureCFW(const char *configPath)
|
|||||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
|
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
|
||||||
|
|
||||||
if(!fileWrite(&config, configPath, 4))
|
|
||||||
{
|
|
||||||
createDirectory("luma");
|
|
||||||
if(!fileWrite(&config, configPath, 4))
|
|
||||||
error("Error writing the configuration file");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Wait for the pressed buttons to change
|
//Wait for the pressed buttons to change
|
||||||
while(HID_PAD == BUTTON_START);
|
while(HID_PAD == BUTTON_START);
|
||||||
}
|
}
|
||||||
@@ -30,4 +30,4 @@
|
|||||||
|
|
||||||
extern u32 config;
|
extern u32 config;
|
||||||
|
|
||||||
void configureCFW(const char *configPath);
|
void configureCFW(void);
|
||||||
@@ -43,7 +43,7 @@ static inline int strlen(const char *string)
|
|||||||
bool loadSplash(void)
|
bool loadSplash(void)
|
||||||
{
|
{
|
||||||
//Don't delay boot nor init the screens if no splash image is on the SD
|
//Don't delay boot nor init the screens if no splash image is on the SD
|
||||||
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splash.bin") == 0)
|
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splashbottom.bin") == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|||||||
@@ -43,16 +43,17 @@ static const firmSectionHeader *section;
|
|||||||
u32 config,
|
u32 config,
|
||||||
emuOffset;
|
emuOffset;
|
||||||
|
|
||||||
bool isN3DS, isDevUnit;
|
bool isN3DS,
|
||||||
|
isDevUnit,
|
||||||
|
isFirmlaunch;
|
||||||
|
|
||||||
FirmwareSource firmSource;
|
FirmwareSource firmSource;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
bool isFirmlaunch,
|
bool isA9lh;
|
||||||
isA9lh;
|
|
||||||
|
|
||||||
u32 newConfig,
|
u32 configTemp,
|
||||||
emuHeader;
|
emuHeader;
|
||||||
|
|
||||||
FirmwareType firmType;
|
FirmwareType firmType;
|
||||||
@@ -101,7 +102,8 @@ void main(void)
|
|||||||
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
||||||
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
|
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
|
||||||
|
|
||||||
newConfig = (u32)isA9lh << 3;
|
//Save old options and begin saving the new boot configuration
|
||||||
|
configTemp = (config & 0xFFFFFFC0) | ((u32)isA9lh << 3);
|
||||||
|
|
||||||
//If it's a MCU reboot, try to force boot options
|
//If it's a MCU reboot, try to force boot options
|
||||||
if(isA9lh && CFG_BOOTENV)
|
if(isA9lh && CFG_BOOTENV)
|
||||||
@@ -114,7 +116,7 @@ void main(void)
|
|||||||
needConfig = DONT_CONFIGURE;
|
needConfig = DONT_CONFIGURE;
|
||||||
|
|
||||||
//Flag to prevent multiple boot options-forcing
|
//Flag to prevent multiple boot options-forcing
|
||||||
newConfig |= 1 << 4;
|
configTemp |= 1 << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Else, force the last used boot options unless a button is pressed
|
/* Else, force the last used boot options unless a button is pressed
|
||||||
@@ -142,7 +144,7 @@ void main(void)
|
|||||||
|
|
||||||
if(shouldLoadConfigurationMenu)
|
if(shouldLoadConfigurationMenu)
|
||||||
{
|
{
|
||||||
configureCFW(configPath);
|
configureCFW();
|
||||||
|
|
||||||
if(!pinExists && CONFIG(7)) newPin();
|
if(!pinExists && CONFIG(7)) newPin();
|
||||||
|
|
||||||
@@ -156,6 +158,9 @@ void main(void)
|
|||||||
{
|
{
|
||||||
nandType = FIRMWARE_SYSNAND;
|
nandType = FIRMWARE_SYSNAND;
|
||||||
firmSource = FIRMWARE_SYSNAND;
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
|
|
||||||
|
//Flag to tell loader to init SD
|
||||||
|
configTemp |= 1 << 5;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -204,17 +209,21 @@ void main(void)
|
|||||||
|
|
||||||
if(!isFirmlaunch)
|
if(!isFirmlaunch)
|
||||||
{
|
{
|
||||||
newConfig |= (u32)nandType | ((u32)firmSource << 2);
|
configTemp |= (u32)nandType | ((u32)firmSource << 2);
|
||||||
|
|
||||||
/* If the boot configuration is different from previously, overwrite it.
|
/* If the configuration is different from previously, overwrite it.
|
||||||
Just the no-forcing flag being set is not enough */
|
Just the no-forcing flag being set is not enough */
|
||||||
if((newConfig & 0x2F) != (config & 0x3F))
|
if((configTemp & 0xFFFFFFEF) != config)
|
||||||
{
|
{
|
||||||
//Preserve user settings (last 26 bits)
|
//Merge the new options and new boot configuration
|
||||||
newConfig |= config & 0xFFFFFFC0;
|
config = (config & 0xFFFFFFC0) | (configTemp & 0x3F);
|
||||||
|
|
||||||
if(!fileWrite(&newConfig, configPath, 4))
|
if(!fileWrite(&config, configPath, 4))
|
||||||
error("Error writing the configuration file");
|
{
|
||||||
|
createDirectory("luma");
|
||||||
|
if(!fileWrite(&config, configPath, 4))
|
||||||
|
error("Error writing the configuration file");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +243,7 @@ void main(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
launchFirm(firmType, isFirmlaunch);
|
launchFirm(firmType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 loadFirm(FirmwareType firmType)
|
static inline u32 loadFirm(FirmwareType firmType)
|
||||||
@@ -246,6 +255,11 @@ static inline u32 loadFirm(FirmwareType firmType)
|
|||||||
|
|
||||||
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
|
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
|
||||||
{
|
{
|
||||||
|
//We can't boot < 3.x NANDs
|
||||||
|
if(firmVersion < 0x18)
|
||||||
|
error("An old unsupported NAND has been detected.\nLuma3DS is unable to boot it.");
|
||||||
|
|
||||||
|
//We can't boot a 4.x NATIVE_FIRM, load one from SD
|
||||||
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
|
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
|
||||||
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
|
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
|
||||||
|
|
||||||
@@ -260,6 +274,7 @@ static inline u32 loadFirm(FirmwareType firmType)
|
|||||||
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
|
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
|
||||||
{
|
{
|
||||||
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
||||||
|
u8 *arm11Section1 = (u8 *)firm + section[1].offset;
|
||||||
|
|
||||||
if(isN3DS)
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
@@ -299,8 +314,10 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
|
|||||||
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
||||||
|
|
||||||
//Restore svcBackdoor
|
//Restore svcBackdoor
|
||||||
reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size);
|
reimplementSvcBackdoor(arm11Section1, section[1].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implementSvcGetCFWInfo(arm11Section1, section[1].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchLegacyFirm(FirmwareType firmType)
|
static inline void patchLegacyFirm(FirmwareType firmType)
|
||||||
@@ -313,6 +330,9 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyLegacyFirmPatches((u8 *)firm, firmType);
|
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||||
|
|
||||||
|
if(firmType == TWL_FIRM && CONFIG(8))
|
||||||
|
patchTwlBg((u8 *)firm + section[1].offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchSafeFirm(void)
|
static inline void patchSafeFirm(void)
|
||||||
@@ -330,25 +350,44 @@ static inline void patchSafeFirm(void)
|
|||||||
else patchFirmWriteSafe(arm9Section, section[2].size);
|
else patchFirmWriteSafe(arm9Section, section[2].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void copySection0AndInjectLoader(void)
|
static inline void copySection0AndInjectSystemModules(void)
|
||||||
{
|
{
|
||||||
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
||||||
|
|
||||||
u32 loaderSize;
|
struct
|
||||||
u32 loaderOffset = getLoader(arm11Section0, &loaderSize);
|
{
|
||||||
|
u32 size;
|
||||||
|
const u8 *addr;
|
||||||
|
} modules[5];
|
||||||
|
|
||||||
memcpy(section[0].address, arm11Section0, loaderOffset);
|
u32 n = 0,
|
||||||
memcpy(section[0].address + loaderOffset, injector, injector_size);
|
loaderIndex;
|
||||||
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize));
|
u8 *pos = arm11Section0;
|
||||||
|
|
||||||
|
for(u8 *end = pos + section[0].size; pos < end; pos += modules[n++].size)
|
||||||
|
{
|
||||||
|
modules[n].addr = pos;
|
||||||
|
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
||||||
|
|
||||||
|
if(memcmp(modules[n].addr + 0x200, "loader", 7) == 0) loaderIndex = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
modules[loaderIndex].addr = injector;
|
||||||
|
modules[loaderIndex].size = injector_size;
|
||||||
|
|
||||||
|
pos = section[0].address;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < n; pos += modules[i++].size)
|
||||||
|
memcpy(pos, modules[i].addr, modules[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
|
static inline void launchFirm(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
|
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
|
||||||
u32 sectionNum;
|
u32 sectionNum;
|
||||||
if(firmType == NATIVE_FIRM)
|
if(firmType == NATIVE_FIRM)
|
||||||
{
|
{
|
||||||
copySection0AndInjectLoader();
|
copySection0AndInjectSystemModules();
|
||||||
sectionNum = 1;
|
sectionNum = 1;
|
||||||
}
|
}
|
||||||
else sectionNum = 0;
|
else sectionNum = 0;
|
||||||
|
|||||||
@@ -24,11 +24,6 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
|
||||||
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
|
||||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
|
||||||
#define CFG_UNITINFO (*(vu8 *)0x10010010)
|
|
||||||
|
|
||||||
//FIRM Header layout
|
//FIRM Header layout
|
||||||
typedef struct firmSectionHeader {
|
typedef struct firmSectionHeader {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
@@ -58,5 +53,5 @@ static inline u32 loadFirm(FirmwareType firmType);
|
|||||||
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
||||||
static inline void patchLegacyFirm(FirmwareType firmType);
|
static inline void patchLegacyFirm(FirmwareType firmType);
|
||||||
static inline void patchSafeFirm(void);
|
static inline void patchSafeFirm(void);
|
||||||
static inline void copySection0AndInjectLoader(void);
|
static inline void copySection0AndInjectSystemModules(void);
|
||||||
static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch);
|
static inline void launchFirm(FirmwareType firmType);
|
||||||
114
source/patches.c
114
source/patches.c
@@ -24,6 +24,49 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "../build/rebootpatch.h"
|
#include "../build/rebootpatch.h"
|
||||||
|
#include "../build/svcGetCFWInfopatch.h"
|
||||||
|
#include "../build/twl_k11modulespatch.h"
|
||||||
|
|
||||||
|
static u32 *arm11ExceptionsPage = NULL;
|
||||||
|
static u32 *arm11SvcTable = NULL;
|
||||||
|
static u32 *arm11SvcHandler = NULL;
|
||||||
|
|
||||||
|
static u8 *freeK11Space = NULL; //other than the one used for svcBackdoor
|
||||||
|
|
||||||
|
static void findArm11ExceptionsPageAndSvcHandlerAndTable(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
const u8 arm11ExceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5};
|
||||||
|
|
||||||
|
if(arm11ExceptionsPage == NULL) arm11ExceptionsPage = (u32 *)memsearch(pos, arm11ExceptionsPagePattern, size, 4) - 0xB;
|
||||||
|
if((arm11SvcTable == NULL || arm11SvcHandler == NULL) && arm11ExceptionsPage != NULL)
|
||||||
|
{
|
||||||
|
u32 svcOffset = (-((arm11ExceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||||
|
arm11SvcHandler = arm11SvcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
|
||||||
|
while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void findFreeK11Space(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
if(freeK11Space == NULL)
|
||||||
|
{
|
||||||
|
const u8 bogus_pattern[] = { 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF,
|
||||||
|
0x2F, 0xE1, 0x00, 0x10, 0xA0, 0xE3, 0x00, 0x10, 0xC0, 0xE5,
|
||||||
|
0x1E, 0xFF, 0x2F, 0xE1 };
|
||||||
|
|
||||||
|
u32 *someSpace = (u32 *)memsearch(pos, bogus_pattern, size, 24);
|
||||||
|
|
||||||
|
// We couldn't find the place where to begin our search of an empty block
|
||||||
|
if (someSpace == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Advance until we reach the padding area (filled with 0xFF)
|
||||||
|
u32 *freeSpace;
|
||||||
|
for(freeSpace = someSpace; *freeSpace != 0xFFFFFFFF; freeSpace++);
|
||||||
|
|
||||||
|
freeK11Space = (u8 *)freeSpace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||||
{
|
{
|
||||||
@@ -111,25 +154,49 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
|
|||||||
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
|
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
|
||||||
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
|
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
|
||||||
|
|
||||||
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
|
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
|
||||||
|
|
||||||
u32 *exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
|
|
||||||
|
|
||||||
u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
if(!arm11SvcTable[0x7B])
|
||||||
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
|
|
||||||
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
|
|
||||||
|
|
||||||
if(svcTable[0x7B] == 0)
|
|
||||||
{
|
{
|
||||||
u32 *freeSpace;
|
u32 *freeSpace;
|
||||||
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
|
for(freeSpace = arm11ExceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
|
||||||
|
|
||||||
memcpy(freeSpace, svcBackdoor, 40);
|
memcpy(freeSpace, svcBackdoor, 40);
|
||||||
|
|
||||||
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage);
|
arm11SvcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)arm11ExceptionsPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void implementSvcGetCFWInfo(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
const char *rev = REVISION;
|
||||||
|
bool isRelease;
|
||||||
|
|
||||||
|
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
|
||||||
|
findFreeK11Space(pos, size);
|
||||||
|
|
||||||
|
memcpy(freeK11Space, svcGetCFWInfo, svcGetCFWInfo_size);
|
||||||
|
|
||||||
|
CFWInfo *info = (CFWInfo *)memsearch(freeK11Space, "LUMA", svcGetCFWInfo_size, 4);
|
||||||
|
|
||||||
|
info->commitHash = COMMIT_HASH;
|
||||||
|
info->config = config;
|
||||||
|
info->versionMajor = (u8)(rev[1] - '0');
|
||||||
|
info->versionMinor = (u8)(rev[3] - '0');
|
||||||
|
if(rev[4] == '.')
|
||||||
|
{
|
||||||
|
info->versionBuild = (u8)(rev[5] - '0');
|
||||||
|
isRelease = rev[6] == 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
isRelease = rev[4] == 0;
|
||||||
|
|
||||||
|
info->flags = 0 /* master branch */ | (((isRelease) ? 1 : 0) << 1) /* is release */;
|
||||||
|
|
||||||
|
arm11SvcTable[0x2E] = 0xFFF00000 + freeK11Space - pos; //stubbed svc
|
||||||
|
freeK11Space += svcGetCFWInfo_size;
|
||||||
|
}
|
||||||
|
|
||||||
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
|
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02};
|
const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02};
|
||||||
@@ -180,19 +247,20 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getLoader(u8 *pos, u32 *loaderSize)
|
void patchTwlBg(u8 *pos)
|
||||||
{
|
{
|
||||||
u8 *off = pos;
|
u8 *dst = pos + ((isN3DS) ? 0xFEA4 : 0xFCA0);
|
||||||
u32 size;
|
u16 *src1 = (u16 *)(pos + ((isN3DS) ? 0xE38 : 0xE3C)), *src2 = (u16 *)(pos + ((isN3DS) ? 0xE54 : 0xE58));
|
||||||
|
memcpy(dst, twl_k11modules, twl_k11modules_size); //install k11 hook
|
||||||
|
|
||||||
|
u32 *off;
|
||||||
|
for(off = (u32 *)dst; *off != 0xABCDABCD; off++);
|
||||||
|
*off = (isN3DS) ? 0xCDE88 : 0xCD5F8; //dev SRL launcher offset
|
||||||
|
|
||||||
|
//Construct BLX instructions:
|
||||||
|
src1[0] = 0xF000 | ((((u32)dst - (u32)src1 - 4) & (0xFFF << 11)) >> 12);
|
||||||
|
src1[1] = 0xE800 | ((((u32)dst - (u32)src1 - 4) & 0xFFF) >> 1);
|
||||||
|
|
||||||
while(true)
|
src2[0] = 0xF000 | ((((u32)dst - (u32)src2 - 4) & (0xFFF << 11)) >> 12);
|
||||||
{
|
src2[1] = 0xE800 | ((((u32)dst - (u32)src2 - 4) & 0xFFF) >> 1);
|
||||||
size = *(u32 *)(off + 0x104) * 0x200;
|
|
||||||
if(*(u32 *)(off + 0x200) == 0x64616F6C) break;
|
|
||||||
off += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
*loaderSize = size;
|
|
||||||
|
|
||||||
return (u32)(off - pos);
|
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,22 @@ typedef struct patchData {
|
|||||||
u32 type;
|
u32 type;
|
||||||
} patchData;
|
} patchData;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
u8 versionMajor;
|
||||||
|
u8 versionMinor;
|
||||||
|
u8 versionBuild;
|
||||||
|
u8 flags;
|
||||||
|
|
||||||
|
u32 commitHash;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CFWInfo;
|
||||||
|
|
||||||
extern bool isN3DS;
|
extern bool isN3DS;
|
||||||
|
extern u32 config;
|
||||||
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||||
void patchSignatureChecks(u8 *pos, u32 size);
|
void patchSignatureChecks(u8 *pos, u32 size);
|
||||||
@@ -42,5 +57,6 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
|||||||
void patchFirmWrites(u8 *pos, u32 size);
|
void patchFirmWrites(u8 *pos, u32 size);
|
||||||
void patchFirmWriteSafe(u8 *pos, u32 size);
|
void patchFirmWriteSafe(u8 *pos, u32 size);
|
||||||
void reimplementSvcBackdoor(u8 *pos, u32 size);
|
void reimplementSvcBackdoor(u8 *pos, u32 size);
|
||||||
|
void implementSvcGetCFWInfo(u8 *pos, u32 size);
|
||||||
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
|
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
|
||||||
u32 getLoader(u8 *pos, u32 *loaderSize);
|
void patchTwlBg(u8 *pos);
|
||||||
@@ -131,12 +131,11 @@ void verifyPin(PINData *in)
|
|||||||
}
|
}
|
||||||
while(!(pressed & PIN_BUTTONS));
|
while(!(pressed & PIN_BUTTONS));
|
||||||
|
|
||||||
pressed &= PIN_BUTTONS & ~BUTTON_START;
|
|
||||||
|
|
||||||
if(!pressed) continue;
|
|
||||||
|
|
||||||
if(pressed & BUTTON_START) mcuPowerOff();
|
if(pressed & BUTTON_START) mcuPowerOff();
|
||||||
|
|
||||||
|
pressed &= PIN_BUTTONS & ~BUTTON_START;
|
||||||
|
if(!pressed) continue;
|
||||||
|
|
||||||
char key = PINKeyToLetter(pressed);
|
char key = PINKeyToLetter(pressed);
|
||||||
enteredPassword[cnt++] = (u8)key; // add character to password.
|
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
|
|
||||||
#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)();
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,13 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||||
|
#define CFG_UNITINFO (*(vu8 *)0x10010010)
|
||||||
|
|
||||||
|
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
||||||
|
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
||||||
|
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
|
||||||
|
|
||||||
//Common data types
|
//Common data types
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
|
extern bool isFirmlaunch;
|
||||||
|
|
||||||
u32 waitInput(void)
|
u32 waitInput(void)
|
||||||
{
|
{
|
||||||
u32 pressedKey = 0,
|
u32 pressedKey = 0,
|
||||||
@@ -56,7 +58,7 @@ u32 waitInput(void)
|
|||||||
|
|
||||||
void mcuReboot(void)
|
void mcuReboot(void)
|
||||||
{
|
{
|
||||||
if(PDN_GPU_CNT != 1) clearScreens();
|
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
|
||||||
|
|
||||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ void mcuReboot(void)
|
|||||||
|
|
||||||
void mcuPowerOff(void)
|
void mcuPowerOff(void)
|
||||||
{
|
{
|
||||||
if(PDN_GPU_CNT != 1) clearScreens();
|
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
|
||||||
|
|
||||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user