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:
TuxSH 2016-08-03 22:52:51 +02:00
commit cf7fa8ecbd
25 changed files with 1490 additions and 954 deletions

View File

@ -408,7 +408,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET case 0x0004001000028000LL: // TWN MSET
{ {
if(CONFIG(5)) if(CONFIG(4))
{ {
static const u16 verPattern[] = u"Ver."; static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3); const u32 currentNand = BOOTCONFIG(0, 3);
@ -577,7 +577,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
} }
default: default:
if(CONFIG(4)) if(CONFIG(3))
{ {
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24; u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;

View File

@ -28,7 +28,7 @@
#define BUTTON_R1 (1 << 8) #define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9) #define BUTTON_L1 (1 << 9)
#define BUTTON_A 1 #define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1) #define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10) #define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11) #define BUTTON_Y (1 << 11)
@ -43,3 +43,4 @@
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y) #define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT) #define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START) #define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_START)

View File

@ -25,13 +25,11 @@
#include "screen.h" #include "screen.h"
#include "draw.h" #include "draw.h"
#include "fs.h" #include "fs.h"
#include "i2c.h"
#include "buttons.h" #include "buttons.h"
void configureCFW(const char *configPath) void configureCFW(const char *configPath)
{ {
bool needToDeinit = initScreens(); clearScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE); drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE); drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
@ -40,13 +38,13 @@ void configureCFW(const char *configPath)
"Dev. features: None( ) ErrDisp( ) UNITINFO( )" }; "Dev. features: None( ) ErrDisp( ) UNITINFO( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND", const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) SysNAND is updated (A9LH-only)", "( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Force A9LH detection",
"( ) Use second EmuNAND as default", "( ) Use second EmuNAND as default",
"( ) Enable region/language emu. and ext. .code", "( ) Enable region/language emu. and ext. .code",
"( ) Show current NAND in System Settings", "( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Enable splash screen with no screen-init" }; "( ) Enable splash screen with no screen-init",
"( ) Use a PIN" };
struct multiOption { struct multiOption {
int posXs[4]; int posXs[4];
@ -196,16 +194,13 @@ void configureCFW(const char *configPath)
for(u32 i = 0; i < singleOptionsAmount; i++) for(u32 i = 0; i < singleOptionsAmount; i++)
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16); config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
fileWrite(&config, configPath, 4); if(!fileWrite(&config, configPath, 4))
{
createDirectory("luma");
if(!fileWrite(&config, configPath, 4))
error("Error writing the configuration file");
}
//Wait for the pressed buttons to change //Wait for the pressed buttons to change
while(HID_PAD == BUTTON_START); while(HID_PAD == BUTTON_START);
if(needToDeinit)
{
//Turn off backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
deinitScreens();
PDN_GPU_CNT = 1;
}
} }

View File

