mirror of
https://github.com/LumaTeam/Luma3DS.git
synced 2026-05-31 01:16:56 +00:00
Add support for SDK 0.12 prototype FIRM
This commit is contained in:
parent
e35972ea82
commit
dd92ab13cd
@ -121,6 +121,9 @@ static inline u32 getProtoSdmmc(u32 *sdmmc, u32 firmVersion)
|
||||
case 238: // SDK 0.10
|
||||
*sdmmc = (0x080BEA70 + 0x690);
|
||||
break;
|
||||
case 1200: // SDK 0.12
|
||||
*sdmmc = (0x080C6A00 + 0x8DC);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@ -288,6 +291,58 @@ static inline u32 patchProtoNandRw238(u8 *pos, u32 size, u32 hookAddr, u32 hookC
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 patchProtoNandRw1200(u8 *pos, u32 size, u32 hookAddr, u32 hookCidAddr)
|
||||
{
|
||||
//Look for read/write code
|
||||
static const u8 pattern[] = {
|
||||
0x03, 0x00, 0x50, 0xE3, // CMP R0, #3
|
||||
0x14, 0xD0, 0x4D, 0xE2, // SUB SP, SP, #0x14
|
||||
0x00, 0x70, 0xA0, 0xE3, // MOV R7, #0
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// static ctor for NAND sdmmc driver
|
||||
static const u8 mount_pattern[] = {
|
||||
0xE8, // byte of some ptr
|
||||
0x01, 0x01, 0x00, 0x00, // sdmmc controller port (0x101, NAND)
|
||||
0x5C // byte of some other ptr
|
||||
};
|
||||
u8 *mountOffset = (u8 *)memsearch(pos, mount_pattern, size, sizeof(mount_pattern));
|
||||
if (mountOffset == NULL) return 1;
|
||||
++mountOffset;
|
||||
|
||||
static const u8 readcid_pattern[] = {
|
||||
0x31, 0xFF, 0x2F, 0xE1, /* BLX R1 */
|
||||
0x00, 0x00, 0x50, 0xE3, /* CMP R0, #0 */
|
||||
0x34, 0x00, 0x9F, 0x05, /* LDREQ R0, #0xE0A0F400 */
|
||||
};
|
||||
u32 *readCidOffset = (u32 *)memsearch(pos, readcid_pattern, size, sizeof(readcid_pattern));
|
||||
if (readCidOffset == NULL) return 1;
|
||||
readCidOffset -= 5; // now points to the instruction following PUSH {R4-R6, LR}
|
||||
|
||||
*(u32 *)mountOffset = 0x100; /* change the SDMMC device used as NAND to SD. note: SD = 0x100, NAND = 0x101 */
|
||||
|
||||
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;
|
||||
@ -329,10 +384,25 @@ u32 patchProtoEmuNand(u8 *process9Offset, u32 process9Size)
|
||||
case 238: // SDK 0.10.x
|
||||
ret += patchProtoNandRw238(process9Offset, process9Size, (u32)emunandProtoPatch238, (u32)emunandProtoCidPatch);
|
||||
break;
|
||||
case 1200: // SDK 0.12
|
||||
ret += patchProtoNandRw1200(process9Offset, process9Size, (u32)emunandProtoPatch1200, (u32)emunandProtoCidPatch1200);
|
||||
break;
|
||||
default:
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
|
||||
// Destroy the copy of the SysNAND NCSD header created by boot9 in ITCM.
|
||||
// Technically not required on O3DS, but absolutely required on N3DS.
|
||||
// On O3DS, the NAND header on EmuNAND is simply a copy of that of SysNAND,
|
||||
// which is fine, since prototype Process9 expects an O3DS NAND header.
|
||||
// On N3DS, it reading the actual SysNAND header would mean providing NCSD partition
|
||||
// info which Process9 doesn't understand, since N3DS CTRNAND uses crypto type 3.
|
||||
|
||||
// Process9 checks the validity of this ITCM copy, and re-reads it from "NAND"
|
||||
// when it is invalid. Because we re-routed NAND to SD, this will effectively
|
||||
// cause Process9 to re-read the header straight from EmuNAND, as it should.
|
||||
memset((void *)0x01FFB900, 0x0, 0x200);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +123,37 @@ emunandProtoCidPatch:
|
||||
@ lr+4 is following instruction (ldr r1, [r0,#8])
|
||||
add lr, #4
|
||||
bx lr
|
||||
|
||||
.global emunandProtoCidPatch1200
|
||||
emunandProtoCidPatch1200:
|
||||
@ If we're already trying to access the SD, return
|
||||
ldr r4, emunandPatchSdmmcStructPtr
|
||||
cmp r0, r4
|
||||
beq _cid_return1200
|
||||
|
||||
@ 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 where we came
|
||||
mov r0, #0
|
||||
pop {r4-r6, pc}
|
||||
|
||||
_cid_return1200:
|
||||
@ Execute original code that got patched.
|
||||
mov r4, r0
|
||||
ldr r0, [r0]
|
||||
mov r6, 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:
|
||||
@ -167,6 +198,48 @@ emunandProtoPatch238:
|
||||
add r1, #4
|
||||
bx r1
|
||||
|
||||
.global emunandProtoPatch1200
|
||||
emunandProtoPatch1200:
|
||||
push {r0-r3}
|
||||
|
||||
@ If we're already trying to access the SD, return
|
||||
ldr r2, [r4]
|
||||
ldr r1, emunandPatchSdmmcStructPtr
|
||||
cmp r1, r2
|
||||
beq _out1200
|
||||
|
||||
ldr r2, [r1, #0x24] @ Get sdmc->m_someObjInitedLater
|
||||
cmp r2, #0 @ Is initialised?
|
||||
beq _pastSdmc1200 @ if not, use "NAND" object, patched elsewhere to access SD
|
||||
str r1, [r4] @ Set object to be SD
|
||||
_pastSdmc1200:
|
||||
|
||||
ldr r2, [r4, #4] @ 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, #4] @ Store sector to read
|
||||
|
||||
_out1200:
|
||||
@ Restore registers
|
||||
pop {r0-r3}
|
||||
cmp r0, #3
|
||||
sub sp, sp, #0x14
|
||||
mov r7, #0
|
||||
|
||||
@ 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 the point after our patching
|
||||
add r1, #4
|
||||
bx r1
|
||||
|
||||
.pool
|
||||
|
||||
.global emunandPatchSdmmcStructPtr
|
||||
|
||||
@ -208,11 +208,13 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
||||
|
||||
if(isO3dsFirm && (*firmType == NATIVE_FIRM || *firmType == NATIVE_FIRM1X2X))
|
||||
{
|
||||
__attribute__((aligned(4))) static const u8 hashes[5][0x20] = {
|
||||
__attribute__((aligned(4))) static const u8 hashes[6][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},
|
||||
{0xD4, 0x91, 0xBC, 0x28, 0xFA, 0xBE, 0xC8, 0xF6, 0x80, 0xD2, 0x62, 0x51, 0xAF, 0x4B, 0x37, 0xBA,
|
||||
0x69, 0x1B, 0x33, 0x8B, 0x51, 0xA0, 0x35, 0x35, 0xF0, 0x2C, 0x66, 0xA6, 0x3A, 0xFB, 0xD5, 0xE7},
|
||||
{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,
|
||||
@ -240,14 +242,19 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
||||
firmProtoVersion = 238;
|
||||
*firmType = NATIVE_PROTOTYPE;
|
||||
break;
|
||||
// Release
|
||||
case 2:
|
||||
firmVersion = 0x0;
|
||||
firmProtoVersion = 1200;
|
||||
*firmType = NATIVE_PROTOTYPE;
|
||||
break;
|
||||
// Release
|
||||
case 3:
|
||||
firmVersion = 0x18;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
firmVersion = 0x1D;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
firmVersion = 0x1F;
|
||||
break;
|
||||
default:
|
||||
@ -773,18 +780,97 @@ u32 patch1x2xNativeAndSafeFirm(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchPrototypeNative(FirmwareSource nandType)
|
||||
struct b9_key {
|
||||
u8 keyslot;
|
||||
u16 b9_offs;
|
||||
};
|
||||
|
||||
static const struct b9_key key_X[23] = {
|
||||
{ .keyslot = 0x2C, .b9_offs = 0xDDD0 }, { .keyslot = 0x2D, .b9_offs = 0xDDD0 },
|
||||
{ .keyslot = 0x2E, .b9_offs = 0xDDD0 }, { .keyslot = 0x2F, .b9_offs = 0xDDD0 },
|
||||
{ .keyslot = 0x30, .b9_offs = 0xDDE0 }, { .keyslot = 0x31, .b9_offs = 0xDDE0 },
|
||||
{ .keyslot = 0x32, .b9_offs = 0xDDE0 }, { .keyslot = 0x33, .b9_offs = 0xDDE0 },
|
||||
{ .keyslot = 0x34, .b9_offs = 0xDDF0 }, { .keyslot = 0x35, .b9_offs = 0xDDF0 },
|
||||
{ .keyslot = 0x36, .b9_offs = 0xDDF0 }, { .keyslot = 0x37, .b9_offs = 0xDDF0 },
|
||||
{ .keyslot = 0x38, .b9_offs = 0xDE00 }, { .keyslot = 0x39, .b9_offs = 0xDE00 },
|
||||
{ .keyslot = 0x3A, .b9_offs = 0xDE00 }, { .keyslot = 0x3B, .b9_offs = 0xDE00 },
|
||||
{ .keyslot = 0x3C, .b9_offs = 0xDE10 }, { .keyslot = 0x3D, .b9_offs = 0xDE20 },
|
||||
{ .keyslot = 0x3E, .b9_offs = 0xDE30 }, { .keyslot = 0x3F, .b9_offs = 0xDE40 },
|
||||
};
|
||||
static const struct b9_key key_Y[9] = {
|
||||
{ .keyslot = 0x8, .b9_offs = 0xDE90 }, { .keyslot = 0x9, .b9_offs = 0xDEA0 },
|
||||
{ .keyslot = 0xA, .b9_offs = 0xDEB0 }, { .keyslot = 0xB, .b9_offs = 0xDEC0 },
|
||||
};
|
||||
|
||||
static const u8 boot9Sha256[32] = {
|
||||
0x2F, 0x88, 0x74, 0x4F, 0xEE, 0xD7, 0x17, 0x85, 0x63, 0x86, 0x40, 0x0A, 0x44, 0xBB, 0xA4, 0xB9,
|
||||
0xCA, 0x62, 0xE7, 0x6A, 0x32, 0xC7, 0x15, 0xD4, 0xF3, 0x09, 0xC3, 0x99, 0xBF, 0x28, 0x16, 0x6F,
|
||||
};
|
||||
|
||||
static void load_key(u8 keyslot, const u8 *key, u8 keytype) {
|
||||
const u32 *key32 = (u32 *)key;
|
||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | AES_INPUT_BE | AES_INPUT_NORMAL;
|
||||
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
||||
|
||||
REG_AESKEYFIFO[keytype] = key32[0];
|
||||
REG_AESKEYFIFO[keytype] = key32[1];
|
||||
REG_AESKEYFIFO[keytype] = key32[2];
|
||||
REG_AESKEYFIFO[keytype] = key32[3];
|
||||
}
|
||||
|
||||
u32 patchPrototypeNative(FirmwareSource nandType, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
|
||||
|
||||
//Find the Process9 .code location, size and memory address
|
||||
u32 process9Size,
|
||||
process9MemAddr;
|
||||
u32 process9Size = 0;
|
||||
u32 process9MemAddr = 0;
|
||||
u8 *process9Offset = getProcess9Info(arm9Section, firm->section[2].size, &process9Size, &process9MemAddr);
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||
ret = 0;
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200;
|
||||
u32 ret = 0;
|
||||
|
||||
if(doUnitinfoPatch && !ISDEVUNIT)
|
||||
{
|
||||
if (firmProtoVersion == 1200)
|
||||
{
|
||||
u8 b9[0x10000] = { 0 };
|
||||
u32 hash[4] = { 0 };
|
||||
sha(hash, (const void *)0x08080000, 0x10000, SHA_256_MODE);
|
||||
|
||||
if (memcmp(hash, boot9Sha256, 32) != 0)
|
||||
{
|
||||
u32 size = getFileSize("sdmc:/luma/backups/boot9.bin");
|
||||
int readres = fileRead(b9, "sdmc:/luma/backups/boot9.bin", 0x10000);
|
||||
sha(hash, b9, 0x10000, SHA_256_MODE);
|
||||
|
||||
if (size != 0x10000 || !readres || memcmp(hash, boot9Sha256, 32) != 0)
|
||||
error("No valid boot9 backup was found in memory or in\nsdmc:/luma/backups/boot9.bin. Please make sure\nyou have a valid backup to use this FIRM.");
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(b9, (const void *)0x08080000, 0x10000);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < sizeof(key_X) / sizeof(key_X[0]); i++)
|
||||
{
|
||||
load_key(key_X[i].keyslot, &b9[key_X[i].b9_offs], AES_KEYX);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < sizeof(key_Y) / sizeof(key_Y[0]); i++)
|
||||
{
|
||||
load_key(key_Y[i].keyslot, &b9[key_Y[i].b9_offs], AES_KEYY);
|
||||
}
|
||||
|
||||
static const u8 dev_keyX_0x25[16] = { 0x81,0x90,0x7A,0x4B,0x6F,0x1B,0x47,0x32,
|
||||
0x3A,0x67,0x79,0x74,0xCE,0x4A,0xD7,0x1B };
|
||||
|
||||
load_key(0x25, dev_keyX_0x25, AES_KEYX);
|
||||
|
||||
ret += patchProtoUnitinfo1200(process9Offset, process9Size, arm9Section, firm->section[2].size);
|
||||
}
|
||||
}
|
||||
|
||||
ret += patchProtoNandSignatureCheck(process9Offset, process9Size);
|
||||
|
||||
//Arm9 exception handlers
|
||||
|
||||
@ -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(FirmwareSource nandType);
|
||||
u32 patchPrototypeNative(FirmwareSource nandType, bool doUnitinfoPatch);
|
||||
void launchFirm(int argc, char **argv);
|
||||
|
||||
@ -28,8 +28,12 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern const u8 emunandPatch[], emunandProtoPatch[], emunandProtoCidPatch[];
|
||||
extern const u8 emunandPatch[];
|
||||
extern const u8 emunandProtoPatch[];
|
||||
extern const u8 emunandProtoCidPatch[];
|
||||
extern const u8 emunandProtoPatch238[];
|
||||
extern const u8 emunandProtoCidPatch1200[];
|
||||
extern const u8 emunandProtoPatch1200[];
|
||||
extern const u32 emunandPatchSize, emunandPatchBssSize;
|
||||
extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset;
|
||||
extern u32 emunandPatchNandCid[4];
|
||||
|
||||
@ -387,7 +387,7 @@ boot:
|
||||
res = patch1x2xNativeAndSafeFirm();
|
||||
break;
|
||||
case NATIVE_PROTOTYPE:
|
||||
res = patchPrototypeNative(nandType);
|
||||
res = patchPrototypeNative(nandType, doUnitinfoPatch);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -891,8 +891,107 @@ u32 patchProtoNandSignatureCheck(u8 *pos, u32 size) {
|
||||
|
||||
off[0x20] = 2;
|
||||
}
|
||||
|
||||
else if (firmProtoVersion == 1200) { // SDK 0.12
|
||||
// Same patch as for v238 and v243 ported to the different ncsd_read() function
|
||||
static const u8 pattern[] = {
|
||||
0x4C, 0x10, 0x9F, 0xE5,
|
||||
0x4C, 0x50, 0x9F, 0xE5,
|
||||
};
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
if (!off)
|
||||
return 1;
|
||||
|
||||
off[0x20] = 2;
|
||||
|
||||
static const u8 pattern_sigcheck[] = {
|
||||
0x33, 0x10, 0xa0, 0xe3, // mov r1, #0x33
|
||||
};
|
||||
u32* off2 = (u32*)memsearch(pos, pattern_sigcheck, size, sizeof(pattern_sigcheck));
|
||||
if (!off2) return 1;
|
||||
for (; off2 < (u32*)&pos[size] && off2[0] != 0xD8E003FF; off2++) {}
|
||||
if (off2 >= (u32*)&pos[size]) return 1;
|
||||
off2[0] = 0; // patch failing result to success.
|
||||
|
||||
}
|
||||
|
||||
else return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 patchSingleInstruction(u8 *pos, u32 size, void *pattern, u32 patternSize, s32 offset, u32 newInsn, u8 **out_pos) {
|
||||
u32 *off = (u32 *)memsearch(pos, pattern, size, patternSize);
|
||||
if (!off) return 1;
|
||||
*out_pos = (u8 *)off;
|
||||
off += offset;
|
||||
*off = newInsn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchProtoUnitinfo1200(u8 *pos, u32 size, u8 *arm9Section, u32 arm9SectionSize) {
|
||||
u8 *tmp_pos = NULL;
|
||||
u8 pattern0[] = { 0x64, 0x10, 0x9F, 0xE5, /* LDR R1, #0x10010000 */
|
||||
0x10, 0x30, 0xD1, 0xE5 }; /* LDRB R3, [R1, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern0, sizeof(pattern0), +1, 0xE3A03001, &tmp_pos)) /* mov r3, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern1[] = { 0x10, 0x00, 0x9F, 0xE5, /* LDR R0, #0x10010000 */
|
||||
0x10, 0x00, 0xD0, 0xE5 }; /* LRDB R0, [R0, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern1, sizeof(pattern1), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
tmp_pos += 8;
|
||||
/* there are two of these */
|
||||
if (patchSingleInstruction(tmp_pos, size, pattern1, sizeof(pattern1), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern2[] = { 0xB8, 0x00, 0x9F, 0xE5, /* LDR R0, #0x10010000 */
|
||||
0x10, 0x00, 0xD0, 0xE5 }; /* LDRB R0, [R0, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern2, sizeof(pattern2), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern3[] = { 0x03, 0x50, 0x04, 0xE2, /* AND R5, R4, #3 */
|
||||
0x10, 0x10, 0xD0, 0xE5 }; /* LDRB R1, [R0, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern3, sizeof(pattern3), +1, 0xE3A01001, &tmp_pos)) /* mov r1, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern4[] = { 0x97, 0x00, 0x00, 0x1A, /* BNE #0x8050D8C */
|
||||
0x10, 0x00, 0xD0, 0xE5 }; /* LDRB R0, [R0, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern4, sizeof(pattern4), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern5[] = { 0x20, 0x01, 0x9F, 0x15, /* LDRNE R0, #0x10010000 */
|
||||
0x10, 0x00, 0xD0, 0x15 }; /* LDRBNE R0, [R0, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern5, sizeof(pattern5), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern6[] = { 0x10, 0x40, 0x2D, 0xE9, /* PUSH {R4, LR} */
|
||||
0x10, 0x00, 0xD1, 0xE5 }; /* LDRB R0, [R1, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern6, sizeof(pattern6), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern7[] = { 0x24, 0xD0, 0x4D, 0xE2, /* SUB SP, SP, #0x24 */
|
||||
0x10, 0x00, 0xD0, 0xE5 }; /* LDRB R0, [R0, #0x10] */
|
||||
if (patchSingleInstruction(pos, size, pattern7, sizeof(pattern7), +1, 0xE3A00001, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
u8 pattern8[] = { 0x01, 0x00, 0x50, 0xE1, /* CMP R0, R1 */
|
||||
0xB8, 0xA4, 0xFF, 0x1B }; /* BLNE svcBreak */
|
||||
if (patchSingleInstruction(pos, size, pattern8, sizeof(pattern8), +1, 0xE320F000, &tmp_pos)) /* mov r0, #1 */
|
||||
return 1;
|
||||
|
||||
/* k9 sync function, sends unitinfo to k11(?) */
|
||||
u8 syncpattern[] = {
|
||||
0x09, 0x00, 0x00, 0x1A, /* BNE 0x808E7A0 */
|
||||
0x10, 0x30, 0xDC, 0xE5, /* LDRB R3, [R12, #0x10] */
|
||||
0x01, 0x00, 0x53, 0xE3 /* CMP R3, #1 */
|
||||
};
|
||||
|
||||
u8 *syncaddr = memsearch(arm9Section, syncpattern, arm9SectionSize, sizeof(syncpattern));
|
||||
if (!syncaddr) return 1;
|
||||
syncaddr += 4;
|
||||
*(u32 *)syncaddr = 0xE3A03001; /* MOV R3, #1 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -69,4 +69,5 @@ u32 patchTwlShaHashChecks(u8 *pos, u32 size);
|
||||
u32 patchAgbBootSplash(u8 *pos, u32 size);
|
||||
void patchTwlBg(u8 *pos, u32 size); // silently fails
|
||||
u32 patchLgyK11(u8 *section1, u32 section1Size, u8 *section2, u32 section2Size);
|
||||
u32 patchProtoNandSignatureCheck(u8 *pos, u32 size);
|
||||
u32 patchProtoNandSignatureCheck(u8 *pos, u32 size);
|
||||
u32 patchProtoUnitinfo1200(u8 *pos, u32 size, u8 *arm9Section, u32 arm9SectionSize);
|
||||
Loading…
x
Reference in New Issue
Block a user