Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c711ed6253 | ||
|
|
356268eae5 | ||
|
|
2dd64b8a92 | ||
|
|
b5cddedb7d | ||
|
|
7afdc2b3b5 | ||
|
|
60c4956290 |
@@ -3,28 +3,7 @@
|
|||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
static CFWInfo info = {0};
|
||||||
{
|
|
||||||
char magic[4];
|
|
||||||
|
|
||||||
u8 versionMajor;
|
|
||||||
u8 versionMinor;
|
|
||||||
u8 versionBuild;
|
|
||||||
u8 flags; /* bit 0: dev branch; bit 1: is release */
|
|
||||||
|
|
||||||
u32 commitHash;
|
|
||||||
|
|
||||||
u32 config;
|
|
||||||
} CFWInfo;
|
|
||||||
|
|
||||||
CFWInfo info = {0};
|
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
|
||||||
#define PATH_MAX 255
|
|
||||||
#define CONFIG(a) (((info.config >> (a + 16)) & 1) != 0)
|
|
||||||
#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3)
|
|
||||||
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||||
{
|
{
|
||||||
@@ -114,17 +93,19 @@ int __attribute__((naked)) svcGetCFWInfo(CFWInfo __attribute__((unused)) *out)
|
|||||||
static void loadCFWInfo(void)
|
static void loadCFWInfo(void)
|
||||||
{
|
{
|
||||||
static bool infoLoaded = false;
|
static bool infoLoaded = false;
|
||||||
|
|
||||||
if(!infoLoaded)
|
if(!infoLoaded)
|
||||||
{
|
{
|
||||||
svcGetCFWInfo(&info);
|
svcGetCFWInfo(&info);
|
||||||
IFile file;
|
IFile file;
|
||||||
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //init SD card for firmlaunch patches
|
if(BOOTCONFIG(5, 1) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
|
||||||
{
|
{
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
infoLoaded = true;
|
infoLoaded = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool secureInfoExists(void)
|
static bool secureInfoExists(void)
|
||||||
{
|
{
|
||||||
@@ -338,6 +319,7 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
|
|||||||
void patchCode(u64 progId, u8 *code, u32 size)
|
void patchCode(u64 progId, u8 *code, u32 size)
|
||||||
{
|
{
|
||||||
loadCFWInfo();
|
loadCFWInfo();
|
||||||
|
|
||||||
switch(progId)
|
switch(progId)
|
||||||
{
|
{
|
||||||
case 0x0004003000008F02LL: // USA Menu
|
case 0x0004003000008F02LL: // USA Menu
|
||||||
|
|||||||
@@ -2,4 +2,24 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
#define PATH_MAX 255
|
||||||
|
|
||||||
|
#define CONFIG(a) (((info.config >> (a + 16)) & 1) != 0)
|
||||||
|
#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
u8 versionMajor;
|
||||||
|
u8 versionMinor;
|
||||||
|
u8 versionBuild;
|
||||||
|
u8 flags; /* bit 0: dev branch; bit 1: is release */
|
||||||
|
|
||||||
|
u32 commitHash;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CFWInfo;
|
||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size);
|
void patchCode(u64 progId, u8 *code, u32 size);
|
||||||
@@ -135,7 +135,7 @@ patchesStart:
|
|||||||
.halfword 1
|
.halfword 1
|
||||||
.halfword 8
|
.halfword 8
|
||||||
.byte 0x83, 0x30, 0x2e, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x01, 0x1a, 0xe3, 0x08, 0x60, 0x87, 0x05)
|
.byte 0x83, 0x30, 0x2e, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x01, 0x1a, 0xe3, 0x08, 0x60, 0x87, 0x05)
|
||||||
.byte 0x89, 0x53, 0xb2, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x08, 0x62, 0x86, 0xe3, 0x08, 0x60, 0x87, 0xe5)
|
.byte 0x83, 0x50, 0xf2, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x61, 0xc6, 0xe3, 0x08, 0x60, 0x87, 0xe5)
|
||||||
|
|
||||||
patchesEnd:
|
patchesEnd:
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,9 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
|
||||||
void configureCFW(const char *configPath)
|
void configureCFW(void)
|
||||||
{
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
@@ -44,7 +43,8 @@ void configureCFW(const char *configPath)
|
|||||||
"( ) 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",
|
||||||
"( ) Display splash screen before payloads",
|
"( ) Display splash screen before payloads",
|
||||||
"( ) Use a PIN" };
|
"( ) Use a PIN",
|
||||||
|
"( ) Enable experimental TwlBg patches" };
|
||||||
|
|
||||||
struct multiOption {
|
struct multiOption {
|
||||||
int posXs[4];
|
int posXs[4];
|
||||||
@@ -193,13 +193,6 @@ 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);
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -30,4 +30,4 @@
|
|||||||
|
|
||||||
extern u32 config;
|
extern u32 config;
|
||||||
|
|
||||||
void configureCFW(const char *configPath);
|
void configureCFW(void);
|
||||||
@@ -43,7 +43,9 @@ static const firmSectionHeader *section;
|
|||||||
u32 config,
|
u32 config,
|
||||||
emuOffset;
|
emuOffset;
|
||||||
|
|
||||||
bool isN3DS, isDevUnit, isFirmlaunch;
|
bool isN3DS,
|
||||||
|
isDevUnit,
|
||||||
|
isFirmlaunch;
|
||||||
|
|
||||||
FirmwareSource firmSource;
|
FirmwareSource firmSource;
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ void main(void)
|
|||||||
{
|
{
|
||||||
bool isA9lh;
|
bool isA9lh;
|
||||||
|
|
||||||
u32 newConfig,
|
u32 configTemp,
|
||||||
emuHeader;
|
emuHeader;
|
||||||
|
|
||||||
FirmwareType firmType;
|
FirmwareType firmType;
|
||||||
@@ -100,7 +102,8 @@ void main(void)
|
|||||||
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
||||||
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
|
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
|
||||||
|
|
||||||
newConfig = (u32)isA9lh << 3;
|
//Save old options and begin saving the new boot configuration
|
||||||
|
configTemp = (config & 0xFFFFFFC0) | ((u32)isA9lh << 3);
|
||||||
|
|
||||||
//If it's a MCU reboot, try to force boot options
|
//If it's a MCU reboot, try to force boot options
|
||||||
if(isA9lh && CFG_BOOTENV)
|
if(isA9lh && CFG_BOOTENV)
|
||||||
@@ -113,7 +116,7 @@ void main(void)
|
|||||||
needConfig = DONT_CONFIGURE;
|
needConfig = DONT_CONFIGURE;
|
||||||
|
|
||||||
//Flag to prevent multiple boot options-forcing
|
//Flag to prevent multiple boot options-forcing
|
||||||
newConfig |= 1 << 4;
|
configTemp |= 1 << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Else, force the last used boot options unless a button is pressed
|
/* Else, force the last used boot options unless a button is pressed
|
||||||
@@ -141,7 +144,7 @@ void main(void)
|
|||||||
|
|
||||||
if(shouldLoadConfigurationMenu)
|
if(shouldLoadConfigurationMenu)
|
||||||
{
|
{
|
||||||
configureCFW(configPath);
|
configureCFW();
|
||||||
|
|
||||||
if(!pinExists && CONFIG(7)) newPin();
|
if(!pinExists && CONFIG(7)) newPin();
|
||||||
|
|
||||||
@@ -155,6 +158,9 @@ void main(void)
|
|||||||
{
|
{
|
||||||
nandType = FIRMWARE_SYSNAND;
|
nandType = FIRMWARE_SYSNAND;
|
||||||
firmSource = FIRMWARE_SYSNAND;
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
|
|
||||||
|
//Flag to tell loader to init SD
|
||||||
|
configTemp |= 1 << 5;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -203,19 +209,23 @@ void main(void)
|
|||||||
|
|
||||||
if(!isFirmlaunch)
|
if(!isFirmlaunch)
|
||||||
{
|
{
|
||||||
newConfig |= (u32)nandType | ((u32)firmSource << 2);
|
configTemp |= (u32)nandType | ((u32)firmSource << 2);
|
||||||
|
|
||||||
/* If the boot configuration is different from previously, overwrite it.
|
/* If the configuration is different from previously, overwrite it.
|
||||||
Just the no-forcing flag being set is not enough */
|
Just the no-forcing flag being set is not enough */
|
||||||
if((newConfig & 0x2F) != (config & 0x3F))
|
if((configTemp & 0xFFFFFFEF) != config)
|
||||||
{
|
{
|
||||||
//Preserve user settings (last 26 bits)
|
//Merge the new options and new boot configuration
|
||||||
newConfig |= config & 0xFFFFFFC0;
|
config = (config & 0xFFFFFFC0) | (configTemp & 0x3F);
|
||||||
|
|
||||||
if(!fileWrite(&newConfig, configPath, 4))
|
if(!fileWrite(&config, configPath, 4))
|
||||||
|
{
|
||||||
|
createDirectory("luma");
|
||||||
|
if(!fileWrite(&config, configPath, 4))
|
||||||
error("Error writing the configuration file");
|
error("Error writing the configuration file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u32 firmVersion = loadFirm(firmType);
|
u32 firmVersion = loadFirm(firmType);
|
||||||
|
|
||||||
@@ -245,6 +255,11 @@ static inline u32 loadFirm(FirmwareType firmType)
|
|||||||
|
|
||||||
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
|
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
|
||||||
{
|
{
|
||||||
|
//We can't boot < 3.x NANDs
|
||||||
|
if(firmVersion < 0x18)
|
||||||
|
error("An old unsupported NAND has been detected.\nLuma3DS is unable to boot it.");
|
||||||
|
|
||||||
|
//We can't boot a 4.x NATIVE_FIRM, load one from SD
|
||||||
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
|
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
|
||||||
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
|
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
|
||||||
|
|
||||||
@@ -316,7 +331,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
|
|||||||
|
|
||||||
applyLegacyFirmPatches((u8 *)firm, firmType);
|
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||||
|
|
||||||
if(firmType == TWL_FIRM)
|
if(firmType == TWL_FIRM && CONFIG(8))
|
||||||
patchTwlBg((u8 *)firm + section[1].offset);
|
patchTwlBg((u8 *)firm + section[1].offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,56 +350,44 @@ static inline void patchSafeFirm(void)
|
|||||||
else patchFirmWriteSafe(arm9Section, section[2].size);
|
else patchFirmWriteSafe(arm9Section, section[2].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
|
static inline void copySection0AndInjectSystemModules(void)
|
||||||
{
|
{
|
||||||
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u32 size;
|
u32 size;
|
||||||
char name[8];
|
|
||||||
const u8 *addr;
|
const u8 *addr;
|
||||||
} modules[5] = {{0}};
|
} modules[5];
|
||||||
|
|
||||||
u8 *pos = arm11Section0, *end = pos + section[0].size;
|
u32 n = 0,
|
||||||
u32 n = 0;
|
loaderIndex;
|
||||||
|
u8 *pos = arm11Section0;
|
||||||
|
|
||||||
u32 loaderIndex = 0;
|
for(u8 *end = pos + section[0].size; pos < end; pos += modules[n++].size)
|
||||||
|
|
||||||
while(pos < end)
|
|
||||||
{
|
{
|
||||||
modules[n].addr = pos;
|
modules[n].addr = pos;
|
||||||
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
|
||||||
|
|
||||||
memcpy(modules[n].name, pos + 0x200, 8);
|
if(memcmp(modules[n].addr + 0x200, "loader", 7) == 0) loaderIndex = n;
|
||||||
pos += modules[n].size;
|
|
||||||
|
|
||||||
if(firmType == NATIVE_FIRM && memcmp(modules[n].name, "loader", 7) == 0) loaderIndex = n;
|
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(firmType == NATIVE_FIRM)
|
|
||||||
{
|
|
||||||
modules[loaderIndex].size = injector_size;
|
|
||||||
modules[loaderIndex].addr = injector;
|
modules[loaderIndex].addr = injector;
|
||||||
}
|
modules[loaderIndex].size = injector_size;
|
||||||
|
|
||||||
pos = section[0].address;
|
pos = section[0].address;
|
||||||
for(u32 i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
memcpy(pos, modules[i].addr, modules[i].size);
|
|
||||||
pos += modules[i].size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for(u32 i = 0; i < n; pos += modules[i++].size)
|
||||||
|
memcpy(pos, modules[i].addr, modules[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void launchFirm(FirmwareType firmType)
|
static inline void launchFirm(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
|
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
|
||||||
u32 sectionNum;
|
u32 sectionNum;
|
||||||
if(firmType != SAFE_FIRM)
|
if(firmType == NATIVE_FIRM)
|
||||||
{
|
{
|
||||||
copySection0AndInjectSystemModules(firmType);
|
copySection0AndInjectSystemModules();
|
||||||
sectionNum = 1;
|
sectionNum = 1;
|
||||||
}
|
}
|
||||||
else sectionNum = 0;
|
else sectionNum = 0;
|
||||||
|
|||||||
@@ -53,5 +53,5 @@ static inline u32 loadFirm(FirmwareType firmType);
|
|||||||
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
||||||
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(FirmwareType firmType);
|
static inline void copySection0AndInjectSystemModules(void);
|
||||||
static inline void launchFirm(FirmwareType firmType);
|
static inline void launchFirm(FirmwareType firmType);
|
||||||
@@ -167,26 +167,10 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern u32 config;
|
|
||||||
|
|
||||||
void implementSvcGetCFWInfo(u8 *pos, u32 size)
|
void implementSvcGetCFWInfo(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
typedef struct __attribute__((packed))
|
|
||||||
{
|
|
||||||
char magic[4];
|
|
||||||
|
|
||||||
u8 versionMajor;
|
|
||||||
u8 versionMinor;
|
|
||||||
u8 versionBuild;
|
|
||||||
u8 flags;
|
|
||||||
|
|
||||||
u32 commitHash;
|
|
||||||
|
|
||||||
u32 config;
|
|
||||||
} CFWInfo;
|
|
||||||
|
|
||||||
const char *rev = REVISION;
|
const char *rev = REVISION;
|
||||||
bool isRelease = false;
|
bool isRelease;
|
||||||
|
|
||||||
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
|
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
|
||||||
findFreeK11Space(pos, size);
|
findFreeK11Space(pos, size);
|
||||||
|
|||||||
@@ -33,7 +33,22 @@ typedef struct patchData {
|
|||||||
u32 type;
|
u32 type;
|
||||||
} patchData;
|
} patchData;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
u8 versionMajor;
|
||||||
|
u8 versionMinor;
|
||||||
|
u8 versionBuild;
|
||||||
|
u8 flags;
|
||||||
|
|
||||||
|
u32 commitHash;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CFWInfo;
|
||||||
|
|
||||||
extern bool isN3DS;
|
extern bool isN3DS;
|
||||||
|
extern u32 config;
|
||||||
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||||
void patchSignatureChecks(u8 *pos, u32 size);
|
void patchSignatureChecks(u8 *pos, u32 size);
|
||||||
|
|||||||
Reference in New Issue
Block a user