Add safety checks, support booting from CTRNAND
This commit is contained in:
parent
bd6c7b7fdb
commit
0caf9f4214
@ -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, \
|
||||
|
@ -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;
|
||||
@ -106,4 +106,4 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId)
|
||||
|
||||
cleanInvalidateDCacheAndDMB();
|
||||
mcuReboot(); //Also contains DCache-cleaning code
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -274,17 +274,17 @@ static u32 calcSDSize(u8 *csd, int type)
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
u32 block_len = csd[9] & 0xF;
|
||||
block_len = 1u << block_len;
|
||||
u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1));
|
||||
mult = 1u << (mult + 2);
|
||||
result = csd[8] & 3;
|
||||
result = (result << 8) | csd[7];
|
||||
result = (result << 2) | (csd[6] >> 6);
|
||||
result = (result + 1) * mult * block_len / 512;
|
||||
}
|
||||
{
|
||||
u32 block_len = csd[9] & 0xF;
|
||||
block_len = 1u << block_len;
|
||||
u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1));
|
||||
mult = 1u << (mult + 2);
|
||||
result = csd[8] & 3;
|
||||
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;
|
||||
}
|
@ -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);
|
||||
|
@ -25,13 +25,18 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
|
||||
cmp r0, r2
|
||||
bne pxi_wait_recv
|
||||
|
||||
; Open file
|
||||
add r0, r7, #8
|
||||
adr r1, fname
|
||||
mov r2, #1
|
||||
ldr r6, [fopen]
|
||||
orr r6, 1
|
||||
blx r6
|
||||
adr r1, sd_fname
|
||||
|
||||
open_payload:
|
||||
; Open file
|
||||
add r0, r7, #8
|
||||
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:
|
||||
|
@ -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)
|
||||
|
@ -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);
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -268,17 +268,17 @@ static u32 calcSDSize(u8 *csd, int type)
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
u32 block_len = csd[9] & 0xF;
|
||||
block_len = 1u << block_len;
|
||||
u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1));
|
||||
mult = 1u << (mult + 2);
|
||||
result = csd[8] & 3;
|
||||
result = (result << 8) | csd[7];
|
||||
result = (result << 2) | (csd[6] >> 6);
|
||||
result = (result + 1) * mult * block_len / 512;
|
||||
}
|
||||
{
|
||||
u32 block_len = csd[9] & 0xF;
|
||||
block_len = 1u << block_len;
|
||||
u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1));
|
||||
mult = 1u << (mult + 2);
|
||||
result = csd[8] & 3;
|
||||
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;
|
||||
}
|
@ -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);
|
||||
|
@ -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)
|
||||
|
74
source/fs.c
74
source/fs.c
@ -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,39 +164,42 @@ u32 firmRead(void *dest, u32 firmType)
|
||||
|
||||
DIR dir;
|
||||
FILINFO info;
|
||||
|
||||
f_opendir(&dir, path);
|
||||
|
||||
u32 firmVersion = 0xFFFFFFFF;
|
||||
|
||||
//Parse the target directory
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
||||
if(f_opendir(&dir, path) == FR_OK)
|
||||
{
|
||||
//Not a cxi
|
||||
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
||||
|
||||
//Convert the .app name to an integer
|
||||
u32 tempVersion = 0;
|
||||
for(char *tmp = info.altname; *tmp != '.'; tmp++)
|
||||
//Parse the target directory
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
||||
{
|
||||
tempVersion <<= 4;
|
||||
tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
|
||||
//Not a cxi
|
||||
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
||||
|
||||
//Convert the .app name to an integer
|
||||
u32 tempVersion = 0;
|
||||
for(char *tmp = info.altname; *tmp != '.'; tmp++)
|
||||
{
|
||||
tempVersion <<= 4;
|
||||
tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
|
||||
}
|
||||
|
||||
//Found an older cxi
|
||||
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||
}
|
||||
|
||||
//Found an older cxi
|
||||
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||
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);
|
||||
|
||||
if(!fileRead(dest, path, 0x400200)) firmVersion = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
//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);
|
||||
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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--;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user