mirror of
https://github.com/LumaTeam/Luma3DS.git
synced 2026-02-22 01:44:38 +00:00
Add emunand support for prototype NFIRM (by @Wack0)
This commit is contained in:
parent
92e586cb3c
commit
60b244d6a3
@ -111,6 +111,23 @@ void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCt
|
|||||||
else *nandType = FIRMWARE_SYSNAND;
|
else *nandType = FIRMWARE_SYSNAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 getProtoSdmmc(u32 *sdmmc, u32 firmVersion)
|
||||||
|
{
|
||||||
|
switch(firmVersion)
|
||||||
|
{
|
||||||
|
case 243: // SDK 0.9.x (0.9.7?)
|
||||||
|
*sdmmc = (0x080AAA28 + 0x4e0);
|
||||||
|
break;
|
||||||
|
case 238: // SDK 0.10
|
||||||
|
*sdmmc = (0x080BEA70 + 0x690);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion)
|
static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion)
|
||||||
{
|
{
|
||||||
switch(firmVersion)
|
switch(firmVersion)
|
||||||
@ -166,6 +183,111 @@ static inline u32 patchNandRw(u8 *pos, u32 size, u32 hookAddr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 patchProtoNandRw(u8 *pos, u32 size, u32 hookAddr, u32 hookCidAddr)
|
||||||
|
{
|
||||||
|
//Look for read/write code
|
||||||
|
static const u8 pattern[] = {
|
||||||
|
0x03, 0x00, 0x51, 0xE3, // cmp r1, #3
|
||||||
|
0x02, 0xC0, 0xA0, 0xE1, // mov r12, r2
|
||||||
|
0x04, 0x00, 0x80, 0xE2, // add r0, r0, #4
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 *writeOffset = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
|
|
||||||
|
if(writeOffset == NULL) return 1;
|
||||||
|
|
||||||
|
u32 *readOffset = (u32 *)memsearch((u8 *)(writeOffset + 3), pattern, 0x400, sizeof(pattern));
|
||||||
|
|
||||||
|
if(readOffset == NULL) return 1;
|
||||||
|
|
||||||
|
// Find the sdmmc mount/init(?) function
|
||||||
|
static const u8 mount_pattern[] = {
|
||||||
|
0x20, 0x00, 0x84, 0xE2, // add r0, r4, 0x20
|
||||||
|
0x01, 0x20, 0xA0, 0xE3, // mov r2, #1
|
||||||
|
0x00, 0x10, 0xA0, 0xE3, // mov r1, #0
|
||||||
|
};
|
||||||
|
u32* mountOffset = (u32*) memsearch(pos, mount_pattern, size, sizeof(mount_pattern));
|
||||||
|
if (mountOffset == NULL) return 1;
|
||||||
|
|
||||||
|
// Find the sdmmc read cid function.
|
||||||
|
static const u8 readcid_pattern[] = {
|
||||||
|
0x31, 0xFF, 0x2F, 0xE1, // blx r1
|
||||||
|
0x20, 0x60, 0x9F, 0xE5, // ldr r6, [pc, #0x20] // =failing_result
|
||||||
|
0x00, 0x00, 0x50, 0xE3, // cmp r0, #0
|
||||||
|
};
|
||||||
|
u32* readCidOffset = (u32*) memsearch(pos, readcid_pattern, size, sizeof(readcid_pattern));
|
||||||
|
if (readCidOffset == NULL) return 1;
|
||||||
|
readCidOffset -= 5;
|
||||||
|
|
||||||
|
mountOffset[1] = 0xe3a02000; // mov r2, #0 // sd-card
|
||||||
|
|
||||||
|
readOffset[0] = writeOffset[0] = 0xe52de004; // push {lr}
|
||||||
|
readOffset[1] = writeOffset[1] = 0xe59fc000; // ldr r12, [pc, #0]
|
||||||
|
readOffset[2] = writeOffset[2] = 0xe12fff3c; // blx r12
|
||||||
|
readOffset[3] = writeOffset[3] = hookAddr;
|
||||||
|
|
||||||
|
readCidOffset[0] = 0xe59fc000; // ldr r12, [pc, #0]
|
||||||
|
readCidOffset[1] = 0xe12fff3c; // blx r12
|
||||||
|
readCidOffset[2] = hookCidAddr;
|
||||||
|
|
||||||
|
// Read the emmc cid into the place hook will copy it from
|
||||||
|
sdmmc_get_cid(1, emunandPatchNandCid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 patchProtoNandRw238(u8 *pos, u32 size, u32 hookAddr, u32 hookCidAddr)
|
||||||
|
{
|
||||||
|
//Look for read/write code
|
||||||
|
static const u8 pattern[] = {
|
||||||
|
0x03, 0x00, 0x50, 0xE3, // cmp r0, #3
|
||||||
|
0x00, 0x00, 0xA0, 0x13, // movne r0, #0
|
||||||
|
0x01, 0x00, 0xA0, 0x03, // moveq r0, #1
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 *writeOffset = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
|
|
||||||
|
if(writeOffset == NULL) return 1;
|
||||||
|
|
||||||
|
u32 *readOffset = (u32 *)memsearch((u8 *)(writeOffset + 3), pattern, 0x400, sizeof(pattern));
|
||||||
|
|
||||||
|
if(readOffset == NULL) return 1;
|
||||||
|
|
||||||
|
// Find the mmc static ctor...
|
||||||
|
static const u8 mount_pattern[] = {
|
||||||
|
0x08, // last byte of some ptr to something in P9
|
||||||
|
0x01, 0x01, 0x00, 0x00, // emmc controller id
|
||||||
|
};
|
||||||
|
u8* mountOffset = (u8*) memsearch(pos, mount_pattern, size, sizeof(mount_pattern));
|
||||||
|
if (mountOffset == NULL) return 1;
|
||||||
|
mountOffset++;
|
||||||
|
|
||||||
|
// Find the sdmmc read cid function.
|
||||||
|
static const u8 readcid_pattern[] = {
|
||||||
|
0x31, 0xFF, 0x2F, 0xE1, // blx r1
|
||||||
|
0x20, 0x60, 0x9F, 0xE5, // ldr r6, [pc, #0x20] // =failing_result
|
||||||
|
0x00, 0x00, 0x50, 0xE3, // cmp r0, #0
|
||||||
|
};
|
||||||
|
u32* readCidOffset = (u32*) memsearch(pos, readcid_pattern, size, sizeof(readcid_pattern));
|
||||||
|
if (readCidOffset == NULL) return 1;
|
||||||
|
readCidOffset -= 5;
|
||||||
|
|
||||||
|
*(u32*)mountOffset = 0x300; // sd card
|
||||||
|
|
||||||
|
readOffset[0] = writeOffset[0] = 0xe59fc000; // ldr r12, [pc, #0]
|
||||||
|
readOffset[1] = writeOffset[1] = 0xe12fff3c; // blx r12
|
||||||
|
readOffset[2] = writeOffset[2] = hookAddr;
|
||||||
|
|
||||||
|
readCidOffset[0] = 0xe59fc000; // ldr r12, [pc, #0]
|
||||||
|
readCidOffset[1] = 0xe12fff3c; // blx r12
|
||||||
|
readCidOffset[2] = hookCidAddr;
|
||||||
|
|
||||||
|
// Read the emmc cid into the place hook will copy it from
|
||||||
|
sdmmc_get_cid(1, emunandPatchNandCid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
|
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
|
||||||
{
|
{
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
@ -184,3 +306,33 @@ u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 patchProtoEmuNand(u8 *process9Offset, u32 process9Size)
|
||||||
|
{
|
||||||
|
extern u32 firmProtoVersion;
|
||||||
|
u32 ret = 0;
|
||||||
|
|
||||||
|
// Add the data of the found EmuNAND
|
||||||
|
emunandPatchNandOffset = emuOffset;
|
||||||
|
emunandPatchNcsdHeaderOffset = emuHeader;
|
||||||
|
|
||||||
|
// Find and add the SDMMC struct
|
||||||
|
u32 sdmmc;
|
||||||
|
ret += getProtoSdmmc(&sdmmc, firmProtoVersion);
|
||||||
|
if(!ret) emunandPatchSdmmcStructPtr = sdmmc;
|
||||||
|
|
||||||
|
// Add EmuNAND hooks
|
||||||
|
switch (firmProtoVersion) {
|
||||||
|
case 243: // SDK 0.9.x (0.9.7?)
|
||||||
|
ret += patchProtoNandRw(process9Offset, process9Size, (u32)emunandProtoPatch, (u32)emunandProtoCidPatch);
|
||||||
|
break;
|
||||||
|
case 238: // SDK 0.10.x
|
||||||
|
ret += patchProtoNandRw238(process9Offset, process9Size, (u32)emunandProtoPatch238, (u32)emunandProtoCidPatch);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@ -39,3 +39,4 @@ extern u32 emuOffset,
|
|||||||
|
|
||||||
void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCtrNandParams);
|
void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCtrNandParams);
|
||||||
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion);
|
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion);
|
||||||
|
u32 patchProtoEmuNand(u8 *process9Offset, u32 process9Size);
|
||||||
@ -45,19 +45,150 @@ emunandPatch:
|
|||||||
|
|
||||||
.pool
|
.pool
|
||||||
|
|
||||||
|
_emunandPatchEnd:
|
||||||
|
|
||||||
|
.global emunandProtoPatch
|
||||||
|
emunandProtoPatch:
|
||||||
|
@ Save registers
|
||||||
|
push {r0-r3}
|
||||||
|
|
||||||
|
@ If we're already trying to access the SD, return
|
||||||
|
ldr r2, [r0, #4]
|
||||||
|
ldr r1, emunandPatchSdmmcStructPtr
|
||||||
|
cmp r2, r1
|
||||||
|
beq _out
|
||||||
|
|
||||||
|
ldrb r2, [r1, #0xc] @ Get sdmc->m_isInitialised
|
||||||
|
cmp r2, #0 @ Is initialised?
|
||||||
|
beq _pastSdmc @ if not, use "NAND" object, patched elsewhere to access SD
|
||||||
|
str r1, [r0, #4] @ Set object to be SD
|
||||||
|
_pastSdmc:
|
||||||
|
ldr r2, [r0, #8] @ Get sector to read
|
||||||
|
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
|
||||||
|
|
||||||
|
ldr r3, emunandPatchNandOffset
|
||||||
|
add r2, r3 @ Add the offset to the NAND in the SD
|
||||||
|
|
||||||
|
ldreq r3, emunandPatchNcsdHeaderOffset
|
||||||
|
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
|
||||||
|
|
||||||
|
str r2, [r0, #8] @ Store sector to read
|
||||||
|
|
||||||
|
_out:
|
||||||
|
@ Restore registers
|
||||||
|
pop {r0-r3}
|
||||||
|
@ Execute original code that got patched.
|
||||||
|
cmp r1, #3
|
||||||
|
mov r12, r2
|
||||||
|
add r0, r0, #4
|
||||||
|
movne r1, #0
|
||||||
|
moveq r1, #1
|
||||||
|
@ r2 about to be overwritten, so it's free to use here.
|
||||||
|
@ Save off our return address and restore lr.
|
||||||
|
mov r2, lr
|
||||||
|
pop {lr}
|
||||||
|
@ r2+0 is return address (patched movne r1, #0)
|
||||||
|
@ r2+4 is moveq r1, #1
|
||||||
|
@ r2+8 is the following instruction (mov r2, r3)
|
||||||
|
add r2, #8
|
||||||
|
bx r2
|
||||||
|
|
||||||
|
.global emunandProtoCidPatch
|
||||||
|
emunandProtoCidPatch:
|
||||||
|
@ If we're already trying to access the SD, return
|
||||||
|
ldr r4, emunandPatchSdmmcStructPtr
|
||||||
|
cmp r0, r4
|
||||||
|
beq _cid_return
|
||||||
|
|
||||||
|
@ Trying to access nand, so copy the NAND cid into r1
|
||||||
|
adr r4, emunandPatchNandCid
|
||||||
|
ldr r2, [r4, #0]
|
||||||
|
ldr r3, [r4, #4]
|
||||||
|
ldr r5, [r4, #8]
|
||||||
|
ldr r6, [r4, #0xc]
|
||||||
|
str r2, [r1, #0]
|
||||||
|
str r3, [r1, #4]
|
||||||
|
str r5, [r1, #8]
|
||||||
|
str r6, [r1, #0xc]
|
||||||
|
@ And return from whence we came
|
||||||
|
mov r0, #0
|
||||||
|
pop {r4-r6, pc}
|
||||||
|
|
||||||
|
_cid_return:
|
||||||
|
@ Execute original code that got patched.
|
||||||
|
mov r4, r0
|
||||||
|
ldr r0, [r0]
|
||||||
|
mov r5, r1
|
||||||
|
@ lr+0 is return address (patched mov r5, r1)
|
||||||
|
@ lr+4 is following instruction (ldr r1, [r0,#8])
|
||||||
|
add lr, #4
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global emunandProtoPatch238
|
||||||
|
emunandProtoPatch238:
|
||||||
|
@ Save registers
|
||||||
|
push {r0-r3}
|
||||||
|
|
||||||
|
@ If we're already trying to access the SD, return
|
||||||
|
ldr r2, [r4, #4]
|
||||||
|
ldr r1, emunandPatchSdmmcStructPtr
|
||||||
|
cmp r2, r1
|
||||||
|
beq _out238
|
||||||
|
|
||||||
|
ldr r2, [r1, #0x24] @ Get sdmc->m_someObjInitedLater
|
||||||
|
cmp r2, #0 @ Is initialised?
|
||||||
|
beq _pastSdmc238 @ if not, use "NAND" object, patched elsewhere to access SD
|
||||||
|
str r1, [r4, #4] @ Set object to be SD
|
||||||
|
_pastSdmc238:
|
||||||
|
|
||||||
|
ldr r2, [r4, #8] @ Get sector to read
|
||||||
|
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
|
||||||
|
|
||||||
|
ldr r3, emunandPatchNandOffset
|
||||||
|
add r2, r3 @ Add the offset to the NAND in the SD
|
||||||
|
|
||||||
|
ldreq r3, emunandPatchNcsdHeaderOffset
|
||||||
|
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
|
||||||
|
|
||||||
|
str r2, [r4, #8] @ Store sector to read
|
||||||
|
|
||||||
|
_out238:
|
||||||
|
@ Restore registers
|
||||||
|
pop {r0-r3}
|
||||||
|
@ Execute original code that got patched.
|
||||||
|
cmp r0, #3
|
||||||
|
movne r0, #0
|
||||||
|
moveq r0, #1
|
||||||
|
@ r1 about to be overwritten, so it's free to use here.
|
||||||
|
@ Save off our return address.
|
||||||
|
mov r1, lr
|
||||||
|
@ r1+0 is return address (patched moveq r1, #1)
|
||||||
|
@ r1+4 is tst r0, #0xff or sub sp, sp, #0xc
|
||||||
|
add r1, #4
|
||||||
|
bx r1
|
||||||
|
|
||||||
|
.pool
|
||||||
|
|
||||||
.global emunandPatchSdmmcStructPtr
|
.global emunandPatchSdmmcStructPtr
|
||||||
.global emunandPatchNandOffset
|
.global emunandPatchNandOffset
|
||||||
.global emunandPatchNcsdHeaderOffset
|
.global emunandPatchNcsdHeaderOffset
|
||||||
|
.global emunandPatchNandCid
|
||||||
|
|
||||||
|
_emunandPatchBssStart:
|
||||||
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
|
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
|
||||||
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
|
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
|
||||||
emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED)
|
emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED)
|
||||||
|
emunandPatchNandCid: @ Store emmc cid here, to override "sdmc's" when trying to read emmc's
|
||||||
|
.word 0,0,0,0
|
||||||
|
_emunandPatchBssEnd:
|
||||||
|
|
||||||
.pool
|
.pool
|
||||||
.balign 4
|
.balign 4
|
||||||
|
|
||||||
_emunandPatchEnd:
|
|
||||||
|
|
||||||
.global emunandPatchSize
|
.global emunandPatchSize
|
||||||
emunandPatchSize:
|
emunandPatchSize:
|
||||||
.word _emunandPatchEnd - emunandPatch
|
.word _emunandPatchEnd - emunandPatch
|
||||||
|
|
||||||
|
.global emunandPatchBssSize
|
||||||
|
emunandPatchBssSize:
|
||||||
|
.word _emunandPatchBssEnd - _emunandPatchBssStart
|
||||||
@ -155,7 +155,21 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
u32 firmVersion = 0xFFFFFFFF,
|
u32 firmVersion = 0xFFFFFFFF,
|
||||||
firmSize;
|
firmSize;
|
||||||
|
|
||||||
bool ctrNandError = isSdMode && !remountCtrNandPartition(false);
|
bool ctrNandError = true;
|
||||||
|
bool loadedFromStorage = false;
|
||||||
|
bool storageLoadError = false;
|
||||||
|
|
||||||
|
// Try loading FIRM from sdmc first if specified.
|
||||||
|
if (loadFromStorage) {
|
||||||
|
firmSize = loadFirmFromStorage(*firmType);
|
||||||
|
if (firmSize != 0) loadedFromStorage = true;
|
||||||
|
else storageLoadError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remount ctrnand and load FIRM from it if loading from sdmc failed.
|
||||||
|
if (!loadedFromStorage) {
|
||||||
|
ctrNandError = isSdMode && !remountCtrNandPartition(false);
|
||||||
|
}
|
||||||
|
|
||||||
if(!ctrNandError)
|
if(!ctrNandError)
|
||||||
{
|
{
|
||||||
@ -170,10 +184,8 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
if(!firmSize || !checkFirm(firmSize)) ctrNandError = true;
|
if(!firmSize || !checkFirm(firmSize)) ctrNandError = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If CTRNAND load failed, and it wasn't tried yet, load FIRM from sdmc.
|
||||||
bool loadedFromStorage = false;
|
if (ctrNandError && !storageLoadError)
|
||||||
|
|
||||||
if(loadFromStorage || ctrNandError)
|
|
||||||
{
|
{
|
||||||
u32 result = loadFirmFromStorage(*firmType);
|
u32 result = loadFirmFromStorage(*firmType);
|
||||||
|
|
||||||
@ -182,33 +194,25 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
loadedFromStorage = true;
|
loadedFromStorage = true;
|
||||||
firmSize = result;
|
firmSize = result;
|
||||||
}
|
}
|
||||||
else if(ctrNandError) error("Unable to mount CTRNAND or load the CTRNAND FIRM.\nPlease use an external one.");
|
else storageLoadError = true;
|
||||||
}
|
}
|
||||||
|
// If all attempts failed, panic.
|
||||||
|
if(ctrNandError && storageLoadError) error("Unable to mount CTRNAND or load the CTRNAND FIRM.\nPlease use an external one.");
|
||||||
|
|
||||||
//Check that the FIRM is right for the console from the Arm9 section address
|
//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))
|
bool isO3dsFirm = firm->section[3].offset == 0 && firm->section[2].address == (u8 *)0x8006800;
|
||||||
error("The %s FIRM is not for this console.", loadedFromStorage ? "external" : "CTRNAND");
|
|
||||||
|
|
||||||
if(!ISN3DS && *firmType == NATIVE_FIRM && firm->section[0].address == (u8 *)0x1FF80000)
|
|
||||||
{
|
|
||||||
//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 you want to use SAFE_FIRM on 1.0, use Luma from NAND & comment this line:
|
|
||||||
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
|
||||||
|
|
||||||
*firmType = NATIVE_FIRM1X2X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(loadedFromStorage || ISDEVUNIT)
|
if(loadedFromStorage || ISDEVUNIT)
|
||||||
{
|
{
|
||||||
firmVersion = 0xFFFFFFFF;
|
firmVersion = 0xFFFFFFFF;
|
||||||
|
|
||||||
if(!ISN3DS && (*firmType == NATIVE_FIRM || *firmType == NATIVE_FIRM1X2X))
|
if(isO3dsFirm && (*firmType == NATIVE_FIRM || *firmType == NATIVE_FIRM1X2X))
|
||||||
{
|
{
|
||||||
__attribute__((aligned(4))) static const u8 hashes[4][0x20] = {
|
__attribute__((aligned(4))) static const u8 hashes[5][0x20] = {
|
||||||
{0xD7, 0x43, 0x0F, 0x27, 0x8D, 0xC9, 0x3F, 0x4C, 0x96, 0xB5, 0xA8, 0x91, 0x48, 0xDB, 0x08, 0x8A,
|
{0xD7, 0x43, 0x0F, 0x27, 0x8D, 0xC9, 0x3F, 0x4C, 0x96, 0xB5, 0xA8, 0x91, 0x48, 0xDB, 0x08, 0x8A,
|
||||||
0x7E, 0x46, 0xB3, 0x95, 0x65, 0xA2, 0x05, 0xF1, 0xF2, 0x41, 0x21, 0xF1, 0x0C, 0x59, 0x6A, 0x9D},
|
0x7E, 0x46, 0xB3, 0x95, 0x65, 0xA2, 0x05, 0xF1, 0xF2, 0x41, 0x21, 0xF1, 0x0C, 0x59, 0x6A, 0x9D},
|
||||||
|
{0x93, 0xDF, 0x49, 0xA1, 0x24, 0x86, 0xBB, 0x6F, 0xAF, 0x49, 0x99, 0x2D, 0xD0, 0x8D, 0xB1, 0x88,
|
||||||
|
0x8A, 0x00, 0xB6, 0xDD, 0x36, 0x89, 0xC0, 0xE2, 0xC9, 0xA9, 0x99, 0x62, 0x57, 0x5E, 0x6C, 0x23},
|
||||||
{0x39, 0x75, 0xB5, 0x28, 0x24, 0x5E, 0x8B, 0x56, 0xBC, 0x83, 0x79, 0x41, 0x09, 0x2C, 0x42, 0xE6,
|
{0x39, 0x75, 0xB5, 0x28, 0x24, 0x5E, 0x8B, 0x56, 0xBC, 0x83, 0x79, 0x41, 0x09, 0x2C, 0x42, 0xE6,
|
||||||
0x26, 0xB6, 0x80, 0x59, 0xA5, 0x56, 0xF9, 0xF9, 0x6E, 0xF3, 0x63, 0x05, 0x58, 0xDF, 0x35, 0xEF},
|
0x26, 0xB6, 0x80, 0x59, 0xA5, 0x56, 0xF9, 0xF9, 0x6E, 0xF3, 0x63, 0x05, 0x58, 0xDF, 0x35, 0xEF},
|
||||||
{0x81, 0x9E, 0x71, 0x58, 0xE5, 0x44, 0x73, 0xF7, 0x48, 0x78, 0x7C, 0xEF, 0x5E, 0x30, 0xE2, 0x28,
|
{0x81, 0x9E, 0x71, 0x58, 0xE5, 0x44, 0x73, 0xF7, 0x48, 0x78, 0x7C, 0xEF, 0x5E, 0x30, 0xE2, 0x28,
|
||||||
@ -228,14 +232,19 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
firmProtoVersion = 243;
|
firmProtoVersion = 243;
|
||||||
*firmType = NATIVE_PROTOTYPE;
|
*firmType = NATIVE_PROTOTYPE;
|
||||||
break;
|
break;
|
||||||
// Release
|
|
||||||
case 1:
|
case 1:
|
||||||
|
firmVersion = 0x0;
|
||||||
|
firmProtoVersion = 238;
|
||||||
|
*firmType = NATIVE_PROTOTYPE;
|
||||||
|
break;
|
||||||
|
// Release
|
||||||
|
case 2:
|
||||||
firmVersion = 0x18;
|
firmVersion = 0x18;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 3:
|
||||||
firmVersion = 0x1D;
|
firmVersion = 0x1D;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 4:
|
||||||
firmVersion = 0x1F;
|
firmVersion = 0x1F;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -244,6 +253,20 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(*firmType != NATIVE_PROTOTYPE && (firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
|
||||||
|
error("The %s FIRM is not for this console.", loadedFromStorage ? "external" : "CTRNAND");
|
||||||
|
|
||||||
|
if(!ISN3DS && *firmType == NATIVE_FIRM && firm->section[0].address == (u8 *)0x1FF80000)
|
||||||
|
{
|
||||||
|
//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 you want to use SAFE_FIRM on 1.0, use Luma from NAND & comment this line:
|
||||||
|
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
||||||
|
|
||||||
|
*firmType = NATIVE_FIRM1X2X;
|
||||||
|
}
|
||||||
|
|
||||||
return firmVersion;
|
return firmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +770,7 @@ u32 patch1x2xNativeAndSafeFirm(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patchPrototypeNative(void)
|
u32 patchPrototypeNative(FirmwareSource nandType)
|
||||||
{
|
{
|
||||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
|
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
|
||||||
|
|
||||||
@ -758,13 +781,16 @@ u32 patchPrototypeNative(void)
|
|||||||
|
|
||||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
ret += patchProtoNandSignatureCheck(process9Offset, process9Size);
|
ret += patchProtoNandSignatureCheck(process9Offset, process9Size);
|
||||||
|
|
||||||
//Arm9 exception handlers
|
//Arm9 exception handlers
|
||||||
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
|
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
|
||||||
|
|
||||||
return ret;
|
//Apply EmuNAND patches
|
||||||
|
if(nandType != FIRMWARE_SYSNAND) ret += patchProtoEmuNand(process9Offset, process9Size);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void launchFirm(int argc, char **argv)
|
void launchFirm(int argc, char **argv)
|
||||||
|
|||||||
@ -35,5 +35,5 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
|
|||||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
||||||
u32 patch1x2xNativeAndSafeFirm(void);
|
u32 patch1x2xNativeAndSafeFirm(void);
|
||||||
u32 patchPrototypeNative(void);
|
u32 patchPrototypeNative(FirmwareSource nandType);
|
||||||
void launchFirm(int argc, char **argv);
|
void launchFirm(int argc, char **argv);
|
||||||
|
|||||||
@ -28,9 +28,11 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
extern const u8 emunandPatch[];
|
extern const u8 emunandPatch[], emunandProtoPatch[], emunandProtoCidPatch[];
|
||||||
extern const u32 emunandPatchSize;
|
extern const u8 emunandProtoPatch238[];
|
||||||
|
extern const u32 emunandPatchSize, emunandPatchBssSize;
|
||||||
extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset;
|
extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset;
|
||||||
|
extern u32 emunandPatchNandCid[4];
|
||||||
|
|
||||||
extern const u8 rebootPatch[];
|
extern const u8 rebootPatch[];
|
||||||
extern const u32 rebootPatchSize;
|
extern const u32 rebootPatchSize;
|
||||||
|
|||||||
@ -387,7 +387,7 @@ boot:
|
|||||||
res = patch1x2xNativeAndSafeFirm();
|
res = patch1x2xNativeAndSafeFirm();
|
||||||
break;
|
break;
|
||||||
case NATIVE_PROTOTYPE:
|
case NATIVE_PROTOTYPE:
|
||||||
res = patchPrototypeNative();
|
res = patchPrototypeNative(nandType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
|||||||
Cxi *off = (Cxi *)(temp - 0x100);
|
Cxi *off = (Cxi *)(temp - 0x100);
|
||||||
|
|
||||||
*process9MemAddr = off->exHeader.systemControlInfo.textCodeSet.address;
|
*process9MemAddr = off->exHeader.systemControlInfo.textCodeSet.address;
|
||||||
|
|
||||||
// Prototype FW has a different NCCH format
|
// Prototype FW has a different NCCH format
|
||||||
if (firmProtoVersion && firmProtoVersion <= 243)
|
if (firmProtoVersion && firmProtoVersion <= 243)
|
||||||
{
|
{
|
||||||
@ -68,7 +68,7 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
|||||||
*process9Size = (off->ncch.exeFsSize - 1) * 0x200;
|
*process9Size = (off->ncch.exeFsSize - 1) * 0x200;
|
||||||
return (u8 *)off + (off->ncch.exeFsOffset + 1) * 0x200;
|
return (u8 *)off + (off->ncch.exeFsOffset + 1) * 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage)
|
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage)
|
||||||
@ -853,12 +853,28 @@ u32 patchProtoNandSignatureCheck(u8 *pos, u32 size) {
|
|||||||
// Signature check function returns 0 if failed and 1 if succeeded.
|
// Signature check function returns 0 if failed and 1 if succeeded.
|
||||||
// Proc9 breaks if the returned value is 0, change it to break if
|
// Proc9 breaks if the returned value is 0, change it to break if
|
||||||
// the returned value is 2 (never).
|
// the returned value is 2 (never).
|
||||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern)) + 0x20;
|
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
if (!off)
|
if (!off)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
*off = 2;
|
off[0x20] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (firmProtoVersion == 238) { // SDK 0.10
|
||||||
|
// Same patch as for v243 ported to the different ncsd_read() function
|
||||||
|
static const u8 pattern[] = {
|
||||||
|
0x00, 0x11, 0x9f, 0xe5,
|
||||||
|
0x00, 0x51, 0x9f, 0xe5,
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
|
if (!off)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
off[0x20] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
else return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user