@ -294,16 +294,16 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
* NAND/FIRM crypto * NAND/FIRM crypto
****************************************************************/ ****************************************************************/
static u8 nandCTR[0x10], static u8 __attribute__((aligned(4))) nandCTR[0x10];
nandSlot; static u8 nandSlot;
static u32 fatStart; static u32 fatStart;
//Initialize the CTRNAND crypto //Initialize the CTRNAND crypto
void ctrNandInit(void) void ctrNandInit(void)
{ {
u8 cid[0x10]; u8 __attribute__((aligned(4))) cid[0x10];
u8 shaSum[0x20]; u8 __attribute__((aligned(4))) shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid); sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE); sha(shaSum, cid, 0x10, SHA_256_MODE);
@ -311,7 +311,7 @@ void ctrNandInit(void)
if(isN3DS) if(isN3DS)
{ {
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; u8 __attribute__((aligned(4))) keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05; nandSlot = 0x05;
fatStart = 0x5CAD7; fatStart = 0x5CAD7;
@ -326,7 +326,7 @@ void ctrNandInit(void)
//Read and decrypt from the selected CTRNAND //Read and decrypt from the selected CTRNAND
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf) u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{ {
u8 tmpCTR[0x10]; u8 __attribute__((aligned(4))) tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10); memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
@ -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 //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
void setRSAMod0DerivedKeys(void) 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 __attribute__((aligned(4))) 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))) 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(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x2F, keyY0x2F, AES_KEYY, 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); aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
//ARM9Loader replacement /* ARM9Loader replacement
//Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 */
void arm9Loader(u8 *arm9Section, u32 mode) void arm9Loader(u8 *arm9Section)
{ {
//Determine the arm9loader version
u32 a9lVersion;
switch(arm9Section[0x53])
{
case 0xFF:
a9lVersion = 0;
break;
case '1':
a9lVersion = 1;
break;
default:
a9lVersion = 2;
break;
}
//Firm keys //Firm keys
u8 keyY[0x10], u8 __attribute__((aligned(4))) keyY[0x10];
arm9BinCTR[0x10], u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
arm9BinSlot = mode ? 0x16 : 0x15; u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption //Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(keyY, arm9Section + 0x10, 0x10);
@ -393,13 +408,13 @@ void arm9Loader(u8 *arm9Section, u32 mode)
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++) for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0'; arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
if(mode) if(a9lVersion)
{ {
const u8 key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, const u8 __attribute__((aligned(4))) 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}; const u8 __attribute__((aligned(4))) 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];
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_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
@ -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); aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Set >=9.6 KeyXs //Set >=9.6 KeyXs
if(mode == 2) if(a9lVersion == 2)
{ {
u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98}, u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
decKey[0x10]; u8 __attribute__((aligned(4))) decKey[0x10];
//Set keys 0x19..0x1F keyXs //Set keys 0x19..0x1F keyXs
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
@ -428,3 +443,15 @@ void arm9Loader(u8 *arm9Section, u32 mode)
} }
} }
} }
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

@ -107,4 +107,6 @@ void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void setRSAMod0DerivedKeys(void); void setRSAMod0DerivedKeys(void);
void decryptExeFs(u8 *inbuf); void decryptExeFs(u8 *inbuf);
void arm9Loader(u8 *arm9Section, u32 mode); void arm9Loader(u8 *arm9Section);
void computePINHash(u8 out[32], u8 *in, u32 blockCount);

View File

@ -46,8 +46,8 @@ bool loadSplash(void)
//Don't delay boot if no splash image is on the SD //Don't delay boot if no splash image is on the SD
if(fileRead(fb->top_left, "/luma/splash.bin") + if(fileRead(fb->top_left, "/luma/splash.bin") +
fileRead(fb->bottom, "/luma/splashbottom.bin") != 0) fileRead(fb->bottom, "/luma/splashbottom.bin")) return true;
return true;
return false; return false;
} }

21
source/fatfs/00history.txt Normal file → Executable file
View File

@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
R0.01 (April 29, 2006) R0.01 (April 29, 2006)
First stable version. The first release.
@ -246,9 +246,22 @@ R0.11a (September 05, 2015)
R0.12 (April 12, 2016) R0.12 (April 12, 2016)
Added support of exFAT file system. (_FS_EXFAT) Added support for exFAT file system. (_FS_EXFAT)
Added f_expand(). (_USE_EXPAND) Added f_expand(). (_USE_EXPAND)
Changed some members in FINFO structure and behavior of f_readdir(). Changed some members in FINFO structure and behavior of f_readdir().
Added an option _USE_CHMOD and removed an option _WORD_ACCESS. Added an option _USE_CHMOD.
Fixed errors in the case conversion teble of Unicode (cc*.c). Removed an option _WORD_ACCESS.
Fixed errors in the case conversion table of Unicode (cc*.c).
R0.12a (July 10, 2016)
Added support for creating exFAT volume with some changes of f_mkfs().
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
f_forward() is available regardless of _FS_TINY.
Fixed f_mkfs() creates wrong volume.
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
Fixed wrong memory read in create_name().

