Compare commits

..

54 Commits
v5.5 ... v6.0.1

Author SHA1 Message Date
Aurora
4f8c66b2b7 There would not be an use for this 2016-08-16 22:59:25 +02:00
Aurora
4d9cbc4e19 Fix fail 2016-08-16 22:46:41 +02:00
Aurora
40369d44df Pin cleanup 2016-08-16 22:39:02 +02:00
Aurora
ee3720f0b7 Make loader more readable, use an array instead of a fixed location for the emuNAND test sector 2016-08-16 18:47:27 +02:00
Aurora
e5dcca1c2b Update gitignore 2016-08-16 01:59:23 +02:00
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
56 changed files with 3074 additions and 1675 deletions

6
.gitignore vendored
View File

@@ -1,12 +1,12 @@
out
build
loader/build
screeninit/build
injector/build
exceptions/arm9/build
exceptions/arm11/build
*.bin
*.3dsx
*.smdh
*.o
*.d
*.elf
*.bat
*.elf

View File

@@ -17,7 +17,6 @@ revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-
dir_source := source
dir_patches := patches
dir_loader := loader
dir_screeninit := screeninit
dir_injector := injector
dir_mset := CakeHax
dir_ninjhax := CakeBrah
@@ -33,7 +32,7 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(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
all: launcher a9lh ninjhax
@@ -55,12 +54,11 @@ clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_screeninit) clean
@$(MAKE) -C $(dir_injector) clean
@rm -rf $(dir_out) $(dir_build)
$(dir_out):
@mkdir -p "$(dir_out)/luma/payloads"
@mkdir -p "$(dir_out)"
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
@@ -102,10 +100,6 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@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)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""

View File

@@ -5,7 +5,7 @@
#ifndef PATH_MAX
#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 BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
#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);
}
static u32 secureInfoExists(void)
static bool secureInfoExists(void)
{
static u32 secureInfoExists = 0;
static bool exists = false;
if(!secureInfoExists)
if(!exists)
{
IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
{
secureInfoExists = 1;
exists = true;
IFile_Close(&file);
}
}
return secureInfoExists;
return exists;
}
static u32 loadConfig(void)
@@ -125,21 +125,48 @@ static u32 loadConfig(void)
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)
{
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
If it exists it should contain, for example, "EUR IT" */
char path[] = "/luma/locales/0000000000000000.txt";
u32 i = 29;
while(progId)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[(u32)(progId & 0xF)];
progId >>= 4;
}
progIdToStr(path + 29, progId);
IFile file;
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
{
u8 *calledFunction = instr;
u32 i = 0,
found;
u32 i = 0;
bool found;
do
{
@@ -337,7 +364,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
);
//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[] = {
0x30, 0xB5, 0xF1, 0xB0
@@ -381,7 +408,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
if(CONFIG(5))
if(CONFIG(4))
{
static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3);
@@ -516,12 +543,15 @@ void patchCode(u64 progId, u8 *code, u32 size)
}
default:
if(CONFIG(4))
if(CONFIG(3))
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
if(tidHigh == 0x0004000)
{
//External .code section loading
loadTitleCodeSection(progId, code, size);
//Language emulation
u8 regionId = 0xFF,
languageId = 0xFF;
@@ -543,4 +573,4 @@ void patchCode(u64 progId, u8 *code, u32 size)
break;
}
}
}

View File

