From dd92ab13cd95fdcc4edc38584027d3f03d9bec5d Mon Sep 17 00:00:00 2001 From: ZeroSkill1 Date: Tue, 17 Mar 2026 16:45:50 +0300 Subject: [PATCH] Add support for SDK 0.12 prototype FIRM --- arm9/source/emunand.c | 72 +++++++++++++++++++++++- arm9/source/emunand_patch.s | 73 +++++++++++++++++++++++++ arm9/source/firm.c | 106 ++++++++++++++++++++++++++++++++---- arm9/source/firm.h | 2 +- arm9/source/large_patches.h | 6 +- arm9/source/main.c | 2 +- arm9/source/patches.c | 99 +++++++++++++++++++++++++++++++++ arm9/source/patches.h | 3 +- 8 files changed, 348 insertions(+), 15 deletions(-) diff --git a/arm9/source/emunand.c b/arm9/source/emunand.c index 64e47129..691a766b 100644 --- a/arm9/source/emunand.c +++ b/arm9/source/emunand.c @@ -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; -} \ No newline at end of file +} diff --git a/arm9/source/emunand_patch.s b/arm9/source/emunand_patch.s index a4a4f8cd..538f5a1d 100644 --- a/arm9/source/emunand_patch.s +++ b/arm9/source/emunand_patch.s @@ -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 diff --git a/arm9/source/firm.c b/arm9/source/firm.c index 04eae324..d54329ff 100755 --- a/arm9/source/firm.c +++ b/arm9/source/firm.c @@ -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 diff --git a/arm9/source/firm.h b/arm9/source/firm.h index 0857e21c..35d329ba 100644 --- a/arm9/source/firm.h +++ b/arm9/source/firm.h @@ -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); diff --git a/arm9/source/large_patches.h b/arm9/source/large_patches.h index a51f06ed..84622631 100644 --- a/arm9/source/large_patches.h +++ b/arm9/source/large_patches.h @@ -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]; diff --git a/arm9/source/main.c b/arm9/source/main.c index 4d95fe74..dd0682e5 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -387,7 +387,7 @@ boot: res = patch1x2xNativeAndSafeFirm(); break; case NATIVE_PROTOTYPE: - res = patchPrototypeNative(nandType); + res = patchPrototypeNative(nandType, doUnitinfoPatch); break; } diff --git a/arm9/source/patches.c b/arm9/source/patches.c index 44d01926..86ad1514 100644 --- a/arm9/source/patches.c +++ b/arm9/source/patches.c @@ -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; } \ No newline at end of file diff --git a/arm9/source/patches.h b/arm9/source/patches.h index 75eb03a9..530f693f 100644 --- a/arm9/source/patches.h +++ b/arm9/source/patches.h @@ -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); \ No newline at end of file +u32 patchProtoNandSignatureCheck(u8 *pos, u32 size); +u32 patchProtoUnitinfo1200(u8 *pos, u32 size, u8 *arm9Section, u32 arm9SectionSize); \ No newline at end of file