2
source/fatfs/00readme.txt Normal file → Executable file
View File

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

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 - Generic FAT file system module R0.12a /
/----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of
/ following conditions.
/ /
/ Copyright (C) 2016, ChaN, all right reserved. / Copyright (C) 2016, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/ 1. Redistributions of source code must retain the above copyright notice, / 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer. / this condition and the following disclaimer.
/ /
@ -13,11 +15,11 @@
/ and any warranties related to this software are DISCLAIMED. / and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused / The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software. / by use of this software.
/---------------------------------------------------------------------------*/ /----------------------------------------------------------------------------*/
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 88100 /* Revision ID */ #define _FATFS 80186 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -25,6 +27,7 @@ extern "C" {
#include "integer.h" /* Basic integer types */ #include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF #if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h). #error Wrong configuration file (ffconf.h).
#endif #endif
@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
/* Type of path name strings on FatFs API */ /* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */ #if _LFN_UNICODE /* Unicode (UTF-16) string */
#if _USE_LFN == 0 #if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg. #error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif #endif
@ -61,14 +64,25 @@ typedef WCHAR TCHAR;
#define _T(x) L ## x #define _T(x) L ## x
#define _TEXT(x) L ## x #define _TEXT(x) L ## x
#endif #endif
#else /* ANSI/OEM string */ #else /* ANSI/OEM string */
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef char TCHAR; typedef char TCHAR;
#define _T(x) x #define _T(x) x
#define _TEXT(x) x #define _TEXT(x) x
#endif #endif
#endif
/* Type of file size variables */
#if _FS_EXFAT
#if _USE_LFN == 0
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif #endif
@ -87,6 +101,9 @@ typedef struct {
#if _MAX_SS != _MIN_SS #if _MAX_SS != _MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif #endif
#if _USE_LFN != 0
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if _FS_EXFAT #if _FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer */ BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#endif #endif
@ -117,19 +134,6 @@ typedef struct {
/* Type of file size variables and object identifier */
#if _FS_EXFAT
#if _USE_LFN == 0
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* Object ID and allocation information (_FDID) */ /* Object ID and allocation information (_FDID) */
typedef struct { typedef struct {
@ -159,14 +163,14 @@ typedef struct {
BYTE flag; /* File status flags */ BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */ BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY #if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */ DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif #endif
#if _USE_FASTSEEK #if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif #endif
#if !_FS_TINY #if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */ BYTE buf[_MAX_SS]; /* File private data read/write window */
@ -183,10 +187,9 @@ typedef struct {
DWORD clust; /* Current cluster */ DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */ DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if _USE_LFN != 0 #if _USE_LFN != 0
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
WCHAR* lfn; /* Pointer to the LFN working buffer */
#endif #endif
#if _USE_FIND #if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */ const TCHAR* pat; /* Pointer to the name matching pattern */
@ -229,7 +232,7 @@ typedef enum {
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
@ -244,11 +247,11 @@ typedef enum {
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */ FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
@ -258,8 +261,8 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
@ -269,8 +272,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
@ -323,40 +326,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
/* Flags and offset address */ /* Flags and offset address */
/* File access control and file status flags (FIL.flag) */ /* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01 #define FA_READ 0x01
#define FA_WRITE 0x02 #define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00 #define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04 #define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08 #define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_ALWAYS 0x10
#define _FA_MODIFIED 0x20 #define FA_OPEN_APPEND 0x30
#define _FA_DIRTY 0x40
/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
/* FAT sub type (FATFS.fs_type) */ /* Format options (2nd argument of f_mkfs) */
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1 #define FS_FAT12 1
#define FS_FAT16 2 #define FS_FAT16 2
#define FS_FAT32 3 #define FS_FAT32 3
#define FS_EXFAT 4 #define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */ #define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */ #define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */ #define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */ #define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */ #define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek controls */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
#ifdef __cplusplus #ifdef __cplusplus

15
source/fatfs/ffconf.h Normal file → Executable file
View File

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016 / FatFs - FAT file system module configuration file
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 88100 /* Revision ID */ #define _FFCONF 80186 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -62,8 +62,7 @@
#define _USE_FORWARD 0 #define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) /* This option switches f_forward() function. (0:Disable or 1:Enable) */
/ To enable it, also _FS_TINY need to be 1. */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
@ -118,13 +117,13 @@
#define _LFN_UNICODE 0 #define _LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ This option also affects behavior of string I/O functions. */ / This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 3 #define _STRF_ENCODE 3
/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to /* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/ /
/ 0: ANSI/OEM / 0: ANSI/OEM
@ -153,7 +152,7 @@
#define _STR_VOLUME_ID 0 #define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" #define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* _STR_VOLUME_ID switches string support of volume ID. /* _STR_VOLUME_ID switches string support of volume ID.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each / number in the path name. _VOLUME_STRS defines the drive ID strings for each
@ -217,7 +216,7 @@
#define _FS_NORTC 1 #define _FS_NORTC 1
#define _NORTC_MON 3 #define _NORTC_MON 1
#define _NORTC_MDAY 1 #define _NORTC_MDAY 1
#define _NORTC_YEAR 2016 #define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have /* The option _FS_NORTC switches timestamp functiton. If the system does not have

0
source/fatfs/integer.h Normal file → Executable file
View File

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

View File

@ -33,6 +33,8 @@
#include "draw.h" #include "draw.h"
#include "screen.h" #include "screen.h"
#include "buttons.h" #include "buttons.h"
#include "pin.h"
#include "i2c.h"
#include "../build/injector.h" #include "../build/injector.h"
static firmHeader *const firm = (firmHeader *)0x24000000; static firmHeader *const firm = (firmHeader *)0x24000000;
@ -45,10 +47,12 @@ bool isN3DS;
FirmwareSource firmSource; FirmwareSource firmSource;
PINData pin;
void main(void) void main(void)
{ {
bool isFirmlaunch, bool isFirmlaunch,
updatedSys; isA9lh;
u32 newConfig, u32 newConfig,
emuHeader, emuHeader,
@ -57,7 +61,6 @@ void main(void)
FirmwareType firmType; FirmwareType firmType;
FirmwareSource nandType; FirmwareSource nandType;
ConfigurationStatus needConfig; ConfigurationStatus needConfig;
A9LHMode a9lhMode;
//Detect the console being used //Detect the console being used
isN3DS = PDN_MPCORE_CFG == 7; isN3DS = PDN_MPCORE_CFG == 7;
@ -88,82 +91,44 @@ void main(void)
nandType = (FirmwareSource)BOOTCONFIG(0, 3); nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1); firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
a9lhMode = (A9LHMode)BOOTCONFIG(3, 1); isA9lh = BOOTCONFIG(3, 1) != 0;
updatedSys = a9lhMode != NO_A9LH && CONFIG(1);
} }
else else
{ {
//Get pressed buttons //Get pressed buttons
u32 pressed = HID_PAD; u32 pressed = HID_PAD;
//If no configuration file exists or SELECT is held, load configuration menu
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; isFirmlaunch = false;
firmType = NATIVE_FIRM; firmType = NATIVE_FIRM;
//Determine if booting with A9LH //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 //Determine if the user chose to use the SysNAND FIRM as default for a R boot
if(a9lhBoot || CONFIG(2)) bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
{
a9lhMode = A9LH_WITH_NFIRM_FIRMPROT;
updatedSys = CONFIG(1);
}
else
{
a9lhMode = NO_A9LH;
updatedSys = 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 //Always force a sysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV) if(CFG_BOOTENV == 7)
{ {
//Always force a sysNAND boot when quitting AGB_FIRM nandType = FIRMWARE_SYSNAND;
if(CFG_BOOTENV == 7) firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
{ needConfig = DONT_CONFIGURE;
nandType = FIRMWARE_SYSNAND;
firmSource = updatedSys ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing //Flag to prevent multiple boot options-forcing
newConfig |= 1 << 4; newConfig |= 1 << 4;
}
/* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1))
{
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
}
} }
//If the SAFE MODE combo is held, force a sysNAND boot /* Else, force the last used boot options unless a button is pressed
else if(pressed == SAFE_MODE) or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1))
{ {
a9lhMode = A9LH_WITH_SFIRM_FIRMPROT; nandType = (FirmwareSource)BOOTCONFIG(0, 3);
nandType = FIRMWARE_SYSNAND; firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
firmSource = FIRMWARE_SYSNAND;
needConfig = DONT_CONFIGURE; needConfig = DONT_CONFIGURE;
} }
} }
@ -171,36 +136,83 @@ void main(void)
//Boot options aren't being forced //Boot options aren't being forced
if(needConfig != DONT_CONFIGURE) if(needConfig != DONT_CONFIGURE)
{ {
/* If L and R/A/Select or one of the single payload buttons are pressed, //If no configuration file exists or SELECT is held, load configuration menu
chainload an external payload */ bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
if(DEVMODE || (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS))) bool pinExists = CONFIG(7) && readPin(&pin);
loadPayload(pressed);
//If screens are inited or the corresponding option is set, load splash screen if(pinExists || shouldLoadConfigurationMenu)
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
{ {
nbChronoStarted = 2; bool needToDeinit = initScreens();
chrono(0);
//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(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
if(pressed & BUTTON_R1)
{ {
nandType = (updatedSys) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; nandType = FIRMWARE_SYSNAND;
firmSource = (updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND; firmSource = FIRMWARE_SYSNAND;
} }
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else else
{ {
nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; /* If L and R/A/Select or one of the single payload buttons are pressed,
firmSource = nandType; 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, if(shouldLoadPayload)
or vice-versa, boot the second emuNAND */ loadPayload(pressed);
if(nandType != FIRMWARE_SYSNAND && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
//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) //Preserve user settings (last 26 bits)
newConfig |= config & 0xFFFFFFC0; newConfig |= config & 0xFFFFFFC0;
fileWrite(&newConfig, configPath, 4); if(!fileWrite(&newConfig, configPath, 4))
error("Error writing the configuration file");
} }
} }
loadFirm(firmType, firmType == NATIVE_FIRM && firmSource == ((updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND)); u32 firmVersion = loadFirm(firmType);
switch(firmType) switch(firmType)
{ {
case NATIVE_FIRM: case NATIVE_FIRM:
patchNativeFirm(nandType, emuHeader, a9lhMode); patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
break; break;
case SAFE_FIRM: case SAFE_FIRM:
patchSafeFirm(); patchSafeFirm();
break; break;
default: default:
patchLegacyFirm(firmType); //Skip patching on unsupported O3DS AGB/TWL FIRMs
if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
break; break;
} }
@ -254,68 +268,40 @@ void main(void)
launchFirm(firmType, isFirmlaunch); launchFirm(firmType, isFirmlaunch);
} }
static inline void loadFirm(FirmwareType firmType, bool externalFirm) static inline u32 loadFirm(FirmwareType firmType)
{ {
section = firm->section; section = firm->section;
bool externalFirmLoaded = externalFirm && //Load FIRM from CTRNAND, unless it's an O3DS and we're loading a pre-5.0 NATIVE FIRM
fileRead(firm, "/luma/firmware.bin") && u32 firmVersion = firmRead(firm, (u32)firmType);
(((u32)section[2].address >> 8) & 0xFF) == (isN3DS ? 0x60 : 0x68);
/* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
doesn't match the console, load FIRM from CTRNAND */
if(!externalFirmLoaded)
{ {
const char *firmFolders[4][2] = {{ "00000002", "20000002" }, if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
{ "00000102", "20000102" }, error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
{ "00000202", "20000202" },
{ "00000003", "20000003" }};
firmRead(firm, firmFolders[(u32)firmType][isN3DS ? 1 : 0]); //9.6 O3DS FIRM
decryptExeFs((u8 *)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, u8 *arm9Section = (u8 *)firm + section[2].offset,
*arm11Section1 = (u8 *)firm + section[1].offset; *arm11Section1 = (u8 *)firm + section[1].offset;
bool is90Firm;
if(isN3DS) 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 //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, a9lVersion); arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C; 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 //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
if(a9lhMode == NO_A9LH) else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
setRSAMod0DerivedKeys();
//Find the Process9 .code location, size and memory address //Find the Process9 .code location, size and memory address
u32 process9Size, u32 process9Size,
@ -333,17 +319,18 @@ static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHM
} }
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH //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 //Apply firmlaunch patches
if(!is90Firm || a9lhMode == A9LH_WITH_SFIRM_FIRMPROT) patchFirmlaunches(process9Offset, process9Size, process9MemAddr); 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); patchTitleInstallMinVersionCheck(process9Offset, process9Size);
//Does nothing if svcBackdoor is still there //Restore svcBackdoor
reimplementSvcBackdoor(arm11Section1, section[1].size); 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 //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(isN3DS) if(isN3DS)
{ {
arm9Loader(arm9Section, 0); arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801301C; firm->arm9Entry = (u8 *)0x801301C;
} }
@ -387,7 +374,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address)); patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address));
} }
applyLegacyFirmPatches((u8 *)firm, firmType, isN3DS); applyLegacyFirmPatches((u8 *)firm, firmType);
} }
static inline void patchSafeFirm(void) static inline void patchSafeFirm(void)
@ -397,7 +384,7 @@ static inline void patchSafeFirm(void)
if(isN3DS) if(isN3DS)
{ {
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, 0); arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C; firm->arm9Entry = (u8 *)0x801B01C;
patchFirmWrites(arm9Section, section[2].size); patchFirmWrites(arm9Section, section[2].size);
@ -500,12 +487,12 @@ static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
arm11 = (u32 *)0x1FFFFFF8; arm11 = (u32 *)0x1FFFFFF8;
} }
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireICache();
//Set ARM11 kernel entrypoint //Set ARM11 kernel entrypoint
*arm11 = (u32)firm->arm11Entry; *arm11 = (u32)firm->arm11Entry;
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireICache();
//Final jump to ARM9 kernel //Final jump to ARM9 kernel
((void (*)())firm->arm9Entry)(); ((void (*)())firm->arm9Entry)();
} }

