Refactor payload loading, fix messy externs, add safety checks to Nintendo FIRMs, fix some Nintendo FIRMs not being loaded as payloads
This commit is contained in:
parent
901d4992c0
commit
0c68750056
@ -28,9 +28,8 @@
|
||||
#include "cache.h"
|
||||
#include "firm.h"
|
||||
|
||||
void main(int argc, char **argv)
|
||||
void main(int argc, char **argv, Firm *firm)
|
||||
{
|
||||
Firm *firm = (Firm *)0x20001000;
|
||||
char *argvPassed[2],
|
||||
absPath[24 + 255];
|
||||
struct fb fbs[2];
|
||||
|
@ -69,6 +69,8 @@ typedef enum ConfigurationStatus
|
||||
CREATE_CONFIGURATION
|
||||
} ConfigurationStatus;
|
||||
|
||||
extern CfgData configData;
|
||||
|
||||
bool readConfig(void);
|
||||
void writeConfig(bool isConfigOptions);
|
||||
void configMenu(bool oldPinStatus, u32 oldPinMode);
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "crypto.h"
|
||||
#include "memory.h"
|
||||
#include "emunand.h"
|
||||
#include "strings.h"
|
||||
#include "utils.h"
|
||||
#include "fatfs/sdmmc/sdmmc.h"
|
||||
@ -421,12 +422,18 @@ int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool decryptExeFs(Cxi *cxi)
|
||||
u32 decryptExeFs(Cxi *cxi)
|
||||
{
|
||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return false;
|
||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return 0;
|
||||
|
||||
if(cxi->ncch.exeFsOffset != 5) return 0;
|
||||
|
||||
u8 *exeFsOffset = (u8 *)cxi + 6 * 0x200;
|
||||
|
||||
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
|
||||
u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
|
||||
|
||||
if(exeFsSize > 0x400000) return 0;
|
||||
|
||||
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
@ -438,12 +445,12 @@ bool decryptExeFs(Cxi *cxi)
|
||||
aes_use_keyslot(0x2C);
|
||||
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
return memcmp(cxi, "FIRM", 4) == 0;
|
||||
return memcmp(cxi, "FIRM", 4) == 0 ? exeFsSize : 0;
|
||||
}
|
||||
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
|
||||
u32 decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
|
||||
{
|
||||
if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return false;
|
||||
if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return 0;
|
||||
|
||||
__attribute__((aligned(4))) static const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
|
||||
__attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE],
|
||||
|
@ -110,8 +110,6 @@
|
||||
#define SHA_224_HASH_SIZE (224 / 8)
|
||||
#define SHA_1_HASH_SIZE (160 / 8)
|
||||
|
||||
extern u32 emuOffset,
|
||||
emuHeader;
|
||||
extern FirmwareSource firmSource;
|
||||
|
||||
void sha(void *res, const void *src, u32 size, u32 mode);
|
||||
@ -119,8 +117,8 @@ void sha(void *res, const void *src, u32 size, u32 mode);
|
||||
int ctrNandInit(void);
|
||||
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
||||
bool decryptExeFs(Cxi *cxi);
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||
u32 decryptExeFs(Cxi *cxi);
|
||||
u32 decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||
void setupKeyslots(void);
|
||||
void kernel9Loader(Arm9Bin *arm9Section);
|
||||
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
||||
|
@ -34,5 +34,8 @@
|
||||
|
||||
#define ROUND_TO_4MB(a) (((a) + 0x2000 - 1) & (~(0x2000 - 1)))
|
||||
|
||||
extern u32 emuOffset,
|
||||
emuHeader;
|
||||
|
||||
void locateEmuNand(FirmwareSource *nandType);
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address);
|
||||
|
271
source/firm.c
271
source/firm.c
@ -39,7 +39,74 @@
|
||||
#include "fmt.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
static Firm *firm = (Firm *)0x20001000;
|
||||
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if(as <= bs && bs <= ae)
|
||||
return true;
|
||||
if(bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if(as >= bs && ae <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkFirm(u32 payloadSize)
|
||||
{
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
if(payloadSize < size) return false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) ||
|
||||
((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000))))
|
||||
return false;
|
||||
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
static inline u32 loadFirmFromStorage(FirmwareType firmType)
|
||||
{
|
||||
const char *firmwareFiles[] = {
|
||||
"native.firm",
|
||||
@ -58,24 +125,108 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
|
||||
u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200);
|
||||
|
||||
if(!firmSize) return false;
|
||||
if(!firmSize) return 0;
|
||||
|
||||
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
|
||||
static const char *extFirmError = "The external FIRM is not valid.";
|
||||
|
||||
if(firmSize <= sizeof(Cxi) + 0x200) error(extFirmError);
|
||||
|
||||
if(memcmp(firm, "FIRM", 4) != 0)
|
||||
{
|
||||
if(firmSize <= sizeof(Cxi) + 0x400) error(extFirmError);
|
||||
|
||||
u8 cetk[0xA50];
|
||||
|
||||
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk) ||
|
||||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
|
||||
error("The FIRM in /luma is encrypted or corrupted.");
|
||||
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk))
|
||||
error("The cetk is missing or corrupted.");
|
||||
|
||||
firmSize = decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize);
|
||||
|
||||
if(!firmSize) error("Unable to decrypt the external FIRM.");
|
||||
}
|
||||
|
||||
return firmSize;
|
||||
}
|
||||
|
||||
u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
{
|
||||
//Load FIRM from CTRNAND
|
||||
u32 firmVersion = firmRead(firm, (u32)*firmType);
|
||||
|
||||
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
|
||||
|
||||
bool mustLoadFromStorage = false;
|
||||
|
||||
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT)
|
||||
{
|
||||
if(firmVersion < 0x18)
|
||||
{
|
||||
//We can't boot < 3.x EmuNANDs
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
|
||||
|
||||
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
||||
|
||||
*firmType = NATIVE_FIRM1X2X;
|
||||
}
|
||||
|
||||
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD/CTRNAND
|
||||
else if(firmVersion < 0x25) mustLoadFromStorage = true;
|
||||
}
|
||||
|
||||
bool loadedFromStorage = false;
|
||||
u32 firmSize;
|
||||
|
||||
if(loadFromStorage || mustLoadFromStorage)
|
||||
{
|
||||
u32 result = loadFirmFromStorage(*firmType);
|
||||
|
||||
if(result != 0)
|
||||
{
|
||||
loadedFromStorage = true;
|
||||
firmSize = result;
|
||||
}
|
||||
}
|
||||
|
||||
if(!loadedFromStorage)
|
||||
{
|
||||
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy an external FIRM to boot.");
|
||||
firmSize = decryptExeFs((Cxi *)firm);
|
||||
if(!firmSize) error("Unable to decrypt the CTRNAND FIRM.");
|
||||
}
|
||||
|
||||
if(!checkFirm(firmSize)) error("The %s FIRM is invalid or corrupted.", loadedFromStorage ? "external" : "CTRNAND");
|
||||
|
||||
//Check that the FIRM is right for the console from the ARM9 section address
|
||||
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
|
||||
error("The FIRM in /luma is not for this console.");
|
||||
error("The %s FIRM is not for this console.", loadedFromStorage ? "external" : "CTRNAND");
|
||||
|
||||
return true;
|
||||
return loadedFromStorage || ISDEVUNIT ? 0xFFFFFFFF : firmVersion;
|
||||
}
|
||||
|
||||
void loadHomebrewFirm(u32 pressed)
|
||||
{
|
||||
char path[10 + 255];
|
||||
|
||||
bool found = !pressed ? payloadMenu(path) : findPayload(path, pressed);
|
||||
|
||||
if(!found) return;
|
||||
|
||||
u32 maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
|
||||
|
||||
u32 payloadSize = fileRead(firm, path, maxPayloadSize);
|
||||
|
||||
if(payloadSize <= 0x200 || !checkFirm(payloadSize)) error("The payload is invalid or corrupted.");
|
||||
|
||||
char absPath[24 + 255];
|
||||
|
||||
if(isSdMode) sprintf(absPath, "sdmc:/luma/%s", path);
|
||||
else sprintf(absPath, "nand:/rw/luma/%s", path);
|
||||
|
||||
char *argv[2] = {absPath, (char *)fbs};
|
||||
initScreens();
|
||||
|
||||
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
|
||||
}
|
||||
|
||||
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
||||
@ -163,43 +314,6 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
||||
}
|
||||
}
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
{
|
||||
//Load FIRM from CTRNAND
|
||||
u32 firmVersion = firmRead(firm, (u32)*firmType);
|
||||
|
||||
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
|
||||
|
||||
bool mustLoadFromStorage = false;
|
||||
|
||||
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT)
|
||||
{
|
||||
if(firmVersion < 0x18)
|
||||
{
|
||||
//We can't boot < 3.x EmuNANDs
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
|
||||
|
||||
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
||||
|
||||
*firmType = NATIVE_FIRM1X2X;
|
||||
}
|
||||
|
||||
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD/CTRNAND
|
||||
else if(firmVersion < 0x25) mustLoadFromStorage = true;
|
||||
}
|
||||
|
||||
if((loadFromStorage || mustLoadFromStorage) && loadFirmFromStorage(*firmType)) firmVersion = 0xFFFFFFFF;
|
||||
else
|
||||
{
|
||||
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot.");
|
||||
if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted.");
|
||||
if(ISDEVUNIT) firmVersion = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
||||
@ -382,71 +496,6 @@ u32 patch1x2xNativeAndSafeFirm(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if(as <= bs && bs <= ae)
|
||||
return true;
|
||||
if(bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if(as >= bs && ae <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkFirmPayload(u32 payloadSize)
|
||||
{
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
if(size != payloadSize) return false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) ||
|
||||
((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000))))
|
||||
return false;
|
||||
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
void launchFirm(int argc, char **argv)
|
||||
{
|
||||
u32 *chainloaderAddress = (u32 *)0x01FF9000;
|
||||
@ -456,5 +505,5 @@ void launchFirm(int argc, char **argv)
|
||||
memcpy(chainloaderAddress, chainloader_bin, chainloader_bin_size);
|
||||
|
||||
// No need to flush caches here, the chainloader is in ITCM
|
||||
((void (*)(int, char **, u32))chainloaderAddress)(argc, argv, 0x0000BEEF);
|
||||
((void (*)(int, char **, Firm *))chainloaderAddress)(argc, argv, firm);
|
||||
}
|
||||
|
@ -29,13 +29,10 @@
|
||||
#include "types.h"
|
||||
#include "3dsheaders.h"
|
||||
|
||||
static Firm *const firm = (Firm *const)0x20001000;
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||
u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||
void loadHomebrewFirm(u32 pressed);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patch1x2xNativeAndSafeFirm(void);
|
||||
|
||||
bool checkFirmPayload(u32 payloadSize);
|
||||
void launchFirm(int argc, char **argv);
|
||||
|
44
source/fs.c
44
source/fs.c
@ -121,16 +121,8 @@ void fileDelete(const char *path)
|
||||
f_unlink(path);
|
||||
}
|
||||
|
||||
void loadPayload(u32 pressed, const char *payloadPath)
|
||||
bool findPayload(char *path, u32 pressed)
|
||||
{
|
||||
u32 payloadSize = 0,
|
||||
maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
|
||||
|
||||
char absPath[24 + _MAX_LFN];
|
||||
char path[10 + _MAX_LFN];
|
||||
|
||||
if(payloadPath == NULL)
|
||||
{
|
||||
const char *pattern;
|
||||
|
||||
if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
|
||||
@ -151,36 +143,22 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
||||
|
||||
result = f_findfirst(&dir, &info, "payloads", pattern);
|
||||
|
||||
if(result != FR_OK) return;
|
||||
if(result != FR_OK) return false;
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(!info.fname[0]) return;
|
||||
if(!info.fname[0]) return false;
|
||||
|
||||
sprintf(path, "payloads/%s", info.fname);
|
||||
|
||||
}
|
||||
else sprintf(path, "%s", payloadPath);
|
||||
|
||||
payloadSize = fileRead(firm, path, maxPayloadSize);
|
||||
|
||||
if(payloadSize <= 0x200 || !checkFirmPayload(payloadSize)) return;
|
||||
|
||||
if(isSdMode) sprintf(absPath, "sdmc:/luma/%s", path);
|
||||
else sprintf(absPath, "nand:/rw/luma/%s", path);
|
||||
|
||||
char *argv[2] = {absPath, (char *)fbs};
|
||||
initScreens();
|
||||
|
||||
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
|
||||
return true;
|
||||
}
|
||||
|
||||
void payloadMenu(void)
|
||||
bool payloadMenu(char *path)
|
||||
{
|
||||
DIR dir;
|
||||
char path[62] = "payloads";
|
||||
|
||||
if(f_opendir(&dir, path) != FR_OK) return;
|
||||
if(f_opendir(&dir, "payloads") != FR_OK) return false;
|
||||
|
||||
FILINFO info;
|
||||
u32 payloadNum = 0;
|
||||
@ -205,7 +183,7 @@ void payloadMenu(void)
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(!payloadNum) return;
|
||||
if(!payloadNum) return false;
|
||||
|
||||
u32 pressed = 0,
|
||||
selectedPayload = 0;
|
||||
@ -261,12 +239,14 @@ void payloadMenu(void)
|
||||
if(pressed != BUTTON_START)
|
||||
{
|
||||
sprintf(path, "payloads/%s.firm", payloadList[selectedPayload]);
|
||||
loadPayload(0, path);
|
||||
error("The payload is too large or corrupted.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
while(HID_PAD & MENU_BUTTONS);
|
||||
wait(2000ULL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 firmRead(void *dest, u32 firmType)
|
||||
@ -308,7 +288,7 @@ u32 firmRead(void *dest, u32 firmType)
|
||||
//Complete the string with the .app name
|
||||
sprintf(path, "%s/%08x.app", folderPath, firmVersion);
|
||||
|
||||
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF;
|
||||
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x400) firmVersion = 0xFFFFFFFF;
|
||||
|
||||
exit:
|
||||
return firmVersion;
|
||||
|
@ -35,7 +35,7 @@ u32 fileRead(void *dest, const char *path, u32 maxSize);
|
||||
u32 getFileSize(const char *path);
|
||||
bool fileWrite(const void *buffer, const char *path, u32 size);
|
||||
void fileDelete(const char *path);
|
||||
void loadPayload(u32 pressed, const char *payloadPath);
|
||||
void payloadMenu(void);
|
||||
bool findPayload(char *path, u32 pressed);
|
||||
bool payloadMenu(char *path);
|
||||
u32 firmRead(void *dest, u32 firmType);
|
||||
void findDumpFile(const char *folderPath, char *fileName);
|
||||
|
@ -207,11 +207,11 @@ void main(int argc, char **argv, u32 magicWord)
|
||||
|
||||
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
|
||||
{
|
||||
payloadMenu();
|
||||
loadHomebrewFirm(0);
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
|
||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadHomebrewFirm(pressed);
|
||||
|
||||
if(splashMode == 2) loadSplash();
|
||||
|
||||
@ -286,7 +286,7 @@ boot:
|
||||
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
|
||||
|
||||
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
|
||||
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
|
||||
u32 firmVersion = loadNintendoFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
|
||||
|
||||
bool doUnitinfoPatch = CONFIG(PATCHUNITINFO);
|
||||
u32 res;
|
||||
|
@ -37,8 +37,6 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern CfgData configData;
|
||||
|
||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage);
|
||||
void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space);
|
||||
|
@ -63,7 +63,6 @@ typedef enum
|
||||
} Arm11Operation;
|
||||
|
||||
extern struct fb fbs[2];
|
||||
extern CfgData configData;
|
||||
|
||||
void prepareArm11ForFirmlaunch(void);
|
||||
void deinitScreens(void);
|
||||
|
Reference in New Issue
Block a user