Merge branch 'master' into developer
Conflicts: source/config.c source/firm.c source/fs.c source/fs.h source/patches.c source/patches.h source/utils.h
This commit is contained in:
commit
cf7fa8ecbd
@ -408,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);
|
||||
@ -577,7 +577,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
||||
}
|
||||
|
||||
default:
|
||||
if(CONFIG(4))
|
||||
if(CONFIG(3))
|
||||
{
|
||||
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
|
||||
|
||||
|
@ -28,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)
|
||||
@ -42,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)
|
@ -25,13 +25,11 @@
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "fs.h"
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
|
||||
void configureCFW(const char *configPath)
|
||||
{
|
||||
bool needToDeinit = initScreens();
|
||||
|
||||
clearScreens();
|
||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
||||
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
||||
|
||||
@ -40,13 +38,13 @@ void configureCFW(const char *configPath)
|
||||
"Dev. features: None( ) ErrDisp( ) UNITINFO( )" };
|
||||
|
||||
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 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" };
|
||||
"( ) Enable splash screen with no screen-init",
|
||||
"( ) Use a PIN" };
|
||||
|
||||
struct multiOption {
|
||||
int posXs[4];
|
||||
@ -196,16 +194,13 @@ void configureCFW(const char *configPath)
|
||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -294,16 +294,16 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||
* 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);
|
||||
@ -311,7 +311,7 @@ void ctrNandInit(void)
|
||||
|
||||
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;
|
||||
@ -326,7 +326,7 @@ 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);
|
||||
|
||||
@ -350,8 +350,8 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
|
||||
void setRSAMod0DerivedKeys(void)
|
||||
{
|
||||
const u8 keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
|
||||
const u8 keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
|
||||
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);
|
||||
@ -374,14 +374,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
|
||||
//Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
|
||||
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);
|
||||
@ -393,13 +408,13 @@ 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];
|
||||
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};
|
||||
u8 __attribute__((aligned(4))) keyX[0x10];
|
||||
|
||||
aes_setkey(0x11, mode == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x11, a9lVersion == 2 ? 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);
|
||||
@ -413,10 +428,10 @@ 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 == 2)
|
||||
if(a9lVersion == 2)
|
||||
{
|
||||
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);
|
||||
@ -427,4 +442,16 @@ void arm9Loader(u8 *arm9Section, u32 mode)
|
||||
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);
|
||||
}
|
@ -107,4 +107,6 @@ 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);
|
@ -46,8 +46,8 @@ bool loadSplash(void)
|
||||
|
||||
//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") != 0)
|
||||
return true;
|
||||
fileRead(fb->bottom, "/luma/splashbottom.bin")) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
21
source/fatfs/00history.txt
Normal file → Executable file
21
source/fatfs/00history.txt
Normal file → Executable file
@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
|
||||
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
2
source/fatfs/00readme.txt
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
FatFs Module Source Files R0.12
|
||||
FatFs Module Source Files R0.12a
|
||||
|
||||
|
||||
FILES
|
||||
|
1500
source/fatfs/ff.c
Normal file → Executable file
1500
source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
102
source/fatfs/ff.h
Normal file → Executable file
102
source/fatfs/ff.h
Normal file → Executable file
@ -1,11 +1,13 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
|
||||
/----------------------------------------------------------------------------/
|
||||
/ FatFs 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
|
||||
|
15
source/fatfs/ffconf.h
Normal file → Executable file
15
source/fatfs/ffconf.h
Normal file → Executable file
@ -1,8 +1,8 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 88100 /* Revision ID */
|
||||
#define _FFCONF 80186 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@ -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
0
source/fatfs/integer.h
Normal file → Executable file
0
source/fatfs/option/ccsbcs.c
Normal file → Executable file
0
source/fatfs/option/ccsbcs.c
Normal file → Executable file
269
source/firm.c
269
source/firm.c
@ -33,6 +33,8 @@
|
||||
#include "draw.h"
|
||||
#include "screen.h"
|
||||
#include "buttons.h"
|
||||
#include "pin.h"
|
||||
#include "i2c.h"
|
||||
#include "../build/injector.h"
|
||||
|
||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
||||
@ -45,10 +47,12 @@ bool isN3DS;
|
||||
|
||||
FirmwareSource firmSource;
|
||||
|
||||
PINData pin;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bool isFirmlaunch,
|
||||
updatedSys;
|
||||
isA9lh;
|
||||
|
||||
u32 newConfig,
|
||||
emuHeader,
|
||||
@ -57,7 +61,6 @@ void main(void)
|
||||
FirmwareType firmType;
|
||||
FirmwareSource nandType;
|
||||
ConfigurationStatus needConfig;
|
||||
A9LHMode a9lhMode;
|
||||
|
||||
//Detect the console being used
|
||||
isN3DS = PDN_MPCORE_CFG == 7;
|
||||
@ -88,82 +91,44 @@ void main(void)
|
||||
|
||||
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
|
||||
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
|
||||
a9lhMode = (A9LHMode)BOOTCONFIG(3, 1);
|
||||
updatedSys = a9lhMode != NO_A9LH && CONFIG(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 == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)))
|
||||
{
|
||||
configureCFW(configPath);
|
||||
|
||||
//Zero the last booted FIRM flag
|
||||
CFG_BOOTENV = 0;
|
||||
|
||||
nbChronoStarted = 1;
|
||||
chrono(0);
|
||||
chrono(2);
|
||||
|
||||
//Update pressed buttons
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
|
||||
isFirmlaunch = false;
|
||||
firmType = NATIVE_FIRM;
|
||||
|
||||
//Determine if booting with A9LH
|
||||
bool a9lhBoot = !PDN_SPI_CNT;
|
||||
isA9lh = !PDN_SPI_CNT;
|
||||
|
||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
||||
if(a9lhBoot || CONFIG(2))
|
||||
{
|
||||
a9lhMode = A9LH_WITH_NFIRM_FIRMPROT;
|
||||
updatedSys = CONFIG(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
a9lhMode = NO_A9LH;
|
||||
updatedSys = false;
|
||||
}
|
||||
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
||||
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
|
||||
|
||||
newConfig = (u32)a9lhMode << 3;
|
||||
newConfig = (u32)isA9lh << 3;
|
||||
|
||||
if(a9lhBoot)
|
||||
//If it's a MCU reboot, try to force boot options
|
||||
if(isA9lh && CFG_BOOTENV)
|
||||
{
|
||||
//If it's a MCU reboot, try to force boot options
|
||||
if(CFG_BOOTENV)
|
||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||
if(CFG_BOOTENV == 7)
|
||||
{
|
||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||
if(CFG_BOOTENV == 7)
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = updatedSys ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
|
||||
needConfig = DONT_CONFIGURE;
|
||||
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 = (FirmwareSource)BOOTCONFIG(0, 3);
|
||||
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
|
||||
needConfig = DONT_CONFIGURE;
|
||||
}
|
||||
//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 = A9LH_WITH_SFIRM_FIRMPROT;
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
|
||||
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
|
||||
needConfig = DONT_CONFIGURE;
|
||||
}
|
||||
}
|
||||
@ -171,36 +136,83 @@ void main(void)
|
||||
//Boot options aren't being forced
|
||||
if(needConfig != DONT_CONFIGURE)
|
||||
{
|
||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||
chainload an external payload */
|
||||
if(DEVMODE || (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
|
||||
loadPayload(pressed);
|
||||
//If no configuration file exists or SELECT is held, load configuration menu
|
||||
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
|
||||
bool pinExists = CONFIG(7) && readPin(&pin);
|
||||
|
||||
//If screens are inited or the corresponding option is set, load splash screen
|
||||
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
|
||||
if(pinExists || shouldLoadConfigurationMenu)
|
||||
{
|
||||
nbChronoStarted = 2;
|
||||
chrono(0);
|
||||
bool needToDeinit = initScreens();
|
||||
|
||||
//If we get here we should check the PIN (if it exists) in all cases
|
||||
if(pinExists) verifyPin(&pin, true);
|
||||
|
||||
if(shouldLoadConfigurationMenu)
|
||||
{
|
||||
configureCFW(configPath);
|
||||
|
||||
if(!pinExists && CONFIG(7)) pin = newPin();
|
||||
|
||||
//Zero the last booted FIRM flag
|
||||
CFG_BOOTENV = 0;
|
||||
|
||||
nbChronoStarted = 1;
|
||||
chrono(0);
|
||||
chrono(2);
|
||||
|
||||
//Update pressed buttons
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
|
||||
if(needToDeinit)
|
||||
{
|
||||
//Turn off backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
|
||||
deinitScreens();
|
||||
PDN_GPU_CNT = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//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) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||
firmSource = (updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||
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)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||
firmSource = nandType;
|
||||
}
|
||||
{
|
||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||
chainload an external payload (verify the PIN if needed)*/
|
||||
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
|
||||
|
||||
/* 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(3) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
|
||||
if(shouldLoadPayload)
|
||||
loadPayload(pressed);
|
||||
|
||||
//If screens are inited or the corresponding option is set, load splash screen
|
||||
if((PDN_GPU_CNT != 1 || CONFIG(6)) && loadSplash())
|
||||
{
|
||||
nbChronoStarted = 2;
|
||||
chrono(0);
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,22 +238,24 @@ 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 == NATIVE_FIRM && firmSource == ((updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND));
|
||||
u32 firmVersion = loadFirm(firmType);
|
||||
|
||||
switch(firmType)
|
||||
{
|
||||
case NATIVE_FIRM:
|
||||
patchNativeFirm(nandType, emuHeader, a9lhMode);
|
||||
patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -254,69 +268,41 @@ void main(void)
|
||||
launchFirm(firmType, isFirmlaunch);
|
||||
}
|
||||
|
||||
static inline void loadFirm(FirmwareType firmType, bool externalFirm)
|
||||
static inline u32 loadFirm(FirmwareType firmType)
|
||||
{
|
||||
section = firm->section;
|
||||
|
||||
bool externalFirmLoaded = externalFirm &&
|
||||
fileRead(firm, "/luma/firmware.bin") &&
|
||||
(((u32)section[2].address >> 8) & 0xFF) == (isN3DS ? 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[(u32)firmType][isN3DS ? 1 : 0]);
|
||||
decryptExeFs((u8 *)firm);
|
||||
//9.6 O3DS FIRM
|
||||
firmVersion = 0x49;
|
||||
}
|
||||
else decryptExeFs((u8 *)firm);
|
||||
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHMode a9lhMode)
|
||||
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + section[2].offset,
|
||||
*arm11Section1 = (u8 *)firm + section[1].offset;
|
||||
|
||||
bool is90Firm;
|
||||
|
||||
if(isN3DS)
|
||||
{
|
||||
u32 a9lVersion;
|
||||
|
||||
//Determine the NATIVE_FIRM/arm9loader version
|
||||
switch(arm9Section[0x53])
|
||||
{
|
||||
case 0xFF:
|
||||
a9lVersion = 0;
|
||||
break;
|
||||
case '1':
|
||||
a9lVersion = 1;
|
||||
break;
|
||||
default:
|
||||
a9lVersion = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||
arm9Loader(arm9Section, a9lVersion);
|
||||
arm9Loader(arm9Section);
|
||||
firm->arm9Entry = (u8 *)0x801B01C;
|
||||
is90Firm = a9lVersion == 0;
|
||||
}
|
||||
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};
|
||||
is90Firm = memcmp(section[2].hash, firm90Hash, 0x10) == 0;
|
||||
}
|
||||
|
||||
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
|
||||
if(a9lhMode == NO_A9LH)
|
||||
setRSAMod0DerivedKeys();
|
||||
|
||||
//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,
|
||||
process9MemAddr;
|
||||
@ -333,17 +319,18 @@ static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHM
|
||||
}
|
||||
|
||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||
else if(a9lhMode != NO_A9LH) patchFirmWrites(process9Offset, process9Size);
|
||||
else if(isA9lh) patchFirmWrites(process9Offset, process9Size);
|
||||
|
||||
//Apply firmlaunch patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||
if(!is90Firm || a9lhMode == A9LH_WITH_SFIRM_FIRMPROT) patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
||||
//Apply firmlaunch patches
|
||||
patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
||||
|
||||
if(!is90Firm)
|
||||
//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(arm11Section1, section[1].size);
|
||||
}
|
||||
|
||||
@ -376,7 +363,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||
if(isN3DS)
|
||||
{
|
||||
arm9Loader(arm9Section, 0);
|
||||
arm9Loader(arm9Section);
|
||||
firm->arm9Entry = (u8 *)0x801301C;
|
||||
}
|
||||
|
||||
@ -387,7 +374,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
||||
patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address));
|
||||
}
|
||||
|
||||
applyLegacyFirmPatches((u8 *)firm, firmType, isN3DS);
|
||||
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||
}
|
||||
|
||||
static inline void patchSafeFirm(void)
|
||||
@ -397,7 +384,7 @@ static inline void patchSafeFirm(void)
|
||||
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);
|
||||
@ -500,12 +487,12 @@ static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
|
||||
arm11 = (u32 *)0x1FFFFFF8;
|
||||
}
|
||||
|
||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
flushEntireICache();
|
||||
|
||||
//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)();
|
||||
}
|
@ -53,15 +53,8 @@ typedef enum ConfigurationStatus
|
||||
CREATE_CONFIGURATION = 2
|
||||
} ConfigurationStatus;
|
||||
|
||||
typedef enum A9LHMode
|
||||
{
|
||||
NO_A9LH = 0,
|
||||
A9LH_WITH_NFIRM_FIRMPROT = 1,
|
||||
A9LH_WITH_SFIRM_FIRMPROT = 2
|
||||
} A9LHMode;
|
||||
|
||||
static inline void loadFirm(FirmwareType firmType, bool externalFirm);
|
||||
static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHMode a9lhMode);
|
||||
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 copySection0AndInjectSystemModules(void);
|
||||
|
46
source/fs.c
46
source/fs.c
@ -31,12 +31,10 @@
|
||||
static FATFS sdFs,
|
||||
nandFs;
|
||||
|
||||
bool mountFs(void)
|
||||
void mountFs(void)
|
||||
{
|
||||
if(f_mount(&sdFs, "0:", 1) != FR_OK) return false;
|
||||
f_mount(&sdFs, "0:", 1);
|
||||
f_mount(&nandFs, "1:", 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 fileRead(void *dest, const char *path)
|
||||
@ -62,7 +60,7 @@ u32 getFileSize(const char *path)
|
||||
return fileRead(NULL, path);
|
||||
}
|
||||
|
||||
void fileWrite(const void *buffer, const char *path, u32 size)
|
||||
bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||
{
|
||||
FIL file;
|
||||
|
||||
@ -71,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)
|
||||
@ -115,6 +122,7 @@ void loadPayload(u32 pressed)
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_size);
|
||||
flushICacheRange(loaderAddress, loader_size);
|
||||
|
||||
((void (*)())loaderAddress)();
|
||||
}
|
||||
}
|
||||
@ -140,17 +148,22 @@ void findDumpFile(const char *path, char *fileName)
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
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])
|
||||
@ -159,15 +172,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);
|
||||
@ -179,12 +192,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;
|
||||
}
|
@ -26,10 +26,13 @@
|
||||
|
||||
#define PATTERN(a) a "_*.bin"
|
||||
|
||||
bool mountFs(void);
|
||||
extern bool isN3DS;
|
||||
|
||||
void mountFs(void);
|
||||
u32 getFileSize(const char *path);
|
||||
u32 fileRead(void *dest, const char *path);
|
||||
void fileWrite(const void *buffer, const char *path, u32 size);
|
||||
bool fileWrite(const void *buffer, const char *path, u32 size);
|
||||
void createDirectory(const char *path);
|
||||
void findDumpFile(const char *path, char *fileName);
|
||||
void loadPayload(u32 pressed);
|
||||
void firmRead(void *dest, const char *firmFolder);
|
||||
u32 firmRead(void *dest, u32 firmType);
|
@ -240,10 +240,10 @@ void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, 4);
|
||||
|
||||
if(off != NULL) off[4] = 0xE0;
|
||||
off[4] = 0xE0;
|
||||
}
|
||||
|
||||
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType, bool isN3DS)
|
||||
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
|
||||
{
|
||||
const patchData twlPatches[] = {
|
||||
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||
@ -264,7 +264,7 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType, bool isN3DS)
|
||||
/* 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 == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
|
||||
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
|
||||
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
|
||||
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
|
||||
|
||||
//Patch
|
||||
|
@ -33,6 +33,8 @@ typedef struct patchData {
|
||||
u32 type;
|
||||
} patchData;
|
||||
|
||||
extern bool isN3DS;
|
||||
|
||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||
u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr, u32 *codeSetOffset);
|
||||
void patchSignatureChecks(u8 *pos, u32 size);
|
||||
@ -46,5 +48,5 @@ void patchSvcBreak11(u8 *pos, u32 size);
|
||||
void patchUnitInfoValueSet(u8 *pos, u32 size);
|
||||
void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size);
|
||||
void reimplementSvcBackdoor(u8 *pos, u32 size);
|
||||
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType, bool isN3DS);
|
||||
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
|
||||
u8 *getUnitInfoValueSet(u8 *pos, u32 size);
|
||||
|
180
source/pin.c
Normal file
180
source/pin.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pin.c
|
||||
* Code to manage pin locking for 3ds. By reworks.
|
||||
*/
|
||||
|
||||
#include "draw.h"
|
||||
#include "screen.h"
|
||||
#include "utils.h"
|
||||
#include "memory.h"
|
||||
#include "buttons.h"
|
||||
#include "fs.h"
|
||||
#include "i2c.h"
|
||||
#include "pin.h"
|
||||
#include "crypto.h"
|
||||
|
||||
bool readPin(PINData *out)
|
||||
{
|
||||
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
|
||||
else if(memcmp(out->magic, "PINF", 4) != 0) return false;
|
||||
|
||||
computePINHash(tmp, zeroes, 1);
|
||||
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
|
||||
}
|
||||
|
||||
static inline char PINKeyToLetter(u32 pressed)
|
||||
{
|
||||
const char keys[] = "AB--------XY";
|
||||
|
||||
u32 i;
|
||||
__asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
|
||||
|
||||
return keys[31 - i];
|
||||
}
|
||||
|
||||
PINData newPin(void)
|
||||
{
|
||||
clearScreens();
|
||||
|
||||
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
|
||||
|
||||
u32 pressed = 0;
|
||||
|
||||
// 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
|
||||
|
||||
int charDrawPos = 20 * SPACING_X;
|
||||
int cnt = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
|
||||
|
||||
pressed &= PIN_BUTTONS & ~BUTTON_START;
|
||||
|
||||
if(!pressed) continue;
|
||||
char key = PINKeyToLetter(pressed);
|
||||
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||
|
||||
// visualize character on screen.
|
||||
drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
|
||||
charDrawPos += 2 * SPACING_X;
|
||||
|
||||
// we leave the rest of the array zeroed out.
|
||||
if (cnt >= PIN_LENGTH)
|
||||
{
|
||||
|
||||
PINData pin = {0};
|
||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||
|
||||
memcpy(pin.magic, "PINF", 4);
|
||||
pin.formatVersionMajor = 1;
|
||||
pin.formatVersionMinor = 0;
|
||||
|
||||
computePINHash(tmp, zeroes, 1);
|
||||
memcpy(pin.testHash, tmp, 32);
|
||||
|
||||
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
||||
memcpy(pin.hash, tmp, 32);
|
||||
|
||||
fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
|
||||
return pin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void verifyPin(PINData *in, bool allowQuit)
|
||||
{
|
||||
clearScreens();
|
||||
|
||||
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
u32 pressed = 0;
|
||||
|
||||
// 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};
|
||||
|
||||
bool unlock;
|
||||
int charDrawPos = 5 * SPACING_X, cnt = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS));
|
||||
|
||||
pressed &= PIN_BUTTONS;// & ~BUTTON_START;
|
||||
if(!allowQuit) pressed &= ~BUTTON_START;
|
||||
if(!pressed) continue;
|
||||
|
||||
if(pressed & BUTTON_START)
|
||||
{
|
||||
clearScreens();
|
||||
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)
|
||||
{
|
||||
// re zero out all 16 just in case.
|
||||
memset32(enteredPassword, 0, 16);
|
||||
|
||||
pressed = 0;
|
||||
charDrawPos = 5 * SPACING_X;
|
||||
cnt = 0;
|
||||
|
||||
clearScreens();
|
||||
|
||||
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
}
|
||||
}
|
49
source/pin.h
Normal file
49
source/pin.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pin.h
|
||||
*
|
||||
* Code to manage pin locking for 3ds. By reworks.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifndef PIN_LENGTH
|
||||
#define PIN_LENGTH 4
|
||||
#endif
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char magic[4];
|
||||
u16 formatVersionMajor, formatVersionMinor;
|
||||
|
||||
u8 testHash[32];
|
||||
u8 hash[32];
|
||||
} PINData;
|
||||
|
||||
bool readPin(PINData* out);
|
||||
|
||||
PINData newPin(void);
|
||||
void verifyPin(PINData *in, bool allowQuit);
|
@ -32,39 +32,36 @@
|
||||
#include "draw.h"
|
||||
#include "i2c.h"
|
||||
|
||||
#define ARM11_STUB_ADDRESS (0x25000000 - 0x40) //It's currently only 0x28 bytes large. We're putting 0x40 just to be sure here
|
||||
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
|
||||
vu32 *arm11Entry = (vu32 *)0x1FFFFFF8;
|
||||
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 inline void invokeArm11Function(void (*func)())
|
||||
static void invokeArm11Function(void (*func)())
|
||||
{
|
||||
static bool hasCopiedStub = false;
|
||||
if(!hasCopiedStub)
|
||||
{
|
||||
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x40);
|
||||
flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x40);
|
||||
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
|
||||
flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x30);
|
||||
hasCopiedStub = true;
|
||||
}
|
||||
|
||||
|
||||
*arm11Entry = (u32)func;
|
||||
while(*arm11Entry);
|
||||
*arm11Entry = ARM11_STUB_ADDRESS;
|
||||
}
|
||||
|
||||
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||
|
||||
void deinitScreens(void)
|
||||
{
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
@ -83,25 +80,24 @@ void deinitScreens(void)
|
||||
if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11);
|
||||
}
|
||||
|
||||
void updateBrightness(u32 brightnessLevel)
|
||||
void updateBrightness(u32 brightnessIndex)
|
||||
{
|
||||
static int brightnessValue;
|
||||
|
||||
brightnessValue = brightness[brightnessLevel];
|
||||
|
||||
static u32 brightnessLevel;
|
||||
brightnessLevel = brightness[brightnessIndex];
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
//Change brightness
|
||||
*(vu32 *)0x10202240 = brightnessValue;
|
||||
*(vu32 *)0x10202A40 = brightnessValue;
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange(&brightnessValue, 4);
|
||||
|
||||
flushDCacheRange(&brightnessLevel, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
}
|
||||
|
||||
@ -111,9 +107,8 @@ void clearScreens(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
|
||||
@ -125,7 +120,7 @@ void clearScreens(void)
|
||||
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)
|
||||
@ -134,33 +129,33 @@ void clearScreens(void)
|
||||
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);
|
||||
}
|
||||
|
||||
u32 initScreens(void)
|
||||
bool initScreens(void)
|
||||
{
|
||||
u32 needToInit = PDN_GPU_CNT == 1;
|
||||
bool needToInit = PDN_GPU_CNT == 1;
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
u32 brightnessLevel = MULTICONFIG(0);
|
||||
u32 brightnessLevel = brightness[MULTICONFIG(0)];
|
||||
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||
*(vu32 *)0x10202240 = brightness[brightnessLevel];
|
||||
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
*(vu32 *)0x10202244 = 0x1023E;
|
||||
*(vu32 *)0x10202A44 = 0x1023E;
|
||||
|
||||
@ -246,7 +241,7 @@ u32 initScreens(void)
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
|
||||
if(needToInit)
|
||||
{
|
||||
flushDCacheRange(&config, 4);
|
||||
@ -256,9 +251,8 @@ u32 initScreens(void)
|
||||
//Turn on backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||
}
|
||||
else
|
||||
updateBrightness(MULTICONFIG(0));
|
||||
|
||||
else updateBrightness(MULTICONFIG(0));
|
||||
|
||||
clearScreens();
|
||||
|
||||
return needToInit;
|
||||
|
@ -30,14 +30,16 @@
|
||||
#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;
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} *const fb = (volatile struct fb *)0x23FFFE00;
|
||||
|
||||
void deinitScreens(void);
|
||||
void updateBrightness(u32 brightnessLevel);
|
||||
void updateBrightness(u32 brightnessIndex);
|
||||
void clearScreens(void);
|
||||
u32 initScreens(void);
|
||||
bool initScreens(void);
|
@ -23,7 +23,8 @@
|
||||
#include "utils.h"
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
#include "memory.h"
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "cache.h"
|
||||
|
||||
u32 waitInput(void)
|
||||
@ -58,7 +59,15 @@ void mcuReboot(void)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void mcuPowerOff(void)
|
||||
@ -104,4 +113,17 @@ void chrono(u32 seconds)
|
||||
void stopChrono(void)
|
||||
{
|
||||
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
|
||||
}
|
||||
|
||||
void error(const char *message)
|
||||
{
|
||||
initScreens();
|
||||
clearScreens();
|
||||
|
||||
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();
|
||||
}
|
@ -24,13 +24,14 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u32 waitInput(void);
|
||||
void mcuReboot(void);
|
||||
void mcuPowerOff(void);
|
||||
|
||||
#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);
|
||||
void mcuPowerOff(void);
|
||||
|
||||
void chrono(u32 seconds);
|
||||
void stopChrono(void);
|
||||
void stopChrono(void);
|
||||
void error(const char *message);
|
Reference in New Issue
Block a user