View File

@ -53,15 +53,8 @@ typedef enum ConfigurationStatus
CREATE_CONFIGURATION = 2 CREATE_CONFIGURATION = 2
} ConfigurationStatus; } ConfigurationStatus;
typedef enum A9LHMode static inline u32 loadFirm(FirmwareType firmType);
{ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
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 void patchLegacyFirm(FirmwareType firmType); static inline void patchLegacyFirm(FirmwareType firmType);
static inline void patchSafeFirm(void); static inline void patchSafeFirm(void);
static inline void copySection0AndInjectSystemModules(void); static inline void copySection0AndInjectSystemModules(void);

View File

@ -31,12 +31,10 @@
static FATFS sdFs, static FATFS sdFs,
nandFs; 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); f_mount(&nandFs, "1:", 0);
return true;
} }
u32 fileRead(void *dest, const char *path) u32 fileRead(void *dest, const char *path)
@ -62,7 +60,7 @@ u32 getFileSize(const char *path)
return fileRead(NULL, 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; FIL file;
@ -71,7 +69,16 @@ void fileWrite(const void *buffer, const char *path, u32 size)
unsigned int written; unsigned int written;
f_write(&file, buffer, size, &written); f_write(&file, buffer, size, &written);
f_close(&file); f_close(&file);
return true;
} }
return false;
}
void createDirectory(const char *path)
{
f_mkdir(path);
} }
void loadPayload(u32 pressed) void loadPayload(u32 pressed)
@ -115,6 +122,7 @@ void loadPayload(u32 pressed)
flushDCacheRange(loaderAddress, loader_size); flushDCacheRange(loaderAddress, loader_size);
flushICacheRange(loaderAddress, loader_size); flushICacheRange(loaderAddress, loader_size);
((void (*)())loaderAddress)(); ((void (*)())loaderAddress)();
} }
} }
@ -140,17 +148,22 @@ void findDumpFile(const char *path, char *fileName)
f_closedir(&dir); 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"; char path[48] = "1:/title/00040138/00000000/content";
memcpy(&path[18], firmFolder, 8); memcpy(&path[18], firmFolders[firmType][isN3DS ? 1 : 0], 8);
DIR dir; DIR dir;
FILINFO info; FILINFO info;
f_opendir(&dir, path); f_opendir(&dir, path);
u32 id = 0xFFFFFFFF; u32 firmVersion = 0xFFFFFFFF;
//Parse the target directory //Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0]) while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
@ -159,15 +172,15 @@ void firmRead(void *dest, const char *firmFolder)
if(info.altname[9] != 'A') continue; if(info.altname[9] != 'A') continue;
//Convert the .app name to an integer //Convert the .app name to an integer
u32 tempId = 0; u32 tempVersion = 0;
for(char *tmp = info.altname; *tmp != '.'; tmp++) for(char *tmp = info.altname; *tmp != '.'; tmp++)
{ {
tempId <<= 4; tempVersion <<= 4;
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0'; tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
} }
//Found an older cxi //Found an older cxi
if(tempId < id) id = tempId; if(tempVersion < firmVersion) firmVersion = tempVersion;
} }
f_closedir(&dir); f_closedir(&dir);
@ -179,12 +192,15 @@ void firmRead(void *dest, const char *firmFolder)
u32 i = 42; u32 i = 42;
//Convert back the .app name from integer to array //Convert back the .app name from integer to array
while(id) u32 tempVersion = firmVersion;
while(tempVersion)
{ {
static const char hexDigits[] = "0123456789ABCDEF"; static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[id & 0xF]; path[i--] = hexDigits[tempVersion & 0xF];
id >>= 4; tempVersion >>= 4;
} }
fileRead(dest, path); fileRead(dest, path);
return firmVersion;
} }

