Add safety checks, support booting from CTRNAND

This commit is contained in:
Aurora 2016-10-07 14:27:30 +02:00
parent bd6c7b7fdb
commit 0caf9f4214
20 changed files with 142 additions and 141 deletions

View File

@ -18,7 +18,7 @@ dir_build := build
dir_out := ../../$(dir_build)
ASFLAGS := -mcpu=mpcore -mfpu=vfp
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -Os -flto -ffast-math
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \

View File

@ -47,7 +47,7 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId)
u32 registerDump[REG_DUMP_SIZE / 4];
u8 codeDump[CODE_DUMP_SIZE];
u8 *const finalBuffer = cannotAccessVA((const void *)0xE5000000) ? (u8 *)0xF5000000 : (u8 *)0xE5000000; //VA for 0x25000000
u8 *finalBuffer = cannotAccessVA((void *)0xE5000000) ? (u8 *)0xF5000000 : (u8 *)0xE5000000; //VA for 0x25000000
u8 *final = finalBuffer;
while(*(vu32 *)final == 0xDEADC0DE && *((vu32 *)final + 1) == 0xDEADCAFE);
@ -88,7 +88,7 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId)
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
final += dumpHeader.stackDumpSize;
if(!cannotAccessVA((u8 *)0xFFFF9004))
if(!cannotAccessVA((void *)0xFFFF9004))
{
vu64 *additionalData = (vu64 *)final;
dumpHeader.additionalDataSize = 16;

View File

@ -33,9 +33,7 @@ DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
sdmmc_sdcard_init();
return RES_OK;
return sdmmc_sdcard_init() ? RES_OK : RES_PARERR;
}

View File

@ -283,8 +283,8 @@ static u32 calcSDSize(u8 *csd, int type)
result = (result << 8) | csd[7];
result = (result << 2) | (csd[6] >> 6);
result = (result + 1) * mult * block_len / 512;
}
break;
}
case 1:
result = csd[7] & 0x3F;
result = (result << 8) | csd[6];
@ -482,9 +482,9 @@ void sdmmc_get_cid(bool isNand, u32 *info)
}
*/
void sdmmc_sdcard_init()
bool sdmmc_sdcard_init()
{
InitSD();
//Nand_Init();
SD_Init();
return SD_Init() == 0;
}

View File

@ -91,7 +91,7 @@ typedef struct mmcdevice {
u32 res;
} mmcdevice;
void sdmmc_sdcard_init();
bool sdmmc_sdcard_init();
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
//int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
//int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);

View File

@ -25,13 +25,18 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
cmp r0, r2
bne pxi_wait_recv
adr r1, sd_fname
open_payload:
; Open file
add r0, r7, #8
adr r1, fname
mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6
cmp r0, #0
adrne r1, nand_fname
bne open_payload
; Read file
mov r0, r7
@ -71,8 +76,11 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
bytes_read: .word 0
fopen: .ascii "OPEN"
.pool
fname: .dcw "sdmc:/arm9loaderhax.bin"
sd_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
.pool
nand_fname: .dcw "nand:/arm9loaderhax.bin"
.word 0
.align 4
kernelcode_start:

View File