@@ -1,7 +1,7 @@
ENTRY(_start)
SECTIONS
{
. = 0x24FFFB00;
. = 0x24FFFF00;
.text.start : { *(.text.start) }
.text : { *(.text) }
.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,37 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "memory.h"
#include "cache.h"
extern u32 payloadSize; //defined in start.s
void main(void)
{
void *payloadAddress = (void *)0x23F00000;
memcpy(payloadAddress, (void*)0x24F00000, *(u32 *)0x24FFFB04);
memcpy(payloadAddress, (void*)0x24F00000, payloadSize);
flushCaches();
((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"
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
#include "types.h"

View File

@@ -1,16 +1,29 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
.section .text.start
.align 4
.global _start
_start:
b start
.word 0
start:
@ Flush caches
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
b main
.global payloadSize
payloadSize:
.word 0

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
#include <stdint.h>

View File

@@ -1,7 +1,7 @@
.arm.little
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
.arm
@@ -41,26 +41,29 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
read_payload:
; Read file
mov r0, r7
mov r0, r7
adr r1, bytes_read
ldr r2, =payload_addr
cmp r4, #0
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6, #0x28]
blx r6
ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6, #0x28]
blx r6
cmp r4, #0
movne r4, #0
bne read_payload ; Go read the real payload.
; Copy the last digits of the wanted firm to the 5th byte of the payload
add r2, sp, #0x3A8 - 0x70
ldr r0, [r2, #0x27]
ldr r1, =payload_addr + 4
str r0, [r1]
ldr r0, [r2, #0x2B]
str r0, [r1, #4]
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
add r0, sp, #0x3A8 - 0x70
add r0, 0x1A
add r1, r0, #0x10
ldr r2, =payload_addr + 4
copy_TID_low:
ldrh r3, [r0], #2
strh r3, [r2], #2
cmp r0, r1
blo copy_TID_low
; Set kernel state
mov r0, #0
@@ -81,67 +84,38 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
bytes_read: .word 0
fopen: .ascii "OPEN"
.pool
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dat_fname: .dcw "sdmc:/Luma3DS.dat"
.word 0
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dat_fname: .dcw "sdmc:/Luma3DS.dat"
.word 0
.align 4
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
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
; Disable MPU
ldr r0, =0x42078 ; alt vector select, enable itcm
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
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
; 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
; Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
; Jump to payload
ldr r0, =payload_addr

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
@@ -10,7 +28,7 @@
#define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9)
#define BUTTON_A 1
#define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
@@ -24,4 +42,5 @@
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define 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 "utils.h"
#include "screeninit.h"
#include "screen.h"
#include "draw.h"
#include "fs.h"
#include "i2c.h"
#include "buttons.h"
void configureCFW(const char *configPath)
{
u32 needToDeinit = initScreens();
initScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
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( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) SysNAND is updated (A9LH-only)",
"( ) Force A9LH detection",
"( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Use second EmuNAND as default",
"( ) Enable region/language emulation",
"( ) Enable region/language emu. and ext. .code",
"( ) Show current NAND in System Settings",
"( ) 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 {
int posXs[4];
int posY;
u32 enabled;
} multiOptions[] = {
{ .posXs = {26, 31, 36, 41} },
{ .posXs = {21, 26, 31, 36} },
{ .posXs = {17, 26, 32, 44} }
};
@@ -46,7 +63,7 @@ void configureCFW(const char *configPath)
struct singleOption {
int posY;
u32 enabled;
bool enabled;
} singleOptions[singleOptionsAmount];
//Parse the existing options
@@ -145,10 +162,13 @@ void configureCFW(const char *configPath)
u32 oldEnabled = multiOptions[selectedOption].enabled;
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
if(!selectedOption)
updateBrightness(multiOptions[selectedOption].enabled);
}
else
{
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
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++)
config |= multiOptions[i].enabled << (i * 2 + 6);
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
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
#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 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
*/
@@ -9,290 +29,291 @@
#include "fatfs/sdmmc/sdmmc.h"
/****************************************************************
* Crypto libs
* Crypto libs
****************************************************************/
/* original version by megazig */
#ifndef __thumb__
#define BSWAP32(x) {\
__asm__\
(\
"eor r1, %1, %1, ror #16\n\t"\
"bic r1, r1, #0xFF0000\n\t"\
"mov %0, %1, ror #8\n\t"\
"eor %0, %0, r1, lsr #8\n\t"\
:"=r"(x)\
:"0"(x)\
:"r1"\
);\
__asm__\
(\
"eor r1, %1, %1, ror #16\n\t"\
"bic r1, r1, #0xFF0000\n\t"\
"mov %0, %1, ror #8\n\t"\
"eor %0, %0, r1, lsr #8\n\t"\
:"=r"(x)\
:"0"(x)\
:"r1"\
);\
};
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
__asm__\
(\
"adds %0, %4\n\t"\
"addcss %1, %1, #1\n\t"\
"addcss %2, %2, #1\n\t"\
"addcs %3, %3, #1\n\t"\
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
: "r"(u32_0)\
: "cc"\
);\
(\
"adds %0, %4\n\t"\
"addcss %1, %1, #1\n\t"\
"addcss %2, %2, #1\n\t"\
"addcs %3, %3, #1\n\t"\
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
: "r"(u32_0)\
: "cc"\
);\
}
#else
#define BSWAP32(x) {x = __builtin_bswap32(x);}
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
__asm__\
(\
"mov r4, #0\n\t"\
"add %0, %0, %4\n\t"\
"adc %1, %1, r4\n\t"\
"adc %2, %2, r4\n\t"\
"adc %3, %3, r4\n\t"\
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
: "r"(u32_0)\
: "cc", "r4"\
);\
(\
"mov r4, #0\n\t"\
"add %0, %0, %4\n\t"\
"adc %1, %1, r4\n\t"\
"adc %2, %2, r4\n\t"\
"adc %3, %3, r4\n\t"\
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
: "r"(u32_0)\
: "cc", "r4"\
);\
}
#endif /*__thumb__*/
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
{
if(keyslot <= 0x03) return; // Ignore TWL keys for now
u32 *key32 = (u32 *)key;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
if(keyslot <= 0x03) return; // Ignore TWL keys for now
u32 *key32 = (u32 *)key;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
REG_AESKEYFIFO[keyType] = key32[0];
REG_AESKEYFIFO[keyType] = key32[1];
REG_AESKEYFIFO[keyType] = key32[2];
REG_AESKEYFIFO[keyType] = key32[3];
REG_AESKEYFIFO[keyType] = key32[0];
REG_AESKEYFIFO[keyType] = key32[1];
REG_AESKEYFIFO[keyType] = key32[2];
REG_AESKEYFIFO[keyType] = key32[3];
}
static void aes_use_keyslot(u8 keyslot)
{
if(keyslot > 0x3F)
return;
if(keyslot > 0x3F)
return;
*REG_AESKEYSEL = keyslot;
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
*REG_AESKEYSEL = keyslot;
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
}
static void aes_setiv(const void *iv, u32 mode)
{
const u32 *iv32 = (const u32 *)iv;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
const u32 *iv32 = (const u32 *)iv;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
if(mode & AES_INPUT_NORMAL)
{
REG_AESCTR[0] = iv32[3];
REG_AESCTR[1] = iv32[2];
REG_AESCTR[2] = iv32[1];
REG_AESCTR[3] = iv32[0];
}
else
{
REG_AESCTR[0] = iv32[0];
REG_AESCTR[1] = iv32[1];
REG_AESCTR[2] = iv32[2];
REG_AESCTR[3] = iv32[3];
}
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
if(mode & AES_INPUT_NORMAL)
{
REG_AESCTR[0] = iv32[3];
REG_AESCTR[1] = iv32[2];
REG_AESCTR[2] = iv32[1];
REG_AESCTR[3] = iv32[0];
}
else
{
REG_AESCTR[0] = iv32[0];
REG_AESCTR[1] = iv32[1];
REG_AESCTR[2] = iv32[2];
REG_AESCTR[3] = iv32[3];
}
}
static void aes_advctr(void *ctr, u32 val, u32 mode)
{
u32 *ctr32 = (u32 *)ctr;
int i;
if(mode & AES_INPUT_BE)
{
for(i = 0; i < 4; ++i) // Endian swap
BSWAP32(ctr32[i]);
}
if(mode & AES_INPUT_NORMAL)
{
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
}
else
{
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
}
if(mode & AES_INPUT_BE)
{
for(i = 0; i < 4; ++i) // Endian swap
BSWAP32(ctr32[i]);
}
u32 *ctr32 = (u32 *)ctr;
int i;
if(mode & AES_INPUT_BE)
{
for(i = 0; i < 4; ++i) // Endian swap
BSWAP32(ctr32[i]);
}
if(mode & AES_INPUT_NORMAL)
{
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
}
else
{
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
}
if(mode & AES_INPUT_BE)
{
for(i = 0; i < 4; ++i) // Endian swap
BSWAP32(ctr32[i]);
}
}
static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
{
u32 *ctr32 = (u32 *)ctr;
int i;
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
{
for(i = 0; i < 4; ++i)
BSWAP32(ctr32[i]);
}
u32 *ctr32 = (u32 *)ctr;
int i;
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
{
for(i = 0; i < 4; ++i)
BSWAP32(ctr32[i]);
}
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
{
u32 temp = ctr32[0];
ctr32[0] = ctr32[3];
ctr32[3] = temp;
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
{
u32 temp = ctr32[0];
ctr32[0] = ctr32[3];
ctr32[3] = temp;
temp = ctr32[1];
ctr32[1] = ctr32[2];
ctr32[2] = temp;
}
temp = ctr32[1];
ctr32[1] = ctr32[2];
ctr32[2] = temp;
}
}
static void aes_batch(void *dst, const void *src, u32 blockCount)
{
*REG_AESBLKCNT = blockCount << 16;
*REG_AESCNT |= AES_CNT_START;
const u32 *src32 = (const u32 *)src;
u32 *dst32 = (u32 *)dst;
u32 wbc = blockCount;
u32 rbc = blockCount;
while(rbc)
{
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
{
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
wbc--;
}
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
{
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
rbc--;
}
}
*REG_AESBLKCNT = blockCount << 16;
*REG_AESCNT |= AES_CNT_START;
const u32 *src32 = (const u32 *)src;
u32 *dst32 = (u32 *)dst;
u32 wbc = blockCount;
u32 rbc = blockCount;
while(rbc)
{
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
{
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
wbc--;
}
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
{
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
rbc--;
}
}
}
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
{
*REG_AESCNT = mode |
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
*REG_AESCNT = mode |
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
u32 blocks;
while(blockCount != 0)
{
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
aes_setiv(iv, ivMode);
u32 blocks;
while(blockCount != 0)
{
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
aes_setiv(iv, ivMode);
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
// Save the last block for the next decryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
{
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
}
// Save the last block for the next decryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
{
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
}
// Process the current batch
aes_batch(dst, src, blocks);
// Process the current batch
aes_batch(dst, src, blocks);
// Save the last block for the next encryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
{
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
}
// Advance counter for CTR mode
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
aes_advctr(iv, blocks, ivMode);
// Save the last block for the next encryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
{
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
}
// Advance counter for CTR mode
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
aes_advctr(iv, blocks, ivMode);
src += blocks * AES_BLOCK_SIZE;
dst += blocks * AES_BLOCK_SIZE;
blockCount -= blocks;
}
src += blocks * AES_BLOCK_SIZE;
dst += blocks * AES_BLOCK_SIZE;
blockCount -= blocks;
}
}
static void sha_wait_idle()
{
while(*REG_SHA_CNT & 1);
while(*REG_SHA_CNT & 1);
}
static void sha(void *res, const void *src, u32 size, u32 mode)
{
sha_wait_idle();
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
const u32 *src32 = (const u32 *)src;
int i;
while(size >= 0x40)
{
sha_wait_idle();
for(i = 0; i < 4; ++i)
{
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
}
sha_wait_idle();
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
const u32 *src32 = (const u32 *)src;
int i;
while(size >= 0x40)
{
sha_wait_idle();
for(i = 0; i < 4; ++i)
{
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
}
size -= 0x40;
}
sha_wait_idle();
memcpy((void *)REG_SHA_INFIFO, src32, size);
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
sha_wait_idle();
u32 hashSize = SHA_256_HASH_SIZE;
if(mode == SHA_224_MODE)
hashSize = SHA_224_HASH_SIZE;
else if(mode == SHA_1_MODE)
hashSize = SHA_1_HASH_SIZE;
size -= 0x40;
}
sha_wait_idle();
memcpy((void *)REG_SHA_INFIFO, src32, size);
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
sha_wait_idle();
u32 hashSize = SHA_256_HASH_SIZE;
if(mode == SHA_224_MODE)
hashSize = SHA_224_HASH_SIZE;
else if(mode == SHA_1_MODE)
hashSize = SHA_1_HASH_SIZE;
memcpy(res, (void *)REG_SHA_HASH, hashSize);
memcpy(res, (void *)REG_SHA_HASH, hashSize);
}
/****************************************************************
* NAND/FIRM crypto
* NAND/FIRM crypto
****************************************************************/
static u8 nandCTR[0x10],
nandSlot;
static u8 __attribute__((aligned(4))) nandCTR[0x10];
static u8 nandSlot;
static u32 fatStart;
//Initialize the CTRNAND crypto
void ctrNandInit(void)
{
u8 cid[0x10];
u8 shaSum[0x20];
u8 __attribute__((aligned(4))) cid[0x10];
u8 __attribute__((aligned(4))) shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE);
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);
nandSlot = 0x05;
fatStart = 0x5CAD7;
}
@@ -306,13 +327,13 @@ void ctrNandInit(void)
//Read and decrypt from the selected CTRNAND
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{
u8 tmpCTR[0x10];
u8 __attribute__((aligned(4))) tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Read
u32 result;
if(!firmSource)
if(firmSource == FIRMWARE_SYSNAND)
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
else
{
@@ -327,6 +348,24 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
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
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);
}
//ARM9Loader replacement
void arm9Loader(u8 *arm9Section, u32 mode)
/* ARM9Loader replacement
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
u8 keyY[0x10],
arm9BinCTR[0x10],
arm9BinSlot = mode ? 0x16 : 0x15;
u8 __attribute__((aligned(4))) keyY[0x10];
u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10);
@@ -362,13 +417,18 @@ void arm9Loader(u8 *arm9Section, u32 mode)
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
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},
key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
u8 keyX[0x10];
u8 __attribute__((aligned(4))) 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(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
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);
//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},
decKey[0x10];
u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
u8 __attribute__((aligned(4))) decKey[0x10];
//Set keys 0x19..0x1F keyXs
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_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
*/
@@ -9,79 +29,85 @@
#include "types.h"
/**************************AES****************************/
#define REG_AESCNT ((vu32 *)0x10009000)
#define REG_AESBLKCNT ((vu32 *)0x10009004)
#define REG_AESWRFIFO ((vu32 *)0x10009008)
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
#define REG_AESKEYSEL ((vu8 *)0x10009010)
#define REG_AESKEYCNT ((vu8 *)0x10009011)
#define REG_AESCTR ((vu32 *)0x10009020)
#define REG_AESCNT ((vu32 *)0x10009000)
#define REG_AESBLKCNT ((vu32 *)0x10009004)
#define REG_AESWRFIFO ((vu32 *)0x10009008)
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
#define REG_AESKEYSEL ((vu8 *)0x10009010)
#define REG_AESKEYCNT ((vu8 *)0x10009011)
#define REG_AESCTR ((vu32 *)0x10009020)
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
#define AES_CCM_DECRYPT_MODE (0u << 27)
#define AES_CCM_ENCRYPT_MODE (1u << 27)
#define AES_CTR_MODE (2u << 27)
#define AES_CTR_MODE (2u << 27)
#define AES_CBC_DECRYPT_MODE (4u << 27)
#define AES_CBC_ENCRYPT_MODE (5u << 27)
#define AES_ECB_DECRYPT_MODE (6u << 27)
#define AES_ECB_ENCRYPT_MODE (7u << 27)
#define AES_ALL_MODES (7u << 27)
#define AES_CCM_DECRYPT_MODE (0u << 27)
#define AES_CCM_ENCRYPT_MODE (1u << 27)
#define AES_CTR_MODE (2u << 27)
#define AES_CTR_MODE (2u << 27)
#define AES_CBC_DECRYPT_MODE (4u << 27)
#define AES_CBC_ENCRYPT_MODE (5u << 27)
#define AES_ECB_DECRYPT_MODE (6u << 27)
#define AES_ECB_ENCRYPT_MODE (7u << 27)
#define AES_ALL_MODES (7u << 27)
#define AES_CNT_START 0x80000000
#define AES_CNT_INPUT_ORDER 0x02000000
#define AES_CNT_OUTPUT_ORDER 0x01000000
#define AES_CNT_INPUT_ENDIAN 0x00800000
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
#define AES_CNT_FLUSH_READ 0x00000800
#define AES_CNT_FLUSH_WRITE 0x00000400
#define AES_CNT_START 0x80000000
#define AES_CNT_INPUT_ORDER 0x02000000
#define AES_CNT_OUTPUT_ORDER 0x01000000
#define AES_CNT_INPUT_ENDIAN 0x00800000
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
#define AES_CNT_FLUSH_READ 0x00000800
#define AES_CNT_FLUSH_WRITE 0x00000400
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
#define AES_INPUT_LE 0
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
#define AES_INPUT_REVERSED 0
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
#define AES_INPUT_LE 0
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
#define AES_INPUT_REVERSED 0
#define AES_BLOCK_SIZE 0x10
#define AES_BLOCK_SIZE 0x10
#define AES_KEYCNT_WRITE (1 << 0x7)
#define AES_KEYNORMAL 0
#define AES_KEYX 1
#define AES_KEYY 2
#define AES_KEYCNT_WRITE (1 << 0x7)
#define AES_KEYNORMAL 0
#define AES_KEYX 1
#define AES_KEYY 2
/**************************SHA****************************/
#define REG_SHA_CNT ((vu32 *)0x1000A000)
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
#define REG_SHA_HASH ((vu32 *)0x1000A040)
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
#define REG_SHA_CNT ((vu32 *)0x1000A000)
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
#define REG_SHA_HASH ((vu32 *)0x1000A040)
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
#define SHA_CNT_STATE 0x00000003
#define SHA_CNT_UNK2 0x00000004
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
#define SHA_CNT_MODE 0x00000030
#define SHA_CNT_ENABLE 0x00010000
#define SHA_CNT_ACTIVE 0x00020000
#define SHA_CNT_STATE 0x00000003
#define SHA_CNT_UNK2 0x00000004
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
#define SHA_CNT_MODE 0x00000030
#define SHA_CNT_ENABLE 0x00010000
#define SHA_CNT_ACTIVE 0x00020000
#define SHA_HASH_READY 0x00000000
#define SHA_NORMAL_ROUND 0x00000001
#define SHA_FINAL_ROUND 0x00000002
#define SHA_HASH_READY 0x00000000
#define SHA_NORMAL_ROUND 0x00000001
#define SHA_FINAL_ROUND 0x00000002
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
#define SHA_OUTPUT_LE 0
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
#define SHA_OUTPUT_LE 0
#define SHA_256_MODE 0
#define SHA_224_MODE 0x00000010
#define SHA_1_MODE 0x00000020
#define SHA_256_MODE 0
#define SHA_224_MODE 0x00000010
#define SHA_1_MODE 0x00000020
#define SHA_256_HASH_SIZE (256 / 8)
#define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8)
#define SHA_256_HASH_SIZE (256 / 8)
#define SHA_224_HASH_SIZE (224 / 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);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void setRSAMod0DerivedKeys(void);
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
* https://github.com/mid-kid/CakesForeveryWan/
*/
#include "draw.h"
#include "screeninit.h"
#include "screen.h"
#include "utils.h"
#include "fs.h"
#include "memory.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)
{
char *stringEnd = (char *)string;
@@ -26,22 +40,20 @@ static inline int strlen(const char *string)
return stringEnd - string;
}
void clearScreens(void)
{
memset32(fb->top_left, 0, 0x46500);
memset32(fb->top_right, 0, 0x46500);
memset32(fb->bottom, 0, 0x38400);
}
u32 loadSplash(void)
bool loadSplash(void)
{
//Don't delay boot nor init the screens if no splash image is on the SD
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splash.bin") == 0)
return false;
initScreens();
//Don't delay boot if no splash image is on the SD
if(fileRead(fb->top_left, "/luma/splash.bin") +
fileRead(fb->bottom, "/luma/splashbottom.bin"))
return 1;
return 0;
fileRead(fb->top_left, "/luma/splash.bin");
fileRead(fb->bottom, "/luma/splashbottom.bin");
chrono(3);
return true;
}
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
* https://github.com/mid-kid/CakesForeveryWan/
*/
#pragma once
@@ -19,7 +40,6 @@
#define COLOR_RED 0x0000FF
#define COLOR_BLACK 0x000000
u32 loadSplash(void);
void clearScreens(void);
bool loadSplash(void);
void drawCharacter(char character, 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"
@@ -7,12 +25,12 @@
#include "fatfs/sdmmc/sdmmc.h"
#include "../build/emunandpatch.h"
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND)
void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND)
{
static u8 *const temp = (u8 *)0x24300000;
static u8 temp[0x200];
const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = *emuNAND == 1 ? 0 :
u32 nandOffset = *emuNAND == FIRMWARE_EMUNAND ? 0 :
(nandSize > 0x200000 ? 0x400000 : 0x200000);
//Check for RedNAND
@@ -35,7 +53,7 @@ void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND)
or to SysNAND if there isn't any */
else
{
(*emuNAND)--;
*emuNAND = (*emuNAND == FIRMWARE_EMUNAND2) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
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
@@ -8,5 +26,5 @@
#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);

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)
First stable version.
The first release.
@@ -246,9 +246,22 @@ R0.11a (September 05, 2015)
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)
Changed some members in FINFO structure and behavior of f_readdir().
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
Fixed errors in the case conversion teble of Unicode (cc*.c).
Added an option _USE_CHMOD.
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