View File

@ -26,10 +26,13 @@
#define PATTERN(a) a "_*.bin" #define PATTERN(a) a "_*.bin"
bool mountFs(void); extern bool isN3DS;
void mountFs(void);
u32 getFileSize(const char *path); u32 getFileSize(const char *path);
u32 fileRead(void *dest, 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 findDumpFile(const char *path, char *fileName);
void loadPayload(u32 pressed); void loadPayload(u32 pressed);
void firmRead(void *dest, const char *firmFolder); u32 firmRead(void *dest, u32 firmType);

View File

@ -240,10 +240,10 @@ void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
u8 *off = memsearch(pos, pattern, size, 4); 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[] = { const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0}, {{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 /* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */ if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) : u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6)); (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches; const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
//Patch //Patch

View File

@ -33,6 +33,8 @@ typedef struct patchData {
u32 type; u32 type;
} patchData; } patchData;
extern bool isN3DS;
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr); u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr, u32 *codeSetOffset); u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr, u32 *codeSetOffset);
void patchSignatureChecks(u8 *pos, u32 size); void patchSignatureChecks(u8 *pos, u32 size);
@ -46,5 +48,5 @@ void patchSvcBreak11(u8 *pos, u32 size);
void patchUnitInfoValueSet(u8 *pos, u32 size); void patchUnitInfoValueSet(u8 *pos, u32 size);
void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size); void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size);
void reimplementSvcBackdoor(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); u8 *getUnitInfoValueSet(u8 *pos, u32 size);