@ -29,18 +29,22 @@
#include "buttons.h"
#include "pin.h"
bool readConfig(void)
bool readConfig(bool isSdMounted)
{
if(fileRead(&configData, CONFIG_PATH, sizeof(CfgData)) != sizeof(CfgData) ||
bool ret;
if(!isSdMounted ||
fileRead(&configData, CONFIG_PATH, sizeof(CfgData)) != sizeof(CfgData) ||
memcmp(configData.magic, "CONF", 4) != 0 ||
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
{
configData.config = 0;
return false;
ret = !isSdMounted;
}
else ret = true;
return true;
return ret;
}
void writeConfig(ConfigurationStatus needConfig, u32 configTemp)

View File

@ -78,6 +78,6 @@ typedef enum ConfigurationStatus
extern CfgData configData;
extern bool isN3DS;
bool readConfig(void);
bool readConfig(bool isSdMounted);
void writeConfig(ConfigurationStatus needConfig, u32 configTemp);
void configMenu(bool oldPinStatus, u32 oldPinMode);

View File

@ -82,7 +82,7 @@ __asm__\
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
{
if(keyslot <= 0x03) return; // Ignore TWL keys for now
if(keyslot <= 0x03) return; //Ignore TWL keys for now
u32 *key32 = (u32 *)key;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
@ -107,7 +107,7 @@ static void aes_setiv(const void *iv, u32 mode)
const u32 *iv32 = (const u32 *)iv;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
//Word order for IV can't be changed in REG_AESCNT and always default to reversed
if(mode & AES_INPUT_NORMAL)
{
REG_AESCTR[0] = iv32[3];
@ -131,7 +131,7 @@ static void aes_advctr(void *ctr, u32 val, u32 mode)
int i;
if(mode & AES_INPUT_BE)
{
for(i = 0; i < 4; ++i) // Endian swap
for(i = 0; i < 4; ++i) //Endian swap
BSWAP32(ctr32[i]);
}
@ -146,7 +146,7 @@ static void aes_advctr(void *ctr, u32 val, u32 mode)
if(mode & AES_INPUT_BE)
{
for(i = 0; i < 4; ++i) // Endian swap
for(i = 0; i < 4; ++i) //Endian swap
BSWAP32(ctr32[i]);
}
}
@ -186,7 +186,7 @@ static void aes_batch(void *dst, const void *src, u32 blockCount)
while(rbc)
{
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) //There's space for at least 4 ints
{
*REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++;
@ -195,7 +195,7 @@ static void aes_batch(void *dst, const void *src, u32 blockCount)
wbc--;
}
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) //At least 4 ints available for read
{
*dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO;
@ -222,24 +222,24 @@ static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode,
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
// Save the last block for the next decryption CBC batch's iv
//Save the last block for the next decryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
{
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
}
// Process the current batch
//Process the current batch
aes_batch(dst, src, blocks);
// Save the last block for the next encryption CBC batch's iv
//Save the last block for the next encryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
{
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
}
// Advance counter for CTR mode
//Advance counter for CTR mode
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
aes_advctr(iv, blocks, ivMode);
@ -324,14 +324,14 @@ void ctrNandInit(void)
}
}
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{
u8 __attribute__((aligned(4))) tmpCtr[sizeof(nandCtr)];
memcpy(tmpCtr, nandCtr, sizeof(nandCtr));
aes_advctr(tmpCtr, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Read
u32 result;
int result;
if(firmSource == FIRMWARE_SYSNAND)
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
else

View File

@ -106,7 +106,7 @@ extern bool isN3DS, isDevUnit, isA9lh;
extern FirmwareSource firmSource;
void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void set6x7xKeys(void);
void decryptExeFs(u8 *inbuf);
void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize);

View File

@ -47,8 +47,8 @@ bool loadSplash(void)
initScreens();
clearScreens(true, true, true);
if(isTopSplashValid) fileRead(fbs[1].top_left, topSplashPath, 0);
if(isBottomSplashValid) fileRead(fbs[1].bottom, bottomSplashPath, 0);
if(isTopSplashValid) fileRead(fbs[1].top_left, topSplashPath, SCREEN_TOP_FBSIZE);
if(isBottomSplashValid) fileRead(fbs[1].bottom, bottomSplashPath, SCREEN_BOTTOM_FBSIZE);
swapFramebuffers(true);

View File

@ -37,17 +37,18 @@ DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
switch(pdrv)
DRESULT ret = RES_OK;
static bool sdmmcInited = false;
if(!sdmmcInited)
{
case SDCARD:
sdmmc_sdcard_init();
break;
case CTRNAND:
ctrNandInit();
break;
if(!sdmmc_sdcard_init()) ret = RES_PARERR;
else sdmmcInited = true;
}
return RES_OK;
if(pdrv == CTRNAND) ctrNandInit();
return ret;
}
@ -63,19 +64,8 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */
)
{
switch(pdrv)
{
case SDCARD:
if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
case CTRNAND:
if(ctrNandRead(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
}
return RES_OK;
return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff)) ||
(pdrv == CTRNAND && !ctrNandRead(sector, count, (BYTE *)buff))) ? RES_OK : RES_PARERR;
}
@ -92,10 +82,7 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */
)
{
if(pdrv == SDCARD && sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
return RES_PARERR;
return RES_OK;
return (pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) ? RES_OK : RES_PARERR;
}
#endif

View File

@ -277,8 +277,8 @@ static u32 calcSDSize(u8 *csd, int type)
result = (result << 8) | csd[7];
result = (result << 2) | (csd[6] >> 6);
result = (result + 1) * mult * block_len / 512;
}
break;
}
case 1:
result = csd[7] & 0x3F;
result = (result << 8) | csd[6];
@ -472,9 +472,8 @@ void sdmmc_get_cid(bool isNand, u32 *info)
sdmmc_send_command(device, 0x10507, device->initarg << 0x10);
}
void sdmmc_sdcard_init()
bool sdmmc_sdcard_init()
{
InitSD();
Nand_Init();
SD_Init();
return (Nand_Init() | SD_Init()) == 0;
}

View File

@ -91,7 +91,7 @@ typedef struct mmcdevice {
u32 res;
} mmcdevice;
void sdmmc_sdcard_init();
bool sdmmc_sdcard_init();
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);

View File

