//******************************************************************* // IRIS-SUBPモニタプログラム サブルーチン //******************************************************************* #include "IrisSubpMon.h" //--------------------- グローバル 変数 ------------------------------- SharedWork *sharedWorkp; // 共有ワークポインタ SecureWork *secureWorkp; // セキュア情報ワークポインタ IntrFuncp intrTable[4]; // 割り込みテーブル u32 CharTmpBuf[0x200/4]; u16 NinLogoBak[256/2]; //---------------------------------------------------------------------- // レジスタ初期化 //---------------------------------------------------------------------- void InitReg(void) { *(vu32 *)REG_IME = 0; // IME クリア *(vu32 *)REG_IE = 0; // IE クリア *(vu32 *)REG_IF = -1; // IF クリア #ifdef BOOT_FROM_CARTRIDGE *(vu16 *)REG_POWCNT = POW_SOUND_ON; // サウンドON ChangeSoundBias16(1, 8) ; // サウンドバイアス セット #endif // BOOT_FROM_CARTRIDGE } //---------------------------------------------------------------------- // メモリ初期化 //---------------------------------------------------------------------- void PreInitRam(void) { CpuClearFast32(0, CPU_WRAM_END - 0x4000, 0x4000 - 512); // ARM7用ワーク領域 後半16KBクリア } void PostInitRam(void) { CpuClearFast32(0, CPU_WRAM, 0x4000); // ARM7用ワーク領域 前半16KBクリア } //---------------------------------------------------------------------- // メインメモリSECURE領域(先頭64KB) クリア //---------------------------------------------------------------------- void ClearMmemSecureArea(void) { CpuClearFast32(0, MAIN_MEM, MROM_SECURE_SIZE * 4); } //---------------------------------------------------------------------- // CRC16bit 算出 //---------------------------------------------------------------------- const u16 crc16_table[16] = { 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 }; u16 GetCRC16(u32 start, u16 *datap, u32 size) { u16 *dataEndp = datap + size/2; u16 data16; u32 shift = 0; u16 r1, total = start; while(datap < dataEndp) { if (!shift) data16 = *datap; // 4bit単位 r1 = crc16_table[total & 0xf]; total = (total >>4); total = total ^ r1 ^ crc16_table[(data16 >>shift) & 0xf]; shift += 4; if (shift >= 0x10) { shift = 0; datap++; } } return total; } //---------------------------------------------------------------------- // メインメモリ 拡張チェック //---------------------------------------------------------------------- const u16 mmemSizeCheckTable[] = {0x56a9, 0x695a, 0xa695, 0x96a5}; s32 IsMmem8MB(void) { u32 mmemExFlag = 0; int i; #ifdef ENABLE_DEBUGGER_ON_4MB return 1; #endif // ENABLE_DEBUGGER_ON_4MB for (i=0; i<4; i++) { *(vu16 *)MMEM_CHK_SIZE_WRITE_BUF = mmemSizeCheckTable[i]; if (*(vu16 *)MMEM_CHK_SIZE_READ_BUF != mmemSizeCheckTable[i]) mmemExFlag++; } *(vu16 *)MMEM_CHK_SIZE_WRITE_BUF = 0; return (mmemExFlag >= 3); } //---------------------------------------------------------------------- // デバッガ上か? //---------------------------------------------------------------------- extern u16 sio_handshake_data[]; extern u16 sio_send_code; extern u16 sio_recv_code; extern u16 sio_add_code; #define SIO_SEND_CODE 0x4e54 #define SIO_RECV_CODE 0x4944 #define SIO_ADD_CODE 0x524f #define SYSROM_VERSION 0x0100 void SendSioData(u32 data) // SIOデータ送信 { *(vu32 *)REG_SIODATA32 = data; StartSio(); WaitSio(); WaitByLoop(0x8000/4); // 0.97ms待ち while (!IsSioSendEnable()) ; } s32 CheckSioData(u32 data, u32 checkMask) // SIO戻り値チェック { #ifndef DISABLE_SECURE_CODE if ((*(vu32 *)REG_SIODATA32 & checkMask) != ((((data + sio_add_code) & 0xffff) | (~data & 0xffff0000)) & checkMask)) return 0; #endif // DISABLE_SECURE_CODE return 1; } void CheckDebugger(void) { SharedWork *shwp = GetSharedWorkAddr(); u32 sioData[2]; int i; shwp->isOnDebugger = 0; if (!IsMmem8MB()) return; // メインメモリが 4MB ならデバッガではない #ifndef DISABLE_SECURE_CODE sioData[0] = shwp->recvRtc[0] | 0x80000000; sioData[1] = shwp->recvRtc[1] | 0x80000000; *(vu16 *)REG_RCNT = R_SIO_MASTER_MODE; // SIOハンドシェイク *(vu16 *)REG_SIOCNT = SIO_32BIT_MODE | SIO_IN_SCK_256K; if (!IsSioSendEnable()) { return; // 初めに SI が Low で無ければデバッガではない } else { *(vu16 *)REG_SIOCNT |= SIO_SCK_IN; // 応答が正しくなければデバッガではない SendSioData((sio_send_code <<16) | SYSROM_VERSION); if (!CheckSioData((~sio_recv_code <<16), 0xffff0000)) return; SendSioData(sioData[1]); SendSioData(sioData[0]); if (!CheckSioData(sioData[1], -1)) return; SendSioData(sioData[1]); if (!CheckSioData(sioData[0], -1)) return; } *(vu32 *)REG_SIODATA32 = 0; *(vu32 *)REG_SIOCNT = 0; shwp->isOnDebugger = 1; #endif // DISABLE_SECURE_CODE } //---------------------------------------------------------------------- // Blowfishテーブル生成 //---------------------------------------------------------------------- void InitBlowfishKeyAnaTableFook(BLOWFISH_CTX *tableBufp, u32 *keyBufp, u32 keyLen); u32 ChangeEncryptKey1(u32 key); u32 ChangeEncryptKey2(u32 key); u32 ChangeEncryptKey3(u32 key); u32 ChangeEncryptKey4(u32 key); void MakeBlowfishTable(BLOWFISH_CTX *tableBufp, const u32 *keyp, u32 *keyBufp, u32 keyLen) { #ifndef DISABLE_SECURE_CODE #ifndef ENABLE_TEST_BLOWFISH const BLOWFISH_CTX *blowfishInitTablep = &blowfishInitTable; #else const BLOWFISH_CTX *blowfishInitTablep = &blowfishTestTable; #endif // ENABLE_TEST_BLOWFISH u32 keyBuf[3]; #ifndef NDEBUG *(u32 *)REG_TM2CNT = TMR_PRESCALER_256CK | TMR_ENABLE; // タイマー スタート #endif // NDEBUG CopyBiosAreaFook(blowfishInitTablep, tableBufp, sizeof(BLOWFISH_CTX)); keyBufp[0] = *keyp; keyBufp[1] = ChangeEncryptKey1(*keyp); keyBufp[2] = ChangeEncryptKey2(*keyp); InitBlowfishKeyAnaTableFook(tableBufp, keyBufp, keyLen); { SecureWork *scwp = GetSecureWorkAddr(); RomHeader *rmhp = GetRomHeaderAddr(); FlashHeader *fhp = GetFlashHeaderAddr(); u32 *blowfishedKeyp; if (keyLen == 8) { *(u64 *)scwp->cardNormalModeKey = *(u64 *)rmhp->romNormalModeKey; blowfishedKeyp = scwp->cardNormalModeKey; } else { *(u64 *)scwp->unScrambleKey = *(u64 *)fhp->unScrambleKey; blowfishedKeyp = scwp->unScrambleKey; } DecryptByBlowfishFook(tableBufp, blowfishedKeyp); if (keyLen > 8) scwp->isGenUnScrambleKey = 1; } #ifndef NDEBUG *(u16 *)REG_TM2CNT_H = 0; #endif // NDEBUG InitBlowfishKeyAnaTableFook(tableBufp, keyBufp, keyLen); #endif // DISABLE_SECURE_CODE } //---------------------------------------------------------------------- // Blowfishキー&テーブル単位初期化 //---------------------------------------------------------------------- void InitBlowfishKeyAnaTable(BLOWFISH_CTX *tableBufp, u32 *keyBufp, u32 keyLen) { #ifndef DISABLE_SECURE_CODE EncryptByBlowfishFook2(tableBufp, keyBufp); // EncryptByBlowfish(tableBufp, &keyBufp[2], &keyBufp[1]); EncryptByBlowfishFook1(tableBufp, keyBufp); // EncryptByBlowfish(tableBufp, &keyBufp[1], &keyBufp[0]); InitBlowfishFook(tableBufp, (u8 *)keyBufp, keyLen); #endif // DISABLE_SECURE_CODE } //---------------------------------------------------------------------- // 暗号化オブジェクトの復号 //---------------------------------------------------------------------- #ifndef DISABLE_SECURE_CODE extern const u32 encrypt_object_key[]; #else const u32 encrypt_object_key[2] = {0x01234567, 0x89abcdef}; #endif // DISABLE_SECURE_CODE #define UNDEF_CODE 0xe7ffdeff #define ENCRYPT_DEF_SIZE 0x800 void DecryptObjectFile(void) { SharedWork *shwp = GetSharedWorkAddr(); SecureWork *scwp = GetSecureWorkAddr(); RomHeader *rmhp = GetRomHeaderAddr(); BLOWFISH_CTX *tableBufp = &scwp->blowfishCardTable; u32 *encBufp = (u32 *)&scwp->blowfishFlashTable; u32 *encDestp = (u32 *)rmhp->arm9.ramAddr; s32 size = scwp->secureSize; s32 restSize; if (size > ENCRYPT_DEF_SIZE) size = ENCRYPT_DEF_SIZE; restSize = size; if (scwp->enableReadSecure) { CpuCopyFast32Fook(encDestp, encBufp, size); // 暗号化オブジェクト 退避 DecryptByBlowfishFook(tableBufp, encBufp); // 暗号化オブジェクトヘッダ プリ復号 } ChangeObjectTableFook(); // Blowfishテーブル変換 if (scwp->enableReadSecure) { DecryptByBlowfishFook(tableBufp, encBufp); // 暗号化オブジェクトヘッダ ポスト復号 #ifndef DISABLE_SECURE_CODE if ((encBufp[0] == encrypt_object_key[0]) // 暗号化オブジェクト有効時 && (encBufp[1] == encrypt_object_key[1])) { u32 *bufp = encBufp; bufp[0] = UNDEF_CODE; bufp[1] = UNDEF_CODE; while ((restSize -= 8) > 0) { bufp += 2; // 復号処理 DecryptByBlowfishFook(tableBufp, bufp); } } else #endif // DISABLE_SECURE_CODE { CpuClearFast32(UNDEF_CODE, encBufp, size); // 未定義コードでクリア shwp->disableEncryptedCardData = 1; // 暗号化オブジェクト無効 通知 } CpuCopyFast32Fook(encBufp, encDestp, size); // 暗号化オブジェクト 復帰 } } //---------------------------------------------------------------------- // 暗号化オブジェクト用Blowfishテーブル変換 //---------------------------------------------------------------------- void ChangeObjectTable(u32 keyLen) { #ifndef DISABLE_SECURE_CODE SecureWork *scwp = GetSecureWorkAddr(); BLOWFISH_CTX *tableBufp = &scwp->blowfishCardTable; u32 *keyBufp = scwp->cardKeyBuf; keyBufp[1] = ChangeEncryptKey3(keyBufp[1]); keyBufp[2] = ChangeEncryptKey4(keyBufp[2]); InitBlowfishKeyAnaTableFook(tableBufp, keyBufp, keyLen); #endif // DISABLE_SECURE_CODE } //---------------------------------------------------------------------- // ハフマンデータ展開(32Bit→32Bit) //---------------------------------------------------------------------- #define TREE_END 0x80 s32 UnCompHuffman32(const u8 *srcp, u32 *destp, u8 *tableBufp, const UC_InternalFuncp *ifp) { u8 *treep;// = (u8 *)srcp + 4; s32 treeSize;// = (*treep + 1) * 2; u32 treeCheck; u32 treeShift; u32 srcTmp; u32 destTmp = 0; u32 destTmpCount = 0; s32 srcCount; s32 error; int i; s32 header = ifp->InitFuncp(srcp, destp, tableBufp); // 初期化(アドレス送信) s32 size = header >>8; s32 destCount = size; s32 dataBit = header & 0x0f; u32 destTmpDataNum = 4 + (dataBit & 0x7); u32 destTopShift = 32 - dataBit; if (header < 0) { size = header; goto terminate; } srcp += 3; tableBufp[0] = ifp->ByteStreamFuncp(++srcp); treeSize = (tableBufp[0] + 1) * 2; for (i=1; iByteStreamFuncp(++srcp); srcp++; treep = tableBufp + 1; while (destCount > 0) { srcCount = 32; srcTmp = ifp->WordStreamFuncp(srcp); srcp += 4; while (--srcCount >= 0) { treeShift = (srcTmp >> 31) & 0x1; treeCheck = *treep; treeCheck <<= treeShift; treep = (u8 *)((((u32 )treep>>1) <<1) + (((*treep & 0x3f)+1) <<1) + treeShift); if (treeCheck & TREE_END) { destTmp >>= dataBit; destTmp |= *treep << destTopShift; treep = tableBufp + 1; if (++destTmpCount == destTmpDataNum) { *destp++ = destTmp; destCount -= 4; destTmpCount = 0; } } if (destCount <= 0) break; srcTmp <<= 1; } } terminate: if (ifp->TerminateFuncp) { // 終了ダミー読み込み if ((error = ifp->TerminateFuncp(srcp)) < 0) return error; } return size; } //---------------------------------------------------------------------- // LZバイトデータ展開(8Bit→16Bit) //---------------------------------------------------------------------- s32 UnCompLZ77Short(const u8 *srcp, u16 *destp, const void *paramp, const UC_InternalFuncp *ifp) { u32 destTmp = 0; u32 flags; s32 offset; s32 offset0_8; s32 length; u32 shift = 0; u8 src; s32 error; int i; s32 header = ifp->InitFuncp(srcp, destp, paramp); // 初期化(アドレス送信) s32 size = header >>8; s32 destCount = size; if (header < 0) { size = header; goto terminate; } srcp += 3; while (destCount > 0) { flags = ifp->ByteStreamFuncp(++srcp); for (i=8; --i>=0; ) { if (!(flags & 0x80)){ destTmp |= ifp->ByteStreamFuncp(++srcp) <ByteStreamFuncp(++srcp)) >>4) + 3; offset = ( src & 0x0f) << 8; offset = (offset | ifp->ByteStreamFuncp(++srcp)) + 1; offset0_8 = (8 - shift) ^ ((offset & 1) <<3); destCount -= length; while (--length >= 0) { offset0_8 ^= 8; destTmp |= (destp[-((offset + ((8 - shift) >>3)) >>1)] & (0xff <>offset0_8 <TerminateFuncp) { // 終了ダミー読み込み if ((error = ifp->TerminateFuncp(++srcp)) < 0) return error; } return size; } //---------------------------------------------------------------------- // ランレングスデータ展開(8Bit→16Bit) //---------------------------------------------------------------------- s32 UnCompRLShort(const u8 *srcp, u16 *destp, const void *paramp, const UC_InternalFuncp *ifp) { s32 srcTmp; s32 destTmp = 0; u32 flags; s32 offset; s32 length; u32 shift = 0; s32 error; s32 header = ifp->InitFuncp(srcp, destp, paramp); // 初期化(アドレス送信) s32 size = header >>8; s32 destCount = size; if (header < 0) { size = header; goto terminate; } srcp += 3; while (destCount > 0) { flags = ifp->ByteStreamFuncp(++srcp); length = flags & 0x7f; if (!(flags & 0x80)) { length++; destCount -= length; while (--length >= 0){ destTmp |= ifp->ByteStreamFuncp(++srcp) << shift; if (!(shift ^= 8)){ *destp++ = destTmp; destTmp = 0; } } } else { length += 3; destCount -= length; srcTmp = ifp->ByteStreamFuncp(++srcp); while (--length >= 0){ destTmp |= srcTmp << shift; if (!(shift ^= 8)){ *destp++ = destTmp; destTmp = 0; } } } } terminate: if (ifp->TerminateFuncp) { // 終了ダミー読み込み if ((error = ifp->TerminateFuncp(++srcp)) < 0) return error; } return size; } //---------------------------------------------------------------------- // サウンドテーブルデータ取得 //---------------------------------------------------------------------- extern s16 snd_sin_table[]; extern u16 snd_ptable[]; extern u8 snd_vtable[]; extern u8 snd_data_start[]; extern u8 snd_data_end[]; static s32 CheckSoundTablep(void *tablep) { if ((tablep < (void *)snd_data_start) || (tablep >= (void *)snd_data_end)) return -1; return 0; } u32 GetSoundSinTable(s32 index) { s16 *tablep = &snd_sin_table[index]; s32 retval; if ((retval = CheckSoundTablep(tablep)) != 0) return retval; return *tablep; } u32 GetSoundPitchTable(s32 index) { u16 *tablep = &snd_ptable[index]; s32 retval; if ((retval = CheckSoundTablep(tablep)) != 0) return retval; return *tablep; } u32 GetSoundVolumeTable(s32 index) { u8 *tablep = &snd_vtable[index]; s32 retval; if ((retval = CheckSoundTablep(tablep)) != 0) return retval; return *tablep; } //---------------------------------------------------------------------- // 割り込み終了処理 //---------------------------------------------------------------------- void TerminateIntr(u32 inrtFlags) { u32 bakIE = *(vu32 *)REG_IME; *(vu32 *)REG_IME = 0; *(vu32 *)REG_IE &= ~inrtFlags; *(vu32 *)REG_IF = inrtFlags; *(vu32 *)REG_IME = bakIE; } //---------------------------------------------------------------------- // Vブランク待ち //---------------------------------------------------------------------- #ifdef BOOT_FROM_CARTRIDGE void WaitVBlank(s32 count) { int i; for (i=0; iblankingV == 1) ; while (((vDispStat *)REG_DISPSTAT)->blankingV != 1) ; } } #endif // BOOT_FROM_CARTRIDGE //---------------------------------------------------------------------- // NINTENDOロゴチェック //---------------------------------------------------------------------- extern const u16 Nin_Char_Diff_Huff[]; #ifdef TEST_AGB_MODE u8 CheckNintendoLogo(u16 *datap) { int i; for (i=0; i