180
source/pin.c Normal file
View 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
View File

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

View File

@ -32,9 +32,8 @@
#include "draw.h" #include "draw.h"
#include "i2c.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 vu32 *const arm11Entry = (vu32 *)0x1FFFFFF8;
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)(); static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
vu32 *arm11Entry = (vu32 *)0x1FFFFFF8;
void __attribute__((naked)) arm11Stub(void) void __attribute__((naked)) arm11Stub(void)
{ {
@ -48,13 +47,13 @@ void __attribute__((naked)) arm11Stub(void)
((void (*)())*arm11Entry)(); ((void (*)())*arm11Entry)();
} }
static inline void invokeArm11Function(void (*func)()) static void invokeArm11Function(void (*func)())
{ {
static bool hasCopiedStub = false; static bool hasCopiedStub = false;
if(!hasCopiedStub) if(!hasCopiedStub)
{ {
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x40); memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x40); flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x30);
hasCopiedStub = true; hasCopiedStub = true;
} }
@ -63,8 +62,6 @@ static inline void invokeArm11Function(void (*func)())
*arm11Entry = ARM11_STUB_ADDRESS; *arm11Entry = ARM11_STUB_ADDRESS;
} }
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
void deinitScreens(void) void deinitScreens(void)
{ {
void __attribute__((naked)) ARM11(void) void __attribute__((naked)) ARM11(void)
@ -83,11 +80,10 @@ void deinitScreens(void)
if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11); if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11);
} }
void updateBrightness(u32 brightnessLevel) void updateBrightness(u32 brightnessIndex)
{ {
static int brightnessValue; static u32 brightnessLevel;
brightnessLevel = brightness[brightnessIndex];
brightnessValue = brightness[brightnessLevel];
void __attribute__((naked)) ARM11(void) void __attribute__((naked)) ARM11(void)
{ {
@ -95,13 +91,13 @@ void updateBrightness(u32 brightnessLevel)
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
//Change brightness //Change brightness
*(vu32 *)0x10202240 = brightnessValue; *(vu32 *)0x10202240 = brightnessLevel;
*(vu32 *)0x10202A40 = brightnessValue; *(vu32 *)0x10202A40 = brightnessLevel;
WAIT_FOR_ARM9(); WAIT_FOR_ARM9();
} }
flushDCacheRange(&brightnessValue, 4); flushDCacheRange(&brightnessLevel, 4);
invokeArm11Function(ARM11); invokeArm11Function(ARM11);
} }
@ -113,7 +109,6 @@ void clearScreens(void)
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
//Setting up two simultaneous memory fills using the GPU //Setting up two simultaneous memory fills using the GPU
vu32 *REGs_PSC0 = (vu32 *)0x10400010; vu32 *REGs_PSC0 = (vu32 *)0x10400010;
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address
@ -145,22 +140,22 @@ void clearScreens(void)
invokeArm11Function(ARM11); 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) void __attribute__((naked)) ARM11(void)
{ {
//Disable interrupts //Disable interrupts
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
u32 brightnessLevel = MULTICONFIG(0); u32 brightnessLevel = brightness[MULTICONFIG(0)];
*(vu32 *)0x10141200 = 0x1007F; *(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001; *(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE; *(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = brightness[brightnessLevel]; *(vu32 *)0x10202240 = brightnessLevel;
*(vu32 *)0x10202A40 = brightness[brightnessLevel]; *(vu32 *)0x10202A40 = brightnessLevel;
*(vu32 *)0x10202244 = 0x1023E; *(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E; *(vu32 *)0x10202A44 = 0x1023E;
@ -256,8 +251,7 @@ u32 initScreens(void)
//Turn on backlight //Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
} }
else else updateBrightness(MULTICONFIG(0));
updateBrightness(MULTICONFIG(0));
clearScreens(); clearScreens();

View File

@ -30,14 +30,16 @@
#include "types.h" #include "types.h"
#define PDN_GPU_CNT (*(vu8 *)0x10141200) #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 { static volatile struct fb {
u8 *top_left; u8 *top_left;
u8 *top_right; u8 *top_right;
u8 *bottom; u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00; } *const fb = (volatile struct fb *)0x23FFFE00;
void deinitScreens(void); void deinitScreens(void);
void updateBrightness(u32 brightnessLevel); void updateBrightness(u32 brightnessIndex);
void clearScreens(void); void clearScreens(void);
u32 initScreens(void); bool initScreens(void);

View File

@ -23,7 +23,8 @@
#include "utils.h" #include "utils.h"
#include "i2c.h" #include "i2c.h"
#include "buttons.h" #include "buttons.h"
#include "memory.h" #include "screen.h"
#include "draw.h"
#include "cache.h" #include "cache.h"
u32 waitInput(void) 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 flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(1); while(true);
}
void mcuPowerOff(void)
{
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) void mcuPowerOff(void)
@ -105,3 +114,16 @@ void stopChrono(void)
{ {
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80; 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();
}

View File

@ -24,13 +24,14 @@
#include "types.h" #include "types.h"
u32 waitInput(void);
void mcuReboot(void);
void mcuPowerOff(void);
#define TICKS_PER_SEC 67027964ULL #define TICKS_PER_SEC 67027964ULL
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i) #define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 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 chrono(u32 seconds);
void stopChrono(void); void stopChrono(void);
void error(const char *message);