1500
source/fatfs/ff.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

102
source/fatfs/ff.h Normal file → Executable file
View File

@@ -1,11 +1,13 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
/----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of
/ following conditions.
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT file system module R0.12a /
/-----------------------------------------------------------------------------/
/
/ 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,
/ this condition and the following disclaimer.
/
@@ -13,11 +15,11 @@
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/---------------------------------------------------------------------------*/
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 88100 /* Revision ID */
#define _FATFS 80186 /* Revision ID */
#ifdef __cplusplus
extern "C" {
@@ -25,6 +27,7 @@ extern "C" {
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
@@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if _LFN_UNICODE /* Unicode (UTF-16) string */
#if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
@@ -61,14 +64,25 @@ typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#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
@@ -87,6 +101,9 @@ typedef struct {
#if _MAX_SS != _MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif
#if _USE_LFN != 0
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if _FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#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) */
typedef struct {
@@ -159,14 +163,14 @@ typedef struct {
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
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) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
#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
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
@@ -183,10 +187,9 @@ typedef struct {
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
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
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
WCHAR* lfn; /* Pointer to the LFN working buffer */
#endif
#if _USE_FIND
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_NOT_ENABLED, /* (12) The volume has no work area */
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_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
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_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_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing 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 the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the 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_closedir (DIR* dp); /* Close an open directory */
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_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_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp 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 a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
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_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_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
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 */
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_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 */
/* 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_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define _FA_MODIFIED 0x20
#define _FA_DIRTY 0x40
#define FA_OPEN_APPEND 0x30
/* 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_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
/* File attribute bits for directory entry */
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#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

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
@@ -15,7 +15,7 @@
/ 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.
/
/ 0: All basic functions are enabled.
@@ -62,8 +62,7 @@
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be 1. */
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
@@ -118,13 +117,13 @@
#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.
/ This option also affects behavior of string I/O functions. */
#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().
/
/ 0: ANSI/OEM
@@ -153,7 +152,7 @@
#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.
/ 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
@@ -217,7 +216,7 @@
#define _FS_NORTC 1
#define _NORTC_MON 3
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2016
/* 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"
@@ -8,35 +26,44 @@
#include "fs.h"
#include "patches.h"
#include "memory.h"
#include "cache.h"
#include "emunand.h"
#include "crypto.h"
#include "draw.h"
#include "screeninit.h"
#include "screen.h"
#include "buttons.h"
#include "pin.h"
#include "../build/injector.h"
extern u16 launchedFirmTIDLow[8]; //defined in start.s
static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section;
u32 config,
console,
firmSource,
emuOffset;
bool isN3DS, isDevUnit;
FirmwareSource firmSource;
void main(void)
{
u32 bootType,
firmType,
nandType,
a9lhMode,
updatedSys,
needConfig,
newConfig,
emuHeader,
chronoStarted = 0;
bool isFirmlaunch,
isA9lh;
u32 newConfig,
emuHeader;
FirmwareType firmType;
FirmwareSource nandType;
ConfigurationStatus needConfig;
//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
mountFs();
@@ -44,153 +71,140 @@ void main(void)
const char configPath[] = "/luma/config.bin";
//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
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
firmType = *(vu8 *)0x23F00009 == '3' ? 3 : *(vu8 *)0x23F00005 - '0';
firmType = launchedFirmTIDLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTIDLow[5] - u'0');
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
a9lhMode = BOOTCONFIG(3, 1);
updatedSys = a9lhMode && CONFIG(1);
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
isA9lh = BOOTCONFIG(3, 1) != 0;
}
else
{
//Get pressed buttons
u32 pressed = HID_PAD;
//If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)))
{
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;
isFirmlaunch = false;
firmType = NATIVE_FIRM;
//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
if(a9lhBoot || CONFIG(2))
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
newConfig = (u32)isA9lh << 3;
//If it's a MCU reboot, try to force boot options
if(isA9lh && CFG_BOOTENV)
{
a9lhMode = 1;
updatedSys = CONFIG(1);
}
else
{
a9lhMode = 0;
updatedSys = 0;
}
newConfig = a9lhMode << 3;
if(a9lhBoot)
{
//Retrieve the last booted FIRM
u32 previousFirm = CFG_BOOTENV;
//If it's a MCU reboot, try to force boot options
if(previousFirm)
//Always force a sysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV == 7)
{
//Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 7)
{
nandType = 0;
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
needConfig = 0;
nandType = FIRMWARE_SYSNAND;
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing
newConfig |= 1 << 4;
}
/* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1))
{
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
needConfig = 0;
}
//Flag to prevent multiple boot options-forcing
newConfig |= 1 << 4;
}
//If the SAFE MODE combo is held, force a sysNAND boot
else if(pressed == SAFE_MODE)
/* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1))
{
a9lhMode = 2;
nandType = 0;
firmSource = 0;
needConfig = 0;
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
}
}
//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,
chainload an external payload */
if((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
loadPayload(pressed);
PINData pin;
//If screens are inited or the corresponding option is set, load splash screen
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
bool pinExists = CONFIG(7) && readPin(&pin);
//If we get here we should check the PIN (if it exists) in all cases
if(pinExists) verifyPin(&pin);
//If no configuration file exists or SELECT is held, load configuration menu
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
if(shouldLoadConfigurationMenu)
{
chronoStarted = 2;
chrono(0);
configureCFW(configPath);
if(!pinExists && CONFIG(7)) newPin();
chrono(2);
//Update pressed buttons
pressed = HID_PAD;
}
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
if(pressed & BUTTON_R1)
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
{
nandType = updatedSys;
firmSource = !nandType;
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_SYSNAND;
}
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else
{
nandType = CONFIG(0) != !(pressed & BUTTON_L1);
firmSource = nandType;
}
if(CONFIG(6) && loadSplash()) pressed = HID_PAD;
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */
if(nandType && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = 2;
/* 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(pressed & BUTTON_R1)
{
nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
}
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else
{
nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = nandType;
}
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */
if(nandType != FIRMWARE_SYSNAND && (CONFIG(2) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
}
}
}
//If we need to boot emuNAND, make sure it exists
if(nandType)
if(nandType != FIRMWARE_SYSNAND)
{
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
else if(firmSource)
else if(firmSource != FIRMWARE_SYSNAND)
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.
Just the no-forcing flag being set is not enough */
@@ -199,88 +213,63 @@ void main(void)
//Preserve user settings (last 26 bits)
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)
{
case 0:
patchNativeFirm(nandType, emuHeader, a9lhMode);
case NATIVE_FIRM:
patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
break;
case 3:
case SAFE_FIRM:
patchSafeFirm();
break;
default:
patchLegacyFirm(firmType);
//Skip patching on unsupported O3DS AGB/TWL FIRMs
if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
break;
}
if(chronoStarted)
{
if(chronoStarted == 2) chrono(3);
stopChrono();
}
launchFirm(firmType, bootType);
launchFirm(firmType, isFirmlaunch);
}
static inline void loadFirm(u32 firmType, u32 externalFirm)
static inline u32 loadFirm(FirmwareType firmType)
{
section = firm->section;
u32 externalFirmLoaded = externalFirm &&
fileRead(firm, "/luma/firmware.bin") &&
(((u32)section[2].address >> 8) & 0xFF) == (console ? 0x60 : 0x68);
//Load FIRM from CTRNAND, unless it's an O3DS and we're loading a pre-5.0 NATIVE FIRM
u32 firmVersion = firmRead(firm, (u32)firmType);
/* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM
doesn't match the console, load FIRM from CTRNAND */
if(!externalFirmLoaded)
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
{
const char *firmFolders[4][2] = {{ "00000002", "20000002" },
{ "00000102", "20000102" },
{ "00000202", "20000202" },
{ "00000003", "20000003" }};
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
firmRead(firm, firmFolders[firmType][console]);
decryptExeFs((u8 *)firm);
//No assumption regarding FIRM version
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;
u32 nativeFirmType;
if(console)
if(isN3DS)
{
//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
arm9Loader(arm9Section, nativeFirmType);
arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C;
}
else
{
//Determine if we're booting the 9.0 FIRM
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;
}
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
//Find the Process9 .code location, size and memory address
u32 process9Size,
@@ -291,48 +280,49 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
patchSignatureChecks(process9Offset, process9Size);
//Apply emuNAND patches
if(nandType)
if(nandType != FIRMWARE_SYSNAND)
{
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
patchEmuNAND(arm9Section, section[2].size, process9Offset, process9Size, emuOffset, emuHeader, branchAdditive);
}
//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
if(nativeFirmType || a9lhMode == 2) patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
//Apply firmlaunch patches
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);
//Does nothing if svcBackdoor is still there
//Restore svcBackdoor
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(console)
if(isN3DS)
{
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;
}
applyLegacyFirmPatches((u8 *)firm, firmType, console);
applyLegacyFirmPatches((u8 *)firm, firmType);
}
static inline void patchSafeFirm(void)
{
u8 *arm9Section = (u8 *)firm + section[2].offset;
if(console)
if(isN3DS)
{
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, 0);
arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C;
patchFirmWrites(arm9Section, section[2].size);
@@ -352,11 +342,11 @@ static inline void copySection0AndInjectLoader(void)
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
u32 sectionNum;
if(!firmType)
if(firmType == NATIVE_FIRM)
{
copySection0AndInjectLoader();
sectionNum = 1;
@@ -369,7 +359,7 @@ static inline void launchFirm(u32 firmType, u32 bootType)
//Determine the ARM11 entry to use
vu32 *arm11;
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
if(isFirmlaunch) arm11 = (u32 *)0x1FFFFFFC;
else
{
deinitScreens();
@@ -379,6 +369,9 @@ static inline void launchFirm(u32 firmType, u32 bootType)
//Set ARM11 kernel entrypoint
*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
((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
@@ -9,6 +27,7 @@
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
#define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CFG_UNITINFO (*(vu8 *)0x10010010)
//FIRM Header layout
typedef struct firmSectionHeader {
@@ -28,9 +47,16 @@ typedef struct firmHeader {
firmSectionHeader section[4];
} firmHeader;
static inline void loadFirm(u32 firmType, u32 externalFirm);
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode);
static inline void patchLegacyFirm(u32 firmType);
typedef enum ConfigurationStatus
{
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 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 "memory.h"
#include "screeninit.h"
#include "cache.h"
#include "screen.h"
#include "fatfs/ff.h"
#include "buttons.h"
#include "../build/loader.h"
@@ -12,12 +31,10 @@
static FATFS sdFs,
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);
return 1;
}
u32 fileRead(void *dest, const char *path)
@@ -29,7 +46,8 @@ u32 fileRead(void *dest, const char *path)
{
unsigned int read;
size = f_size(&file);
f_read(&file, dest, size, &read);
if(dest != NULL)
f_read(&file, dest, size, &read);
f_close(&file);
}
else size = 0;
@@ -37,7 +55,12 @@ u32 fileRead(void *dest, const char *path)
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;
@@ -46,7 +69,16 @@ void fileWrite(const void *buffer, const char *path, u32 size)
unsigned int written;
f_write(&file, buffer, size, &written);
f_close(&file);
return true;
}
return false;
}
void createDirectory(const char *path)
{
f_mkdir(path);
}
void loadPayload(u32 pressed)
@@ -76,7 +108,7 @@ void loadPayload(u32 pressed)
{
initScreens();
u32 *const loaderAddress = (u32 *)0x24FFFB00;
u32 *const loaderAddress = (u32 *)0x24FFFF00;
memcpy(loaderAddress, loader, loader_size);
@@ -85,21 +117,29 @@ void loadPayload(u32 pressed)
loaderAddress[1] = fileRead((void *)0x24F00000, path);
flushDCacheRange(loaderAddress, loader_size);
flushICacheRange(loaderAddress, loader_size);
((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";
memcpy(&path[18], firmFolder, 8);
memcpy(&path[18], firmFolders[firmType][isN3DS ? 1 : 0], 8);
DIR dir;
FILINFO info;
f_opendir(&dir, path);
u32 id = 0xFFFFFFFF;
u32 firmVersion = 0xFFFFFFFF;
//Parse the target directory
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;
//Convert the .app name to an integer
u32 tempId = 0;
u32 tempVersion = 0;
for(char *tmp = info.altname; *tmp != '.'; tmp++)
{
tempId <<= 4;
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
tempVersion <<= 4;
tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
}
//Found an older cxi
if(tempId < id) id = tempId;
if(tempVersion < firmVersion) firmVersion = tempVersion;
}
f_closedir(&dir);
@@ -128,12 +168,15 @@ void firmRead(void *dest, const char *firmFolder)
u32 i = 42;
//Convert back the .app name from integer to array
while(id)
u32 tempVersion = firmVersion;
while(tempVersion)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[id & 0xF];
id >>= 4;
path[i--] = hexDigits[tempVersion & 0xF];
tempVersion >>= 4;
}
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
@@ -8,8 +26,12 @@
#define PATTERN(a) a "_*.bin"
u32 mountFs(void);
extern bool isN3DS;
void mountFs(void);
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 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"
//-----------------------------------------------------------------------------

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
#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
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#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
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#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"
@@ -101,7 +119,7 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
if(!svcTable[0x7B])
if(svcTable[0x7B] == 0)
{
u32 *freeSpace;
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
@@ -121,7 +139,7 @@ void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
if(off != NULL) off[4] = 0xE0;
}
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
{
const patchData twlPatches[] = {
{{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
if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) :
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
//Patch
for(u32 i = 0; i < numPatches; i++)
@@ -151,12 +169,12 @@ void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
switch(patches[i].type)
{
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;
case 2:
*(u16 *)(pos + patches[i].offset[console] + 2) = 0;
*(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0] + 2) = 0;
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;
}
}
@@ -167,7 +185,7 @@ u32 getLoader(u8 *pos, u32 *loaderSize)
u8 *off = pos;
u32 size;
while(1)
while(true)
{
size = *(u32 *)(off + 0x104) * 0x200;
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
@@ -15,6 +33,8 @@ typedef struct patchData {
u32 type;
} patchData;
extern bool isN3DS;
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
void patchSignatureChecks(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 patchFirmWriteSafe(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);

167
source/pin.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* pin.c
* Code to manage pin locking for 3ds. By reworks.
*/
#include "draw.h"
#include "screen.h"
#include "utils.h"
#include "memory.h"
#include "buttons.h"
#include "fs.h"
#include "pin.h"
#include "crypto.h"
bool readPin(PINData *out)
{
u8 __attribute__((aligned(4))) zeroes[16] = {0};
u8 __attribute__((aligned(4))) tmp[32] = {0};
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
if(memcmp(out->magic, "PINF", 4) != 0) return false;
computePINHash(tmp, zeroes, 1);
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
}
static inline char PINKeyToLetter(u32 pressed)
{
const char keys[] = "AB--------XY";
u32 i;
__asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
return keys[31 - i];
}
void newPin(void)
{
clearScreens();
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
// Set the default value as 0x00 so we can check if there are any unentered characters.
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
u32 cnt = 0;
int charDrawPos = 20 * SPACING_X;
while(cnt < PIN_LENGTH)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
pressed &= PIN_BUTTONS & ~BUTTON_START;
if(!pressed) continue;
char key = PINKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; // add character to password.
// visualize character on screen.
drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
charDrawPos += 2 * SPACING_X;
}
PINData pin = {0};
u8 __attribute__((aligned(4))) tmp[32] = {0};
u8 __attribute__((aligned(4))) zeroes[16] = {0};
memcpy(pin.magic, "PINF", 4);
pin.formatVersionMajor = 1;
pin.formatVersionMinor = 0;
computePINHash(tmp, zeroes, 1);
memcpy(pin.testHash, tmp, 32);
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
memcpy(pin.hash, tmp, 32);
fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
while(HID_PAD & PIN_BUTTONS);
}
void verifyPin(PINData *in)
{
initScreens();
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
// Set the default characters as 0x00 so we can check if there are any unentered characters.
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
u32 cnt = 0;
bool unlock = false;
int charDrawPos = 5 * SPACING_X;
while(!unlock)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS));
pressed &= PIN_BUTTONS & ~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);
}
}
}
}

46
source/pin.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* pin.h
*
* Code to manage pin locking for 3ds. By reworks.
*/
#pragma once
#include "types.h"
#define PIN_LENGTH 4
typedef struct __attribute__((packed))
{
char magic[4];
u16 formatVersionMajor, formatVersionMinor;
u8 testHash[32];
u8 hash[32];
} PINData;
bool readPin(PINData* out);
void newPin(void);
void verifyPin(PINData *in);

259
source/screen.c Normal file
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
.align 4
.global _start
_start:
b start
.word 0, 0
.global launchedFirmTIDLow
launchedFirmTIDLow:
.hword 0, 0, 0, 0, 0, 0, 0, 0
start:
@ Change the stack pointer
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
ldr r0, =0x33333333
ldr r0, =0x3333333
mcr p15, 0, r0, c5, c0, 2 @ write data access
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
@ Set MPU permissions and cache settings
ldr r0, =0xFFFF001D @ ffff0000 32k
ldr r1, =0x01FF801D @ 01ff8000 32k
ldr r2, =0x08000027 @ 08000000 1M
ldr r3, =0x10000021 @ 10000000 128k
ldr r4, =0x10100025 @ 10100000 512k
ldr r5, =0x20000035 @ 20000000 128M
ldr r6, =0x1FF00027 @ 1FF00000 1M
ldr r7, =0x1800002D @ 18000000 8M
ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
ldr r6, =0x1800002D @ 18000000 8M | vram (+ 2MB)
mov r7, #0
mov r8, #0x15
mcr p15, 0, r0, c6, c0, 0
mcr p15, 0, r1, c6, c1, 0
mcr p15, 0, r2, c6, c2, 0
@@ -32,24 +73,18 @@ start:
mcr p15, 0, r5, c6, c5, 0
mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0
mov r0, #0x25
mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5
mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5
mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 4
mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 4
mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 4
@ Enable caches
@ Enable caches / MPU / ITCM
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<<2) @ - data cache enable
orr r0, r0, #(1<<0) @ - mpu enable
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
ldr r0, =0x10000020
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
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
//Common data types
typedef uint8_t u8;
@@ -15,4 +34,20 @@ typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
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 "i2c.h"
#include "buttons.h"
#include "screen.h"
#include "draw.h"
#include "cache.h"
u32 waitInput(void)
{
@@ -35,8 +56,22 @@ u32 waitInput(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);
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
@@ -44,34 +79,46 @@ static inline void startChrono(u64 initialTicks)
{
//Based on a NATIVE_FIRM disassembly
*(vu16 *)0x10003002 = 0; //67MHz
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 4; //Count-up
REG_TIMER_CNT(0) = 0; //67MHz
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
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 0x84; //Count-up; enabled
REG_TIMER_CNT(0) = 0x80; //67MHz; 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)
{
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;
do
{
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);
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
#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);
void mcuReboot(void);
#define TICKS_PER_SEC 67027964ULL
void mcuPowerOff(void);
void chrono(u32 seconds);
void stopChrono(void);
void error(const char *message);