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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch(firmVersion)
|
||||
@ -166,6 +183,111 @@ static inline u32 patchNandRw(u8 *pos, u32 size, u32 hookAddr)
|
||||
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 ret = 0;
|
||||
@ -184,3 +306,33 @@ u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
|
||||
|
||||
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);
|
||||
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion);
|
||||
u32 patchProtoEmuNand(u8 *process9Offset, u32 process9Size);
|
||||
@ -45,19 +45,150 @@ emunandPatch:
|
||||
|
||||
.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 emunandPatchNandOffset
|
||||
.global emunandPatchNcsdHeaderOffset
|
||||
.global emunandPatchNandCid
|
||||
|
||||
_emunandPatchBssStart:
|
||||
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
|
||||
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
|
||||
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
|
||||
.balign 4
|
||||
|
||||
_emunandPatchEnd:
|
||||
|
||||
.global emunandPatchSize
|
||||
emunandPatchSize:
|
||||
.word _emunandPatchEnd - emunandPatch
|
||||
|
||||
.global emunandPatchBssSize
|
||||
emunandPatchBssSize:
|
||||
.word _emunandPatchBssEnd - _emunandPatchBssStart
|
||||
@ -155,7 +155,21 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
||||
u32 firmVersion = 0xFFFFFFFF,
|
||||
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)
|
||||
{
|
||||
@ -170,10 +184,8 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
||||
if(!firmSize || !checkFirm(firmSize)) ctrNandError = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool loadedFromStorage = false;
|
||||
|
||||
if(loadFromStorage || ctrNandError)
|
||||
// If CTRNAND load failed, and it wasn't tried yet, load FIRM from sdmc.
|
||||
if (ctrNandError && !storageLoadError)
|
||||
{
|
||||
u32 result = loadFirmFromStorage(*firmType);
|
||||
|
||||
@ -182,33 +194,25 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
||||
loadedFromStorage = true;
|
||||
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
|
||||
if((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;
|
||||
}
|
||||
bool isO3dsFirm = firm->section[3].offset == 0 && firm->section[2].address == (u8 *)0x8006800;
|
||||
|
||||
if(loadedFromStorage || ISDEVUNIT)
|
||||
{
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
@ -228,14 +232,19 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
||||
firmProtoVersion = 243;
|
||||
*firmType = NATIVE_PROTOTYPE;
|
||||
break;
|
||||
// Release
|
||||
case 1:
|
||||
firmVersion = 0x0;
|
||||
firmProtoVersion = 238;
|
||||
*firmType = NATIVE_PROTOTYPE;
|
||||
break;
|
||||
// Release
|
||||
case 2:
|
||||
firmVersion = 0x18;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
firmVersion = 0x1D;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
firmVersion = 0x1F;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -747,7 +770,7 @@ u32 patch1x2xNativeAndSafeFirm(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchPrototypeNative(void)
|
||||
u32 patchPrototypeNative(FirmwareSource nandType)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
|
||||
|
||||
@ -764,6 +787,9 @@ u32 patchPrototypeNative(void)
|
||||
//Arm9 exception handlers
|
||||
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
|
||||
|
||||
//Apply EmuNAND patches
|
||||
if(nandType != FIRMWARE_SYSNAND) ret += patchProtoEmuNand(process9Offset, process9Size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -35,5 +35,5 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patch1x2xNativeAndSafeFirm(void);
|
||||
u32 patchPrototypeNative(void);
|
||||
u32 patchPrototypeNative(FirmwareSource nandType);
|
||||
void launchFirm(int argc, char **argv);
|
||||
|
||||
@ -28,9 +28,11 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern const u8 emunandPatch[];
|
||||
extern const u32 emunandPatchSize;
|
||||
extern const u8 emunandPatch[], emunandProtoPatch[], emunandProtoCidPatch[];
|
||||
extern const u8 emunandProtoPatch238[];
|
||||
extern const u32 emunandPatchSize, emunandPatchBssSize;
|
||||
extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset;
|
||||
extern u32 emunandPatchNandCid[4];
|
||||
|
||||
extern const u8 rebootPatch[];
|
||||
extern const u32 rebootPatchSize;
|
||||
|
||||
@ -387,7 +387,7 @@ boot:
|
||||
res = patch1x2xNativeAndSafeFirm();
|
||||
break;
|
||||
case NATIVE_PROTOTYPE:
|
||||
res = patchPrototypeNative();
|
||||
res = patchPrototypeNative(nandType);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -853,12 +853,28 @@ u32 patchProtoNandSignatureCheck(u8 *pos, u32 size) {
|
||||
// Signature check function returns 0 if failed and 1 if succeeded.
|
||||
// Proc9 breaks if the returned value is 0, change it to break if
|
||||
// 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)
|
||||
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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user