Compare commits

...

49 Commits
v5.5 ... v6.0

Author SHA1 Message Date
TuxSH
a381c2a811 Update config.c 2016-08-15 21:37:25 +02:00
TuxSH
eef30ceb3c Make the multi-choice options look cleaner 2016-08-15 21:25:06 +02:00
TuxSH
a1024c288e Update pin.c 2016-08-15 17:15:16 +02:00
TuxSH
d445b20e90 Fix bugs 2016-08-15 16:50:58 +02:00
Aurora
bb117d3d74 Clear screens before turning on the backlight to mitigate previous FB contents persisting 2016-08-15 15:25:44 +02:00
Aurora
c101653077 Clear screens before a power off/reboot 2016-08-15 14:46:33 +02:00
Aurora
5248b96f8a No need for this 2016-08-15 13:41:52 +02:00
Aurora
7ab59e420a Fix comment 2016-08-15 13:28:43 +02:00
Aurora
83a849126a Move stuff from firm.c (2) 2016-08-15 13:23:27 +02:00
Aurora
c9c373f607 Move stuff from firm.c 2016-08-15 13:11:27 +02:00
Aurora
aa7c2c0009 Various changes/cleanups, removed useless code, simplified chronometer functions 2016-08-15 03:51:48 +02:00
TuxSH
75acdc8a98 Fix setRSAMod0DerivedKeys 2016-08-14 23:32:56 +02:00
TuxSH
9b304404f7 Enable access to the ITCM (older k9lh payloads disabled access to it).
Thanks @Normmatt for reporting that bug.
2016-08-14 12:30:12 +02:00
TuxSH
95ef379ac5 Remove the empty "luma" folder from the output folder since it will be created automatically when running Luma3DS. 2016-08-13 23:56:07 +02:00
TuxSH
3bc966f84e Replace "Enable splash screen with no screen-init" by "Display splash screen before payloads".
The screens will be initied if and only if there are splash files to display.
2016-08-13 22:23:14 +02:00
TuxSH
457b4cec13 Disable interrupts and do some refactoring. 2016-08-13 20:49:40 +02:00
TuxSH
905777466d Don't set retail keys on dev units. 2016-08-06 22:38:06 +02:00
TuxSH
18b5cdcddf Don't make any assumption regarding version when loading an external firmware file. 2016-08-04 00:05:01 +02:00
TuxSH
389a169443 pin.c cleanup 2016-08-03 20:49:10 +02:00
TuxSH
e01802e299 Check the PIN before loading a payload.
Also fix some bugs.
2016-08-03 16:58:03 +02:00
TuxSH
709aefba5d Implement a PIN-checking system.
Idea and original code by @reworks
2016-08-03 14:13:26 +02:00
Aurora
e4ed713fce Update FatFs to 0.12a 2016-07-20 15:07:13 +02:00
Aurora
d3c507b0d4 Minor stuff 2016-07-20 00:11:59 +02:00
Aurora
a68e14def3 Added error screen when booting an unsupported NAND with no firmware.bin or writing to the config fails, added code for creating the "luma" directory if it is missing 2016-07-18 23:07:28 +02:00
Aurora
8175642a2a Fix changing the brightness
Needs to be static for some reason
2016-07-18 21:57:31 +02:00
Aurora
8d1befea9e Rename "Updated SysNAND" to reflect its only new purpose 2016-07-18 19:10:41 +02:00
Aurora
e7b8a0ef39 Force A9LH detection is not needed anymore 2016-07-18 18:53:23 +02:00
Aurora
be6ee894f9 Fix firmware.bin loading 2016-07-18 17:28:04 +02:00
Aurora
e0e8ed2113 Hardcode 9.6 FIRM version for firmware.bin 2016-07-18 17:13:46 +02:00
Aurora
c63e46b1a9 Added FIRM version detection, removed firmware.bin loading unless an unsupported O3DS NATIVE_FIRM (pre-5.0) is being loaded, skip patching old unsupported O3DS AGB/TWL FIRMs, only apply 11.0 patches with 11.0 or greater 2016-07-18 16:58:29 +02:00
Aurora
eb9c74a1ed Bool-ify 2016-07-18 15:46:29 +02:00
Aurora
efd83e063e Remove code to skip the rbeoot patch on 9.0 as it is not needed anymore with A9LH and constitutes a brick risk 2016-07-18 15:40:31 +02:00
Aurora
ae23a1c84d Fixed Luma allowing users to go to the configuration after AGB_FIRM quits 2016-07-18 15:09:04 +02:00
TuxSH
a0e8bc1de3 Add support for launching >= 6.x/7.x emuNANDs properly when the sysNAND is on a lower firmware version
To launch 3.x - 4.x emuNANDs, you'll need to use an external firmware file (10.x or so should do the trick)
2016-07-14 21:20:45 +02:00
TuxSH
72caad86cc Minor stuff 2016-07-05 16:05:53 +02:00
TuxSH
575adcbb9d Revert part of 136e0d89 (due to cache issues) 2016-07-03 20:53:13 +02:00
TuxSH
53d2aac2ae Update CakeBrah 2016-07-02 17:38:33 +02:00
TuxSH
96211813e3 Use bool instead of u32 where it's relevant 2016-07-02 14:44:01 +02:00
TuxSH
730e716f0f Update CakeBrah 2016-07-02 12:32:39 +02:00
TuxSH
2238293c0f Fix indentation 2016-07-02 10:59:21 +02:00
Aurora
29d8e637d8 One-liners ftw 2016-07-01 20:36:43 +02:00
Aurora
136e0d8974 Cleanup 2016-07-01 20:27:28 +02:00
TuxSH
61684ecb68 We need to clean and flush caches before jumping to payloads, actually. 2016-06-14 19:50:38 +02:00
TuxSH
159c9cb475 Implement our own DCache cleaning functions 2016-06-13 21:14:53 +02:00
TuxSH
2943dcb2e9 Refactor firm.c as well as other files 2016-06-12 22:14:52 +02:00
TuxSH
edfd63e1f7 We don't need to flush DCache when launching payloads.
Fixes a derp as well.
2016-06-10 23:33:03 +02:00
TuxSH
e593584a47 Move screen management code to screen.c and fix cache-related issues
- Screen brightness is now updated as soon as the user selects a brightness option, on all boot environments
- Payloads can now be 1KB bigger
- Some cache-related bugs may have been fixed
2016-06-10 21:48:22 +02:00
TuxSH
f78dd5365c External .code section loading for titles and some refactoring 2016-06-05 20:43:49 +02:00
TuxSH
ae1033d975 Update start.s (thanks @delebile and/or @d0k3) 2016-05-28 23:47:30 +02:00
55 changed files with 3075 additions and 1670 deletions

