Add support for SDK 0.12 prototype FIRM

This commit is contained in:
ZeroSkill1 2026-03-17 16:45:50 +03:00 committed by TuxSH
parent e35972ea82
commit dd92ab13cd
8 changed files with 348 additions and 15 deletions

View File

@ -121,6 +121,9 @@ static inline u32 getProtoSdmmc(u32 *sdmmc, u32 firmVersion)
case 238: // SDK 0.10 case 238: // SDK 0.10
*sdmmc = (0x080BEA70 + 0x690); *sdmmc = (0x080BEA70 + 0x690);
break; break;
case 1200: // SDK 0.12
*sdmmc = (0x080C6A00 + 0x8DC);
break;
default: default:
return 1; return 1;
} }
@ -288,6 +291,58 @@ static inline u32 patchProtoNandRw238(u8 *pos, u32 size, u32 hookAddr, u32 hookC
return 0; 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 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
{ {
u32 ret = 0; u32 ret = 0;
@ -329,10 +384,25 @@ u32 patchProtoEmuNand(u8 *process9Offset, u32 process9Size)
case 238: // SDK 0.10.x case 238: // SDK 0.10.x
ret += patchProtoNandRw238(process9Offset, process9Size, (u32)emunandProtoPatch238, (u32)emunandProtoCidPatch); ret += patchProtoNandRw238(process9Offset, process9Size, (u32)emunandProtoPatch238, (u32)emunandProtoCidPatch);
break; break;
case 1200: // SDK 0.12
ret += patchProtoNandRw1200(process9Offset, process9Size, (u32)emunandProtoPatch1200, (u32)emunandProtoCidPatch1200);
break;
default: default:
ret++; ret++;
break; 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; return ret;
} }

View File

@ -124,6 +124,37 @@ emunandProtoCidPatch:
add lr, #4 add lr, #4
bx lr 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 .global emunandProtoPatch238
emunandProtoPatch238: emunandProtoPatch238:
@ Save registers @ Save registers
@ -167,6 +198,48 @@ emunandProtoPatch238:
add r1, #4 add r1, #4
bx r1 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 .pool
.global emunandPatchSdmmcStructPtr .global emunandPatchSdmmcStructPtr

View File

@ -208,11 +208,13 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
if(isO3dsFirm && (*firmType == NATIVE_FIRM || *firmType == NATIVE_FIRM1X2X)) 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, {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, {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}, 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, {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,
@ -240,14 +242,19 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
firmProtoVersion = 238; firmProtoVersion = 238;
*firmType = NATIVE_PROTOTYPE; *firmType = NATIVE_PROTOTYPE;
break; break;
// Release
case 2: case 2:
firmVersion = 0x0;
firmProtoVersion = 1200;
*firmType = NATIVE_PROTOTYPE;
break;
// Release
case 3:
firmVersion = 0x18; firmVersion = 0x18;
break; break;
case 3: case 4:
firmVersion = 0x1D; firmVersion = 0x1D;
break; break;
case 4: case 5:
firmVersion = 0x1F; firmVersion = 0x1F;
break; break;
default: default:
@ -773,17 +780,96 @@ u32 patch1x2xNativeAndSafeFirm(void)
return ret; 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; u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
//Find the Process9 .code location, size and memory address //Find the Process9 .code location, size and memory address
u32 process9Size, u32 process9Size = 0;
process9MemAddr; u32 process9MemAddr = 0;
u8 *process9Offset = getProcess9Info(arm9Section, firm->section[2].size, &process9Size, &process9MemAddr); u8 *process9Offset = getProcess9Info(arm9Section, firm->section[2].size, &process9Size, &process9MemAddr);
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200, u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200;
ret = 0; 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); ret += patchProtoNandSignatureCheck(process9Offset, process9Size);

View File

@ -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(FirmwareSource nandType); u32 patchPrototypeNative(FirmwareSource nandType, bool doUnitinfoPatch);
void launchFirm(int argc, char **argv); void launchFirm(int argc, char **argv);

View File

@ -28,8 +28,12 @@
#include "types.h" #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 emunandProtoPatch238[];
extern const u8 emunandProtoCidPatch1200[];
extern const u8 emunandProtoPatch1200[];
extern const u32 emunandPatchSize, emunandPatchBssSize; extern const u32 emunandPatchSize, emunandPatchBssSize;
extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset; extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset;
extern u32 emunandPatchNandCid[4]; extern u32 emunandPatchNandCid[4];

View File

@ -387,7 +387,7 @@ boot:
res = patch1x2xNativeAndSafeFirm(); res = patch1x2xNativeAndSafeFirm();
break; break;
case NATIVE_PROTOTYPE: case NATIVE_PROTOTYPE:
res = patchPrototypeNative(nandType); res = patchPrototypeNative(nandType, doUnitinfoPatch);
break; break;
} }

View File

@ -892,7 +892,106 @@ u32 patchProtoNandSignatureCheck(u8 *pos, u32 size) {
off[0x20] = 2; 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; else return 1;
return 0; 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;
}

View File

@ -70,3 +70,4 @@ u32 patchAgbBootSplash(u8 *pos, u32 size);
void patchTwlBg(u8 *pos, u32 size); // silently fails void patchTwlBg(u8 *pos, u32 size); // silently fails
u32 patchLgyK11(u8 *section1, u32 section1Size, u8 *section2, u32 section2Size); 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);