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 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;
|
||||||
|
|
||||||
|
@ -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)
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -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);
|
@ -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
21
source/fatfs/00history.txt
Normal file → Executable file
@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
|
|||||||
|
|
||||||
R0.01 (April 29, 2006)
|
R0.01 (April 29, 2006)
|
||||||
|
|
||||||
First stable version.
|
The first release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -246,9 +246,22 @@ R0.11a (September 05, 2015)
|
|||||||
|
|
||||||
R0.12 (April 12, 2016)
|
R0.12 (April 12, 2016)
|
||||||
|
|
||||||
Added support of exFAT file system. (_FS_EXFAT)
|
Added support for exFAT file system. (_FS_EXFAT)
|
||||||
Added f_expand(). (_USE_EXPAND)
|
Added f_expand(). (_USE_EXPAND)
|
||||||
Changed some members in FINFO structure and behavior of f_readdir().
|
Changed some members in FINFO structure and behavior of f_readdir().
|
||||||
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
|
Added an option _USE_CHMOD.
|
||||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
Removed an option _WORD_ACCESS.
|
||||||
|
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12a (July 10, 2016)
|
||||||
|
|
||||||
|
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||||
|
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||||
|
f_forward() is available regardless of _FS_TINY.
|
||||||
|
Fixed f_mkfs() creates wrong volume.
|
||||||
|
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||||
|
Fixed wrong memory read in create_name().
|
||||||
|
|
||||||
|
|
||||||
|
2
source/fatfs/00readme.txt
Normal file → Executable file
2
source/fatfs/00readme.txt
Normal file → Executable file
@ -1,4 +1,4 @@
|
|||||||
FatFs Module Source Files R0.12
|
FatFs Module Source Files R0.12a
|
||||||
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
|
1482
source/fatfs/ff.c
Normal file → Executable file
1482
source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
102
source/fatfs/ff.h
Normal file → Executable file
102
source/fatfs/ff.h
Normal file → Executable file
@ -1,11 +1,13 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*----------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
|
/ FatFs - Generic FAT file system module R0.12a /
|
||||||
/----------------------------------------------------------------------------/
|
/-----------------------------------------------------------------------------/
|
||||||
/ FatFs module is a free software that opened under license policy of
|
|
||||||
/ following conditions.
|
|
||||||
/
|
/
|
||||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
/ Copyright (C) 2016, ChaN, all right reserved.
|
||||||
/
|
/
|
||||||
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
|
/ that the following condition is met:
|
||||||
|
|
||||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||||
/ this condition and the following disclaimer.
|
/ this condition and the following disclaimer.
|
||||||
/
|
/
|
||||||
@ -13,11 +15,11 @@
|
|||||||
/ and any warranties related to this software are DISCLAIMED.
|
/ and any warranties related to this software are DISCLAIMED.
|
||||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||||
/ by use of this software.
|
/ by use of this software.
|
||||||
/---------------------------------------------------------------------------*/
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FATFS
|
#ifndef _FATFS
|
||||||
#define _FATFS 88100 /* Revision ID */
|
#define _FATFS 80186 /* Revision ID */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -25,6 +27,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include "integer.h" /* Basic integer types */
|
#include "integer.h" /* Basic integer types */
|
||||||
#include "ffconf.h" /* FatFs configuration options */
|
#include "ffconf.h" /* FatFs configuration options */
|
||||||
|
|
||||||
#if _FATFS != _FFCONF
|
#if _FATFS != _FFCONF
|
||||||
#error Wrong configuration file (ffconf.h).
|
#error Wrong configuration file (ffconf.h).
|
||||||
#endif
|
#endif
|
||||||
@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
|||||||
|
|
||||||
/* Type of path name strings on FatFs API */
|
/* Type of path name strings on FatFs API */
|
||||||
|
|
||||||
#if _LFN_UNICODE /* Unicode string */
|
#if _LFN_UNICODE /* Unicode (UTF-16) string */
|
||||||
#if _USE_LFN == 0
|
#if _USE_LFN == 0
|
||||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||||
#endif
|
#endif
|
||||||
@ -61,14 +64,25 @@ typedef WCHAR TCHAR;
|
|||||||
#define _T(x) L ## x
|
#define _T(x) L ## x
|
||||||
#define _TEXT(x) L ## x
|
#define _TEXT(x) L ## x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* ANSI/OEM string */
|
#else /* ANSI/OEM string */
|
||||||
#ifndef _INC_TCHAR
|
#ifndef _INC_TCHAR
|
||||||
typedef char TCHAR;
|
typedef char TCHAR;
|
||||||
#define _T(x) x
|
#define _T(x) x
|
||||||
#define _TEXT(x) x
|
#define _TEXT(x) x
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type of file size variables */
|
||||||
|
|
||||||
|
#if _FS_EXFAT
|
||||||
|
#if _USE_LFN == 0
|
||||||
|
#error LFN must be enabled when enable exFAT
|
||||||
|
#endif
|
||||||
|
typedef QWORD FSIZE_t;
|
||||||
|
#else
|
||||||
|
typedef DWORD FSIZE_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -87,6 +101,9 @@ typedef struct {
|
|||||||
#if _MAX_SS != _MIN_SS
|
#if _MAX_SS != _MIN_SS
|
||||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||||
#endif
|
#endif
|
||||||
|
#if _USE_LFN != 0
|
||||||
|
WCHAR* lfnbuf; /* LFN working buffer */
|
||||||
|
#endif
|
||||||
#if _FS_EXFAT
|
#if _FS_EXFAT
|
||||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
||||||
#endif
|
#endif
|
||||||
@ -117,19 +134,6 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Type of file size variables and object identifier */
|
|
||||||
|
|
||||||
#if _FS_EXFAT
|
|
||||||
#if _USE_LFN == 0
|
|
||||||
#error LFN must be enabled when enable exFAT
|
|
||||||
#endif
|
|
||||||
typedef QWORD FSIZE_t;
|
|
||||||
#else
|
|
||||||
typedef DWORD FSIZE_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Object ID and allocation information (_FDID) */
|
/* Object ID and allocation information (_FDID) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -159,14 +163,14 @@ typedef struct {
|
|||||||
BYTE flag; /* File status flags */
|
BYTE flag; /* File status flags */
|
||||||
BYTE err; /* Abort flag (error code) */
|
BYTE err; /* Abort flag (error code) */
|
||||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||||
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
|
DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
|
||||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||||
#if !_FS_READONLY
|
#if !_FS_READONLY
|
||||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||||
#endif
|
#endif
|
||||||
#if _USE_FASTSEEK
|
#if _USE_FASTSEEK
|
||||||
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||||
#endif
|
#endif
|
||||||
#if !_FS_TINY
|
#if !_FS_TINY
|
||||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||||
@ -183,10 +187,9 @@ typedef struct {
|
|||||||
DWORD clust; /* Current cluster */
|
DWORD clust; /* Current cluster */
|
||||||
DWORD sect; /* Current sector */
|
DWORD sect; /* Current sector */
|
||||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||||
BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
|
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||||
#if _USE_LFN != 0
|
#if _USE_LFN != 0
|
||||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
|
||||||
#endif
|
#endif
|
||||||
#if _USE_FIND
|
#if _USE_FIND
|
||||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||||
@ -229,7 +232,7 @@ typedef enum {
|
|||||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
@ -244,11 +247,11 @@ typedef enum {
|
|||||||
|
|
||||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
|
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||||
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||||
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||||
@ -258,8 +261,8 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
|||||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
|
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
|
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||||
@ -269,8 +272,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
|||||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||||
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||||
@ -323,40 +326,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
|||||||
/* Flags and offset address */
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
|
||||||
/* File access control and file status flags (FIL.flag) */
|
/* File access mode and open method flags (3rd argument of f_open) */
|
||||||
|
|
||||||
#define FA_READ 0x01
|
#define FA_READ 0x01
|
||||||
#define FA_WRITE 0x02
|
#define FA_WRITE 0x02
|
||||||
#define FA_OPEN_EXISTING 0x00
|
#define FA_OPEN_EXISTING 0x00
|
||||||
#define FA_CREATE_NEW 0x04
|
#define FA_CREATE_NEW 0x04
|
||||||
#define FA_CREATE_ALWAYS 0x08
|
#define FA_CREATE_ALWAYS 0x08
|
||||||
#define FA_OPEN_ALWAYS 0x10
|
#define FA_OPEN_ALWAYS 0x10
|
||||||
#define _FA_MODIFIED 0x20
|
#define FA_OPEN_APPEND 0x30
|
||||||
#define _FA_DIRTY 0x40
|
|
||||||
|
|
||||||
|
/* Fast seek controls (2nd argument of f_lseek) */
|
||||||
|
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||||
|
|
||||||
/* FAT sub type (FATFS.fs_type) */
|
/* Format options (2nd argument of f_mkfs) */
|
||||||
|
#define FM_FAT 0x01
|
||||||
|
#define FM_FAT32 0x02
|
||||||
|
#define FM_EXFAT 0x04
|
||||||
|
#define FM_ANY 0x07
|
||||||
|
#define FM_SFD 0x08
|
||||||
|
|
||||||
|
/* Filesystem type (FATFS.fs_type) */
|
||||||
#define FS_FAT12 1
|
#define FS_FAT12 1
|
||||||
#define FS_FAT16 2
|
#define FS_FAT16 2
|
||||||
#define FS_FAT32 3
|
#define FS_FAT32 3
|
||||||
#define FS_EXFAT 4
|
#define FS_EXFAT 4
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||||
/* File attribute bits for directory entry */
|
|
||||||
|
|
||||||
#define AM_RDO 0x01 /* Read only */
|
#define AM_RDO 0x01 /* Read only */
|
||||||
#define AM_HID 0x02 /* Hidden */
|
#define AM_HID 0x02 /* Hidden */
|
||||||
#define AM_SYS 0x04 /* System */
|
#define AM_SYS 0x04 /* System */
|
||||||
#define AM_VOL 0x08 /* Volume label */
|
|
||||||
#define AM_LFN 0x0F /* LFN entry */
|
|
||||||
#define AM_DIR 0x10 /* Directory */
|
#define AM_DIR 0x10 /* Directory */
|
||||||
#define AM_ARC 0x20 /* Archive */
|
#define AM_ARC 0x20 /* Archive */
|
||||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
|
||||||
|
|
||||||
|
|
||||||
/* Fast seek controls */
|
|
||||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
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
|
/ 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
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
211
source/firm.c
211
source/firm.c
@ -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,60 +91,32 @@ 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 it's a MCU reboot, try to force boot options
|
||||||
if(CFG_BOOTENV)
|
if(isA9lh && CFG_BOOTENV)
|
||||||
{
|
{
|
||||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||||
if(CFG_BOOTENV == 7)
|
if(CFG_BOOTENV == 7)
|
||||||
{
|
{
|
||||||
nandType = FIRMWARE_SYSNAND;
|
nandType = FIRMWARE_SYSNAND;
|
||||||
firmSource = updatedSys ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
|
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
|
||||||
needConfig = DONT_CONFIGURE;
|
needConfig = DONT_CONFIGURE;
|
||||||
|
|
||||||
//Flag to prevent multiple boot options-forcing
|
//Flag to prevent multiple boot options-forcing
|
||||||
@ -158,26 +133,62 @@ void main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the SAFE MODE combo is held, force a sysNAND boot
|
|
||||||
else if(pressed == SAFE_MODE)
|
|
||||||
{
|
|
||||||
a9lhMode = A9LH_WITH_SFIRM_FIRMPROT;
|
|
||||||
nandType = FIRMWARE_SYSNAND;
|
|
||||||
firmSource = FIRMWARE_SYSNAND;
|
|
||||||
needConfig = DONT_CONFIGURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Boot options aren't being forced
|
//Boot options aren't being forced
|
||||||
if(needConfig != DONT_CONFIGURE)
|
if(needConfig != DONT_CONFIGURE)
|
||||||
|
{
|
||||||
|
//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(pinExists || shouldLoadConfigurationMenu)
|
||||||
|
{
|
||||||
|
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(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||||
|
{
|
||||||
|
nandType = FIRMWARE_SYSNAND;
|
||||||
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||||
chainload an external payload */
|
chainload an external payload (verify the PIN if needed)*/
|
||||||
if(DEVMODE || (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
|
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
|
||||||
|
|
||||||
|
if(shouldLoadPayload)
|
||||||
loadPayload(pressed);
|
loadPayload(pressed);
|
||||||
|
|
||||||
//If screens are inited or the corresponding option is set, load splash screen
|
//If screens are inited or the corresponding option is set, load splash screen
|
||||||
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
|
if((PDN_GPU_CNT != 1 || CONFIG(6)) && loadSplash())
|
||||||
{
|
{
|
||||||
nbChronoStarted = 2;
|
nbChronoStarted = 2;
|
||||||
chrono(0);
|
chrono(0);
|
||||||
@ -186,8 +197,8 @@ void main(void)
|
|||||||
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||||
if(pressed & BUTTON_R1)
|
if(pressed & BUTTON_R1)
|
||||||
{
|
{
|
||||||
nandType = (updatedSys) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||||
firmSource = (updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||||
@ -200,7 +211,8 @@ void main(void)
|
|||||||
|
|
||||||
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
||||||
or vice-versa, boot the second emuNAND */
|
or vice-versa, boot the second emuNAND */
|
||||||
if(nandType != FIRMWARE_SYSNAND && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
|
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)();
|
||||||
}
|
}
|
@ -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);
|
||||||
|
46
source/fs.c
46
source/fs.c
@ -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;
|
||||||
}
|
}
|
@ -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);
|
@ -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
|
||||||
|
@ -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
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,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();
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#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;
|
||||||
@ -38,6 +40,6 @@ static volatile struct fb {
|
|||||||
} *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);
|
@ -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();
|
||||||
|
}
|
@ -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);
|
Reference in New Issue
Block a user