View File

@@ -17,7 +17,6 @@ revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-
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 +32,7 @@ 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)/injector.h $(dir_build)/loader.h
.PHONY: all .PHONY: all
all: launcher a9lh ninjhax all: launcher a9lh ninjhax
@@ -55,12 +54,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
@@ -102,10 +100,6 @@ $(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\""

View File

@@ -5,7 +5,7 @@
#ifndef PATH_MAX #ifndef PATH_MAX
#define PATH_MAX 255 #define PATH_MAX 255
#define CONFIG(a) ((loadConfig() >> (a + 16)) & 1) #define CONFIG(a) (((loadConfig() >> (a + 16)) & 1) != 0)
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3) #define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b) #define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
#endif #endif
@@ -90,21 +90,21 @@ 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) static bool secureInfoExists(void)
{ {
static u32 secureInfoExists = 0; static bool exists = false;
if(!secureInfoExists) 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 u32 loadConfig(void)
@@ -125,21 +125,48 @@ static u32 loadConfig(void)
return config; return config;
} }
static void progIdToStr(char *strEnd, u64 progId)
{
while(progId)
{
static const char hexDigits[] = "0123456789ABCDEF";
*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)
{
ret = IFile_Read(&file, &total, code, fileSize);
IFile_Close(&file);
}
}
}
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
{ {
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt" /* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
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 +263,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
{ {
@@ -337,7 +364,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 +408,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 +543,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;

View File

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

View File

@@ -1,10 +1,35 @@
/*
* 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"
void main(void) void main(void)
{ {
void *payloadAddress = (void *)0x23F00000; void *payloadAddress = (void *)0x23F00000;
memcpy(payloadAddress, (void*)0x24F00000, *(u32 *)0x24FFFB04); memcpy(payloadAddress, (void*)0x24F00000, *(u32 *)0x24FFFF04);
flushCaches();
((void (*)())payloadAddress)(); ((void (*)())payloadAddress)();
} }

View File

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

View File

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

View File

@@ -1,16 +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.
.section .text.start .section .text.start
.align 4 .align 4
.global _start .global _start
_start: _start:
b start b main
.word 0 .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

View File

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

View File

@@ -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
@@ -54,13 +54,16 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
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
@@ -88,61 +91,32 @@ dat_fname: .dcw "sdmc:/Luma3DS.dat"
.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
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 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
bx r0 bx r0

View File

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

View File

@@ -1,12 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 0x24FFFC00;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

View File

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

View File

@@ -1,10 +0,0 @@
.section .text.start
.align 4
.global _start
_start:
@ Disable interrupts
CPSID aif
b main
.word 0

View File

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

View File

@@ -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)
@@ -25,3 +43,4 @@
#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
View 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
View 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

View File

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

View File

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

View File

@@ -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
*/ */
@@ -274,25 +294,26 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
* 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);
}

View File

@@ -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
*/ */
@@ -79,9 +99,15 @@
#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);

View File

@@ -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); //Don't delay boot nor init the screens if no splash image is on the SD
memset32(fb->top_right, 0, 0x46500); if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splash.bin") == 0)
memset32(fb->bottom, 0, 0x38400); return false;
}
u32 loadSplash(void)
{
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)