@ -64,11 +64,11 @@ void main(void)
//Detect dev units
isDevUnit = CFG_UNITINFO != 0;
//Mount filesystems. CTRNAND will be mounted only if/when needed
mountFs();
//Mount SD
bool isSdMounted = mountFs(true);
//Attempt to read the configuration file
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
needConfig = readConfig(isSdMounted) ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
u32 devMode = MULTICONFIG(DEVOPTIONS);
@ -102,8 +102,15 @@ void main(void)
//Save old options and begin saving the new boot configuration
configTemp = (configData.config & 0xFFFFFE00) | ((u32)isA9lh << 6);
if(!isSdMounted)
{
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_SYSNAND;
needConfig = DONT_CONFIGURE;
}
//If it's a MCU reboot, try to force boot options
if(isA9lh && CFG_BOOTENV)
else if(isA9lh && CFG_BOOTENV)
{
//Always force a sysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV == 7)
@ -241,7 +248,7 @@ void main(void)
else if(firmSource != FIRMWARE_SYSNAND)
locateEmuNand(&emuHeader, &firmSource);
if(!isFirmlaunch)
if(isSdMounted && !isFirmlaunch)
{
configTemp |= (u32)nandType | ((u32)firmSource << 3);
writeConfig(needConfig, configTemp);
@ -284,9 +291,13 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo
"/luma/cetk_safe"
};
if(!mountFs(false)) error("Error mounting CTRNAND.");
//Load FIRM from CTRNAND
u32 firmVersion = firmRead(firm, (u32)*firmType);
if(firmVersion == 0xFFFFFFFF) error("Error getting the CTRNAND FIRM.");
bool mustLoadFromSd = false;
if(!isN3DS && *firmType == NATIVE_FIRM)

View File

@ -33,10 +33,9 @@
static FATFS sdFs,
nandFs;
void mountFs(void)
bool mountFs(bool isSd)
{
f_mount(&sdFs, "0:", 1);
f_mount(&nandFs, "1:", 0);
return isSd ? f_mount(&sdFs, "0:", 1) == FR_OK : f_mount(&nandFs, "1:", 1) == FR_OK;
}
u32 fileRead(void *dest, const char *path, u32 maxSize)
@ -48,7 +47,7 @@ u32 fileRead(void *dest, const char *path, u32 maxSize)
{
u32 size = f_size(&file);
if(dest == NULL) ret = size;
else if(!(maxSize > 0 && size > maxSize))
else if(size <= maxSize)
f_read(&file, dest, size, (unsigned int *)&ret);
f_close(&file);
}
@ -64,6 +63,7 @@ u32 getFileSize(const char *path)
bool fileWrite(const void *buffer, const char *path, u32 size)
{
FIL file;
bool ret;
FRESULT result = f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS);
@ -74,10 +74,9 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
f_truncate(&file);
f_close(&file);
return true;
ret = (u32)written == size;
}
if(result == FR_NO_PATH)
else if(result == FR_NO_PATH)
{
for(u32 i = 1; path[i] != 0; i++)
if(path[i] == '/')
@ -85,13 +84,15 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
char folder[i + 1];
memcpy(folder, path, i);
folder[i] = 0;
f_mkdir(folder);
ret = f_mkdir(folder) == FR_OK;
if(!ret) break;
}
return fileWrite(buffer, path, size);
if(ret) ret = fileWrite(buffer, path, size);
}
else ret = false;
return false;
return ret;
}
void fileDelete(const char *path)
@ -163,11 +164,10 @@ u32 firmRead(void *dest, u32 firmType)
DIR dir;
FILINFO info;
f_opendir(&dir, path);
u32 firmVersion = 0xFFFFFFFF;
if(f_opendir(&dir, path) == FR_OK)
{
//Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
{
@ -188,13 +188,17 @@ u32 firmRead(void *dest, u32 firmType)
f_closedir(&dir);
if(firmVersion != 0xFFFFFFFF)
{
//Complete the string with the .app name
concatenateStrings(path, "/00000000.app");
//Convert back the .app name from integer to array
hexItoa(firmVersion, &path[35], 8);
fileRead(dest, path, 0);
if(!fileRead(dest, path, 0x400200)) firmVersion = 0xFFFFFFFF;
}
}
return firmVersion;
}

View File

@ -28,7 +28,7 @@
extern bool isN3DS, isA9lh;
void mountFs(void);
bool mountFs(bool isSd);
u32 fileRead(void *dest, const char *path, u32 maxSize);
u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size);

View File

@ -100,7 +100,7 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
if(pathSize > 5 && pathSize < 58)
{
u8 path[pathSize];
fileRead(path, pathPath, 0);
fileRead(path, pathPath, pathSize);
if(path[pathSize - 1] == 0xA) pathSize--;
if(path[pathSize - 1] == 0xD) pathSize--;

View File

@ -139,7 +139,7 @@ bool verifyPin(u32 pinMode)
if(messageSize > 0 && messageSize <= 800)
{
char message[messageSize + 1];
fileRead(message, messagePath, 0);
fileRead(message, messagePath, messageSize);
message[messageSize] = 0;
drawString(message, false, 10, 10, COLOR_WHITE);
}

View File

@ -41,7 +41,7 @@
#include "cache.h"
#include "i2c.h"
vu32 *const arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
vu32 *arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
void __attribute__((naked)) arm11Stub(void)
@ -167,16 +167,6 @@ void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate)
while(!((!clearTopTmp || (REGs_PSC0[3] & 2)) && (!clearBottomTmp || (REGs_PSC1[3] & 2))));
if(fbTmp->top_right != fbTmp->top_left && clearTopTmp)
{
REGs_PSC0[0] = (u32)fbTmp->top_right >> 3; //Start address
REGs_PSC0[1] = (u32)(fbTmp->top_right + SCREEN_TOP_FBSIZE) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
while(!(REGs_PSC0[3] & 2));
}
WAIT_FOR_ARM9();
}