Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7331a919e4 | ||
|
|
33238cee54 | ||
|
|
384dd2ad81 | ||
|
|
74ac76ba84 | ||
|
|
253e031f83 | ||
|
|
ef1ecf859c | ||
|
|
a302ad3bea | ||
|
|
b87dadbb72 | ||
|
|
50a2424001 | ||
|
|
4f8c66b2b7 | ||
|
|
4d9cbc4e19 | ||
|
|
40369d44df | ||
|
|
ee3720f0b7 | ||
|
|
e5dcca1c2b | ||
|
|
a381c2a811 | ||
|
|
eef30ceb3c | ||
|
|
a1024c288e | ||
|
|
d445b20e90 | ||
|
|
bb117d3d74 | ||
|
|
c101653077 | ||
|
|
5248b96f8a | ||
|
|
7ab59e420a | ||
|
|
83a849126a | ||
|
|
c9c373f607 | ||
|
|
aa7c2c0009 | ||
|
|
75acdc8a98 | ||
|
|
9b304404f7 | ||
|
|
95ef379ac5 | ||
|
|
3bc966f84e | ||
|
|
457b4cec13 | ||
|
|
905777466d | ||
|
|
18b5cdcddf | ||
|
|
389a169443 | ||
|
|
e01802e299 | ||
|
|
709aefba5d | ||
|
|
e4ed713fce | ||
|
|
d3c507b0d4 | ||
|
|
a68e14def3 | ||
|
|
8175642a2a | ||
|
|
8d1befea9e | ||
|
|
e7b8a0ef39 | ||
|
|
be6ee894f9 | ||
|
|
e0e8ed2113 | ||
|
|
c63e46b1a9 | ||
|
|
eb9c74a1ed | ||
|
|
efd83e063e | ||
|
|
ae23a1c84d | ||
|
|
a0e8bc1de3 | ||
|
|
72caad86cc | ||
|
|
575adcbb9d | ||
|
|
53d2aac2ae | ||
|
|
96211813e3 | ||
|
|
730e716f0f | ||
|
|
2238293c0f | ||
|
|
29d8e637d8 | ||
|
|
136e0d8974 | ||
|
|
61684ecb68 | ||
|
|
159c9cb475 | ||
|
|
2943dcb2e9 | ||
|
|
edfd63e1f7 | ||
|
|
e593584a47 | ||
|
|
f78dd5365c | ||
|
|
ae1033d975 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,12 +1,12 @@
|
|||||||
out
|
out
|
||||||
build
|
build
|
||||||
loader/build
|
loader/build
|
||||||
screeninit/build
|
|
||||||
injector/build
|
injector/build
|
||||||
|
exceptions/arm9/build
|
||||||
|
exceptions/arm11/build
|
||||||
*.bin
|
*.bin
|
||||||
*.3dsx
|
*.3dsx
|
||||||
*.smdh
|
*.smdh
|
||||||
*.o
|
*.o
|
||||||
*.d
|
*.d
|
||||||
*.elf
|
*.elf
|
||||||
*.bat
|
|
||||||
2
CakeBrah
2
CakeBrah
Submodule CakeBrah updated: 42ebe0d0bc...9f7cea77d4
23
Makefile
23
Makefile
@@ -13,11 +13,11 @@ 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
|
||||||
dir_loader := loader
|
dir_loader := loader
|
||||||
dir_screeninit := screeninit
|
|
||||||
dir_injector := injector
|
dir_injector := injector
|
||||||
dir_mset := CakeHax
|
dir_mset := CakeHax
|
||||||
dir_ninjhax := CakeBrah
|
dir_ninjhax := CakeBrah
|
||||||
@@ -33,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 $(dir_build)/screeninit.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
|
||||||
@@ -55,12 +56,11 @@ clean:
|
|||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) 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_screeninit) clean
|
|
||||||
@$(MAKE) -C $(dir_injector) clean
|
@$(MAKE) -C $(dir_injector) clean
|
||||||
@rm -rf $(dir_out) $(dir_build)
|
@rm -rf $(dir_out) $(dir_build)
|
||||||
|
|
||||||
$(dir_out):
|
$(dir_out):
|
||||||
@mkdir -p "$(dir_out)/luma/payloads"
|
@mkdir -p "$(dir_out)"
|
||||||
|
|
||||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||||
@@ -93,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,12 +112,9 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
|
|||||||
@$(MAKE) -C $(dir_loader)
|
@$(MAKE) -C $(dir_loader)
|
||||||
@bin2c -o $@ -n loader $(@D)/loader.bin
|
@bin2c -o $@ -n loader $(@D)/loader.bin
|
||||||
|
|
||||||
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
|
||||||
@$(MAKE) -C $(dir_screeninit)
|
|
||||||
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
|
||||||
|
|
||||||
$(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,11 +3,27 @@
|
|||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
CFWInfo info = {0};
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 255
|
#define PATH_MAX 255
|
||||||
#define CONFIG(a) ((loadConfig() >> (a + 16)) & 1)
|
#define CONFIG(a) (((info.config >> (a + 16)) & 1) != 0)
|
||||||
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
|
#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3)
|
||||||
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
|
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||||
@@ -90,39 +106,76 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 secureInfoExists(void)
|
int __attribute__((naked)) svcGetCFWInfo(CFWInfo __attribute__((unused)) *out)
|
||||||
{
|
{
|
||||||
static u32 secureInfoExists = 0;
|
__asm__ volatile("svc 0x2E; bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
if(!secureInfoExists)
|
static void loadCFWInfo(void)
|
||||||
|
{
|
||||||
|
static bool infoLoaded = false;
|
||||||
|
if(!infoLoaded)
|
||||||
|
{
|
||||||
|
svcGetCFWInfo(&info);
|
||||||
|
IFile file;
|
||||||
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //init SD card for firmlaunch patches
|
||||||
|
{
|
||||||
|
IFile_Close(&file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infoLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool secureInfoExists(void)
|
||||||
|
{
|
||||||
|
static bool exists = false;
|
||||||
|
|
||||||
|
if(!exists)
|
||||||
{
|
{
|
||||||
IFile file;
|
IFile file;
|
||||||
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
|
||||||
{
|
{
|
||||||
secureInfoExists = 1;
|
exists = true;
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return secureInfoExists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 loadConfig(void)
|
static void progIdToStr(char *strEnd, u64 progId)
|
||||||
{
|
{
|
||||||
static u32 config = 0;
|
while(progId)
|
||||||
|
|
||||||
if(!config)
|
|
||||||
{
|
{
|
||||||
IFile file;
|
static const char hexDigits[] = "0123456789ABCDEF";
|
||||||
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ)))
|
*strEnd-- = hexDigits[(u32)(progId & 0xF)];
|
||||||
|
progId >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
||||||
|
{
|
||||||
|
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
|
||||||
|
If it exists it should be a decompressed binary code file */
|
||||||
|
|
||||||
|
char path[] = "/luma/code_sections/0000000000000000.bin";
|
||||||
|
progIdToStr(path + 35, progId);
|
||||||
|
|
||||||
|
IFile file;
|
||||||
|
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(ret))
|
||||||
|
{
|
||||||
|
u64 fileSize, total;
|
||||||
|
|
||||||
|
ret = IFile_GetSize(&file, &fileSize);
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(ret) && fileSize <= size)
|
||||||
{
|
{
|
||||||
u64 total;
|
ret = IFile_Read(&file, &total, code, fileSize);
|
||||||
if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4;
|
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
||||||
@@ -131,15 +184,7 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
|||||||
If it exists it should contain, for example, "EUR IT" */
|
If it exists it should contain, for example, "EUR IT" */
|
||||||
|
|
||||||
char path[] = "/luma/locales/0000000000000000.txt";
|
char path[] = "/luma/locales/0000000000000000.txt";
|
||||||
|
progIdToStr(path + 29, progId);
|
||||||
u32 i = 29;
|
|
||||||
|
|
||||||
while(progId)
|
|
||||||
{
|
|
||||||
static const char hexDigits[] = "0123456789ABCDEF";
|
|
||||||
path[i--] = hexDigits[(u32)(progId & 0xF)];
|
|
||||||
progId >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFile file;
|
IFile file;
|
||||||
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
|
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
|
||||||
@@ -236,8 +281,8 @@ static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetC
|
|||||||
if(instr[3] == 0xEB) //We're looking for BL
|
if(instr[3] == 0xEB) //We're looking for BL
|
||||||
{
|
{
|
||||||
u8 *calledFunction = instr;
|
u8 *calledFunction = instr;
|
||||||
u32 i = 0,
|
u32 i = 0;
|
||||||
found;
|
bool found;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -292,6 +337,7 @@ 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
|
||||||
@@ -337,7 +383,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Apply only if the updated NAND hasn't been booted
|
//Apply only if the updated NAND hasn't been booted
|
||||||
if((BOOTCONFIG(0, 3) != 0) == (BOOTCONFIG(3, 1) && CONFIG(1)))
|
if((BOOTCONFIG(0, 3) != 0) == (BOOTCONFIG(2, 1) && CONFIG(1)))
|
||||||
{
|
{
|
||||||
static const u8 skipEshopUpdateCheckPattern[] = {
|
static const u8 skipEshopUpdateCheckPattern[] = {
|
||||||
0x30, 0xB5, 0xF1, 0xB0
|
0x30, 0xB5, 0xF1, 0xB0
|
||||||
@@ -381,7 +427,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
case 0x0004001000027000LL: // KOR MSET
|
case 0x0004001000027000LL: // KOR MSET
|
||||||
case 0x0004001000028000LL: // TWN MSET
|
case 0x0004001000028000LL: // TWN MSET
|
||||||
{
|
{
|
||||||
if(CONFIG(5))
|
if(CONFIG(4))
|
||||||
{
|
{
|
||||||
static const u16 verPattern[] = u"Ver.";
|
static const u16 verPattern[] = u"Ver.";
|
||||||
const u32 currentNand = BOOTCONFIG(0, 3);
|
const u32 currentNand = BOOTCONFIG(0, 3);
|
||||||
@@ -516,12 +562,15 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(CONFIG(4))
|
if(CONFIG(3))
|
||||||
{
|
{
|
||||||
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
|
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
|
||||||
|
|
||||||
if(tidHigh == 0x0004000)
|
if(tidHigh == 0x0004000)
|
||||||
{
|
{
|
||||||
|
//External .code section loading
|
||||||
|
loadTitleCodeSection(progId, code, size);
|
||||||
|
|
||||||
//Language emulation
|
//Language emulation
|
||||||
u8 regionId = 0xFF,
|
u8 regionId = 0xFF,
|
||||||
languageId = 0xFF;
|
languageId = 0xFF;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x24FFFB00;
|
. = 0x24FFFF00;
|
||||||
.text.start : { *(.text.start) }
|
.text.start : { *(.text.start) }
|
||||||
.text : { *(.text) }
|
.text : { *(.text) }
|
||||||
.data : { *(.data) }
|
.data : { *(.data) }
|
||||||
|
|||||||
27
loader/source/cache.h
Normal file
27
loader/source/cache.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void flushCaches(void);
|
||||||
52
loader/source/cache.s
Normal file
52
loader/source/cache.s
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
@ 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
|
||||||
|
.global flushCaches
|
||||||
|
.type flushCaches STT_FUNC
|
||||||
|
|
||||||
|
flushCaches:
|
||||||
|
@ Clean and flush data cache
|
||||||
|
@ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html ,
|
||||||
|
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
|
||||||
|
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
|
||||||
|
@ Implemented in bootROM at address 0xffff0830
|
||||||
|
|
||||||
|
mov r1, #0 @ segment counter
|
||||||
|
outer_loop:
|
||||||
|
mov r0, #0 @ line counter
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
orr r2, r1, r0 @ generate segment and line address
|
||||||
|
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
|
||||||
|
add r0, #0x20 @ increment to next line
|
||||||
|
cmp r0, #0x400
|
||||||
|
bne inner_loop
|
||||||
|
|
||||||
|
add r1, #0x40000000
|
||||||
|
cmp r1, #0
|
||||||
|
bne outer_loop
|
||||||
|
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
|
||||||
|
|
||||||
|
@ Flush instruction cache
|
||||||
|
mcr p15, 0, r1, c7, c5, 0
|
||||||
|
|
||||||
|
bx lr
|
||||||
@@ -1,10 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
|
extern u32 payloadSize; //defined in start.s
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
void *payloadAddress = (void *)0x23F00000;
|
void *payloadAddress = (void *)0x23F00000;
|
||||||
|
|
||||||
memcpy(payloadAddress, (void*)0x24F00000, *(u32 *)0x24FFFB04);
|
memcpy(payloadAddress, (void*)0x24F00000, payloadSize);
|
||||||
|
|
||||||
|
flushCaches();
|
||||||
|
|
||||||
((void (*)())payloadAddress)();
|
((void (*)())payloadAddress)();
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||||
|
*/
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
void memcpy(void *dest, const void *src, u32 size)
|
void memcpy(void *dest, const void *src, u32 size)
|
||||||
|
|||||||
@@ -1,3 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|||||||
@@ -1,16 +1,29 @@
|
|||||||
|
@ 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.
|
||||||
|
|
||||||
.section .text.start
|
.section .text.start
|
||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
b start
|
|
||||||
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
start:
|
|
||||||
@ Flush caches
|
|
||||||
mov r0, #0
|
|
||||||
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
|
|
||||||
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
|
||||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
|
||||||
|
|
||||||
b main
|
b main
|
||||||
|
|
||||||
|
.global payloadSize
|
||||||
|
payloadSize:
|
||||||
|
.word 0
|
||||||
|
|||||||
@@ -1,3 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
108
patches/reboot.s
108
patches/reboot.s
@@ -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 0x20000 ; Maximum size for the payload (200 KB will do).
|
payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeBrah supports).
|
||||||
|
|
||||||
.create "build/reboot.bin", 0
|
.create "build/reboot.bin", 0
|
||||||
.arm
|
.arm
|
||||||
@@ -41,26 +41,29 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
|||||||
|
|
||||||
read_payload:
|
read_payload:
|
||||||
; Read file
|
; Read file
|
||||||
mov r0, r7
|
mov r0, r7
|
||||||
adr r1, bytes_read
|
adr r1, bytes_read
|
||||||
ldr r2, =payload_addr
|
ldr r2, =payload_addr
|
||||||
cmp r4, #0
|
cmp r4, #0
|
||||||
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
|
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
|
||||||
moveq r3, payload_maxsize
|
moveq r3, payload_maxsize
|
||||||
ldr r6, [sp, #0x3A8-0x198]
|
ldr r6, [sp, #0x3A8-0x198]
|
||||||
ldr r6, [r6, #0x28]
|
ldr r6, [r6, #0x28]
|
||||||
blx r6
|
blx r6
|
||||||
cmp r4, #0
|
cmp r4, #0
|
||||||
movne r4, #0
|
movne r4, #0
|
||||||
bne read_payload ; Go read the real payload.
|
bne read_payload ; Go read the real payload.
|
||||||
|
|
||||||
; Copy the last digits 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 r2, sp, #0x3A8 - 0x70
|
add r0, sp, #0x3A8 - 0x70
|
||||||
ldr r0, [r2, #0x27]
|
add r0, 0x1A
|
||||||
ldr r1, =payload_addr + 4
|
add r1, r0, #0x10
|
||||||
str r0, [r1]
|
ldr r2, =payload_addr + 4
|
||||||
ldr r0, [r2, #0x2B]
|
copy_TID_low:
|
||||||
str r0, [r1, #4]
|
ldrh r3, [r0], #2
|
||||||
|
strh r3, [r2], #2
|
||||||
|
cmp r0, r1
|
||||||
|
blo copy_TID_low
|
||||||
|
|
||||||
; Set kernel state
|
; Set kernel state
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
@@ -81,67 +84,38 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
|||||||
bytes_read: .word 0
|
bytes_read: .word 0
|
||||||
fopen: .ascii "OPEN"
|
fopen: .ascii "OPEN"
|
||||||
.pool
|
.pool
|
||||||
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
|
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"
|
dat_fname: .dcw "sdmc:/Luma3DS.dat"
|
||||||
.word 0
|
.word 0
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
kernelcode_start:
|
kernelcode_start:
|
||||||
; Set MPU settings
|
|
||||||
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
|
|
||||||
mrc p15, 0, r12, c2, c0, 1 ; icacheable
|
|
||||||
mrc p15, 0, r1, c3, c0, 0 ; write bufferable
|
|
||||||
mrc p15, 0, r2, c5, c0, 2 ; daccess
|
|
||||||
mrc p15, 0, r3, c5, c0, 3 ; iaccess
|
|
||||||
ldr r4, =0x18000035 ; 0x18000000 128M
|
|
||||||
bic r2, r2, #0xF0000 ; unprotect region 4
|
|
||||||
bic r3, r3, #0xF0000 ; unprotect region 4
|
|
||||||
orr r0, r0, #0x10 ; dcacheable region 4
|
|
||||||
orr r2, r2, #0x30000 ; region 4 r/w
|
|
||||||
orr r3, r3, #0x30000 ; region 4 r/w
|
|
||||||
orr r12, r12, #0x10 ; icacheable region 4
|
|
||||||
orr r1, r1, #0x10 ; write bufferable region 4
|
|
||||||
mcr p15, 0, r0, c2, c0, 0
|
|
||||||
mcr p15, 0, r12, c2, c0, 1
|
|
||||||
mcr p15, 0, r1, c3, c0, 0 ; write bufferable
|
|
||||||
mcr p15, 0, r2, c5, c0, 2 ; daccess
|
|
||||||
mcr p15, 0, r3, c5, c0, 3 ; iaccess
|
|
||||||
mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
|
|
||||||
|
|
||||||
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
|
; Disable MPU
|
||||||
mrc p15, 0, r1, c2, c0, 1 ; icacheable
|
|
||||||
mrc p15, 0, r2, c3, c0, 0 ; write bufferable
|
|
||||||
orr r0, r0, #0x20 ; dcacheable region 5
|
|
||||||
orr r1, r1, #0x20 ; icacheable region 5
|
|
||||||
orr r2, r2, #0x20 ; write bufferable region 5
|
|
||||||
mcr p15, 0, r0, c2, c0, 0 ; dcacheable
|
|
||||||
mcr p15, 0, r1, c2, c0, 1 ; icacheable
|
|
||||||
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
|
|
||||||
|
|
||||||
; Flush cache
|
|
||||||
mov r2, #0
|
|
||||||
mov r1, r2
|
|
||||||
flush_cache:
|
|
||||||
mov r0, #0
|
|
||||||
mov r3, r2, lsl #30
|
|
||||||
flush_cache_inner_loop:
|
|
||||||
orr r12, r3, r0, lsl#5
|
|
||||||
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
|
||||||
mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
|
|
||||||
add r0, #1
|
|
||||||
cmp r0, #0x20
|
|
||||||
bcc flush_cache_inner_loop
|
|
||||||
add r2, #1
|
|
||||||
cmp r2, #4
|
|
||||||
bcc flush_cache
|
|
||||||
|
|
||||||
; Enable MPU
|
|
||||||
ldr r0, =0x42078 ; alt vector select, enable itcm
|
ldr r0, =0x42078 ; alt vector select, enable itcm
|
||||||
mcr p15, 0, r0, c1, c0, 0
|
mcr p15, 0, r0, c1, c0, 0
|
||||||
mcr p15, 0, r1, c7, c5, 0 ; flush dcache
|
|
||||||
mcr p15, 0, r1, c7, c6, 0 ; flush icache
|
; Clean and flush data cache
|
||||||
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
mov r1, #0 ; segment counter
|
||||||
|
outer_loop:
|
||||||
|
mov r0, #0 ; line counter
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
orr r2, r1, r0 ; generate segment and line address
|
||||||
|
mcr p15, 0, r2, c7, c14, 2 ; clean and flush the line
|
||||||
|
add r0, #0x20 ; increment to next line
|
||||||
|
cmp r0, #0x400
|
||||||
|
bne inner_loop
|
||||||
|
|
||||||
|
add r1, #0x40000000
|
||||||
|
cmp r1, #0
|
||||||
|
bne outer_loop
|
||||||
|
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
||||||
|
|
||||||
|
; Flush instruction cache
|
||||||
|
mcr p15, 0, r1, c7, c5, 0
|
||||||
|
|
||||||
; Jump to payload
|
; Jump to payload
|
||||||
ldr r0, =payload_addr
|
ldr r0, =payload_addr
|
||||||
|
|||||||
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 0x89, 0x53, 0xb2, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x08, 0x62, 0x86, 0xe3, 0x08, 0x60, 0x87, 0xe5)
|
||||||
|
|
||||||
|
patchesEnd:
|
||||||
|
|
||||||
|
.pool
|
||||||
|
|
||||||
|
.close
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
|
||||||
endif
|
|
||||||
|
|
||||||
include $(DEVKITARM)/3ds_rules
|
|
||||||
|
|
||||||
CC := arm-none-eabi-gcc
|
|
||||||
AS := arm-none-eabi-as
|
|
||||||
LD := arm-none-eabi-ld
|
|
||||||
OC := arm-none-eabi-objcopy
|
|
||||||
|
|
||||||
name := $(shell basename $(CURDIR))
|
|
||||||
|
|
||||||
dir_source := source
|
|
||||||
dir_build := build
|
|
||||||
|
|
||||||
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
|
|
||||||
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
|
||||||
LDFLAGS := -nostdlib
|
|
||||||
|
|
||||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|
||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
|
||||||
|
|
||||||
.PHONY: all
|
|
||||||
all: ../$(dir_build)/$(name).bin
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
@rm -rf $(dir_build)
|
|
||||||
|
|
||||||
../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
|
||||||
$(OC) -S -O binary $< $@
|
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.s
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
|
||||||
include $(call rwildcard, $(dir_build), *.d)
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x24FFFC00;
|
|
||||||
.text.start : { *(.text.start) }
|
|
||||||
.text : { *(.text) }
|
|
||||||
.data : { *(.data) }
|
|
||||||
.bss : { *(.bss COMMON) }
|
|
||||||
.rodata : { *(.rodata) }
|
|
||||||
. = ALIGN(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
#include "types.h"
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
|
||||||
u32 brightnessLevel = *(vu32 *)0x24FFFC08;
|
|
||||||
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
|
||||||
|
|
||||||
*(vu32 *)0x10141200 = 0x1007F;
|
|
||||||
*(vu32 *)0x10202014 = 0x00000001;
|
|
||||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
|
||||||
*(vu32 *)0x10202240 = brightness[brightnessLevel];
|
|
||||||
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
|
|
||||||
*(vu32 *)0x10202244 = 0x1023E;
|
|
||||||
*(vu32 *)0x10202A44 = 0x1023E;
|
|
||||||
|
|
||||||
// Top screen
|
|
||||||
*(vu32 *)0x10400400 = 0x000001c2;
|
|
||||||
*(vu32 *)0x10400404 = 0x000000d1;
|
|
||||||
*(vu32 *)0x10400408 = 0x000001c1;
|
|
||||||
*(vu32 *)0x1040040c = 0x000001c1;
|
|
||||||
*(vu32 *)0x10400410 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400414 = 0x000000cf;
|
|
||||||
*(vu32 *)0x10400418 = 0x000000d1;
|
|
||||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
|
||||||
*(vu32 *)0x10400420 = 0x00010000;
|
|
||||||
*(vu32 *)0x10400424 = 0x0000019d;
|
|
||||||
*(vu32 *)0x10400428 = 0x00000002;
|
|
||||||
*(vu32 *)0x1040042c = 0x00000192;
|
|
||||||
*(vu32 *)0x10400430 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400434 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400438 = 0x00000001;
|
|
||||||
*(vu32 *)0x1040043c = 0x00000002;
|
|
||||||
*(vu32 *)0x10400440 = 0x01960192;
|
|
||||||
*(vu32 *)0x10400444 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400448 = 0x00000000;
|
|
||||||
*(vu32 *)0x1040045C = 0x00f00190;
|
|
||||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
|
||||||
*(vu32 *)0x10400464 = 0x01920002;
|
|
||||||
*(vu32 *)0x10400468 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400470 = 0x80341;
|
|
||||||
*(vu32 *)0x10400474 = 0x00010501;
|
|
||||||
*(vu32 *)0x10400478 = 0;
|
|
||||||
*(vu32 *)0x10400490 = 0x000002D0;
|
|
||||||
*(vu32 *)0x1040049C = 0x00000000;
|
|
||||||
|
|
||||||
// Disco register
|
|
||||||
for(u32 i = 0; i < 256; i++)
|
|
||||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
|
||||||
|
|
||||||
// Bottom screen
|
|
||||||
*(vu32 *)0x10400500 = 0x000001c2;
|
|
||||||
*(vu32 *)0x10400504 = 0x000000d1;
|
|
||||||
*(vu32 *)0x10400508 = 0x000001c1;
|
|
||||||
*(vu32 *)0x1040050c = 0x000001c1;
|
|
||||||
*(vu32 *)0x10400510 = 0x000000cd;
|
|
||||||
*(vu32 *)0x10400514 = 0x000000cf;
|
|
||||||
*(vu32 *)0x10400518 = 0x000000d1;
|
|
||||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
|
||||||
*(vu32 *)0x10400520 = 0x00010000;
|
|
||||||
*(vu32 *)0x10400524 = 0x0000019d;
|
|
||||||
*(vu32 *)0x10400528 = 0x00000052;
|
|
||||||
*(vu32 *)0x1040052c = 0x00000192;
|
|
||||||
*(vu32 *)0x10400530 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400534 = 0x0000004f;
|
|
||||||
*(vu32 *)0x10400538 = 0x00000050;
|
|
||||||
*(vu32 *)0x1040053c = 0x00000052;
|
|
||||||
*(vu32 *)0x10400540 = 0x01980194;
|
|
||||||
*(vu32 *)0x10400544 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400548 = 0x00000011;
|
|
||||||
*(vu32 *)0x1040055C = 0x00f00140;
|
|
||||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
|
||||||
*(vu32 *)0x10400564 = 0x01920052;
|
|
||||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
|
||||||
*(vu32 *)0x10400570 = 0x80301;
|
|
||||||
*(vu32 *)0x10400574 = 0x00010501;
|
|
||||||
*(vu32 *)0x10400578 = 0;
|
|
||||||
*(vu32 *)0x10400590 = 0x000002D0;
|
|
||||||
*(vu32 *)0x1040059C = 0x00000000;
|
|
||||||
|
|
||||||
// Disco register
|
|
||||||
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;
|
|
||||||
|
|
||||||
//Set CakeBrah framebuffers
|
|
||||||
*((vu32 *)0x23FFFE00) = 0x18300000;
|
|
||||||
*((vu32 *)0x23FFFE04) = 0x18300000;
|
|
||||||
*((vu32 *)0x23FFFE08) = 0x18346500;
|
|
||||||
|
|
||||||
//Clear ARM11 entry offset
|
|
||||||
*arm11 = 0;
|
|
||||||
|
|
||||||
//Wait for the entry to be set
|
|
||||||
while(!*arm11);
|
|
||||||
|
|
||||||
//Jump to it
|
|
||||||
((void (*)())*arm11)();
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
.section .text.start
|
|
||||||
.align 4
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
@ Disable interrupts
|
|
||||||
CPSID aif
|
|
||||||
|
|
||||||
b main
|
|
||||||
|
|
||||||
.word 0
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
//Common data types
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef volatile u8 vu8;
|
|
||||||
typedef volatile u16 vu16;
|
|
||||||
typedef volatile u32 vu32;
|
|
||||||
typedef volatile u64 vu64;
|
|
||||||
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* buttons.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -10,7 +28,7 @@
|
|||||||
|
|
||||||
#define BUTTON_R1 (1 << 8)
|
#define BUTTON_R1 (1 << 8)
|
||||||
#define BUTTON_L1 (1 << 9)
|
#define BUTTON_L1 (1 << 9)
|
||||||
#define BUTTON_A 1
|
#define BUTTON_A (1 << 0)
|
||||||
#define BUTTON_B (1 << 1)
|
#define BUTTON_B (1 << 1)
|
||||||
#define BUTTON_X (1 << 10)
|
#define BUTTON_X (1 << 10)
|
||||||
#define BUTTON_Y (1 << 11)
|
#define BUTTON_Y (1 << 11)
|
||||||
@@ -24,4 +42,5 @@
|
|||||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
|
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
|
||||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
|
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
|
||||||
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
||||||
|
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_START)
|
||||||
39
source/cache.h
Normal file
39
source/cache.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/***
|
||||||
|
The following functions flush the data cache, then waits for all memory transfers to be finished.
|
||||||
|
The data cache and/or the instruction cache MUST be flushed before doing one of the following:
|
||||||
|
- rebooting
|
||||||
|
- powering down
|
||||||
|
- setting the ARM11 entrypoint to execute a function
|
||||||
|
- jumping to a payload
|
||||||
|
***/
|
||||||
|
|
||||||
|
void flushEntireDCache(void); //actually: "clean and flush"
|
||||||
|
void flushDCacheRange(void *startAddress, u32 size);
|
||||||
|
void flushEntireICache(void);
|
||||||
|
void flushICacheRange(void *startAddress, u32 size);
|
||||||
89
source/cache.s
Normal file
89
source/cache.s
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@ 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.
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global flushEntireDCache
|
||||||
|
.type flushEntireDCache, %function
|
||||||
|
flushEntireDCache:
|
||||||
|
@ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html,
|
||||||
|
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
|
||||||
|
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
|
||||||
|
|
||||||
|
@ Implemented in bootROM at address 0xffff0830
|
||||||
|
mov r1, #0 @ segment counter
|
||||||
|
outer_loop:
|
||||||
|
mov r0, #0 @ line counter
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
orr r2, r1, r0 @ generate segment and line address
|
||||||
|
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
|
||||||
|
add r0, #0x20 @ increment to next line
|
||||||
|
cmp r0, #0x400
|
||||||
|
bne inner_loop
|
||||||
|
|
||||||
|
add r1, #0x40000000
|
||||||
|
cmp r1, #0
|
||||||
|
bne outer_loop
|
||||||
|
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global flushDCacheRange
|
||||||
|
.type flushDCacheRange, %function
|
||||||
|
flushDCacheRange:
|
||||||
|
@ Implemented in bootROM at address 0xffff08a0
|
||||||
|
add r1, r0, r1 @ end address
|
||||||
|
bic r0, #0x1f @ align source address to cache line size (32 bytes)
|
||||||
|
|
||||||
|
flush_dcache_range_loop:
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding
|
||||||
|
add r0, #0x20
|
||||||
|
cmp r0, r1
|
||||||
|
blo flush_dcache_range_loop
|
||||||
|
|
||||||
|
mov r0, #0
|
||||||
|
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global flushEntireICache
|
||||||
|
.type flushEntireICache, %function
|
||||||
|
flushEntireICache:
|
||||||
|
@ Implemented in bootROM at address 0xffff0ab4
|
||||||
|
mov r0, #0
|
||||||
|
mcr p15, 0, r0, c7, c5, 0
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global flushICacheRange
|
||||||
|
.type flushICacheRange, %function
|
||||||
|
flushICacheRange:
|
||||||
|
@ Implemented in bootROM at address 0xffff0ac0
|
||||||
|
add r1, r0, r1 @ end address
|
||||||
|
bic r0, #0x1f @ align source address to cache line size (32 bytes)
|
||||||
|
|
||||||
|
flush_icache_range_loop:
|
||||||
|
mcr p15, 0, r0, c7, c5, 1 @ flush the line corresponding to the address r0 is holding
|
||||||
|
add r0, #0x20
|
||||||
|
cmp r0, r1
|
||||||
|
blo flush_icache_range_loop
|
||||||
|
|
||||||
|
bx lr
|
||||||
@@ -1,40 +1,57 @@
|
|||||||
/*
|
/*
|
||||||
* config.c
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "screeninit.h"
|
#include "screen.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "i2c.h"
|
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
|
||||||
void configureCFW(const char *configPath)
|
void configureCFW(const char *configPath)
|
||||||
{
|
{
|
||||||
u32 needToDeinit = initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
||||||
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
||||||
|
|
||||||
const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
|
const char *multiOptionsText[] = { "Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
||||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
|
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
|
||||||
|
|
||||||
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
||||||
"( ) SysNAND is updated (A9LH-only)",
|
"( ) Use SysNAND FIRM if booting with R (A9LH)",
|
||||||
"( ) Force A9LH detection",
|
|
||||||
"( ) Use second EmuNAND as default",
|
"( ) Use second EmuNAND as default",
|
||||||
"( ) Enable region/language emulation",
|
"( ) Enable region/language emu. and ext. .code",
|
||||||
"( ) 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",
|
||||||
"( ) Enable splash screen with no screen-init" };
|
"( ) Display splash screen before payloads",
|
||||||
|
"( ) Use a PIN" };
|
||||||
|
|
||||||
struct multiOption {
|
struct multiOption {
|
||||||
int posXs[4];
|
int posXs[4];
|
||||||
int posY;
|
int posY;
|
||||||
u32 enabled;
|
u32 enabled;
|
||||||
} multiOptions[] = {
|
} multiOptions[] = {
|
||||||
{ .posXs = {26, 31, 36, 41} },
|
{ .posXs = {21, 26, 31, 36} },
|
||||||
{ .posXs = {17, 26, 32, 44} }
|
{ .posXs = {17, 26, 32, 44} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,7 +63,7 @@ void configureCFW(const char *configPath)
|
|||||||
|
|
||||||
struct singleOption {
|
struct singleOption {
|
||||||
int posY;
|
int posY;
|
||||||
u32 enabled;
|
bool enabled;
|
||||||
} singleOptions[singleOptionsAmount];
|
} singleOptions[singleOptionsAmount];
|
||||||
|
|
||||||
//Parse the existing options
|
//Parse the existing options
|
||||||
@@ -145,10 +162,13 @@ void configureCFW(const char *configPath)
|
|||||||
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
||||||
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
||||||
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
|
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
|
||||||
|
|
||||||
|
if(!selectedOption)
|
||||||
|
updateBrightness(multiOptions[selectedOption].enabled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
||||||
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
||||||
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
|
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
|
||||||
}
|
}
|
||||||
@@ -171,18 +191,15 @@ void configureCFW(const char *configPath)
|
|||||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
config |= multiOptions[i].enabled << (i * 2 + 6);
|
config |= multiOptions[i].enabled << (i * 2 + 6);
|
||||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
config |= singleOptions[i].enabled << (i + 16);
|
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
|
||||||
|
|
||||||
fileWrite(&config, configPath, 4);
|
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);
|
||||||
|
|
||||||
if(needToDeinit)
|
|
||||||
{
|
|
||||||
//Turn off backlight
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
|
|
||||||
deinitScreens();
|
|
||||||
PDN_GPU_CNT = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,30 @@
|
|||||||
/*
|
/*
|
||||||
* config.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define CONFIG(a) ((config >> (a + 16)) & 1)
|
#define CONFIG(a) (((config >> (a + 16)) & 1) != 0)
|
||||||
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
|
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
|
||||||
#define BOOTCONFIG(a, b) ((config >> a) & b)
|
#define BOOTCONFIG(a, b) ((config >> a) & b)
|
||||||
|
|
||||||
|
|||||||
507
source/crypto.c
507
source/crypto.c
@@ -1,6 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
* crypto.c
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Crypto libs from http://github.com/b1l1s/ctr
|
* Crypto libs from http://github.com/b1l1s/ctr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -9,290 +29,291 @@
|
|||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Crypto libs
|
* Crypto libs
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
/* original version by megazig */
|
/* original version by megazig */
|
||||||
|
|
||||||
#ifndef __thumb__
|
#ifndef __thumb__
|
||||||
#define BSWAP32(x) {\
|
#define BSWAP32(x) {\
|
||||||
__asm__\
|
__asm__\
|
||||||
(\
|
(\
|
||||||
"eor r1, %1, %1, ror #16\n\t"\
|
"eor r1, %1, %1, ror #16\n\t"\
|
||||||
"bic r1, r1, #0xFF0000\n\t"\
|
"bic r1, r1, #0xFF0000\n\t"\
|
||||||
"mov %0, %1, ror #8\n\t"\
|
"mov %0, %1, ror #8\n\t"\
|
||||||
"eor %0, %0, r1, lsr #8\n\t"\
|
"eor %0, %0, r1, lsr #8\n\t"\
|
||||||
:"=r"(x)\
|
:"=r"(x)\
|
||||||
:"0"(x)\
|
:"0"(x)\
|
||||||
:"r1"\
|
:"r1"\
|
||||||
);\
|
);\
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
||||||
__asm__\
|
__asm__\
|
||||||
(\
|
(\
|
||||||
"adds %0, %4\n\t"\
|
"adds %0, %4\n\t"\
|
||||||
"addcss %1, %1, #1\n\t"\
|
"addcss %1, %1, #1\n\t"\
|
||||||
"addcss %2, %2, #1\n\t"\
|
"addcss %2, %2, #1\n\t"\
|
||||||
"addcs %3, %3, #1\n\t"\
|
"addcs %3, %3, #1\n\t"\
|
||||||
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
||||||
: "r"(u32_0)\
|
: "r"(u32_0)\
|
||||||
: "cc"\
|
: "cc"\
|
||||||
);\
|
);\
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define BSWAP32(x) {x = __builtin_bswap32(x);}
|
#define BSWAP32(x) {x = __builtin_bswap32(x);}
|
||||||
|
|
||||||
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
||||||
__asm__\
|
__asm__\
|
||||||
(\
|
(\
|
||||||
"mov r4, #0\n\t"\
|
"mov r4, #0\n\t"\
|
||||||
"add %0, %0, %4\n\t"\
|
"add %0, %0, %4\n\t"\
|
||||||
"adc %1, %1, r4\n\t"\
|
"adc %1, %1, r4\n\t"\
|
||||||
"adc %2, %2, r4\n\t"\
|
"adc %2, %2, r4\n\t"\
|
||||||
"adc %3, %3, r4\n\t"\
|
"adc %3, %3, r4\n\t"\
|
||||||
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
||||||
: "r"(u32_0)\
|
: "r"(u32_0)\
|
||||||
: "cc", "r4"\
|
: "cc", "r4"\
|
||||||
);\
|
);\
|
||||||
}
|
}
|
||||||
#endif /*__thumb__*/
|
#endif /*__thumb__*/
|
||||||
|
|
||||||
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
|
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
|
||||||
{
|
{
|
||||||
if(keyslot <= 0x03) return; // Ignore TWL keys for now
|
if(keyslot <= 0x03) return; // Ignore TWL keys for now
|
||||||
u32 *key32 = (u32 *)key;
|
u32 *key32 = (u32 *)key;
|
||||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
||||||
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
||||||
|
|
||||||
REG_AESKEYFIFO[keyType] = key32[0];
|
REG_AESKEYFIFO[keyType] = key32[0];
|
||||||
REG_AESKEYFIFO[keyType] = key32[1];
|
REG_AESKEYFIFO[keyType] = key32[1];
|
||||||
REG_AESKEYFIFO[keyType] = key32[2];
|
REG_AESKEYFIFO[keyType] = key32[2];
|
||||||
REG_AESKEYFIFO[keyType] = key32[3];
|
REG_AESKEYFIFO[keyType] = key32[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_use_keyslot(u8 keyslot)
|
static void aes_use_keyslot(u8 keyslot)
|
||||||
{
|
{
|
||||||
if(keyslot > 0x3F)
|
if(keyslot > 0x3F)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
*REG_AESKEYSEL = keyslot;
|
*REG_AESKEYSEL = keyslot;
|
||||||
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
|
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_setiv(const void *iv, u32 mode)
|
static void aes_setiv(const void *iv, u32 mode)
|
||||||
{
|
{
|
||||||
const u32 *iv32 = (const u32 *)iv;
|
const u32 *iv32 = (const u32 *)iv;
|
||||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
||||||
|
|
||||||
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
|
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
|
||||||
if(mode & AES_INPUT_NORMAL)
|
if(mode & AES_INPUT_NORMAL)
|
||||||
{
|
{
|
||||||
REG_AESCTR[0] = iv32[3];
|
REG_AESCTR[0] = iv32[3];
|
||||||
REG_AESCTR[1] = iv32[2];
|
REG_AESCTR[1] = iv32[2];
|
||||||
REG_AESCTR[2] = iv32[1];
|
REG_AESCTR[2] = iv32[1];
|
||||||
REG_AESCTR[3] = iv32[0];
|
REG_AESCTR[3] = iv32[0];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
REG_AESCTR[0] = iv32[0];
|
REG_AESCTR[0] = iv32[0];
|
||||||
REG_AESCTR[1] = iv32[1];
|
REG_AESCTR[1] = iv32[1];
|
||||||
REG_AESCTR[2] = iv32[2];
|
REG_AESCTR[2] = iv32[2];
|
||||||
REG_AESCTR[3] = iv32[3];
|
REG_AESCTR[3] = iv32[3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_advctr(void *ctr, u32 val, u32 mode)
|
static void aes_advctr(void *ctr, u32 val, u32 mode)
|
||||||
{
|
{
|
||||||
u32 *ctr32 = (u32 *)ctr;
|
u32 *ctr32 = (u32 *)ctr;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
if(mode & AES_INPUT_BE)
|
if(mode & AES_INPUT_BE)
|
||||||
{
|
{
|
||||||
for(i = 0; i < 4; ++i) // Endian swap
|
for(i = 0; i < 4; ++i) // Endian swap
|
||||||
BSWAP32(ctr32[i]);
|
BSWAP32(ctr32[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode & AES_INPUT_NORMAL)
|
if(mode & AES_INPUT_NORMAL)
|
||||||
{
|
{
|
||||||
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
|
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
|
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode & AES_INPUT_BE)
|
if(mode & AES_INPUT_BE)
|
||||||
{
|
{
|
||||||
for(i = 0; i < 4; ++i) // Endian swap
|
for(i = 0; i < 4; ++i) // Endian swap
|
||||||
BSWAP32(ctr32[i]);
|
BSWAP32(ctr32[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
|
static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
|
||||||
{
|
{
|
||||||
u32 *ctr32 = (u32 *)ctr;
|
u32 *ctr32 = (u32 *)ctr;
|
||||||
int i;
|
int i;
|
||||||
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
|
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
|
||||||
{
|
{
|
||||||
for(i = 0; i < 4; ++i)
|
for(i = 0; i < 4; ++i)
|
||||||
BSWAP32(ctr32[i]);
|
BSWAP32(ctr32[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
|
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
|
||||||
{
|
{
|
||||||
u32 temp = ctr32[0];
|
u32 temp = ctr32[0];
|
||||||
ctr32[0] = ctr32[3];
|
ctr32[0] = ctr32[3];
|
||||||
ctr32[3] = temp;
|
ctr32[3] = temp;
|
||||||
|
|
||||||
temp = ctr32[1];
|
temp = ctr32[1];
|
||||||
ctr32[1] = ctr32[2];
|
ctr32[1] = ctr32[2];
|
||||||
ctr32[2] = temp;
|
ctr32[2] = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_batch(void *dst, const void *src, u32 blockCount)
|
static void aes_batch(void *dst, const void *src, u32 blockCount)
|
||||||
{
|
{
|
||||||
*REG_AESBLKCNT = blockCount << 16;
|
*REG_AESBLKCNT = blockCount << 16;
|
||||||
*REG_AESCNT |= AES_CNT_START;
|
*REG_AESCNT |= AES_CNT_START;
|
||||||
|
|
||||||
const u32 *src32 = (const u32 *)src;
|
const u32 *src32 = (const u32 *)src;
|
||||||
u32 *dst32 = (u32 *)dst;
|
u32 *dst32 = (u32 *)dst;
|
||||||
|
|
||||||
u32 wbc = blockCount;
|
u32 wbc = blockCount;
|
||||||
u32 rbc = blockCount;
|
u32 rbc = blockCount;
|
||||||
|
|
||||||
while(rbc)
|
while(rbc)
|
||||||
{
|
{
|
||||||
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
|
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
|
||||||
{
|
{
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
wbc--;
|
wbc--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
|
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
|
||||||
{
|
{
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
rbc--;
|
rbc--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
|
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
|
||||||
{
|
{
|
||||||
*REG_AESCNT = mode |
|
*REG_AESCNT = mode |
|
||||||
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
|
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
|
||||||
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
|
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
|
||||||
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
|
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
|
||||||
|
|
||||||
u32 blocks;
|
u32 blocks;
|
||||||
while(blockCount != 0)
|
while(blockCount != 0)
|
||||||
{
|
{
|
||||||
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
|
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
|
||||||
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
|
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
|
||||||
aes_setiv(iv, ivMode);
|
aes_setiv(iv, ivMode);
|
||||||
|
|
||||||
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
|
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
|
||||||
|
|
||||||
// Save the last block for the next decryption CBC batch's iv
|
// Save the last block for the next decryption CBC batch's iv
|
||||||
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
|
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
|
||||||
{
|
{
|
||||||
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
||||||
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the current batch
|
// Process the current batch
|
||||||
aes_batch(dst, src, blocks);
|
aes_batch(dst, src, blocks);
|
||||||
|
|
||||||
// Save the last block for the next encryption CBC batch's iv
|
// Save the last block for the next encryption CBC batch's iv
|
||||||
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
|
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
|
||||||
{
|
{
|
||||||
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
||||||
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance counter for CTR mode
|
// Advance counter for CTR mode
|
||||||
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
|
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
|
||||||
aes_advctr(iv, blocks, ivMode);
|
aes_advctr(iv, blocks, ivMode);
|
||||||
|
|
||||||
src += blocks * AES_BLOCK_SIZE;
|
src += blocks * AES_BLOCK_SIZE;
|
||||||
dst += blocks * AES_BLOCK_SIZE;
|
dst += blocks * AES_BLOCK_SIZE;
|
||||||
blockCount -= blocks;
|
blockCount -= blocks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha_wait_idle()
|
static void sha_wait_idle()
|
||||||
{
|
{
|
||||||
while(*REG_SHA_CNT & 1);
|
while(*REG_SHA_CNT & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha(void *res, const void *src, u32 size, u32 mode)
|
static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||||
{
|
{
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
||||||
|
|
||||||
const u32 *src32 = (const u32 *)src;
|
const u32 *src32 = (const u32 *)src;
|
||||||
int i;
|
int i;
|
||||||
while(size >= 0x40)
|
while(size >= 0x40)
|
||||||
{
|
{
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
for(i = 0; i < 4; ++i)
|
for(i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
}
|
}
|
||||||
|
|
||||||
size -= 0x40;
|
size -= 0x40;
|
||||||
}
|
}
|
||||||
|
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
memcpy((void *)REG_SHA_INFIFO, src32, size);
|
memcpy((void *)REG_SHA_INFIFO, src32, size);
|
||||||
|
|
||||||
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
|
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
|
||||||
|
|
||||||
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
|
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
|
|
||||||
u32 hashSize = SHA_256_HASH_SIZE;
|
u32 hashSize = SHA_256_HASH_SIZE;
|
||||||
if(mode == SHA_224_MODE)
|
if(mode == SHA_224_MODE)
|
||||||
hashSize = SHA_224_HASH_SIZE;
|
hashSize = SHA_224_HASH_SIZE;
|
||||||
else if(mode == SHA_1_MODE)
|
else if(mode == SHA_1_MODE)
|
||||||
hashSize = SHA_1_HASH_SIZE;
|
hashSize = SHA_1_HASH_SIZE;
|
||||||
|
|
||||||
memcpy(res, (void *)REG_SHA_HASH, hashSize);
|
memcpy(res, (void *)REG_SHA_HASH, hashSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* NAND/FIRM crypto
|
* NAND/FIRM crypto
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
static u8 nandCTR[0x10],
|
static u8 __attribute__((aligned(4))) nandCTR[0x10];
|
||||||
nandSlot;
|
static u8 nandSlot;
|
||||||
|
|
||||||
static u32 fatStart;
|
static u32 fatStart;
|
||||||
|
|
||||||
//Initialize the CTRNAND crypto
|
//Initialize the CTRNAND crypto
|
||||||
void ctrNandInit(void)
|
void ctrNandInit(void)
|
||||||
{
|
{
|
||||||
u8 cid[0x10];
|
u8 __attribute__((aligned(4))) cid[0x10];
|
||||||
u8 shaSum[0x20];
|
u8 __attribute__((aligned(4))) shaSum[0x20];
|
||||||
|
|
||||||
sdmmc_get_cid(1, (u32 *)cid);
|
sdmmc_get_cid(1, (u32 *)cid);
|
||||||
sha(shaSum, cid, 0x10, SHA_256_MODE);
|
sha(shaSum, cid, 0x10, SHA_256_MODE);
|
||||||
memcpy(nandCTR, shaSum, 0x10);
|
memcpy(nandCTR, shaSum, 0x10);
|
||||||
|
|
||||||
if(console)
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
u8 __attribute__((aligned(4))) keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
||||||
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
nandSlot = 0x05;
|
nandSlot = 0x05;
|
||||||
fatStart = 0x5CAD7;
|
fatStart = 0x5CAD7;
|
||||||
}
|
}
|
||||||
@@ -306,13 +327,13 @@ void ctrNandInit(void)
|
|||||||
//Read and decrypt from the selected CTRNAND
|
//Read and decrypt from the selected CTRNAND
|
||||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||||
{
|
{
|
||||||
u8 tmpCTR[0x10];
|
u8 __attribute__((aligned(4))) tmpCTR[0x10];
|
||||||
memcpy(tmpCTR, nandCTR, 0x10);
|
memcpy(tmpCTR, nandCTR, 0x10);
|
||||||
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
//Read
|
//Read
|
||||||
u32 result;
|
u32 result;
|
||||||
if(!firmSource)
|
if(firmSource == FIRMWARE_SYSNAND)
|
||||||
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
|
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -327,6 +348,24 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
|
||||||
|
void setRSAMod0DerivedKeys(void)
|
||||||
|
{
|
||||||
|
if(!isDevUnit)
|
||||||
|
{
|
||||||
|
const u8 __attribute__((aligned(4))) keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
|
||||||
|
const u8 __attribute__((aligned(4))) keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
|
||||||
|
|
||||||
|
aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
/* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function,
|
||||||
|
when non-zero it clears this block and continues to do the key generation.
|
||||||
|
Otherwise when this block was already all-zero, it immediately returns. */
|
||||||
|
memset32((void *)0x01FFCD00, 0, 0x10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Decrypt a FIRM ExeFS
|
//Decrypt a FIRM ExeFS
|
||||||
void decryptExeFs(u8 *inbuf)
|
void decryptExeFs(u8 *inbuf)
|
||||||
{
|
{
|
||||||
@@ -344,13 +383,29 @@ void decryptExeFs(u8 *inbuf)
|
|||||||
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ARM9Loader replacement
|
/* ARM9Loader replacement
|
||||||
void arm9Loader(u8 *arm9Section, u32 mode)
|
Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 */
|
||||||
|
void arm9Loader(u8 *arm9Section)
|
||||||
{
|
{
|
||||||
|
//Determine the arm9loader version
|
||||||
|
u32 a9lVersion;
|
||||||
|
switch(arm9Section[0x53])
|
||||||
|
{
|
||||||
|
case 0xFF:
|
||||||
|
a9lVersion = 0;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
a9lVersion = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
a9lVersion = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Firm keys
|
//Firm keys
|
||||||
u8 keyY[0x10],
|
u8 __attribute__((aligned(4))) keyY[0x10];
|
||||||
arm9BinCTR[0x10],
|
u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
|
||||||
arm9BinSlot = mode ? 0x16 : 0x15;
|
u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
|
||||||
|
|
||||||
//Setup keys needed for arm9bin decryption
|
//Setup keys needed for arm9bin decryption
|
||||||
memcpy(keyY, arm9Section + 0x10, 0x10);
|
memcpy(keyY, arm9Section + 0x10, 0x10);
|
||||||
@@ -362,13 +417,18 @@ void arm9Loader(u8 *arm9Section, u32 mode)
|
|||||||
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
||||||
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
|
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
|
||||||
|
|
||||||
if(mode)
|
if(a9lVersion)
|
||||||
{
|
{
|
||||||
const u8 key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
|
u8 __attribute__((aligned(4))) keyX[0x10];
|
||||||
key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
|
||||||
u8 keyX[0x10];
|
if(!isDevUnit)
|
||||||
|
{
|
||||||
|
const u8 __attribute__((aligned(4))) key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8};
|
||||||
|
const u8 __attribute__((aligned(4))) key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||||
|
|
||||||
|
aes_setkey(0x11, a9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
aes_setkey(0x11, mode == 1 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
@@ -382,18 +442,29 @@ void arm9Loader(u8 *arm9Section, u32 mode)
|
|||||||
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
//Set >=9.6 KeyXs
|
//Set >=9.6 KeyXs
|
||||||
if(mode == 1)
|
if(a9lVersion == 2 && !isDevUnit)
|
||||||
{
|
{
|
||||||
u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98},
|
u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
|
||||||
decKey[0x10];
|
u8 __attribute__((aligned(4))) decKey[0x10];
|
||||||
|
|
||||||
//Set keys 0x19..0x1F keyXs
|
//Set keys 0x19..0x1F keyXs
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
for(u8 slot = 0x19; slot < 0x20; slot++)
|
for(u8 slot = 0x19; slot < 0x20; slot++, keyData[0xF]++)
|
||||||
{
|
{
|
||||||
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
keyData[0xF] += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void computePINHash(u8 out[32], u8 *in, u32 blockCount)
|
||||||
|
{
|
||||||
|
u8 __attribute__((aligned(4))) cid[0x10];
|
||||||
|
u8 __attribute__((aligned(4))) cipherText[0x10];
|
||||||
|
sdmmc_get_cid(1, (u32 *)cid);
|
||||||
|
|
||||||
|
aes_use_keyslot(4); // console-unique keyslot which keys are set by the Arm9 bootROM
|
||||||
|
aes(cipherText, in, blockCount, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
sha(out, cipherText, 0x10, SHA_256_MODE);
|
||||||
}
|
}
|
||||||
144
source/crypto.h
144
source/crypto.h
@@ -1,6 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
* crypto.h
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Crypto libs from http://github.com/b1l1s/ctr
|
* Crypto libs from http://github.com/b1l1s/ctr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -9,79 +29,85 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
/**************************AES****************************/
|
/**************************AES****************************/
|
||||||
#define REG_AESCNT ((vu32 *)0x10009000)
|
#define REG_AESCNT ((vu32 *)0x10009000)
|
||||||
#define REG_AESBLKCNT ((vu32 *)0x10009004)
|
#define REG_AESBLKCNT ((vu32 *)0x10009004)
|
||||||
#define REG_AESWRFIFO ((vu32 *)0x10009008)
|
#define REG_AESWRFIFO ((vu32 *)0x10009008)
|
||||||
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
|
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
|
||||||
#define REG_AESKEYSEL ((vu8 *)0x10009010)
|
#define REG_AESKEYSEL ((vu8 *)0x10009010)
|
||||||
#define REG_AESKEYCNT ((vu8 *)0x10009011)
|
#define REG_AESKEYCNT ((vu8 *)0x10009011)
|
||||||
#define REG_AESCTR ((vu32 *)0x10009020)
|
#define REG_AESCTR ((vu32 *)0x10009020)
|
||||||
|
|
||||||
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
|
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
|
||||||
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
|
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
|
||||||
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
|
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
|
||||||
|
|
||||||
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
||||||
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
||||||
#define AES_CTR_MODE (2u << 27)
|
#define AES_CTR_MODE (2u << 27)
|
||||||
#define AES_CTR_MODE (2u << 27)
|
#define AES_CTR_MODE (2u << 27)
|
||||||
#define AES_CBC_DECRYPT_MODE (4u << 27)
|
#define AES_CBC_DECRYPT_MODE (4u << 27)
|
||||||
#define AES_CBC_ENCRYPT_MODE (5u << 27)
|
#define AES_CBC_ENCRYPT_MODE (5u << 27)
|
||||||
#define AES_ECB_DECRYPT_MODE (6u << 27)
|
#define AES_ECB_DECRYPT_MODE (6u << 27)
|
||||||
#define AES_ECB_ENCRYPT_MODE (7u << 27)
|
#define AES_ECB_ENCRYPT_MODE (7u << 27)
|
||||||
#define AES_ALL_MODES (7u << 27)
|
#define AES_ALL_MODES (7u << 27)
|
||||||
|
|
||||||
#define AES_CNT_START 0x80000000
|
#define AES_CNT_START 0x80000000
|
||||||
#define AES_CNT_INPUT_ORDER 0x02000000
|
#define AES_CNT_INPUT_ORDER 0x02000000
|
||||||
#define AES_CNT_OUTPUT_ORDER 0x01000000
|
#define AES_CNT_OUTPUT_ORDER 0x01000000
|
||||||
#define AES_CNT_INPUT_ENDIAN 0x00800000
|
#define AES_CNT_INPUT_ENDIAN 0x00800000
|
||||||
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
|
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
|
||||||
#define AES_CNT_FLUSH_READ 0x00000800
|
#define AES_CNT_FLUSH_READ 0x00000800
|
||||||
#define AES_CNT_FLUSH_WRITE 0x00000400
|
#define AES_CNT_FLUSH_WRITE 0x00000400
|
||||||
|
|
||||||
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
|
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
|
||||||
#define AES_INPUT_LE 0
|
#define AES_INPUT_LE 0
|
||||||
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
|
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
|
||||||
#define AES_INPUT_REVERSED 0
|
#define AES_INPUT_REVERSED 0
|
||||||
|
|
||||||
#define AES_BLOCK_SIZE 0x10
|
#define AES_BLOCK_SIZE 0x10
|
||||||
|
|
||||||
#define AES_KEYCNT_WRITE (1 << 0x7)
|
#define AES_KEYCNT_WRITE (1 << 0x7)
|
||||||
#define AES_KEYNORMAL 0
|
#define AES_KEYNORMAL 0
|
||||||
#define AES_KEYX 1
|
#define AES_KEYX 1
|
||||||
#define AES_KEYY 2
|
#define AES_KEYY 2
|
||||||
|
|
||||||
/**************************SHA****************************/
|
/**************************SHA****************************/
|
||||||
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
||||||
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
||||||
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
||||||
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
||||||
|
|
||||||
#define SHA_CNT_STATE 0x00000003
|
#define SHA_CNT_STATE 0x00000003
|
||||||
#define SHA_CNT_UNK2 0x00000004
|
#define SHA_CNT_UNK2 0x00000004
|
||||||
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
||||||
#define SHA_CNT_MODE 0x00000030
|
#define SHA_CNT_MODE 0x00000030
|
||||||
#define SHA_CNT_ENABLE 0x00010000
|
#define SHA_CNT_ENABLE 0x00010000
|
||||||
#define SHA_CNT_ACTIVE 0x00020000
|
#define SHA_CNT_ACTIVE 0x00020000
|
||||||
|
|
||||||
#define SHA_HASH_READY 0x00000000
|
#define SHA_HASH_READY 0x00000000
|
||||||
#define SHA_NORMAL_ROUND 0x00000001
|
#define SHA_NORMAL_ROUND 0x00000001
|
||||||
#define SHA_FINAL_ROUND 0x00000002
|
#define SHA_FINAL_ROUND 0x00000002
|
||||||
|
|
||||||
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
||||||
#define SHA_OUTPUT_LE 0
|
#define SHA_OUTPUT_LE 0
|
||||||
|
|
||||||
#define SHA_256_MODE 0
|
#define SHA_256_MODE 0
|
||||||
#define SHA_224_MODE 0x00000010
|
#define SHA_224_MODE 0x00000010
|
||||||
#define SHA_1_MODE 0x00000020
|
#define SHA_1_MODE 0x00000020
|
||||||
|
|
||||||
#define SHA_256_HASH_SIZE (256 / 8)
|
#define SHA_256_HASH_SIZE (256 / 8)
|
||||||
#define SHA_224_HASH_SIZE (224 / 8)
|
#define SHA_224_HASH_SIZE (224 / 8)
|
||||||
#define SHA_1_HASH_SIZE (160 / 8)
|
#define SHA_1_HASH_SIZE (160 / 8)
|
||||||
|
|
||||||
extern u32 emuOffset, console, firmSource;
|
extern u32 emuOffset;
|
||||||
|
extern bool isN3DS;
|
||||||
|
extern bool isDevUnit;
|
||||||
|
extern FirmwareSource firmSource;
|
||||||
|
|
||||||
void ctrNandInit(void);
|
void ctrNandInit(void);
|
||||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||||
|
void setRSAMod0DerivedKeys(void);
|
||||||
void decryptExeFs(u8 *inbuf);
|
void decryptExeFs(u8 *inbuf);
|
||||||
void arm9Loader(u8 *arm9Section, u32 mode);
|
void arm9Loader(u8 *arm9Section);
|
||||||
|
|
||||||
|
void computePINHash(u8 out[32], u8 *in, u32 blockCount);
|
||||||
@@ -1,22 +1,36 @@
|
|||||||
/*
|
/*
|
||||||
* draw.c
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Code to print to the screen by mid-kid @CakesFW
|
* Code to print to the screen by mid-kid @CakesFW
|
||||||
|
* https://github.com/mid-kid/CakesForeveryWan/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "screeninit.h"
|
#include "screen.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "memory.h"
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
static const struct fb {
|
|
||||||
u8 *top_left;
|
|
||||||
u8 *top_right;
|
|
||||||
u8 *bottom;
|
|
||||||
} *const fb = (struct fb *)0x23FFFE00;
|
|
||||||
|
|
||||||
static inline int strlen(const char *string)
|
static inline int strlen(const char *string)
|
||||||
{
|
{
|
||||||
char *stringEnd = (char *)string;
|
char *stringEnd = (char *)string;
|
||||||
@@ -26,22 +40,20 @@ static inline int strlen(const char *string)
|
|||||||
return stringEnd - string;
|
return stringEnd - string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearScreens(void)
|
bool loadSplash(void)
|
||||||
{
|
|
||||||
memset32(fb->top_left, 0, 0x46500);
|
|
||||||
memset32(fb->top_right, 0, 0x46500);
|
|
||||||
memset32(fb->bottom, 0, 0x38400);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 loadSplash(void)
|
|
||||||
{
|
{
|
||||||
|
//Don't delay boot nor init the screens if no splash image is on the SD
|
||||||
|
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splashbottom.bin") == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
//Don't delay boot if no splash image is on the SD
|
fileRead(fb->top_left, "/luma/splash.bin");
|
||||||
if(fileRead(fb->top_left, "/luma/splash.bin") +
|
fileRead(fb->bottom, "/luma/splashbottom.bin");
|
||||||
fileRead(fb->bottom, "/luma/splashbottom.bin"))
|
|
||||||
return 1;
|
chrono(3);
|
||||||
return 0;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCharacter(char character, int posX, int posY, u32 color)
|
void drawCharacter(char character, int posX, int posY, u32 color)
|
||||||
@@ -86,4 +98,4 @@ int drawString(const char *string, int posX, int posY, u32 color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return posY;
|
return posY;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
* draw.h
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Code to print to the screen by mid-kid @CakesFW
|
* Code to print to the screen by mid-kid @CakesFW
|
||||||
|
* https://github.com/mid-kid/CakesForeveryWan/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -19,7 +40,6 @@
|
|||||||
#define COLOR_RED 0x0000FF
|
#define COLOR_RED 0x0000FF
|
||||||
#define COLOR_BLACK 0x000000
|
#define COLOR_BLACK 0x000000
|
||||||
|
|
||||||
u32 loadSplash(void);
|
bool loadSplash(void);
|
||||||
void clearScreens(void);
|
|
||||||
void drawCharacter(char character, int posX, int posY, u32 color);
|
void drawCharacter(char character, int posX, int posY, u32 color);
|
||||||
int drawString(const char *string, int posX, int posY, u32 color);
|
int drawString(const char *string, int posX, int posY, u32 color);
|
||||||
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* emunand.c
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
@@ -7,12 +25,12 @@
|
|||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
#include "../build/emunandpatch.h"
|
#include "../build/emunandpatch.h"
|
||||||
|
|
||||||
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND)
|
void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND)
|
||||||
{
|
{
|
||||||
static u8 *const temp = (u8 *)0x24300000;
|
static u8 temp[0x200];
|
||||||
|
|
||||||
const u32 nandSize = getMMCDevice(0)->total_size;
|
const u32 nandSize = getMMCDevice(0)->total_size;
|
||||||
u32 nandOffset = *emuNAND == 1 ? 0 :
|
u32 nandOffset = *emuNAND == FIRMWARE_EMUNAND ? 0 :
|
||||||
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
||||||
|
|
||||||
//Check for RedNAND
|
//Check for RedNAND
|
||||||
@@ -35,7 +53,7 @@ void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND)
|
|||||||
or to SysNAND if there isn't any */
|
or to SysNAND if there isn't any */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(*emuNAND)--;
|
*emuNAND = (*emuNAND == FIRMWARE_EMUNAND2) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||||
if(*emuNAND) locateEmuNAND(off, head, emuNAND);
|
if(*emuNAND) locateEmuNAND(off, head, emuNAND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* emunand.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -8,5 +26,5 @@
|
|||||||
|
|
||||||
#define NCSD_MAGIC 0x4453434E
|
#define NCSD_MAGIC 0x4453434E
|
||||||
|
|
||||||
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND);
|
void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND);
|
||||||
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);
|
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);
|
||||||
21
source/fatfs/00history.txt
Normal file → Executable file
21
source/fatfs/00history.txt
Normal file → Executable file
@@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
|
|||||||
|
|
||||||
R0.01 (April 29, 2006)
|
R0.01 (April 29, 2006)
|
||||||
|
|
||||||
First stable version.
|
The first release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -246,9 +246,22 @@ R0.11a (September 05, 2015)
|
|||||||
|
|
||||||
R0.12 (April 12, 2016)
|
R0.12 (April 12, 2016)
|
||||||
|
|
||||||
Added support of exFAT file system. (_FS_EXFAT)
|
Added support for exFAT file system. (_FS_EXFAT)
|
||||||
Added f_expand(). (_USE_EXPAND)
|
Added f_expand(). (_USE_EXPAND)
|
||||||
Changed some members in FINFO structure and behavior of f_readdir().
|
Changed some members in FINFO structure and behavior of f_readdir().
|
||||||
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
|
Added an option _USE_CHMOD.
|
||||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
Removed an option _WORD_ACCESS.
|
||||||
|
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12a (July 10, 2016)
|
||||||
|
|
||||||
|
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||||
|
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||||
|
f_forward() is available regardless of _FS_TINY.
|
||||||
|
Fixed f_mkfs() creates wrong volume.
|
||||||
|
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||||
|
Fixed wrong memory read in create_name().
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
source/fatfs/00readme.txt
Normal file → Executable file
2
source/fatfs/00readme.txt
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
FatFs Module Source Files R0.12
|
FatFs Module Source Files R0.12a
|
||||||
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
|
|||||||
1500
source/fatfs/ff.c
Normal file → Executable file
1500
source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
102
source/fatfs/ff.h
Normal file → Executable file
102
source/fatfs/ff.h
Normal file → Executable file
@@ -1,11 +1,13 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*----------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
|
/ FatFs - Generic FAT file system module R0.12a /
|
||||||
/----------------------------------------------------------------------------/
|
/-----------------------------------------------------------------------------/
|
||||||
/ FatFs module is a free software that opened under license policy of
|
|
||||||
/ following conditions.
|
|
||||||
/
|
/
|
||||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
/ Copyright (C) 2016, ChaN, all right reserved.
|
||||||
/
|
/
|
||||||
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
|
/ that the following condition is met:
|
||||||
|
|
||||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||||
/ this condition and the following disclaimer.
|
/ this condition and the following disclaimer.
|
||||||
/
|
/
|
||||||
@@ -13,11 +15,11 @@
|
|||||||
/ and any warranties related to this software are DISCLAIMED.
|
/ and any warranties related to this software are DISCLAIMED.
|
||||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||||
/ by use of this software.
|
/ by use of this software.
|
||||||
/---------------------------------------------------------------------------*/
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FATFS
|
#ifndef _FATFS
|
||||||
#define _FATFS 88100 /* Revision ID */
|
#define _FATFS 80186 /* Revision ID */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -25,6 +27,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include "integer.h" /* Basic integer types */
|
#include "integer.h" /* Basic integer types */
|
||||||
#include "ffconf.h" /* FatFs configuration options */
|
#include "ffconf.h" /* FatFs configuration options */
|
||||||
|
|
||||||
#if _FATFS != _FFCONF
|
#if _FATFS != _FFCONF
|
||||||
#error Wrong configuration file (ffconf.h).
|
#error Wrong configuration file (ffconf.h).
|
||||||
#endif
|
#endif
|
||||||
@@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
|||||||
|
|
||||||
/* Type of path name strings on FatFs API */
|
/* Type of path name strings on FatFs API */
|
||||||
|
|
||||||
#if _LFN_UNICODE /* Unicode string */
|
#if _LFN_UNICODE /* Unicode (UTF-16) string */
|
||||||
#if _USE_LFN == 0
|
#if _USE_LFN == 0
|
||||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||||
#endif
|
#endif
|
||||||
@@ -61,14 +64,25 @@ typedef WCHAR TCHAR;
|
|||||||
#define _T(x) L ## x
|
#define _T(x) L ## x
|
||||||
#define _TEXT(x) L ## x
|
#define _TEXT(x) L ## x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* ANSI/OEM string */
|
#else /* ANSI/OEM string */
|
||||||
#ifndef _INC_TCHAR
|
#ifndef _INC_TCHAR
|
||||||
typedef char TCHAR;
|
typedef char TCHAR;
|
||||||
#define _T(x) x
|
#define _T(x) x
|
||||||
#define _TEXT(x) x
|
#define _TEXT(x) x
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type of file size variables */
|
||||||
|
|
||||||
|
#if _FS_EXFAT
|
||||||
|
#if _USE_LFN == 0
|
||||||
|
#error LFN must be enabled when enable exFAT
|
||||||
|
#endif
|
||||||
|
typedef QWORD FSIZE_t;
|
||||||
|
#else
|
||||||
|
typedef DWORD FSIZE_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -87,6 +101,9 @@ typedef struct {
|
|||||||
#if _MAX_SS != _MIN_SS
|
#if _MAX_SS != _MIN_SS
|
||||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||||
#endif
|
#endif
|
||||||
|
#if _USE_LFN != 0
|
||||||
|
WCHAR* lfnbuf; /* LFN working buffer */
|
||||||
|
#endif
|
||||||
#if _FS_EXFAT
|
#if _FS_EXFAT
|
||||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
||||||
#endif
|
#endif
|
||||||
@@ -117,19 +134,6 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Type of file size variables and object identifier */
|
|
||||||
|
|
||||||
#if _FS_EXFAT
|
|
||||||
#if _USE_LFN == 0
|
|
||||||
#error LFN must be enabled when enable exFAT
|
|
||||||
#endif
|
|
||||||
typedef QWORD FSIZE_t;
|
|
||||||
#else
|
|
||||||
typedef DWORD FSIZE_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Object ID and allocation information (_FDID) */
|
/* Object ID and allocation information (_FDID) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -159,14 +163,14 @@ typedef struct {
|
|||||||
BYTE flag; /* File status flags */
|
BYTE flag; /* File status flags */
|
||||||
BYTE err; /* Abort flag (error code) */
|
BYTE err; /* Abort flag (error code) */
|
||||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||||
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
|
DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
|
||||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||||
#if !_FS_READONLY
|
#if !_FS_READONLY
|
||||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||||
#endif
|
#endif
|
||||||
#if _USE_FASTSEEK
|
#if _USE_FASTSEEK
|
||||||
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||||
#endif
|
#endif
|
||||||
#if !_FS_TINY
|
#if !_FS_TINY
|
||||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||||
@@ -183,10 +187,9 @@ typedef struct {
|
|||||||
DWORD clust; /* Current cluster */
|
DWORD clust; /* Current cluster */
|
||||||
DWORD sect; /* Current sector */
|
DWORD sect; /* Current sector */
|
||||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||||
BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
|
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||||
#if _USE_LFN != 0
|
#if _USE_LFN != 0
|
||||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
|
||||||
#endif
|
#endif
|
||||||
#if _USE_FIND
|
#if _USE_FIND
|
||||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||||
@@ -229,7 +232,7 @@ typedef enum {
|
|||||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
@@ -244,11 +247,11 @@ typedef enum {
|
|||||||
|
|
||||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
|
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||||
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||||
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||||
@@ -258,8 +261,8 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
|||||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
|
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
|
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||||
@@ -269,8 +272,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
|||||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||||
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||||
@@ -323,40 +326,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
|||||||
/* Flags and offset address */
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
|
||||||
/* File access control and file status flags (FIL.flag) */
|
/* File access mode and open method flags (3rd argument of f_open) */
|
||||||
|
|
||||||
#define FA_READ 0x01
|
#define FA_READ 0x01
|
||||||
#define FA_WRITE 0x02
|
#define FA_WRITE 0x02
|
||||||
#define FA_OPEN_EXISTING 0x00
|
#define FA_OPEN_EXISTING 0x00
|
||||||
#define FA_CREATE_NEW 0x04
|
#define FA_CREATE_NEW 0x04
|
||||||
#define FA_CREATE_ALWAYS 0x08
|
#define FA_CREATE_ALWAYS 0x08
|
||||||
#define FA_OPEN_ALWAYS 0x10
|
#define FA_OPEN_ALWAYS 0x10
|
||||||
#define _FA_MODIFIED 0x20
|
#define FA_OPEN_APPEND 0x30
|
||||||
#define _FA_DIRTY 0x40
|
|
||||||
|
|
||||||
|
/* Fast seek controls (2nd argument of f_lseek) */
|
||||||
|
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||||
|
|
||||||
/* FAT sub type (FATFS.fs_type) */
|
/* Format options (2nd argument of f_mkfs) */
|
||||||
|
#define FM_FAT 0x01
|
||||||
|
#define FM_FAT32 0x02
|
||||||
|
#define FM_EXFAT 0x04
|
||||||
|
#define FM_ANY 0x07
|
||||||
|
#define FM_SFD 0x08
|
||||||
|
|
||||||
|
/* Filesystem type (FATFS.fs_type) */
|
||||||
#define FS_FAT12 1
|
#define FS_FAT12 1
|
||||||
#define FS_FAT16 2
|
#define FS_FAT16 2
|
||||||
#define FS_FAT32 3
|
#define FS_FAT32 3
|
||||||
#define FS_EXFAT 4
|
#define FS_EXFAT 4
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||||
/* File attribute bits for directory entry */
|
|
||||||
|
|
||||||
#define AM_RDO 0x01 /* Read only */
|
#define AM_RDO 0x01 /* Read only */
|
||||||
#define AM_HID 0x02 /* Hidden */
|
#define AM_HID 0x02 /* Hidden */
|
||||||
#define AM_SYS 0x04 /* System */
|
#define AM_SYS 0x04 /* System */
|
||||||
#define AM_VOL 0x08 /* Volume label */
|
|
||||||
#define AM_LFN 0x0F /* LFN entry */
|
|
||||||
#define AM_DIR 0x10 /* Directory */
|
#define AM_DIR 0x10 /* Directory */
|
||||||
#define AM_ARC 0x20 /* Archive */
|
#define AM_ARC 0x20 /* Archive */
|
||||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
|
||||||
|
|
||||||
|
|
||||||
/* Fast seek controls */
|
|
||||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
17
source/fatfs/ffconf.h
Normal file → Executable file
17
source/fatfs/ffconf.h
Normal file → Executable file
@@ -1,8 +1,8 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
|
/ FatFs - FAT file system module configuration file
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _FFCONF 88100 /* Revision ID */
|
#define _FFCONF 80186 /* Revision ID */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ Function Configurations
|
/ Function Configurations
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
/ and optional writing functions as well. */
|
/ and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_MINIMIZE 1
|
#define _FS_MINIMIZE 0
|
||||||
/* This option defines minimization level to remove some basic API functions.
|
/* This option defines minimization level to remove some basic API functions.
|
||||||
/
|
/
|
||||||
/ 0: All basic functions are enabled.
|
/ 0: All basic functions are enabled.
|
||||||
@@ -62,8 +62,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _USE_FORWARD 0
|
#define _USE_FORWARD 0
|
||||||
/* This option switches f_forward() function. (0:Disable or 1:Enable)
|
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||||
/ To enable it, also _FS_TINY need to be 1. */
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
@@ -118,13 +117,13 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _LFN_UNICODE 0
|
#define _LFN_UNICODE 0
|
||||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
|
||||||
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
||||||
/ This option also affects behavior of string I/O functions. */
|
/ This option also affects behavior of string I/O functions. */
|
||||||
|
|
||||||
|
|
||||||
#define _STRF_ENCODE 3
|
#define _STRF_ENCODE 3
|
||||||
/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to
|
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
|
||||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||||
/
|
/
|
||||||
/ 0: ANSI/OEM
|
/ 0: ANSI/OEM
|
||||||
@@ -153,7 +152,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _STR_VOLUME_ID 0
|
#define _STR_VOLUME_ID 0
|
||||||
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||||
@@ -217,7 +216,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _FS_NORTC 1
|
#define _FS_NORTC 1
|
||||||
#define _NORTC_MON 3
|
#define _NORTC_MON 1
|
||||||
#define _NORTC_MDAY 1
|
#define _NORTC_MDAY 1
|
||||||
#define _NORTC_YEAR 2016
|
#define _NORTC_YEAR 2016
|
||||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||||
|
|||||||
0
source/fatfs/integer.h
Normal file → Executable file
0
source/fatfs/integer.h
Normal file → Executable file
0
source/fatfs/option/ccsbcs.c
Normal file → Executable file
0
source/fatfs/option/ccsbcs.c
Normal file → Executable file
407
source/firm.c
407
source/firm.c
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* firm.c
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
@@ -8,35 +26,43 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "cache.h"
|
||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "screeninit.h"
|
#include "screen.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
#include "pin.h"
|
||||||
#include "../build/injector.h"
|
#include "../build/injector.h"
|
||||||
|
|
||||||
|
extern u16 launchedFirmTIDLow[8]; //defined in start.s
|
||||||
|
|
||||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
static firmHeader *const firm = (firmHeader *)0x24000000;
|
||||||
static const firmSectionHeader *section;
|
static const firmSectionHeader *section;
|
||||||
|
|
||||||
u32 config,
|
u32 config,
|
||||||
console,
|
|
||||||
firmSource,
|
|
||||||
emuOffset;
|
emuOffset;
|
||||||
|
|
||||||
|
bool isN3DS, isDevUnit, isFirmlaunch;
|
||||||
|
|
||||||
|
FirmwareSource firmSource;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
u32 bootType,
|
bool isA9lh;
|
||||||
firmType,
|
|
||||||
nandType,
|
u32 newConfig,
|
||||||
a9lhMode,
|
emuHeader;
|
||||||
updatedSys,
|
|
||||||
needConfig,
|
FirmwareType firmType;
|
||||||
newConfig,
|
FirmwareSource nandType;
|
||||||
emuHeader,
|
ConfigurationStatus needConfig;
|
||||||
chronoStarted = 0;
|
|
||||||
|
|
||||||
//Detect the console being used
|
//Detect the console being used
|
||||||
console = PDN_MPCORE_CFG == 7;
|
isN3DS = PDN_MPCORE_CFG == 7;
|
||||||
|
|
||||||
|
//Detect dev units
|
||||||
|
isDevUnit = CFG_UNITINFO != 0;
|
||||||
|
|
||||||
//Mount filesystems. CTRNAND will be mounted only if/when needed
|
//Mount filesystems. CTRNAND will be mounted only if/when needed
|
||||||
mountFs();
|
mountFs();
|
||||||
@@ -44,153 +70,140 @@ void main(void)
|
|||||||
const char configPath[] = "/luma/config.bin";
|
const char configPath[] = "/luma/config.bin";
|
||||||
|
|
||||||
//Attempt to read the configuration file
|
//Attempt to read the configuration file
|
||||||
needConfig = fileRead(&config, configPath) ? 1 : 2;
|
needConfig = fileRead(&config, configPath) ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
|
||||||
|
|
||||||
//Determine if this is a firmlaunch boot
|
//Determine if this is a firmlaunch boot
|
||||||
if(*(vu8 *)0x23F00005)
|
if(launchedFirmTIDLow[5] != 0)
|
||||||
{
|
{
|
||||||
if(needConfig == 2) mcuReboot();
|
if(needConfig == CREATE_CONFIGURATION) mcuReboot();
|
||||||
|
|
||||||
bootType = 1;
|
isFirmlaunch = true;
|
||||||
|
|
||||||
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
|
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
|
||||||
firmType = *(vu8 *)0x23F00009 == '3' ? 3 : *(vu8 *)0x23F00005 - '0';
|
firmType = launchedFirmTIDLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTIDLow[5] - u'0');
|
||||||
|
|
||||||
nandType = BOOTCONFIG(0, 3);
|
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
|
||||||
firmSource = BOOTCONFIG(2, 1);
|
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
|
||||||
a9lhMode = BOOTCONFIG(3, 1);
|
isA9lh = BOOTCONFIG(3, 1) != 0;
|
||||||
updatedSys = a9lhMode && CONFIG(1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Get pressed buttons
|
//Get pressed buttons
|
||||||
u32 pressed = HID_PAD;
|
u32 pressed = HID_PAD;
|
||||||
|
|
||||||
//If no configuration file exists or SELECT is held, load configuration menu
|
isFirmlaunch = false;
|
||||||
if(needConfig == 2 || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)))
|
firmType = NATIVE_FIRM;
|
||||||
{
|
|
||||||
configureCFW(configPath);
|
|
||||||
|
|
||||||
//Zero the last booted FIRM flag
|
|
||||||
CFG_BOOTENV = 0;
|
|
||||||
|
|
||||||
chronoStarted = 1;
|
|
||||||
chrono(0);
|
|
||||||
chrono(2);
|
|
||||||
|
|
||||||
//Update pressed buttons
|
|
||||||
pressed = HID_PAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
bootType = 0;
|
|
||||||
firmType = 0;
|
|
||||||
|
|
||||||
//Determine if booting with A9LH
|
//Determine if booting with A9LH
|
||||||
u32 a9lhBoot = !PDN_SPI_CNT;
|
isA9lh = !PDN_SPI_CNT;
|
||||||
|
|
||||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
||||||
if(a9lhBoot || CONFIG(2))
|
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
|
||||||
|
|
||||||
|
newConfig = (u32)isA9lh << 3;
|
||||||
|
|
||||||
|
//If it's a MCU reboot, try to force boot options
|
||||||
|
if(isA9lh && CFG_BOOTENV)
|
||||||
{
|
{
|
||||||
a9lhMode = 1;
|
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||||
updatedSys = CONFIG(1);
|
if(CFG_BOOTENV == 7)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a9lhMode = 0;
|
|
||||||
updatedSys = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
newConfig = a9lhMode << 3;
|
|
||||||
|
|
||||||
if(a9lhBoot)
|
|
||||||
{
|
|
||||||
//Retrieve the last booted FIRM
|
|
||||||
u32 previousFirm = CFG_BOOTENV;
|
|
||||||
|
|
||||||
//If it's a MCU reboot, try to force boot options
|
|
||||||
if(previousFirm)
|
|
||||||
{
|
{
|
||||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
nandType = FIRMWARE_SYSNAND;
|
||||||
if(previousFirm == 7)
|
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
|
||||||
{
|
needConfig = DONT_CONFIGURE;
|
||||||
nandType = 0;
|
|
||||||
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
|
|
||||||
needConfig = 0;
|
|
||||||
|
|
||||||
//Flag to prevent multiple boot options-forcing
|
//Flag to prevent multiple boot options-forcing
|
||||||
newConfig |= 1 << 4;
|
newConfig |= 1 << 4;
|
||||||
}
|
|
||||||
|
|
||||||
/* Else, force the last used boot options unless a button is pressed
|
|
||||||
or the no-forcing flag is set */
|
|
||||||
else if(!pressed && !BOOTCONFIG(4, 1))
|
|
||||||
{
|
|
||||||
nandType = BOOTCONFIG(0, 3);
|
|
||||||
firmSource = BOOTCONFIG(2, 1);
|
|
||||||
needConfig = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the SAFE MODE combo is held, force a sysNAND boot
|
/* Else, force the last used boot options unless a button is pressed
|
||||||
else if(pressed == SAFE_MODE)
|
or the no-forcing flag is set */
|
||||||
|
else if(!pressed && !BOOTCONFIG(4, 1))
|
||||||
{
|
{
|
||||||
a9lhMode = 2;
|
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
|
||||||
nandType = 0;
|
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
|
||||||
firmSource = 0;
|
needConfig = DONT_CONFIGURE;
|
||||||
needConfig = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Boot options aren't being forced
|
//Boot options aren't being forced
|
||||||
if(needConfig)
|
if(needConfig != DONT_CONFIGURE)
|
||||||
{
|
{
|
||||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
PINData pin;
|
||||||
chainload an external payload */
|
|
||||||
if((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
|
|
||||||
loadPayload(pressed);
|
|
||||||
|
|
||||||
//If screens are inited or the corresponding option is set, load splash screen
|
bool pinExists = CONFIG(7) && readPin(&pin);
|
||||||
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
|
|
||||||
|
//If we get here we should check the PIN (if it exists) in all cases
|
||||||
|
if(pinExists) verifyPin(&pin);
|
||||||
|
|
||||||
|
//If no configuration file exists or SELECT is held, load configuration menu
|
||||||
|
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
|
||||||
|
|
||||||
|
if(shouldLoadConfigurationMenu)
|
||||||
{
|
{
|
||||||
chronoStarted = 2;
|
configureCFW(configPath);
|
||||||
chrono(0);
|
|
||||||
|
if(!pinExists && CONFIG(7)) newPin();
|
||||||
|
|
||||||
|
chrono(2);
|
||||||
|
|
||||||
|
//Update pressed buttons
|
||||||
|
pressed = HID_PAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||||
if(pressed & BUTTON_R1)
|
|
||||||
{
|
{
|
||||||
nandType = updatedSys;
|
nandType = FIRMWARE_SYSNAND;
|
||||||
firmSource = !nandType;
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
|
||||||
with their own FIRM */
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nandType = CONFIG(0) != !(pressed & BUTTON_L1);
|
if(CONFIG(6) && loadSplash()) pressed = HID_PAD;
|
||||||
firmSource = nandType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||||
or vice-versa, boot the second emuNAND */
|
chainload an external payload (the PIN, if any, has been verified)*/
|
||||||
if(nandType && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = 2;
|
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
|
||||||
|
|
||||||
|
if(shouldLoadPayload) loadPayload(pressed);
|
||||||
|
|
||||||
|
if(!CONFIG(6)) loadSplash();
|
||||||
|
|
||||||
|
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||||
|
if(pressed & BUTTON_R1)
|
||||||
|
{
|
||||||
|
nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||||
|
firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||||
|
with their own FIRM */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||||
|
firmSource = nandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
||||||
|
or vice-versa, boot the second emuNAND */
|
||||||
|
if(nandType != FIRMWARE_SYSNAND && (CONFIG(2) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we need to boot emuNAND, make sure it exists
|
//If we need to boot emuNAND, make sure it exists
|
||||||
if(nandType)
|
if(nandType != FIRMWARE_SYSNAND)
|
||||||
{
|
{
|
||||||
locateEmuNAND(&emuOffset, &emuHeader, &nandType);
|
locateEmuNAND(&emuOffset, &emuHeader, &nandType);
|
||||||
if(!nandType) firmSource = 0;
|
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Same if we're using emuNAND as the FIRM source
|
//Same if we're using emuNAND as the FIRM source
|
||||||
else if(firmSource)
|
else if(firmSource != FIRMWARE_SYSNAND)
|
||||||
locateEmuNAND(&emuOffset, &emuHeader, &firmSource);
|
locateEmuNAND(&emuOffset, &emuHeader, &firmSource);
|
||||||
|
|
||||||
if(!bootType)
|
if(!isFirmlaunch)
|
||||||
{
|
{
|
||||||
newConfig |= nandType | (firmSource << 2);
|
newConfig |= (u32)nandType | ((u32)firmSource << 2);
|
||||||
|
|
||||||
/* If the boot configuration is different from previously, overwrite it.
|
/* If the boot 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 */
|
||||||
@@ -199,88 +212,64 @@ void main(void)
|
|||||||
//Preserve user settings (last 26 bits)
|
//Preserve user settings (last 26 bits)
|
||||||
newConfig |= config & 0xFFFFFFC0;
|
newConfig |= config & 0xFFFFFFC0;
|
||||||
|
|
||||||
fileWrite(&newConfig, configPath, 4);
|
if(!fileWrite(&newConfig, configPath, 4))
|
||||||
|
error("Error writing the configuration file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFirm(firmType, !firmType && updatedSys == !firmSource);
|
u32 firmVersion = loadFirm(firmType);
|
||||||
|
|
||||||
switch(firmType)
|
switch(firmType)
|
||||||
{
|
{
|
||||||
case 0:
|
case NATIVE_FIRM:
|
||||||
patchNativeFirm(nandType, emuHeader, a9lhMode);
|
patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case SAFE_FIRM:
|
||||||
patchSafeFirm();
|
patchSafeFirm();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
patchLegacyFirm(firmType);
|
//Skip patching on unsupported O3DS AGB/TWL FIRMs
|
||||||
|
if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chronoStarted)
|
launchFirm(firmType);
|
||||||
{
|
|
||||||
if(chronoStarted == 2) chrono(3);
|
|
||||||
stopChrono();
|
|
||||||
}
|
|
||||||
|
|
||||||
launchFirm(firmType, bootType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void loadFirm(u32 firmType, u32 externalFirm)
|
static inline u32 loadFirm(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
section = firm->section;
|
section = firm->section;
|
||||||
|
|
||||||
u32 externalFirmLoaded = externalFirm &&
|
//Load FIRM from CTRNAND, unless it's an O3DS and we're loading a pre-5.0 NATIVE FIRM
|
||||||
fileRead(firm, "/luma/firmware.bin") &&
|
u32 firmVersion = firmRead(firm, (u32)firmType);
|
||||||
(((u32)section[2].address >> 8) & 0xFF) == (console ? 0x60 : 0x68);
|
|
||||||
|
|
||||||
/* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM
|
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
|
||||||
doesn't match the console, load FIRM from CTRNAND */
|
|
||||||
if(!externalFirmLoaded)
|
|
||||||
{
|
{
|
||||||
const char *firmFolders[4][2] = {{ "00000002", "20000002" },
|
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
|
||||||
{ "00000102", "20000102" },
|
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
|
||||||
{ "00000202", "20000202" },
|
|
||||||
{ "00000003", "20000003" }};
|
|
||||||
|
|
||||||
firmRead(firm, firmFolders[firmType][console]);
|
//No assumption regarding FIRM version
|
||||||
decryptExeFs((u8 *)firm);
|
firmVersion = 0xffffffff;
|
||||||
}
|
}
|
||||||
|
else decryptExeFs((u8 *)firm);
|
||||||
|
|
||||||
|
return firmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
|
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;
|
||||||
|
|
||||||
u32 nativeFirmType;
|
if(isN3DS)
|
||||||
|
|
||||||
if(console)
|
|
||||||
{
|
{
|
||||||
//Determine the NATIVE_FIRM version
|
|
||||||
switch(arm9Section[0x53])
|
|
||||||
{
|
|
||||||
case 0xFF:
|
|
||||||
nativeFirmType = 0;
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
nativeFirmType = 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
nativeFirmType = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
arm9Loader(arm9Section, nativeFirmType);
|
arm9Loader(arm9Section);
|
||||||
firm->arm9Entry = (u8 *)0x801B01C;
|
firm->arm9Entry = (u8 *)0x801B01C;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
|
||||||
//Determine if we're booting the 9.0 FIRM
|
else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
|
||||||
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
|
|
||||||
nativeFirmType = memcmp(section[2].hash, firm90Hash, 0x10) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Find the Process9 .code location, size and memory address
|
//Find the Process9 .code location, size and memory address
|
||||||
u32 process9Size,
|
u32 process9Size,
|
||||||
@@ -291,48 +280,54 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
|
|||||||
patchSignatureChecks(process9Offset, process9Size);
|
patchSignatureChecks(process9Offset, process9Size);
|
||||||
|
|
||||||
//Apply emuNAND patches
|
//Apply emuNAND patches
|
||||||
if(nandType)
|
if(nandType != FIRMWARE_SYSNAND)
|
||||||
{
|
{
|
||||||
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
|
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
|
||||||
patchEmuNAND(arm9Section, section[2].size, process9Offset, process9Size, emuOffset, emuHeader, branchAdditive);
|
patchEmuNAND(arm9Section, section[2].size, process9Offset, process9Size, emuOffset, emuHeader, branchAdditive);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||||
else if(a9lhMode) patchFirmWrites(process9Offset, process9Size);
|
else if(isA9lh) patchFirmWrites(process9Offset, process9Size);
|
||||||
|
|
||||||
//Apply firmlaunch patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
//Apply firmlaunch patches
|
||||||
if(nativeFirmType || a9lhMode == 2) patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
||||||
|
|
||||||
if(nativeFirmType == 1)
|
//11.0 FIRM patches
|
||||||
|
if(firmVersion >= (isN3DS ? 0x21 : 0x52))
|
||||||
{
|
{
|
||||||
//Apply anti-anti-DG patches for >= 11.0 firmwares
|
//Apply anti-anti-DG patches
|
||||||
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
||||||
|
|
||||||
//Does nothing if svcBackdoor is still there
|
//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(u32 firmType)
|
static inline void patchLegacyFirm(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
if(isN3DS)
|
||||||
if(console)
|
|
||||||
{
|
{
|
||||||
arm9Loader((u8 *)firm + section[3].offset, 0);
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
|
arm9Loader((u8 *)firm + section[3].offset);
|
||||||
firm->arm9Entry = (u8 *)0x801301C;
|
firm->arm9Entry = (u8 *)0x801301C;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyLegacyFirmPatches((u8 *)firm, firmType, console);
|
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||||
|
|
||||||
|
if(firmType == TWL_FIRM)
|
||||||
|
patchTwlBg((u8 *)firm + section[1].offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchSafeFirm(void)
|
static inline void patchSafeFirm(void)
|
||||||
{
|
{
|
||||||
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
||||||
|
|
||||||
if(console)
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
arm9Loader(arm9Section, 0);
|
arm9Loader(arm9Section);
|
||||||
firm->arm9Entry = (u8 *)0x801B01C;
|
firm->arm9Entry = (u8 *)0x801B01C;
|
||||||
|
|
||||||
patchFirmWrites(arm9Section, section[2].size);
|
patchFirmWrites(arm9Section, section[2].size);
|
||||||
@@ -340,25 +335,56 @@ 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(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
||||||
|
|
||||||
u32 loaderSize;
|
struct
|
||||||
u32 loaderOffset = getLoader(arm11Section0, &loaderSize);
|
{
|
||||||
|
u32 size;
|
||||||
|
char name[8];
|
||||||
|
const u8 *addr;
|
||||||
|
} modules[5] = {{0}};
|
||||||
|
|
||||||
|
u8 *pos = arm11Section0, *end = pos + section[0].size;
|
||||||
|
u32 n = 0;
|
||||||
|
|
||||||
|
u32 loaderIndex = 0;
|
||||||
|
|
||||||
|
while(pos < end)
|
||||||
|
{
|
||||||
|
modules[n].addr = pos;
|
||||||
|
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
||||||
|
|
||||||
|
memcpy(modules[n].name, pos + 0x200, 8);
|
||||||
|
pos += modules[n].size;
|
||||||
|
|
||||||
|
if(firmType == NATIVE_FIRM && memcmp(modules[n].name, "loader", 7) == 0) loaderIndex = n;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(firmType == NATIVE_FIRM)
|
||||||
|
{
|
||||||
|
modules[loaderIndex].size = injector_size;
|
||||||
|
modules[loaderIndex].addr = injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = section[0].address;
|
||||||
|
for(u32 i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
memcpy(pos, modules[i].addr, modules[i].size);
|
||||||
|
pos += modules[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(section[0].address, arm11Section0, loaderOffset);
|
|
||||||
memcpy(section[0].address + loaderOffset, injector, injector_size);
|
|
||||||
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void launchFirm(u32 firmType, u32 bootType)
|
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)
|
if(firmType != SAFE_FIRM)
|
||||||
{
|
{
|
||||||
copySection0AndInjectLoader();
|
copySection0AndInjectSystemModules(firmType);
|
||||||
sectionNum = 1;
|
sectionNum = 1;
|
||||||
}
|
}
|
||||||
else sectionNum = 0;
|
else sectionNum = 0;
|
||||||
@@ -369,7 +395,7 @@ static inline void launchFirm(u32 firmType, u32 bootType)
|
|||||||
|
|
||||||
//Determine the ARM11 entry to use
|
//Determine the ARM11 entry to use
|
||||||
vu32 *arm11;
|
vu32 *arm11;
|
||||||
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
|
if(isFirmlaunch) arm11 = (u32 *)0x1FFFFFFC;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
deinitScreens();
|
deinitScreens();
|
||||||
@@ -379,6 +405,9 @@ static inline void launchFirm(u32 firmType, u32 bootType)
|
|||||||
//Set ARM11 kernel entrypoint
|
//Set ARM11 kernel entrypoint
|
||||||
*arm11 = (u32)firm->arm11Entry;
|
*arm11 = (u32)firm->arm11Entry;
|
||||||
|
|
||||||
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
flushEntireICache();
|
||||||
|
|
||||||
//Final jump to ARM9 kernel
|
//Final jump to ARM9 kernel
|
||||||
((void (*)())firm->arm9Entry)();
|
((void (*)())firm->arm9Entry)();
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,29 @@
|
|||||||
/*
|
/*
|
||||||
* firm.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
|
||||||
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
|
||||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
|
||||||
|
|
||||||
//FIRM Header layout
|
//FIRM Header layout
|
||||||
typedef struct firmSectionHeader {
|
typedef struct firmSectionHeader {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
@@ -28,9 +42,16 @@ typedef struct firmHeader {
|
|||||||
firmSectionHeader section[4];
|
firmSectionHeader section[4];
|
||||||
} firmHeader;
|
} firmHeader;
|
||||||
|
|
||||||
static inline void loadFirm(u32 firmType, u32 externalFirm);
|
typedef enum ConfigurationStatus
|
||||||
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode);
|
{
|
||||||
static inline void patchLegacyFirm(u32 firmType);
|
DONT_CONFIGURE = 0,
|
||||||
|
MODIFY_CONFIGURATION = 1,
|
||||||
|
CREATE_CONFIGURATION = 2
|
||||||
|
} ConfigurationStatus;
|
||||||
|
|
||||||
|
static inline u32 loadFirm(FirmwareType firmType);
|
||||||
|
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
||||||
|
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(FirmwareType firmType);
|
||||||
static inline void launchFirm(u32 sectionNum, u32 bootType);
|
static inline void launchFirm(FirmwareType firmType);
|
||||||
81
source/fs.c
81
source/fs.c
@@ -1,10 +1,29 @@
|
|||||||
/*
|
/*
|
||||||
* fs.c
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "screeninit.h"
|
#include "cache.h"
|
||||||
|
#include "screen.h"
|
||||||
#include "fatfs/ff.h"
|
#include "fatfs/ff.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "../build/loader.h"
|
#include "../build/loader.h"
|
||||||
@@ -12,12 +31,10 @@
|
|||||||
static FATFS sdFs,
|
static FATFS sdFs,
|
||||||
nandFs;
|
nandFs;
|
||||||
|
|
||||||
u32 mountFs(void)
|
void mountFs(void)
|
||||||
{
|
{
|
||||||
if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
|
f_mount(&sdFs, "0:", 1);
|
||||||
f_mount(&nandFs, "1:", 0);
|
f_mount(&nandFs, "1:", 0);
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileRead(void *dest, const char *path)
|
u32 fileRead(void *dest, const char *path)
|
||||||
@@ -29,7 +46,8 @@ u32 fileRead(void *dest, const char *path)
|
|||||||
{
|
{
|
||||||
unsigned int read;
|
unsigned int read;
|
||||||
size = f_size(&file);
|
size = f_size(&file);
|
||||||
f_read(&file, dest, size, &read);
|
if(dest != NULL)
|
||||||
|
f_read(&file, dest, size, &read);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
else size = 0;
|
else size = 0;
|
||||||
@@ -37,7 +55,12 @@ u32 fileRead(void *dest, const char *path)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileWrite(const void *buffer, const char *path, u32 size)
|
u32 getFileSize(const char *path)
|
||||||
|
{
|
||||||
|
return fileRead(NULL, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||||
{
|
{
|
||||||
FIL file;
|
FIL file;
|
||||||
|
|
||||||
@@ -46,7 +69,16 @@ void 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_close(&file);
|
f_close(&file);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createDirectory(const char *path)
|
||||||
|
{
|
||||||
|
f_mkdir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadPayload(u32 pressed)
|
void loadPayload(u32 pressed)
|
||||||
@@ -76,7 +108,7 @@ void loadPayload(u32 pressed)
|
|||||||
{
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
u32 *const loaderAddress = (u32 *)0x24FFFB00;
|
u32 *const loaderAddress = (u32 *)0x24FFFF00;
|
||||||
|
|
||||||
memcpy(loaderAddress, loader, loader_size);
|
memcpy(loaderAddress, loader, loader_size);
|
||||||
|
|
||||||
@@ -85,21 +117,29 @@ void loadPayload(u32 pressed)
|
|||||||
|
|
||||||
loaderAddress[1] = fileRead((void *)0x24F00000, path);
|
loaderAddress[1] = fileRead((void *)0x24F00000, path);
|
||||||
|
|
||||||
|
flushDCacheRange(loaderAddress, loader_size);
|
||||||
|
flushICacheRange(loaderAddress, loader_size);
|
||||||
|
|
||||||
((void (*)())loaderAddress)();
|
((void (*)())loaderAddress)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void firmRead(void *dest, const char *firmFolder)
|
u32 firmRead(void *dest, u32 firmType)
|
||||||
{
|
{
|
||||||
|
const char *firmFolders[4][2] = {{ "00000002", "20000002" },
|
||||||
|
{ "00000102", "20000102" },
|
||||||
|
{ "00000202", "20000202" },
|
||||||
|
{ "00000003", "20000003" }};
|
||||||
|
|
||||||
char path[48] = "1:/title/00040138/00000000/content";
|
char path[48] = "1:/title/00040138/00000000/content";
|
||||||
memcpy(&path[18], firmFolder, 8);
|
memcpy(&path[18], firmFolders[firmType][isN3DS ? 1 : 0], 8);
|
||||||
|
|
||||||
DIR dir;
|
DIR dir;
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
|
|
||||||
f_opendir(&dir, path);
|
f_opendir(&dir, path);
|
||||||
|
|
||||||
u32 id = 0xFFFFFFFF;
|
u32 firmVersion = 0xFFFFFFFF;
|
||||||
|
|
||||||
//Parse the target directory
|
//Parse the target directory
|
||||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
|
while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
|
||||||
@@ -108,15 +148,15 @@ void firmRead(void *dest, const char *firmFolder)
|
|||||||
if(info.altname[9] != 'A') continue;
|
if(info.altname[9] != 'A') continue;
|
||||||
|
|
||||||
//Convert the .app name to an integer
|
//Convert the .app name to an integer
|
||||||
u32 tempId = 0;
|
u32 tempVersion = 0;
|
||||||
for(char *tmp = info.altname; *tmp != '.'; tmp++)
|
for(char *tmp = info.altname; *tmp != '.'; tmp++)
|
||||||
{
|
{
|
||||||
tempId <<= 4;
|
tempVersion <<= 4;
|
||||||
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
|
tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
//Found an older cxi
|
//Found an older cxi
|
||||||
if(tempId < id) id = tempId;
|
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
f_closedir(&dir);
|
f_closedir(&dir);
|
||||||
@@ -128,12 +168,15 @@ void firmRead(void *dest, const char *firmFolder)
|
|||||||
u32 i = 42;
|
u32 i = 42;
|
||||||
|
|
||||||
//Convert back the .app name from integer to array
|
//Convert back the .app name from integer to array
|
||||||
while(id)
|
u32 tempVersion = firmVersion;
|
||||||
|
while(tempVersion)
|
||||||
{
|
{
|
||||||
static const char hexDigits[] = "0123456789ABCDEF";
|
static const char hexDigits[] = "0123456789ABCDEF";
|
||||||
path[i--] = hexDigits[id & 0xF];
|
path[i--] = hexDigits[tempVersion & 0xF];
|
||||||
id >>= 4;
|
tempVersion >>= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileRead(dest, path);
|
fileRead(dest, path);
|
||||||
|
|
||||||
|
return firmVersion;
|
||||||
}
|
}
|
||||||
30
source/fs.h
30
source/fs.h
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* fs.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -8,8 +26,12 @@
|
|||||||
|
|
||||||
#define PATTERN(a) a "_*.bin"
|
#define PATTERN(a) a "_*.bin"
|
||||||
|
|
||||||
u32 mountFs(void);
|
extern bool isN3DS;
|
||||||
|
|
||||||
|
void mountFs(void);
|
||||||
u32 fileRead(void *dest, const char *path);
|
u32 fileRead(void *dest, const char *path);
|
||||||
void fileWrite(const void *buffer, const char *path, u32 size);
|
u32 getFileSize(const char *path);
|
||||||
|
bool fileWrite(const void *buffer, const char *path, u32 size);
|
||||||
|
void createDirectory(const char *path);
|
||||||
void loadPayload(u32 pressed);
|
void loadPayload(u32 pressed);
|
||||||
void firmRead(void *dest, const char *firmFolder);
|
u32 firmRead(void *dest, u32 firmType);
|
||||||
22
source/i2c.c
22
source/i2c.c
@@ -1,3 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
26
source/i2c.h
26
source/i2c.h
@@ -1,3 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thanks to the everyone who contributed in the development of this file
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
/*
|
/*
|
||||||
* memory.c
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
||||||
|
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
/*
|
/*
|
||||||
* memory.h
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
||||||
|
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
164
source/patches.c
164
source/patches.c
@@ -1,11 +1,72 @@
|
|||||||
/*
|
/*
|
||||||
* patches.c
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#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)
|
||||||
{
|
{
|
||||||
@@ -93,25 +154,65 @@ 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])
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern u32 config;
|
||||||
|
|
||||||
|
void implementSvcGetCFWInfo(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
u8 versionMajor;
|
||||||
|
u8 versionMinor;
|
||||||
|
u8 versionBuild;
|
||||||
|
u8 flags;
|
||||||
|
|
||||||
|
u32 commitHash;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CFWInfo;
|
||||||
|
|
||||||
|
const char *rev = REVISION;
|
||||||
|
bool isRelease = false;
|
||||||
|
|
||||||
|
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};
|
||||||
@@ -121,7 +222,7 @@ void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
|
|||||||
if(off != NULL) off[4] = 0xE0;
|
if(off != NULL) off[4] = 0xE0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
|
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
|
||||||
{
|
{
|
||||||
const patchData twlPatches[] = {
|
const patchData twlPatches[] = {
|
||||||
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||||
@@ -141,9 +242,9 @@ void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
|
|||||||
|
|
||||||
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
||||||
if the matching option was enabled (keep it as last) */
|
if the matching option was enabled (keep it as last) */
|
||||||
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) :
|
u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
|
||||||
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
|
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
|
||||||
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
|
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
|
||||||
|
|
||||||
//Patch
|
//Patch
|
||||||
for(u32 i = 0; i < numPatches; i++)
|
for(u32 i = 0; i < numPatches; i++)
|
||||||
@@ -151,30 +252,31 @@ void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
|
|||||||
switch(patches[i].type)
|
switch(patches[i].type)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
memcpy(pos + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
memcpy(pos + patches[i].offset[isN3DS ? 1 : 0], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
*(u16 *)(pos + patches[i].offset[console] + 2) = 0;
|
*(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0] + 2) = 0;
|
||||||
case 1:
|
case 1:
|
||||||
*(u16 *)(pos + patches[i].offset[console]) = patches[i].patch.type1;
|
*(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0]) = patches[i].patch.type1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(1)
|
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);
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* patches.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -15,6 +33,8 @@ typedef struct patchData {
|
|||||||
u32 type;
|
u32 type;
|
||||||
} patchData;
|
} patchData;
|
||||||
|
|
||||||
|
extern bool isN3DS;
|
||||||
|
|
||||||
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);
|
||||||
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
|
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
|
||||||
@@ -22,5 +42,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 applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console);
|
void implementSvcGetCFWInfo(u8 *pos, u32 size);
|
||||||
u32 getLoader(u8 *pos, u32 *loaderSize);
|
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
|
||||||
|
void patchTwlBg(u8 *pos);
|
||||||
166
source/pin.c
Normal file
166
source/pin.c
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pin.c
|
||||||
|
* Code to manage pin locking for 3ds. By reworks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "draw.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "buttons.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "pin.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
bool readPin(PINData *out)
|
||||||
|
{
|
||||||
|
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||||
|
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||||
|
|
||||||
|
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
|
||||||
|
if(memcmp(out->magic, "PINF", 4) != 0) return false;
|
||||||
|
|
||||||
|
computePINHash(tmp, zeroes, 1);
|
||||||
|
|
||||||
|
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char PINKeyToLetter(u32 pressed)
|
||||||
|
{
|
||||||
|
const char keys[] = "AB--------XY";
|
||||||
|
|
||||||
|
u32 i;
|
||||||
|
__asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
|
||||||
|
|
||||||
|
return keys[31 - i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void newPin(void)
|
||||||
|
{
|
||||||
|
clearScreens();
|
||||||
|
|
||||||
|
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
|
||||||
|
|
||||||
|
// Set the default value as 0x00 so we can check if there are any unentered characters.
|
||||||
|
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
|
||||||
|
|
||||||
|
u32 cnt = 0;
|
||||||
|
int charDrawPos = 20 * SPACING_X;
|
||||||
|
|
||||||
|
while(cnt < PIN_LENGTH)
|
||||||
|
{
|
||||||
|
u32 pressed;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pressed = waitInput();
|
||||||
|
}
|
||||||
|
while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
|
||||||
|
|
||||||
|
pressed &= PIN_BUTTONS & ~BUTTON_START;
|
||||||
|
|
||||||
|
if(!pressed) continue;
|
||||||
|
char key = PINKeyToLetter(pressed);
|
||||||
|
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||||
|
|
||||||
|
// visualize character on screen.
|
||||||
|
drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
|
||||||
|
charDrawPos += 2 * SPACING_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
PINData pin = {0};
|
||||||
|
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||||
|
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||||
|
|
||||||
|
memcpy(pin.magic, "PINF", 4);
|
||||||
|
pin.formatVersionMajor = 1;
|
||||||
|
pin.formatVersionMinor = 0;
|
||||||
|
|
||||||
|
computePINHash(tmp, zeroes, 1);
|
||||||
|
memcpy(pin.testHash, tmp, 32);
|
||||||
|
|
||||||
|
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
||||||
|
memcpy(pin.hash, tmp, 32);
|
||||||
|
|
||||||
|
fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
|
||||||
|
|
||||||
|
while(HID_PAD & PIN_BUTTONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifyPin(PINData *in)
|
||||||
|
{
|
||||||
|
initScreens();
|
||||||
|
|
||||||
|
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||||
|
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||||
|
|
||||||
|
// Set the default characters as 0x00 so we can check if there are any unentered characters.
|
||||||
|
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
|
||||||
|
|
||||||
|
u32 cnt = 0;
|
||||||
|
bool unlock = false;
|
||||||
|
int charDrawPos = 5 * SPACING_X;
|
||||||
|
|
||||||
|
while(!unlock)
|
||||||
|
{
|
||||||
|
u32 pressed;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pressed = waitInput();
|
||||||
|
}
|
||||||
|
while(!(pressed & PIN_BUTTONS));
|
||||||
|
|
||||||
|
if(pressed & BUTTON_START) mcuPowerOff();
|
||||||
|
|
||||||
|
pressed &= PIN_BUTTONS & ~BUTTON_START;
|
||||||
|
if(!pressed) continue;
|
||||||
|
|
||||||
|
char key = PINKeyToLetter(pressed);
|
||||||
|
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||||
|
|
||||||
|
// visualize character on screen.
|
||||||
|
drawCharacter(key, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||||
|
charDrawPos += 2 * SPACING_X;
|
||||||
|
|
||||||
|
if(cnt >= PIN_LENGTH)
|
||||||
|
{
|
||||||
|
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||||
|
|
||||||
|
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
||||||
|
unlock = memcmp(in->hash, tmp, 32) == 0;
|
||||||
|
|
||||||
|
if(!unlock)
|
||||||
|
{
|
||||||
|
charDrawPos = 5 * SPACING_X;
|
||||||
|
cnt = 0;
|
||||||
|
|
||||||
|
clearScreens();
|
||||||
|
|
||||||
|
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||||
|
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||||
|
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
source/pin.h
Normal file
46
source/pin.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pin.h
|
||||||
|
*
|
||||||
|
* Code to manage pin locking for 3ds. By reworks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#define PIN_LENGTH 4
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
u16 formatVersionMajor, formatVersionMinor;
|
||||||
|
|
||||||
|
u8 testHash[32];
|
||||||
|
u8 hash[32];
|
||||||
|
} PINData;
|
||||||
|
|
||||||
|
bool readPin(PINData* out);
|
||||||
|
void newPin(void);
|
||||||
|
void verifyPin(PINData *in);
|
||||||
259
source/screen.c
Normal file
259
source/screen.c
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
|
||||||
|
* Screen deinit code by tiniVi.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "cache.h"
|
||||||
|
#include "draw.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
vu32 *const arm11Entry = (vu32 *)0x1FFFFFF8;
|
||||||
|
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||||
|
|
||||||
|
void __attribute__((naked)) arm11Stub(void)
|
||||||
|
{
|
||||||
|
//Disable interrupts
|
||||||
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
|
//Wait for the entry to be set
|
||||||
|
while(*arm11Entry == ARM11_STUB_ADDRESS);
|
||||||
|
|
||||||
|
//Jump to it
|
||||||
|
((void (*)())*arm11Entry)();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invokeArm11Function(void (*func)())
|
||||||
|
{
|
||||||
|
static bool hasCopiedStub = false;
|
||||||
|
if(!hasCopiedStub)
|
||||||
|
{
|
||||||
|
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
|
||||||
|
flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x30);
|
||||||
|
hasCopiedStub = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*arm11Entry = (u32)func;
|
||||||
|
while(*arm11Entry);
|
||||||
|
*arm11Entry = ARM11_STUB_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinitScreens(void)
|
||||||
|
{
|
||||||
|
void __attribute__((naked)) ARM11(void)
|
||||||
|
{
|
||||||
|
//Disable interrupts
|
||||||
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
|
//Shutdown LCDs
|
||||||
|
*(vu32 *)0x10202A44 = 0;
|
||||||
|
*(vu32 *)0x10202244 = 0;
|
||||||
|
*(vu32 *)0x10202014 = 0;
|
||||||
|
|
||||||
|
WAIT_FOR_ARM9();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBrightness(u32 brightnessIndex)
|
||||||
|
{
|
||||||
|
static u32 brightnessLevel;
|
||||||
|
brightnessLevel = brightness[brightnessIndex];
|
||||||
|
|
||||||
|
void __attribute__((naked)) ARM11(void)
|
||||||
|
{
|
||||||
|
//Disable interrupts
|
||||||
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
|
//Change brightness
|
||||||
|
*(vu32 *)0x10202240 = brightnessLevel;
|
||||||
|
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||||
|
|
||||||
|
WAIT_FOR_ARM9();
|
||||||
|
}
|
||||||
|
|
||||||
|
flushDCacheRange(&brightnessLevel, 4);
|
||||||
|
invokeArm11Function(ARM11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearScreens(void)
|
||||||
|
{
|
||||||
|
void __attribute__((naked)) ARM11(void)
|
||||||
|
{
|
||||||
|
//Disable interrupts
|
||||||
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
|
//Setting up two simultaneous memory fills using the GPU
|
||||||
|
vu32 *REGs_PSC0 = (vu32 *)0x10400010;
|
||||||
|
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
|
||||||
|
REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address
|
||||||
|
REGs_PSC0[2] = 0; //Fill value
|
||||||
|
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||||
|
|
||||||
|
vu32 *REGs_PSC1 = (vu32 *)0x10400020;
|
||||||
|
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
|
||||||
|
REGs_PSC1[1] = (u32)(fb->bottom + 0x38400) >> 3; //End address
|
||||||
|
REGs_PSC1[2] = 0; //Fill value
|
||||||
|
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||||
|
|
||||||
|
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
|
||||||
|
|
||||||
|
if(fb->top_right != fb->top_left)
|
||||||
|
{
|
||||||
|
REGs_PSC0[0] = (u32)fb->top_right >> 3; //Start address
|
||||||
|
REGs_PSC0[1] = (u32)(fb->top_right + 0x46500) >> 3; //End address
|
||||||
|
REGs_PSC0[2] = 0; //Fill value
|
||||||
|
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||||
|
|
||||||
|
while(!(REGs_PSC0[3] & 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
WAIT_FOR_ARM9();
|
||||||
|
}
|
||||||
|
|
||||||
|
flushDCacheRange((void *)fb, sizeof(struct fb));
|
||||||
|
invokeArm11Function(ARM11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initScreens(void)
|
||||||
|
{
|
||||||
|
void __attribute__((naked)) ARM11(void)
|
||||||
|
{
|
||||||
|
//Disable interrupts
|
||||||
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
|
u32 brightnessLevel = brightness[MULTICONFIG(0)];
|
||||||
|
|
||||||
|
*(vu32 *)0x10141200 = 0x1007F;
|
||||||
|
*(vu32 *)0x10202014 = 0x00000001;
|
||||||
|
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||||
|
*(vu32 *)0x10202240 = brightnessLevel;
|
||||||
|
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||||
|
*(vu32 *)0x10202244 = 0x1023E;
|
||||||
|
*(vu32 *)0x10202A44 = 0x1023E;
|
||||||
|
|
||||||
|
// Top screen
|
||||||
|
*(vu32 *)0x10400400 = 0x000001c2;
|
||||||
|
*(vu32 *)0x10400404 = 0x000000d1;
|
||||||
|
*(vu32 *)0x10400408 = 0x000001c1;
|
||||||
|
*(vu32 *)0x1040040c = 0x000001c1;
|
||||||
|
*(vu32 *)0x10400410 = 0x00000000;
|
||||||
|
*(vu32 *)0x10400414 = 0x000000cf;
|
||||||
|
*(vu32 *)0x10400418 = 0x000000d1;
|
||||||
|
*(vu32 *)0x1040041c = 0x01c501c1;
|
||||||
|
*(vu32 *)0x10400420 = 0x00010000;
|
||||||
|
*(vu32 *)0x10400424 = 0x0000019d;
|
||||||
|
*(vu32 *)0x10400428 = 0x00000002;
|
||||||
|
*(vu32 *)0x1040042c = 0x00000192;
|
||||||
|
*(vu32 *)0x10400430 = 0x00000192;
|
||||||
|
*(vu32 *)0x10400434 = 0x00000192;
|
||||||
|
*(vu32 *)0x10400438 = 0x00000001;
|
||||||
|
*(vu32 *)0x1040043c = 0x00000002;
|
||||||
|
*(vu32 *)0x10400440 = 0x01960192;
|
||||||
|
*(vu32 *)0x10400444 = 0x00000000;
|
||||||
|
*(vu32 *)0x10400448 = 0x00000000;
|
||||||
|
*(vu32 *)0x1040045C = 0x00f00190;
|
||||||
|
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||||
|
*(vu32 *)0x10400464 = 0x01920002;
|
||||||
|
*(vu32 *)0x10400468 = 0x18300000;
|
||||||
|
*(vu32 *)0x10400470 = 0x80341;
|
||||||
|
*(vu32 *)0x10400474 = 0x00010501;
|
||||||
|
*(vu32 *)0x10400478 = 0;
|
||||||
|
*(vu32 *)0x10400490 = 0x000002D0;
|
||||||
|
*(vu32 *)0x1040049C = 0x00000000;
|
||||||
|
|
||||||
|
// Disco register
|
||||||
|
for(u32 i = 0; i < 256; i++)
|
||||||
|
*(vu32 *)0x10400484 = 0x10101 * i;
|
||||||
|
|
||||||
|
// Bottom screen
|
||||||
|
*(vu32 *)0x10400500 = 0x000001c2;
|
||||||
|
*(vu32 *)0x10400504 = 0x000000d1;
|
||||||
|
*(vu32 *)0x10400508 = 0x000001c1;
|
||||||
|
*(vu32 *)0x1040050c = 0x000001c1;
|
||||||
|
*(vu32 *)0x10400510 = 0x000000cd;
|
||||||
|
*(vu32 *)0x10400514 = 0x000000cf;
|
||||||
|
*(vu32 *)0x10400518 = 0x000000d1;
|
||||||
|
*(vu32 *)0x1040051c = 0x01c501c1;
|
||||||
|
*(vu32 *)0x10400520 = 0x00010000;
|
||||||
|
*(vu32 *)0x10400524 = 0x0000019d;
|
||||||
|
*(vu32 *)0x10400528 = 0x00000052;
|
||||||
|
*(vu32 *)0x1040052c = 0x00000192;
|
||||||
|
*(vu32 *)0x10400530 = 0x00000192;
|
||||||
|
*(vu32 *)0x10400534 = 0x0000004f;
|
||||||
|
*(vu32 *)0x10400538 = 0x00000050;
|
||||||
|
*(vu32 *)0x1040053c = 0x00000052;
|
||||||
|
*(vu32 *)0x10400540 = 0x01980194;
|
||||||
|
*(vu32 *)0x10400544 = 0x00000000;
|
||||||
|
*(vu32 *)0x10400548 = 0x00000011;
|
||||||
|
*(vu32 *)0x1040055C = 0x00f00140;
|
||||||
|
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||||
|
*(vu32 *)0x10400564 = 0x01920052;
|
||||||
|
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||||
|
*(vu32 *)0x10400570 = 0x80301;
|
||||||
|
*(vu32 *)0x10400574 = 0x00010501;
|
||||||
|
*(vu32 *)0x10400578 = 0;
|
||||||
|
*(vu32 *)0x10400590 = 0x000002D0;
|
||||||
|
*(vu32 *)0x1040059C = 0x00000000;
|
||||||
|
|
||||||
|
// Disco register
|
||||||
|
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;
|
||||||
|
|
||||||
|
//Set CakeBrah framebuffers
|
||||||
|
fb->top_left = (u8 *)0x18300000;
|
||||||
|
fb->top_right = (u8 *)0x18300000;
|
||||||
|
fb->bottom = (u8 *)0x18346500;
|
||||||
|
|
||||||
|
WAIT_FOR_ARM9();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(PDN_GPU_CNT == 1)
|
||||||
|
{
|
||||||
|
flushDCacheRange(&config, 4);
|
||||||
|
flushDCacheRange((void *)fb, sizeof(struct fb));
|
||||||
|
invokeArm11Function(ARM11);
|
||||||
|
|
||||||
|
clearScreens();
|
||||||
|
|
||||||
|
//Turn on backlight
|
||||||
|
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clearScreens();
|
||||||
|
updateBrightness(MULTICONFIG(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
44
source/screen.h
Normal file
44
source/screen.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
|
||||||
|
* Screen deinit code by tiniVi.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#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)();
|
||||||
|
|
||||||
|
static volatile struct fb {
|
||||||
|
u8 *top_left;
|
||||||
|
u8 *top_right;
|
||||||
|
u8 *bottom;
|
||||||
|
} *const fb = (volatile struct fb *)0x23FFFE00;
|
||||||
|
|
||||||
|
void deinitScreens(void);
|
||||||
|
void updateBrightness(u32 brightnessIndex);
|
||||||
|
void clearScreens(void);
|
||||||
|
void initScreens(void);
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* screeninit.c
|
|
||||||
*
|
|
||||||
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
|
|
||||||
* Screen deinit code by tiniVi.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "screeninit.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "draw.h"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "../build/screeninit.h"
|
|
||||||
|
|
||||||
vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
|
|
||||||
|
|
||||||
void deinitScreens(void)
|
|
||||||
{
|
|
||||||
void __attribute__((naked)) ARM11(void)
|
|
||||||
{
|
|
||||||
//Disable interrupts
|
|
||||||
__asm(".word 0xF10C01C0");
|
|
||||||
|
|
||||||
//Clear ARM11 entry offset
|
|
||||||
*arm11Entry = 0;
|
|
||||||
|
|
||||||
//Shutdown LCDs
|
|
||||||
*(vu32 *)0x10202A44 = 0;
|
|
||||||
*(vu32 *)0x10202244 = 0;
|
|
||||||
*(vu32 *)0x10202014 = 0;
|
|
||||||
|
|
||||||
//Wait for the entry to be set
|
|
||||||
while(!*arm11Entry);
|
|
||||||
|
|
||||||
//Jump to it
|
|
||||||
((void (*)())*arm11Entry)();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(PDN_GPU_CNT != 1)
|
|
||||||
{
|
|
||||||
*arm11Entry = (u32)ARM11;
|
|
||||||
while(*arm11Entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 initScreens(void)
|
|
||||||
{
|
|
||||||
u32 needToInit = PDN_GPU_CNT == 1;
|
|
||||||
|
|
||||||
if(needToInit)
|
|
||||||
{
|
|
||||||
u32 *const screenInitAddress = (u32 *)0x24FFFC00;
|
|
||||||
|
|
||||||
memcpy(screenInitAddress, screeninit, screeninit_size);
|
|
||||||
|
|
||||||
//Write brightness level for the stub to pick up
|
|
||||||
screenInitAddress[2] = MULTICONFIG(0);
|
|
||||||
|
|
||||||
*arm11Entry = (u32)screenInitAddress;
|
|
||||||
while(*arm11Entry);
|
|
||||||
|
|
||||||
//Turn on backlight
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearScreens();
|
|
||||||
|
|
||||||
return needToInit;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* screeninit.h
|
|
||||||
*
|
|
||||||
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
|
|
||||||
* Screen deinit code by tiniVi.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
|
|
||||||
|
|
||||||
void deinitScreens(void);
|
|
||||||
u32 initScreens(void);
|
|
||||||
@@ -1,29 +1,70 @@
|
|||||||
|
@ 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.
|
||||||
|
|
||||||
|
@ Thanks to the numerous people who took part in writing this file
|
||||||
|
|
||||||
.section .text.start
|
.section .text.start
|
||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
b start
|
b start
|
||||||
|
|
||||||
.word 0, 0
|
.global launchedFirmTIDLow
|
||||||
|
launchedFirmTIDLow:
|
||||||
|
.hword 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
|
||||||
start:
|
start:
|
||||||
@ Change the stack pointer
|
@ Change the stack pointer
|
||||||
mov sp, #0x27000000
|
mov sp, #0x27000000
|
||||||
|
|
||||||
|
@ Disable interrupts
|
||||||
|
mrs r0, cpsr
|
||||||
|
orr r0, #0x1C0
|
||||||
|
msr cpsr_cx, r0
|
||||||
|
|
||||||
|
@ Disable caches / MPU
|
||||||
|
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
||||||
|
bic r0, #(1<<12) @ - instruction cache disable
|
||||||
|
bic r0, #(1<<2) @ - data cache disable
|
||||||
|
bic r0, #(1<<0) @ - mpu disable
|
||||||
|
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
||||||
|
|
||||||
|
@ Flush caches
|
||||||
|
bl flushEntireDCache
|
||||||
|
bl flushEntireICache
|
||||||
|
|
||||||
@ Give read/write access to all the memory regions
|
@ Give read/write access to all the memory regions
|
||||||
ldr r0, =0x33333333
|
ldr r0, =0x3333333
|
||||||
mcr p15, 0, r0, c5, c0, 2 @ write data access
|
mcr p15, 0, r0, c5, c0, 2 @ write data access
|
||||||
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
|
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
|
||||||
|
|
||||||
@ Set MPU permissions and cache settings
|
@ Set MPU permissions and cache settings
|
||||||
ldr r0, =0xFFFF001D @ ffff0000 32k
|
ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
|
||||||
ldr r1, =0x01FF801D @ 01ff8000 32k
|
ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
|
||||||
ldr r2, =0x08000027 @ 08000000 1M
|
ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
|
||||||
ldr r3, =0x10000021 @ 10000000 128k
|
ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
|
||||||
ldr r4, =0x10100025 @ 10100000 512k
|
ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
|
||||||
ldr r5, =0x20000035 @ 20000000 128M
|
ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
|
||||||
ldr r6, =0x1FF00027 @ 1FF00000 1M
|
ldr r6, =0x1800002D @ 18000000 8M | vram (+ 2MB)
|
||||||
ldr r7, =0x1800002D @ 18000000 8M
|
mov r7, #0
|
||||||
|
mov r8, #0x15
|
||||||
mcr p15, 0, r0, c6, c0, 0
|
mcr p15, 0, r0, c6, c0, 0
|
||||||
mcr p15, 0, r1, c6, c1, 0
|
mcr p15, 0, r1, c6, c1, 0
|
||||||
mcr p15, 0, r2, c6, c2, 0
|
mcr p15, 0, r2, c6, c2, 0
|
||||||
@@ -32,24 +73,18 @@ start:
|
|||||||
mcr p15, 0, r5, c6, c5, 0
|
mcr p15, 0, r5, c6, c5, 0
|
||||||
mcr p15, 0, r6, c6, c6, 0
|
mcr p15, 0, r6, c6, c6, 0
|
||||||
mcr p15, 0, r7, c6, c7, 0
|
mcr p15, 0, r7, c6, c7, 0
|
||||||
mov r0, #0x25
|
mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 4
|
||||||
mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5
|
mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 4
|
||||||
mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5
|
mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 4
|
||||||
mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
|
|
||||||
|
|
||||||
@ Enable caches
|
@ Enable caches / MPU / ITCM
|
||||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
||||||
|
orr r0, r0, #(1<<18) @ - ITCM enable
|
||||||
orr r0, r0, #(1<<12) @ - instruction cache enable
|
orr r0, r0, #(1<<12) @ - instruction cache enable
|
||||||
orr r0, r0, #(1<<2) @ - data cache enable
|
orr r0, r0, #(1<<2) @ - data cache enable
|
||||||
orr r0, r0, #(1<<0) @ - mpu enable
|
orr r0, r0, #(1<<0) @ - mpu enable
|
||||||
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
||||||
|
|
||||||
@ Flush caches
|
|
||||||
mov r0, #0
|
|
||||||
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
|
|
||||||
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
|
||||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
|
||||||
|
|
||||||
@ Fix mounting of SDMC
|
@ Fix mounting of SDMC
|
||||||
ldr r0, =0x10000020
|
ldr r0, =0x10000020
|
||||||
mov r1, #0x340
|
mov r1, #0x340
|
||||||
|
|||||||
@@ -1,11 +1,37 @@
|
|||||||
/*
|
/*
|
||||||
* types.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.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;
|
||||||
@@ -15,4 +41,20 @@ typedef uint64_t u64;
|
|||||||
typedef volatile u8 vu8;
|
typedef volatile u8 vu8;
|
||||||
typedef volatile u16 vu16;
|
typedef volatile u16 vu16;
|
||||||
typedef volatile u32 vu32;
|
typedef volatile u32 vu32;
|
||||||
typedef volatile u64 vu64;
|
typedef volatile u64 vu64;
|
||||||
|
|
||||||
|
//Used by multiple files:
|
||||||
|
typedef enum FirmwareSource
|
||||||
|
{
|
||||||
|
FIRMWARE_SYSNAND = 0,
|
||||||
|
FIRMWARE_EMUNAND = 1,
|
||||||
|
FIRMWARE_EMUNAND2 = 2
|
||||||
|
} FirmwareSource;
|
||||||
|
|
||||||
|
typedef enum FirmwareType
|
||||||
|
{
|
||||||
|
NATIVE_FIRM = 0,
|
||||||
|
TWL_FIRM = 1,
|
||||||
|
AGB_FIRM = 2,
|
||||||
|
SAFE_FIRM = 3
|
||||||
|
} FirmwareType;
|
||||||
@@ -1,10 +1,33 @@
|
|||||||
/*
|
/*
|
||||||
* utils.c
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "draw.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
|
extern bool isFirmlaunch;
|
||||||
|
|
||||||
u32 waitInput(void)
|
u32 waitInput(void)
|
||||||
{
|
{
|
||||||
@@ -35,8 +58,22 @@ u32 waitInput(void)
|
|||||||
|
|
||||||
void mcuReboot(void)
|
void mcuReboot(void)
|
||||||
{
|
{
|
||||||
|
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
|
||||||
|
|
||||||
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||||
while(1);
|
while(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mcuPowerOff(void)
|
||||||
|
{
|
||||||
|
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
|
||||||
|
|
||||||
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
|
||||||
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||||
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: add support for TIMER IRQ
|
//TODO: add support for TIMER IRQ
|
||||||
@@ -44,34 +81,46 @@ static inline void startChrono(u64 initialTicks)
|
|||||||
{
|
{
|
||||||
//Based on a NATIVE_FIRM disassembly
|
//Based on a NATIVE_FIRM disassembly
|
||||||
|
|
||||||
*(vu16 *)0x10003002 = 0; //67MHz
|
REG_TIMER_CNT(0) = 0; //67MHz
|
||||||
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 4; //Count-up
|
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
||||||
|
|
||||||
for(u32 i = 0; i < 4; i++) *(vu16 *)(0x10003000 + 4 * i) = (u16)(initialTicks >> (16 * i));
|
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = (u16)(initialTicks >> (16 * i));
|
||||||
|
|
||||||
*(vu16 *)0x10003002 = 0x80; //67MHz; enabled
|
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
|
||||||
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 0x84; //Count-up; enabled
|
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stopChrono(void)
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
void chrono(u32 seconds)
|
void chrono(u32 seconds)
|
||||||
{
|
{
|
||||||
static u64 startingTicks = 0;
|
startChrono(0);
|
||||||
|
|
||||||
if(!startingTicks) startChrono(0);
|
u64 startingTicks = 0;
|
||||||
|
for(u32 i = 0; i < 4; i++) startingTicks |= REG_TIMER_VAL(i) << (16 * i);
|
||||||
|
|
||||||
u64 res;
|
u64 res;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
res = 0;
|
res = 0;
|
||||||
for(u32 i = 0; i < 4; i++) res |= *(vu16 *)(0x10003000 + 4 * i) << (16 * i);
|
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
||||||
}
|
}
|
||||||
while(res - startingTicks < seconds * TICKS_PER_SEC);
|
while(res - startingTicks < seconds * TICKS_PER_SEC);
|
||||||
|
|
||||||
if(!seconds) startingTicks = res;
|
stopChrono();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopChrono(void)
|
void error(const char *message)
|
||||||
{
|
{
|
||||||
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) &= ~0x80;
|
initScreens();
|
||||||
|
|
||||||
|
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
||||||
|
int posY = drawString(message, 10, 30, COLOR_WHITE);
|
||||||
|
drawString("Press any button to shutdown", 10, posY + 2 * SPACING_Y, COLOR_WHITE);
|
||||||
|
|
||||||
|
waitInput();
|
||||||
|
mcuPowerOff();
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,35 @@
|
|||||||
/*
|
/*
|
||||||
* utils.h
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define TICKS_PER_SEC 67027964ULL
|
||||||
|
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
|
||||||
|
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
|
||||||
|
|
||||||
u32 waitInput(void);
|
u32 waitInput(void);
|
||||||
void mcuReboot(void);
|
void mcuReboot(void);
|
||||||
|
void mcuPowerOff(void);
|
||||||
#define TICKS_PER_SEC 67027964ULL
|
|
||||||
|
|
||||||
void chrono(u32 seconds);
|
void chrono(u32 seconds);
|
||||||
void stopChrono(void);
|
void error(const char *message);
|
||||||
Reference in New Issue
Block a user