View File

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

View File

@@ -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 *const temp = (u8 *)0x24300000;
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);
} }
} }

View File

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

@@ -1,4 +1,4 @@
FatFs Module Source Files R0.12 FatFs Module Source Files R0.12a
FILES FILES

1482
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
View 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
View 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
View File

0
source/fatfs/option/ccsbcs.c Normal file → Executable file
View File

View File

@@ -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,47 @@
#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 "i2c.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;
FirmwareSource firmSource;
PINData pin;
void main(void) void main(void)
{ {
u32 bootType, bool isFirmlaunch,
firmType, isA9lh;
nandType,
a9lhMode, u32 newConfig,
updatedSys, emuHeader;
needConfig,
newConfig, FirmwareType firmType;
emuHeader, FirmwareSource nandType;
chronoStarted = 0; ConfigurationStatus needConfig;
//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,78 +74,47 @@ 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;
{
a9lhMode = 1;
updatedSys = CONFIG(1);
}
else
{
a9lhMode = 0;
updatedSys = 0;
}
newConfig = a9lhMode << 3; newConfig = (u32)isA9lh << 3;
if(a9lhBoot)
{
//Retrieve the last booted FIRM
u32 previousFirm = CFG_BOOTENV;
//If it's a MCU reboot, try to force boot options //If it's a MCU reboot, try to force boot options
if(previousFirm) if(isA9lh && CFG_BOOTENV)
{ {
//Always force a sysNAND boot when quitting AGB_FIRM //Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 7) if(CFG_BOOTENV == 7)
{ {
nandType = 0; nandType = FIRMWARE_SYSNAND;
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1); firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = 0; needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing //Flag to prevent multiple boot options-forcing
newConfig |= 1 << 4; newConfig |= 1 << 4;
@@ -125,72 +124,88 @@ void main(void)
or the no-forcing flag is set */ or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1)) else if(!pressed && !BOOTCONFIG(4, 1))
{ {
nandType = BOOTCONFIG(0, 3); nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1); firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = 0; needConfig = DONT_CONFIGURE;
}
}
//If the SAFE MODE combo is held, force a sysNAND boot
else if(pressed == SAFE_MODE)
{
a9lhMode = 2;
nandType = 0;
firmSource = 0;
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, bool pinExists = CONFIG(7) && readPin(&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 //If we get here we should check the PIN (if it exists) in all cases
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash()) if(pinExists) verifyPin(&pin, true);
//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)) pin = newPin();
chrono(2);
//Update pressed buttons
pressed = HID_PAD;
} }
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
{
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_SYSNAND;
}
else
{
if(CONFIG(6) && loadSplash()) pressed = HID_PAD;
/* If L and R/A/Select or one of the single payload buttons are pressed,
chainload an external payload (the PIN, if any, has been verified)*/
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 R is pressed, boot the non-updated NAND with the FIRM of the opposite one
if(pressed & BUTTON_R1) if(pressed & BUTTON_R1)
{ {
nandType = updatedSys; nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = !nandType; firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
} }
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */ with their own FIRM */
else else
{ {
nandType = CONFIG(0) != !(pressed & BUTTON_L1); nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = nandType; firmSource = nandType;
} }
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed, /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */ or vice-versa, boot the second emuNAND */
if(nandType && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = 2; 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 +214,63 @@ 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, isFirmlaunch);
{
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;
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 +281,49 @@ 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((u8 *)firm + section[1].offset, 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);
} }
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);
@@ -352,11 +343,11 @@ static inline void copySection0AndInjectLoader(void)
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize)); 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, bool isFirmlaunch)
{ {
//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 == NATIVE_FIRM)
{ {
copySection0AndInjectLoader(); copySection0AndInjectLoader();
sectionNum = 1; sectionNum = 1;
@@ -369,7 +360,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 +370,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)();
} }

View File

@@ -1,5 +1,23 @@
/* /*
* 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
@@ -9,6 +27,7 @@
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) #define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu32 *)0x101401C0) #define PDN_SPI_CNT (*(vu32 *)0x101401C0)
#define CFG_BOOTENV (*(vu32 *)0x10010000) #define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CFG_UNITINFO (*(vu8 *)0x10010010)
//FIRM Header layout //FIRM Header layout
typedef struct firmSectionHeader { typedef struct firmSectionHeader {
@@ -28,9 +47,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 copySection0AndInjectLoader(void);
static inline void launchFirm(u32 sectionNum, u32 bootType); static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch);

View File

@@ -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,6 +46,7 @@ u32 fileRead(void *dest, const char *path)
{ {
unsigned int read; unsigned int read;
size = f_size(&file); size = f_size(&file);
if(dest != NULL)
f_read(&file, dest, size, &read); f_read(&file, dest, size, &read);
f_close(&file); f_close(&file);
} }
@@ -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;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,23 @@
/* /*
* 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"
@@ -101,7 +119,7 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*svcTable) svcTable++; //Look for SVC0 (NULL) while(*svcTable) svcTable++; //Look for SVC0 (NULL)
if(!svcTable[0x7B]) if(svcTable[0x7B] == 0)
{ {
u32 *freeSpace; u32 *freeSpace;
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
@@ -121,7 +139,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 +159,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,12 +169,12 @@ 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;
} }
} }
@@ -167,7 +185,7 @@ u32 getLoader(u8 *pos, u32 *loaderSize)
u8 *off = pos; u8 *off = pos;
u32 size; u32 size;
while(1) while(true)
{ {
size = *(u32 *)(off + 0x104) * 0x200; size = *(u32 *)(off + 0x104) * 0x200;
if(*(u32 *)(off + 0x200) == 0x64616F6C) break; if(*(u32 *)(off + 0x200) == 0x64616F6C) break;

View File

@@ -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,5 @@ 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 applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
u32 getLoader(u8 *pos, u32 *loaderSize); u32 getLoader(u8 *pos, u32 *loaderSize);

173
source/pin.c Normal file
View File

@@ -0,0 +1,173 @@
/*
* 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 "i2c.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];
}
PINData 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(true)
{
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;
// we leave the rest of the array zeroed out.
if(cnt >= PIN_LENGTH)
{
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));
return pin;
}
}
while(HID_PAD & PIN_BUTTONS);
}
void verifyPin(PINData *in, bool allowQuit)
{
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;
int charDrawPos = 5 * SPACING_X;
while(true)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS));
pressed &= PIN_BUTTONS;// & ~BUTTON_START;
if(!allowQuit) pressed &= ~BUTTON_START;
if(!pressed) continue;
if(pressed & BUTTON_START) mcuPowerOff();
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);
}
else break;
}
}
}

49
source/pin.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* 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"
#ifndef PIN_LENGTH
#define PIN_LENGTH 4
#endif
typedef struct __attribute__((packed))
{
char magic[4];
u16 formatVersionMajor, formatVersionMinor;
u8 testHash[32];
u8 hash[32];
} PINData;
bool readPin(PINData* out);
PINData newPin(void);
void verifyPin(PINData *in, bool allowQuit);

259
source/screen.c Normal file
View 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));
}
}

45
source/screen.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* 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 PDN_GPU_CNT (*(vu8 *)0x10141200)
#define ARM11_STUB_ADDRESS (0x25000000 - 0x30) //It's currently only 0x28 bytes large. We're putting 0x30 just to be sure here
#define 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);

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,30 @@
/* /*
* 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>
//Common data types //Common data types
typedef uint8_t u8; typedef uint8_t u8;
@@ -16,3 +35,19 @@ 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;

View File

@@ -1,10 +1,31 @@
/* /*
* 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"
u32 waitInput(void) u32 waitInput(void)
{ {
@@ -35,8 +56,22 @@ u32 waitInput(void)
void mcuReboot(void) void mcuReboot(void)
{ {
if(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(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 +79,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();
} }

View File

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