TwlIPL/build/libraries_sysmenu/hotsw/ARM7/src/hotsw.c
yosiokat b01ff7f8a1 ・カードアプリ、NANDアプリロード時に、ROMヘッダCRCチェックとリージョンチェックを行うよう変更。
・未使用関数の削除
 DS_CheckROMCloneBoot, DSi_ExistNitroCard, SYSMi_CheckCardCloneBoot, SYSMi_IsValidCard
・関数整理に伴い未使用になったSYSM_work構造体メンバ、cardHeaderCrc16とcardHeaderCrc16_bakを削除。
・ドキュメント更新。

git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@1860 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2008-07-11 08:56:30 +00:00

2419 lines
80 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*---------------------------------------------------------------------------*
Project: TwlIPL
File: hotsw.c
Copyright 2007-2008 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
*---------------------------------------------------------------------------*/
#include <twl.h>
#include <twl/os/common/format_rom.h>
#include <twl/mcu.h>
#include <nitro/card/types.h>
#include <firm/os/common/system.h>
#include <sysmenu.h>
#include <hotswTypes.h>
#include <blowfish.h>
#include <dsCardCommon.h>
#include <romEmulation.h>
#include <customNDma.h>
#include <../build/libraries/mb/common/include/mb_fileinfo.h>
#define DEBUG_MODE
//#define HOTSW_DISABLE_FORCE_CARD_OFF
// カード電源ONからROMヘッダロードまでの期間にスリープに入る時のワンセグ対策しない場合
//#define HOWSW_ENABLE_DEEP_SLEEP_WHILE_INSERT_CARD
// define -------------------------------------------------------------------
#define CHATTERING_COUNTER 0x1988 // 100ms分 (0x1988 * 15.3us = 100000us)
//#define CHATTERING_COUNTER 0x264c // 150ms分 (0x264c * 15.3us = 150001us)
//#define CHATTERING_COUNTER 0x3310 // 200ms分 (0x3310 * 15.3us = 200001us)
//#define CHATTERING_COUNTER 0x4c98 // 300ms分 (0x4c98 * 15.3us = 300002us)
#define COUNTER_A 0x264c // 150ms分 (0x264c * 15.3us = 150001us)
#define CARD_EXIST_CHECK_POLLING_TIME 100
#define CARD_INSERT_CHECK_INTERVAL 5
#define UNDEF_CODE 0xe7ffdeff // 未定義コード
#define ENCRYPT_DEF_SIZE 0x800 // 2KB ※ ARM9常駐モジュール先頭2KB
#define DIGEST_HASH_BLOCK_SIZE_SHA1 (512/8)
#define SLOT_B_LOCK_BUF HW_CTRDG_LOCK_BUF
#define HOTSW_DSTV_GAME_CODE 'JSNU'
#ifdef SDK_ARM9
#define reg_HOTSW_EXMEMCNT reg_MI_EXMEMCNT
#define HOTSW_EXMEMCNT_SELB_MASK REG_MI_EXMEMCNT_MPB_MASK
#define HOTSW_EXMEMCNT_SELB_SHIFT REG_MI_EXMEMCNT_MPB_SHIFT
#else // SDK_ARM7
#define reg_HOTSW_EXMEMCNT reg_MI_EXMEMCNT_L
#define HOTSW_EXMEMCNT_SELB_MASK 0x0400
#define HOTSW_EXMEMCNT_SELB_SHIFT 10
#endif
// enum ---------------------------------------------------------------------
typedef enum HotSwCallBackType{
HOTSW_CHANGE_GAMEMODE = 0,
HOTSW_CARD_INSERT,
HOTSW_CARD_PULLOUT
} HotSwCallBackType;
// Function prototype -------------------------------------------------------
static u32 GetMcSlotMode(void);
static void SetMcSlotMode(u32 mode);
static void SetInterruptCallback( OSIrqMask intr_bit, OSIrqFunction func );
static void SetInterruptCallbackEx( OSIrqMask intr_bit, void *func );
static void SetInterrupt(void);
static void InterruptCallbackCardDet(void);
static void InterruptCallbackPxi(PXIFifoTag tag, u32 data, BOOL err);
#ifndef USE_NEW_DMA
static void InterruptCallbackCardData(void);
#endif
static void LockHotSwRsc(OSLockWord* word);
static void UnlockHotSwRsc(OSLockWord* word);
static void HotSwThread(void *arg);
static void MonitorThread(void *arg);
static void McPowerOn(void);
static void McPowerOff(void);
static void SetMCSCR(void);
static BOOL isTwlModeLoad(void);
static HotSwState ReadSecureModeCardData(void);
static void ClearCardFlgs(void);
static void FinalizeHotSw(HotSwCardState state);
static void ForceNitroModeToFinalize(void);
static void ForceNormalModeToFinalize(void);
static BOOL ChangeGameMode(void);
static void ClearCardIrq(void);
static void ClearAllCardRegister(void);
static HotSwState LoadCardData(void);
static void RegisterRomEmuInfo(void);
static void GenVA_VB_VD(void);
static HotSwState ReadImageReturnErrorCode(void* dest, s32 offset, s32 length, void* arg);
static BOOL ReadImage(void* dest, s32 offset, s32 length, void* arg);
static HotSwState LoadBannerData(void);
static HotSwState CheckCardAuthCode(void);
#ifndef USE_WRAM_LOAD
static HotSwState DecryptObjectFile(void);
static HotSwState LoadStaticModule(void);
static HotSwState CheckStaticModuleHash(void);
static BOOL CheckArm7HashValue(void);
static BOOL CheckArm9HashValue(void);
static BOOL CheckExtArm7HashValue(void);
static BOOL CheckExtArm9HashValue(void);
#else
static void ReadCardData(u32 src, u32 dest, u32 size);
static void SendPxiMessage(HotSwCallBackType type);
#endif
static void DebugPrintErrorMessage(HotSwState state);
HotSwState HOTSWi_RefreshBadBlock(u32 romMode);
static void CheckCardInsert(BOOL cardExist);
static void CheckCardPullOut(BOOL cardExist);
// Static Values ------------------------------------------------------------
#include <twl/ltdwram_begin.h>
static char encrypt_object_key[] ATTRIBUTE_ALIGN(4) = "encryObj";
static u16 s_RscLockID;
static u16 s_CardLockID;
static u16 s_bondingOp;
static u32 s_BootSegBufSize, s_SecureSegBufSize, s_Secure2SegBufSize;
static BootSegmentData *s_pBootSegBuffer;
static u32 *s_pSecureSegBuffer;
static u32 *s_pSecure2SegBuffer;
static CardBootData s_cbData;
static SYSMRomEmuInfo s_romEmuInfo;
static BOOL s_debuggerFlg;
static BOOL s_isPulledOut = TRUE;
static BOOL s_isHotSwBusy = FALSE;
static BOOL s_pollingThreadSleepFlg = FALSE;
// HMACSHA1の鍵
static u8 s_digestDefaultKey[ DIGEST_HASH_BLOCK_SIZE_SHA1 ] = {
0x21, 0x06, 0xc0, 0xde,
0xba, 0x98, 0xce, 0x3f,
0xa6, 0x92, 0xe3, 0x9d,
0x46, 0xf2, 0xed, 0x01,
0x76, 0xe3, 0xcc, 0x08,
0x56, 0x23, 0x63, 0xfa,
0xca, 0xd4, 0xec, 0xdf,
0x9a, 0x62, 0x78, 0x34,
0x8f, 0x6d, 0x63, 0x3c,
0xfe, 0x22, 0xca, 0x92,
0x20, 0x88, 0x97, 0x23,
0xd2, 0xcf, 0xae, 0xc2,
0x32, 0x67, 0x8d, 0xfe,
0xca, 0x83, 0x64, 0x98,
0xac, 0xfd, 0x3e, 0x37,
0x87, 0x46, 0x58, 0x24
};
static CardSecureModeFunction s_funcTable[] = {
// Game Card
{ ReadIDSecure, ReadSegSecure, SwitchONPNGSecure, ChangeModeSecure},
// RomEmulation
{ ReadIDSecure_ROMEMU, ReadSegSecure_ROMEMU, SwitchONPNGSecure_ROMEMU, ChangeModeSecure_ROMEMU }
};
// Global Values ------------------------------------------------------------
BLOWFISH_CTX HotSwBlowfishInitTableBufDS;
CardThreadData HotSwThreadData;
#include <twl/ltdwram_end.h>
// ===========================================================================
// Function Describe
// ===========================================================================
/*---------------------------------------------------------------------------*
Name: HOTSW_Init
Description:
*---------------------------------------------------------------------------*/
void HOTSW_Init(u32 threadPrio)
{
SYSM_work* sw = SYSMi_GetWork();
OS_InitTick();
OS_InitThread();
// 初期化後に他の用途でWRAM_0を使用できるようにローカルバッファへコピーしておく
MI_CpuCopyFast((void *)HW_WRAM_0_LTD, &HotSwBlowfishInitTableBufDS, sizeof(BLOWFISH_CTX));
// PXI初期化
PXI_Init();
PXI_SetFifoRecvCallback(PXI_FIFO_TAG_HOTSW, InterruptCallbackPxi);
#ifdef USE_WRAM_LOAD
while(!PXI_IsCallbackReady(PXI_FIFO_TAG_HOTSW, PXI_PROC_ARM9))
{
// do nothing
}
#endif
// 割り込みマスクの設定
SetInterrupt();
// 割り込みの有効化
(void)OS_EnableIrq();
(void)OS_EnableInterrupts();
// チャッタリングカウンタの値を設定
reg_MI_MC1 = (u32)((reg_MI_MC1 & ~REG_MI_MC1_CC_MASK) |
(CHATTERING_COUNTER << REG_MI_MC1_CC_SHIFT));
// Counter-Aの値を設定
reg_MI_MC2 = COUNTER_A;
// Bonding Optionの取得
s_bondingOp = SCFG_REG_GetBondingOption();
// 構造体の初期化
MI_CpuClear8(&s_cbData, sizeof(CardBootData));
// カードスレッド用構造体の初期化
MI_CpuClear8(&HotSwThreadData, sizeof(CardThreadData));
// HotSwリソースの排他制御用Lock IDの取得(開放しないで持ち続ける)
{
s32 tempLockID;
// ARM9と排他制御用のロックIDの取得
while((tempLockID = OS_GetLockID()) == OS_LOCK_ID_ERROR){
// do nothing
}
s_RscLockID = (u16)tempLockID;
// カードアクセス用のロックIDの取得
while((tempLockID = OS_GetLockID()) == OS_LOCK_ID_ERROR){
// do nothing
}
s_CardLockID = (u16)tempLockID;
}
// カードの状態監視用スレッドの生成 ( DSテレビ対策 )
OS_CreateThread(&HotSwThreadData.monitorThread,
MonitorThread,
NULL,
HotSwThreadData.monitorStack + HOTSW_THREAD_STACK_SIZE / sizeof(u64),
HOTSW_THREAD_STACK_SIZE,
threadPrio
);
// カードデータロード用スレッドの生成 ※カード状態監視スレッドと優先度同じだけど、後に作成したこっちのスレッドが優先される
OS_CreateThread(&HotSwThreadData.hotswThread,
HotSwThread,
NULL,
HotSwThreadData.hotswStack + HOTSW_THREAD_STACK_SIZE / sizeof(u64),
HOTSW_THREAD_STACK_SIZE,
threadPrio
);
// メッセージキューの初期化
OS_InitMessageQueue( &HotSwThreadData.hotswQueue, &HotSwThreadData.hotswMsgBuffer[0], HOTSW_MSG_BUFFER_NUM );
OS_InitMessageQueue( &HotSwThreadData.hotswDmaQueue, &HotSwThreadData.hotswDmaMsgBuffer[0], HOTSW_DMA_MSG_NUM );
OS_InitMessageQueue( &HotSwThreadData.hotswPollingCtrlQueue, &HotSwThreadData.hotswPollingCtrlBuffer[0], HOTSW_POLLING_CTRL_BUFFER_NUM );
// スレッド起動
OS_WakeupThreadDirect(&HotSwThreadData.hotswThread);
OS_WakeupThreadDirect(&HotSwThreadData.monitorThread);
// バッファの設定
HOTSW_SetBootSegmentBuffer((void *)SYSM_CARD_ROM_HEADER_BAK, SYSM_APP_ROM_HEADER_SIZE );
HOTSW_SetSecureSegmentBuffer(HOTSW_MODE1, (void *)SYSM_CARD_NTR_SECURE_BUF, SECURE_AREA_SIZE );
HOTSW_SetSecureSegmentBuffer(HOTSW_MODE2, (void *)SYSM_CARD_TWL_SECURE_BUF, SECURE_AREA_SIZE );
// カードが挿さってあったらスレッドを起動する
if(HOTSW_IsCardExist()){
// メッセージ送信
OS_SendMessage(&HotSwThreadData.hotswQueue, (OSMessage)&HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert], OS_MESSAGE_NOBLOCK);
// メッセージインデックスをインクリメント
HotSwThreadData.idx_insert = (HotSwThreadData.idx_insert+1) % HOTSW_INSERT_MSG_NUM;
}
else{
sw->flags.hotsw.is1stCardChecked = TRUE;
}
}
/*---------------------------------------------------------------------------*
Name: LoadCardData
Description: カードからデータをロードする
※BootSegmentBuffer SecureSegmentBufferの設定を行ってから
この関数を呼んでください。
*---------------------------------------------------------------------------*/
static HotSwState LoadCardData(void)
{
HotSwState retval = HOTSW_SUCCESS;
HotSwState state = HOTSW_SUCCESS;
u32 romMode = HOTSW_ROM_MODE_NULL;
s_isHotSwBusy = TRUE;
// カードのロック
CARD_LockRom(s_CardLockID);
// カード電源リセット
McPowerOff();
#ifndef HOWSW_ENABLE_DEEP_SLEEP_WHILE_INSERT_CARD
MCU_EnableDeepSleepToPowerLine( MCU_PWR_LINE_33, FALSE );
#endif
McPowerOn();
// バッファを設定
s_cbData.pBootSegBuf = s_pBootSegBuffer;
s_cbData.pSecureSegBuf = s_pSecureSegBuffer;
s_cbData.pSecure2SegBuf= s_pSecure2SegBuffer;
// ロード処理開始
if(HOTSW_IsCardAccessible()){
s_cbData.modeType = HOTSW_MODE1;
// カード側でKey Tableをロードする
state = LoadTable();
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ---------------------- Normal Mode ----------------------
romMode = HOTSW_ROM_MODE_NORMAL;
// カードID読み込み
state = ReadIDNormal(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// カードタイプを判別をして、使う関数を切替える IDの最上位ビットが1なら3DM
s_cbData.cardType = (s_cbData.id_nml & HOTSW_ROMID_1TROM_MASK) ? DS_CARD_TYPE_2 : DS_CARD_TYPE_1;
{
SYSMRomEmuInfo *romEmuInfo = (void *)&s_romEmuInfo;
BOOL enableDeepSleep = TRUE;
// バナーリードが完了して、フラグ処理が終わるまでARM9と排他制御する
LockHotSwRsc(&SYSMi_GetWork()->lockCardRsc);
// Boot Segment読み込み
state = ReadBootSegNormal(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ワンセグ差込み時はカードバス電源をディープスリープPFMに入れない
// (スリープ時シャットダウン対策。カードロード中にスリープしても良いように早目に設定)
if ( *(u32*)(s_cbData.pBootSegBuf->rh.s.game_code) == HOTSW_DSTV_GAME_CODE )
{
enableDeepSleep = FALSE;
}
MCU_EnableDeepSleepToPowerLine( MCU_PWR_LINE_33, enableDeepSleep );
// ARM9/7で不整合が発生しないようにRomエミュレーション情報ロードは初回のみ
if ( ! SYSMi_GetWork()->flags.hotsw.is1stCardChecked )
{
// Romエミュレーション情報を取得
//(製品本体なら内部で構造体をクリアするだけ)
state = ReadRomEmulationInfo(&s_romEmuInfo);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// 取得したRomエミュレーション情報を比較
s_debuggerFlg = TRUE;
if ( romEmuInfo->magic_code != SYSM_ROMEMU_INFO_MAGIC_CODE ){
s_debuggerFlg = FALSE;
}
}
// 初回のRomエミュレーション情報を使用
if(HOTSWi_IsRomEmulation()){
OS_PutString("Read Emulation ROM\n");
s_cbData.cardType = ROM_EMULATION;
s_cbData.gameCommondParam = s_cbData.pBootSegBuf->rh.s.game_cmd_param & ~SCRAMBLE_MASK;
OS_TPrintf("SYSMi_GetWork()->gameCommondParam : 0x%08x\n", s_cbData.gameCommondParam);
}
else{
s_cbData.gameCommondParam = s_cbData.pBootSegBuf->rh.s.game_cmd_param;
}
SYSMi_GetWork()->gameCommondParam = s_cbData.gameCommondParam;
// CRCチェック
if( !UTL_CheckAppCRC16( &s_cbData.pBootSegBuf->rh.s ) ) {
retval = (retval == HOTSW_SUCCESS) ? HOTSW_CRC_CHECK_ERROR : retval;
}
// リージョンチェック
if( !UTL_CheckAppRegion( s_cbData.pBootSegBuf->rh.s.card_region_bitmap ) ) {
retval = (retval == HOTSW_SUCCESS) ? HOWSW_REGION_CHECK_ERROR : retval;
}
// アプリジャンプのデバッグ時にROMエミュレーション情報だけ必要な場合
if(SYSMi_GetWork()->flags.hotsw.isLoadRomEmuOnly){
SYSMi_GetWork()->flags.hotsw.isExistCard = TRUE;
RegisterRomEmuInfo();
// 排他制御ここまで
UnlockHotSwRsc(&SYSMi_GetWork()->lockCardRsc);
goto finalize;
}
}
if( retval == HOTSW_SUCCESS ) {
// NTRカードかTWLカードか
#ifdef DEBUG_MODE
if(s_cbData.pBootSegBuf->rh.s.main_ltd_rom_offset && s_cbData.pBootSegBuf->rh.s.sub_ltd_rom_offset)
#else
if(s_cbData.pBootSegBuf->rh.s.platform_code & 0x02)
#endif
{
OS_TPrintf("TWL Card.\n");
s_cbData.twlFlg = TRUE;
}
else{
if ( !s_cbData.pBootSegBuf->rh.s.exFlags.enable_nitro_whitelist_signature )
// NTRカードの場合はRomHeaderバッファの1ページ目以降をクリアしておく。
MI_CpuClearFast((void *)(SYSM_CARD_ROM_HEADER_BAK + PAGE_SIZE), SYSM_APP_ROM_HEADER_SIZE - PAGE_SIZE);
}
// SecureコマンドのPNG_ONコマンドetc用のレイテンシを求める(Latency1とLatency2を足す)
s_cbData.secureLatency = AddLatency2ToLatency1(s_cbData.pBootSegBuf->rh.s.secure_cmd_param);
// Key Table初期化
MakeBlowfishTableDS(&s_cbData, 8);
// コマンド認証値・コマンドカウンタ初期値・PNジェネレータ初期値の生成
GenVA_VB_VD();
// セキュアモードに移行
state = ChangeModeNormal(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ---------------------- Secure Mode ----------------------
romMode = HOTSW_ROM_MODE_SECURE;
// SecureモードのIDとSecureSegmentを読み込む
state = ReadSecureModeCardData();
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ★TWLカード対応 一旦リセット後Secure2モードに移行
// SCFG
if((s_cbData.isLoadTypeTwl = isTwlModeLoad()) == TRUE){
OS_PutString("Read Mode : TwlCard\n");
// Mode2に移行する準備
s_cbData.modeType = HOTSW_MODE2;
// ---------------------- Reset ----------------------
McPowerOff();
McPowerOn();
// ---------------------- Normal Mode ----------------------
// 先頭1Page分だけでOK。データは読み捨てバッファに
state = ReadBootSegNormal(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// Key Table初期化
MakeBlowfishTableTWL(&s_cbData, 8, s_bondingOp);
// コマンド認証値・コマンドカウンタ初期値・PNジェネレータ初期値の生成
GenVA_VB_VD();
// セキュア2モードに移行
state = ChangeModeNormal2(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ---------------------- Secure2 Mode ----------------------
// Secure2モードのIDとSecureSegmentを読み込む
state = ReadSecureModeCardData();
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
// ゲームモードに移行
state = s_funcTable[s_debuggerFlg].ChangeMode_S(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ---------------------- Game Mode ----------------------
romMode = HOTSW_ROM_MODE_GAME;
// ID読み込み
state = ReadIDGame(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// バナーファイルの読み込み
state = LoadBannerData();
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// 排他制御ここまで(※CRCチェックまでにミスがなかったら、排他制御ここまで)
UnlockHotSwRsc(&SYSMi_GetWork()->lockCardRsc);
// カードIDの比較をして、一致しなければFALSEを返す
if(s_cbData.id_scr != s_cbData.id_gam){
retval = (retval == HOTSW_SUCCESS) ? HOTSW_ID_CHECK_ERROR : retval;
goto finalize;
}
// 認証コード読み込み&ワーク領域にコピー
state = CheckCardAuthCode();
retval = (retval == HOTSW_SUCCESS) ? state : retval;
#ifndef USE_WRAM_LOAD
// 常駐モジュール残りを指定先に転送
state = LoadStaticModule();
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// ARM9常駐モジュールの先頭2KBの暗号化領域を複合化
(void)DecryptObjectFile();
#endif
}
else{
// 排他制御ここまで(※CRCチェックまでにミスがあったら、ここで開放する)
UnlockHotSwRsc(&SYSMi_GetWork()->lockCardRsc);
OS_TPrintf("ng... Card Data Load Skip ( state : %d )\n", retval);
}
}
else{
state = HOTSW_PULLED_OUT_ERROR;
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
finalize:
if( retval == HOTSW_SUCCESS )
{
// バッドブロックを置換
state = HOTSWi_RefreshBadBlock(romMode);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
end:
// カードDMA終了確認
#ifdef USE_NEW_DMA
HOTSW_WaitNDmaCtrl(HOTSW_NDMA_NO);
#else
HOTSW_WaitDmaCtrl(HOTSW_DMA_NO);
#endif
// カードアクセス終了確認
HOTSW_WaitCardCtrl();
// カードのロック開放(※ロックIDは開放せずに持ち続ける)
CARD_UnlockRom(s_CardLockID);
s_isHotSwBusy = FALSE;
return retval;
}
/*---------------------------------------------------------------------------*
Name: isTwlModeLoad
Description: カードのロードをTWLモードで行うかDSモードで行うかを決める
※ 読み込みシーケンスの詳細は docs/ゲームカード/カード読み込みシーケンス表.xls 参照
*---------------------------------------------------------------------------*/
static BOOL isTwlModeLoad(void)
{
// TWLカード
if(s_cbData.id_nml & HOTSW_ROMID_TWLROM_MASK){
// PlatformCodeがTwl or Hybridの場合
if(s_cbData.pBootSegBuf->rh.s.platform_code & 0x02){
return TRUE;
}
else{
return FALSE;
}
}
// DSカード
else{
// PlatformCodeがTwl or Hybridの場合
if(s_cbData.pBootSegBuf->rh.s.platform_code & 0x02){
// 製品用本体 (最終的には開発用本体も)
#ifdef HOTSW_FINAL_VERSION
if(s_bondingOp == SCFG_OP_PRODUCT || !s_debuggerFlg)
#else
if(s_bondingOp == SCFG_OP_PRODUCT)
#endif
{
s_cbData.illegalCardFlg = TRUE;
}
}
return FALSE;
}
}
/*---------------------------------------------------------------------------*
Name: ReadSecureModeCardData
Description: セキュアモードの各種読み込みを行う関数
※ s_cbData.modeTypeの設定はこの関数の外で行う
*---------------------------------------------------------------------------*/
static HotSwState ReadSecureModeCardData(void)
{
HotSwState retval = HOTSW_SUCCESS;
HotSwState state = HOTSW_SUCCESS;
// PNG設定
state = s_funcTable[s_debuggerFlg].SetPNG_S(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// DS側符号生成回路初期値設定 (レジスタ設定)
SetMCSCR();
// ID読み込み
state = s_funcTable[s_debuggerFlg].ReadID_S(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// カードIDの比較をして、一致しなければFALSEを返す
if(s_cbData.id_nml != s_cbData.id_scr){
retval = (retval == HOTSW_SUCCESS) ? HOTSW_ID_CHECK_ERROR : retval;
}
if(retval == HOTSW_SUCCESS){
// Secure領域のSegment読み込み
state = s_funcTable[s_debuggerFlg].ReadSegment_S(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
return retval;
}
/*---------------------------------------------------------------------------*
Name: HOTSWi_RefreshBadBlock
Description: ノーマルモードまたはゲームモードでバッドブロックを置換
*---------------------------------------------------------------------------*/
HotSwState HOTSWi_RefreshBadBlock(u32 romMode)
{
HotSwState retval = HOTSW_SUCCESS;
HotSwState state = HOTSW_SUCCESS;
HotSwState (*pReadStatus)(CardBootData *cbd);
HotSwState (*pRefreshBadBlock)(CardBootData *cbd);
if ( ! ( romMode == HOTSW_ROM_MODE_NORMAL || romMode == HOTSW_ROM_MODE_GAME ) )
{
return HOTSW_SUCCESS;
}
if ( romMode == HOTSW_ROM_MODE_NORMAL )
{
pReadStatus = ReadStatusNormal;
pRefreshBadBlock = RefreshBadBlockNormal;
}
else
if ( romMode == HOTSW_ROM_MODE_GAME )
{
pReadStatus = ReadStatusGame;
pRefreshBadBlock = RefreshBadBlockGame;
}
// ステータス対応ROMのみステータス読み込み
if ( s_cbData.id_nml & HOTSW_ROMID_RFSSUP_MASK )
{
state = pReadStatus(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
// 要求レベルに関わらずバッドブロックを置換(製品カードでは滅多に発生しない)
if ( s_cbData.romStatus & (HOTSW_ROMST_RFS_WARN_L1_MASK | HOTSW_ROMST_RFS_WARN_L2_MASK) )
{
state = pRefreshBadBlock(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
while (1)
{
state = pReadStatus(&s_cbData);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
if ( s_cbData.romStatus & HOTSW_ROMST_RFS_READY_MASK ||
(retval != HOTSW_SUCCESS) )
{
break;
}
OS_Sleep(1);
}
}
}
return retval;
}
/*---------------------------------------------------------------------------*
Name: HOTSWi_IsRunOnDebugger
Description: ISデバッガ上で動作しているか
*---------------------------------------------------------------------------*/
BOOL HOTSWi_IsRunOnDebugger(void)
{
return s_debuggerFlg;
}
/*---------------------------------------------------------------------------*
Name: HOTSWi_IsRomEmulation
Description: ROMをエミュレーションしているか
*---------------------------------------------------------------------------*/
BOOL HOTSWi_IsRomEmulation(void)
{
return s_debuggerFlg && s_romEmuInfo.isEnableSlot1;
}
/*---------------------------------------------------------------------------*
Name: RegisterRomEmuInfo
Description: ROMエミュレーション情報を登録
*---------------------------------------------------------------------------*/
static void RegisterRomEmuInfo(void)
{
SYSM_work* sw = SYSMi_GetWork();
// デバッガ情報
if ( ! sw->flags.hotsw.is1stCardChecked && s_debuggerFlg )
{
MI_CpuCopy8( &s_romEmuInfo, &(sw->romEmuInfo), ROM_EMULATION_DATA_SIZE );
sw->flags.hotsw.isOnDebugger = s_debuggerFlg;
}
sw->flags.hotsw.isCardStateChanged = TRUE;
sw->flags.hotsw.is1stCardChecked = TRUE;
}
/*---------------------------------------------------------------------------*
Name: LoadBannerData
Description: バナーデータを読み込む
注:ゲームモードになってから呼び出してください
*---------------------------------------------------------------------------*/
static HotSwState LoadBannerData(void)
{
BOOL state;
HotSwState retval = HOTSW_SUCCESS;
SYSM_work* sw = SYSMi_GetWork();
// バナーリード
if( s_cbData.pBootSegBuf->rh.s.banner_offset ) {
retval = ReadPageGame(&s_cbData, s_cbData.pBootSegBuf->rh.s.banner_offset,
(u32 *)SYSM_CARD_BANNER_BUF,
sizeof(TWLBannerFile) );
// バナーリードが成功していたら各種フラグTRUE その他の場合はFALSE (この関数の外で排他制御されているからここでは排他制御しないでOK)
state = (retval == HOTSW_SUCCESS) ? TRUE : FALSE;
sw->flags.hotsw.isValidCardBanner = state;
sw->flags.hotsw.isExistCard = state;
}
else{
// バナーデータが登録されていない場合 (この関数の外で排他制御されているからここでは排他制御しないでOK)
sw->flags.hotsw.isValidCardBanner = FALSE;
sw->flags.hotsw.isExistCard = TRUE;
}
if ( sw->flags.hotsw.isExistCard )
{
sw->flags.hotsw.isInspectCard = s_cbData.pBootSegBuf->rh.s.inspect_card;
}
else
{
sw->flags.hotsw.isInspectCard = FALSE;
}
// デバッガ情報を登録
RegisterRomEmuInfo();
return retval;
}
/*---------------------------------------------------------------------------*
Name: ReadImageReturnErrorCode
Description: カードから中途半端なサイズ(page途中)のデータを読み出す関数
エラーコードを返す
*---------------------------------------------------------------------------*/
static HotSwState ReadImageReturnErrorCode(void* dest, s32 offset, s32 length, void* arg)
{
HotSwState retval = HOTSW_SUCCESS;
static u8 page_buffer[512];
u32 page_offset = (u32)(offset & -512);
u32 buffer_offset = (u32)(offset % 512);
u32 valid_length = 512 - buffer_offset;
u32 remain_length;
// 開始アドレスがページの途中
if ( offset % 512 )
{
retval = ReadPageGame((CardBootData*)arg, page_offset, page_buffer, 512);
if (retval != HOTSW_SUCCESS)
{
return retval;
}
MI_CpuCopy8(page_buffer + buffer_offset, dest, (length < valid_length ? length : valid_length));
dest = (u8*)dest + valid_length;
offset += valid_length;
length -= valid_length;
if ( length < 0)
{
return retval;
}
}
remain_length = (u32)(length % 512);
retval = ReadPageGame((CardBootData*)arg, (u32)offset, dest, (u32)(length - remain_length));
// ケツがページ途中
if( remain_length ){
dest = (u8*)dest + (length - remain_length);
offset += length - remain_length;
retval = ReadPageGame((CardBootData*)arg, (u32)offset, page_buffer, 512);
if (retval != HOTSW_SUCCESS)
{
return retval;
}
MI_CpuCopy8(page_buffer, dest, remain_length);
}
return retval;
}
/*---------------------------------------------------------------------------*
Name: ReadImage
Description: カードから中途半端なサイズ(page途中)のデータを読み出す関数
成功するとTRUEを返す
*---------------------------------------------------------------------------*/
static BOOL ReadImage(void* dest, s32 offset, s32 length, void* arg)
{
return (ReadImageReturnErrorCode(dest, offset, length, arg) == HOTSW_SUCCESS);
}
/*---------------------------------------------------------------------------*
Name: ReadCardData
Description: ARM9から通知された範囲のデータをカードから読み込み
*---------------------------------------------------------------------------*/
#ifdef USE_WRAM_LOAD
static void ReadCardData(u32 src, u32 dest, u32 size)
{
u32 sendSize = 0;
HotSwState state = HOTSW_SUCCESS;
if(!SYSMi_GetWork()->flags.hotsw.isCardGameMode){
state = HOTSW_MODE_ERROR;
}
// カードのロック
CARD_LockRom(s_CardLockID);
while(size > 0 && state == HOTSW_SUCCESS){
// --- Boot Segment
if(src >= HOTSW_BOOTSEGMENT_AREA_OFS && src < HOTSW_KEYTABLE_AREA_OFS){
sendSize = ((src + size) > HOTSW_KEYTABLE_AREA_OFS) ? HOTSW_KEYTABLE_AREA_OFS - src : size;
MI_CpuCopy8((u32 *)(SYSM_CARD_ROM_HEADER_BAK + (src - HOTSW_BOOTSEGMENT_AREA_OFS)), (u32 *)dest, sendSize);
}
// --- Key Table
else if(src >= HOTSW_KEYTABLE_AREA_OFS && src < HOTSW_SECURE_AREA_OFS){
sendSize = ((src + size) > HOTSW_SECURE_AREA_OFS) ? HOTSW_SECURE_AREA_OFS - src : size;
state = ReadImageReturnErrorCode((u32 *)dest, (s32)src, (s32)sendSize, &s_cbData);
}
// --- Secure Segment
else if(src >= HOTSW_SECURE_AREA_OFS && src < HOTSW_GAME_AREA_OFS){
sendSize = ((src + size) > HOTSW_GAME_AREA_OFS) ? HOTSW_GAME_AREA_OFS - src : size;
MI_CpuCopy8((u32 *)((u32)s_cbData.pSecureSegBuf + (src - HOTSW_SECURE_AREA_OFS)), (u32 *)dest, sendSize);
}
// --- Game Segment
else if(src >= HOTSW_GAME_AREA_OFS){
// KeyTable2が設定されている場合
if(s_cbData.isLoadTypeTwl){
u32 keyTable2Adr = (u32)s_cbData.pBootSegBuf->rh.s.twl_card_keytable_area_rom_offset * TWLCARD_BORDER_OFFSET;
u32 Secure2Adr = keyTable2Adr + HOTSW_SECURE2_AREA_OFS;
u32 Game2Adr = keyTable2Adr + HOTSW_GAME2_AREA_OFS;
// --- Game Segment
if(src < keyTable2Adr){
sendSize = ((src + size) > keyTable2Adr) ? keyTable2Adr - src : size;
state = ReadImageReturnErrorCode((u32 *)dest, (s32)src, (s32)sendSize, &s_cbData);
}
// --- Key Table2
else if(src >= keyTable2Adr && src < Secure2Adr){
sendSize = ((src + size) > Secure2Adr) ? Secure2Adr - src : size;
state = ReadImageReturnErrorCode((u32 *)dest, (s32)src, (s32)sendSize, &s_cbData);
}
// --- Secure2 Segment
else if(src >= Secure2Adr && src < Game2Adr){
sendSize = ((src + size) > Game2Adr) ? Game2Adr - src : size;
MI_CpuCopy8((u32 *)((u32)s_cbData.pSecure2SegBuf + (src - Secure2Adr)), (u32 *)dest, sendSize);
}
// --- Game2 Segment
else{
sendSize = size;
state = ReadImageReturnErrorCode((u32 *)dest, (s32)src, (s32)sendSize, &s_cbData);
}
}
// --- Game Segment
else{
sendSize = size;
state = ReadImageReturnErrorCode((u32 *)dest, (s32)src, (s32)sendSize, &s_cbData);
}
}
size -= sendSize;
src += sendSize;
dest += sendSize;
}
// カードのアンロック
CARD_UnlockRom(s_CardLockID);
{
HotSwPxiMessageForArm9 msg;
CardDataReadState retval;
switch(state){
case HOTSW_SUCCESS:
retval = CARD_READ_SUCCESS;
break;
case HOTSW_TIME_OUT:
retval = CARD_READ_TIME_OUT;
break;
case HOTSW_PULLED_OUT_ERROR:
retval = CARD_READ_PULLED_OUT_ERROR;
break;
case HOTSW_BUFFER_OVERRUN_ERROR:
retval = CARD_READ_BUFFER_OVERRUN_ERROR;
break;
case HOTSW_MODE_ERROR:
retval = CARD_READ_MODE_ERROR;
break;
default:
retval = CARD_READ_UNEXPECTED_ERROR;
break;
}
MI_CpuClear8( &msg, sizeof(HotSwPxiMessageForArm9));
msg.msg.read = TRUE;
msg.msg.result = (u8)retval;
while (PXI_SendWordByFifo(PXI_FIFO_TAG_HOTSW, msg.data, FALSE) != PXI_FIFO_SUCCESS)
{
// do nothing
}
}
}
#endif
/*---------------------------------------------------------------------------*
Name: LoadStaticModule
Description: ARM7,9の常駐モジュールを展開する関数
注:ゲームモードになってから呼び出してください
*---------------------------------------------------------------------------*/
#ifndef USE_WRAM_LOAD
static HotSwState LoadStaticModule(void)
{
HotSwState retval = HOTSW_SUCCESS;
HotSwState state = HOTSW_SUCCESS;
u32 arm9StcEnd = s_cbData.pBootSegBuf->rh.s.main_rom_offset + s_cbData.pBootSegBuf->rh.s.main_size;
u32 arm9LtdStcEnd = s_cbData.pBootSegBuf->rh.s.main_ltd_rom_offset + s_cbData.pBootSegBuf->rh.s.main_ltd_size;
u32 secure2SegEnd = (u32)(s_cbData.pBootSegBuf->rh.s.twl_card_keytable_area_rom_offset * TWLCARD_BORDER_OFFSET + SECURE_SEGMENT_SIZE);
// 配置先と再配置情報を取得 & Arm9の常駐モジュール残りを指定先に転送
s_cbData.arm9Stc = (u32)s_cbData.pBootSegBuf->rh.s.main_ram_address;
if(SYSM_CheckLoadRegionAndSetRelocateInfo( ARM9_STATIC, &s_cbData.arm9Stc, s_cbData.pBootSegBuf->rh.s.main_size, &SYSMi_GetWork()->romRelocateInfo[ARM9_STATIC] , s_cbData.twlFlg)){
if(arm9StcEnd > SECURE_SEGMENT_END){
state = ReadPageGame(&s_cbData, s_cbData.pBootSegBuf->rh.s.main_rom_offset + SECURE_SEGMENT_SIZE, (u32 *)(s_cbData.arm9Stc + SECURE_SEGMENT_SIZE), MATH_ROUNDUP( arm9StcEnd, SYSM_ALIGNMENT_LOAD_MODULE ) - SECURE_SEGMENT_END);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
}
else{
retval = (retval == HOTSW_SUCCESS) ? HOTSW_BUFFER_OVERRUN_ERROR : retval;
}
if(retval != HOTSW_SUCCESS){
return retval;
}
// 配置先と再配置情報を取得 & Arm7の常駐モジュールを指定先に転送
s_cbData.arm7Stc = (u32)s_cbData.pBootSegBuf->rh.s.sub_ram_address;
if(SYSM_CheckLoadRegionAndSetRelocateInfo( ARM7_STATIC, &s_cbData.arm7Stc, s_cbData.pBootSegBuf->rh.s.sub_size, &SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC], s_cbData.twlFlg)){
state = ReadPageGame(&s_cbData, s_cbData.pBootSegBuf->rh.s.sub_rom_offset, (u32 *)s_cbData.arm7Stc, MATH_ROUNDUP( s_cbData.pBootSegBuf->rh.s.sub_size, SYSM_ALIGNMENT_LOAD_MODULE ) );
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
else{
retval = (retval == HOTSW_SUCCESS) ? HOTSW_BUFFER_OVERRUN_ERROR : retval;
}
if(retval != HOTSW_SUCCESS){
return retval;
}
// 拡張常駐モジュールの読み込み
if( s_cbData.twlFlg ) {
u32 size = ( s_cbData.pBootSegBuf->rh.s.main_ltd_size < SECURE_SEGMENT_SIZE ) ? s_cbData.pBootSegBuf->rh.s.main_ltd_size : SECURE_SEGMENT_SIZE;
s_cbData.arm9Ltd = (u32)s_cbData.pBootSegBuf->rh.s.main_ltd_ram_address;
// 配置先と再配置情報を取得 & Arm9の常駐モジュールを指定先に転送
if(SYSM_CheckLoadRegionAndSetRelocateInfo( ARM9_LTD_STATIC, &s_cbData.arm9Ltd, s_cbData.pBootSegBuf->rh.s.main_ltd_size, &SYSMi_GetWork()->romRelocateInfo[ARM9_LTD_STATIC] , TRUE)){
if(!s_cbData.isLoadTypeTwl){
// Secure2領域読み
state = ReadPageGame(&s_cbData, s_cbData.pBootSegBuf->rh.s.main_ltd_rom_offset, (u32 *)SYSM_CARD_TWL_SECURE_BUF, MATH_ROUNDUP( size, SYSM_ALIGNMENT_LOAD_MODULE ));
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
// (Arm9Ltd領域 - Secure2領域)分の読み込み
if( s_cbData.pBootSegBuf->rh.s.main_ltd_size > SECURE_SEGMENT_SIZE ) {
state = ReadPageGame(&s_cbData, s_cbData.pBootSegBuf->rh.s.main_ltd_rom_offset + SECURE_SEGMENT_SIZE,
(u32 *)(s_cbData.arm9Ltd + SECURE_SEGMENT_SIZE),
MATH_ROUNDUP( s_cbData.pBootSegBuf->rh.s.main_ltd_size, SYSM_ALIGNMENT_LOAD_MODULE ) - size);
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
}
else{
retval = (retval == HOTSW_SUCCESS) ? HOTSW_BUFFER_OVERRUN_ERROR : retval;
}
if(retval != HOTSW_SUCCESS){
return retval;
}
// 配置先と再配置情報を取得 & Arm7の常駐モジュールを指定先に転送
s_cbData.arm7Ltd = (u32)s_cbData.pBootSegBuf->rh.s.sub_ltd_ram_address;
if(SYSM_CheckLoadRegionAndSetRelocateInfo( ARM7_LTD_STATIC, &s_cbData.arm7Ltd, s_cbData.pBootSegBuf->rh.s.sub_ltd_size, &SYSMi_GetWork()->romRelocateInfo[ARM7_LTD_STATIC], TRUE)){
state = ReadPageGame(&s_cbData, s_cbData.pBootSegBuf->rh.s.sub_ltd_rom_offset, (u32 *)s_cbData.arm7Ltd, MATH_ROUNDUP( s_cbData.pBootSegBuf->rh.s.sub_ltd_size, SYSM_ALIGNMENT_LOAD_MODULE ) );
retval = (retval == HOTSW_SUCCESS) ? state : retval;
}
else{
retval = (retval == HOTSW_SUCCESS) ? HOTSW_BUFFER_OVERRUN_ERROR : retval;
}
if(retval != HOTSW_SUCCESS){
return retval;
}
// セキュア領域先頭2K分のハッシュ値を求めて、Work領域にコピー
{
SVCHMACSHA1Context hash;
// ハッシュ初期化
SVC_HMACSHA1Init( &hash, s_digestDefaultKey, sizeof(s_digestDefaultKey) );
// セキュア領域先頭2kb分UpDate
SVC_HMACSHA1Update( &hash, s_cbData.pSecureSegBuf, ENCRYPT_DEF_SIZE );
// Arm9と排他制御する
LockHotSwRsc(&SYSMi_GetWork()->lockHotSW);
// ハッシュコンテキストをWork領域にコピー
MI_CpuCopy8( &hash, &SYSMi_GetWork2()->hmac_sha1_context, sizeof(SVCHMACSHA1Context) );
// Arm9との排他制御、ここまで
UnlockHotSwRsc(&SYSMi_GetWork()->lockHotSW);
}
//#define MY_DEBUG
#ifdef MY_DEBUG
(void)CheckStaticModuleHash();
#endif
}
return retval;
}
#endif
/*---------------------------------------------------------------------------*
Name: CheckCardAuthCode
Description: Rom Headerの認証コードアドレスを読んで、クローンブート対応か判定する
*---------------------------------------------------------------------------*/
static HotSwState CheckCardAuthCode(void)
{
u32 authBuf[PAGE_SIZE/sizeof(u32)];
u32 auth_offset = s_cbData.pBootSegBuf->rh.s.rom_valid_size ? s_cbData.pBootSegBuf->rh.s.rom_valid_size : 0x01000000;
u32 page_offset = auth_offset & 0xFFFFFE00;
HotSwState retval = HOTSW_SUCCESS;
u8 *p = (u8 *)authBuf;
if(!HOTSW_IsCardAccessible()){
return HOTSW_PULLED_OUT_ERROR;
}
retval = ReadPageGame( &s_cbData, page_offset, authBuf, MB_AUTHCODE_SIZE );
p += auth_offset & 0x000001FF;
if( *p++ == 'a' && *p == 'c' ) {
OS_PutString(" ☆ Clone Boot Mode\n");
SYSMi_GetWork()->cloneBootMode = SYSM_CLONE_BOOT_MODE;
}else {
OS_PutString(" □ Other Boot Mode\n");
SYSMi_GetWork()->cloneBootMode = SYSM_OTHER_BOOT_MODE;
}
return retval;
}
/*---------------------------------------------------------------------------*
Name: HOTSW_SetBootSegmentBuffer
Description: Boot Segment バッファの指定
注:カードデータロード中は呼び出さないようにする
*---------------------------------------------------------------------------*/
void HOTSW_SetBootSegmentBuffer(void* buf, u32 size)
{
SDK_ASSERT(size > BOOT_SEGMENT_SIZE);
s_pBootSegBuffer = (BootSegmentData *)buf;
s_BootSegBufSize = size;
s_cbData.pBootSegBuf = s_pBootSegBuffer;
// バッファの初期化
MI_CpuClear8(s_pBootSegBuffer, size);
}
/*---------------------------------------------------------------------------*
Name: HOTSW_SetSecureSegmentBuffer
Description: Secure Segment バッファの指定
注:カードデータロード中は呼び出さないようにする
*---------------------------------------------------------------------------*/
void HOTSW_SetSecureSegmentBuffer(ModeType type ,void* buf, u32 size)
{
HOTSWi_SetSecureSegmentBuffer(type, buf, size);
// バッファの初期化
MI_CpuClear8(s_pSecureSegBuffer, size);
}
void HOTSWi_SetSecureSegmentBuffer(ModeType type ,void* buf, u32 size)
{
SDK_ASSERT(size > SECURE_SEGMENT_SIZE);
if(type == HOTSW_MODE1){
s_pSecureSegBuffer = (u32 *)buf;
s_SecureSegBufSize = size;
s_cbData.pSecureSegBuf = s_pSecureSegBuffer;
}
else{
s_pSecure2SegBuffer = (u32 *)buf;
s_Secure2SegBufSize = size;
s_cbData.pSecure2SegBuf = s_pSecure2SegBuffer;
}
}
/*---------------------------------------------------------------------------*
Name: GenVA_VB_VD
Description: コマンド認証値・コマンドカウンタ・PNジェネレータ初期値の生成
*---------------------------------------------------------------------------*/
static void GenVA_VB_VD(void)
{
SYSM_work* sw = SYSMi_GetWork();
u32 dummy = 0;
MATHRandContext32 rnd;
// 乱数を初期化
// チックRTC初回ロード値ゲームコードを種とする。
// (起動する度に変化するパラメータと組み合わせる。
// Vカウンタは2130サイクル変化しないので固定値になりやすい。
MATH_InitRand32(&rnd, OS_GetTick() ^ sw->Rtc1stData.words[0] ^ sw->Rtc1stData.words[1] ^ *(u32*)(s_cbData.pBootSegBuf->rh.s.game_code));
s_cbData.vae = MATH_Rand32(&rnd, 0);
s_cbData.vbi = MATH_Rand32(&rnd, 0);
s_cbData.vd = MATH_Rand32(&rnd, 0);
dummy = MATH_Rand32(&rnd, 0);
EncryptByBlowfish(&s_cbData.keyTable, &s_cbData.vae, &s_cbData.vbi);
EncryptByBlowfish(&s_cbData.keyTable, &s_cbData.vd , &dummy);
s_cbData.vae &= 0xffffff;
s_cbData.vbi &= 0xfffff;
s_cbData.vd &= 0xffffff;
}
/*---------------------------------------------------------------------------*
Name: DecryptObjectFile
Description: セキュア領域先頭2KBの暗号化領域を復号化
*---------------------------------------------------------------------------*/
static u32 encDestBuf[ENCRYPT_DEF_SIZE/sizeof(u32)];
#ifndef USE_WRAM_LOAD
static HotSwState DecryptObjectFile(void)
#else
BOOL HOTSW_DecryptObjectFile(void* dest)
#endif
{
u8 i;
s32 restSize;
s32 size = (s32)s_cbData.pBootSegBuf->rh.s.main_size;
u32 *pEncBuf = encDestBuf;
#ifndef USE_WRAM_LOAD
u32 *pEncDes = s_cbData.pSecureSegBuf;
#else
u32 *pEncDes = (u32 *)dest;
#endif
BLOWFISH_CTX *tableBufp = &s_cbData.keyTable;
BOOL exist = TRUE;
#ifndef USE_WRAM_LOAD
HotSwState retval = HOTSW_SUCCESS;
#else
BOOL retval = TRUE;
#endif
if (size > ENCRYPT_DEF_SIZE) {
size = ENCRYPT_DEF_SIZE;
}
restSize = size;
// 読み込んだセキュア領域をバッファから一時バッファにコピー
MI_CpuCopy32(pEncDes, pEncBuf, (u32)size);
// セキュア領域先頭8バイトをBlowfishで複合化
DecryptByBlowfish(&s_cbData.keyTable, &(pEncBuf)[1], &(pEncBuf)[0]);
// Key Tableを変換
s_cbData.keyBuf[1] = (s_cbData.keyBuf[1] << 1);
s_cbData.keyBuf[2] = (s_cbData.keyBuf[2] >> 1);
InitBlowfishKeyAndTableDS(&s_cbData.keyTable, s_cbData.keyBuf, 8);
// もう一度セキュア領域先頭8バイトをBlowfishで複合化
DecryptByBlowfish(&s_cbData.keyTable, &(pEncBuf)[1], &(pEncBuf)[0]);
for ( i=0; i<8; i++ ){
// 先頭8バイトが複合化の結果 "encryObj" となっていたら複合化成功
if ( encrypt_object_key[i] != ((char*)pEncBuf)[i] ){
exist = FALSE;
break;
}
}
// 暗号化オブジェクト有効時
if ( exist ){
u32 *bufp = pEncBuf;
bufp[0] = UNDEF_CODE;
bufp[1] = UNDEF_CODE;
while ((restSize -= 8) > 0) {
bufp += 2; // 復号処理
DecryptByBlowfish(tableBufp, &(bufp)[1], &(bufp)[0]);
}
}
else{
#ifndef USE_WRAM_LOAD
retval = HOTSW_DATA_DECRYPT_ERROR;
#else
retval = FALSE;
#endif
MI_NDmaFill( HOTSW_NDMA_NO, pEncBuf, UNDEF_CODE, (u32)size ); // 未定義コードでクリア
}
MI_CpuCopy32(pEncBuf, pEncDes, (u32)size);
return retval;
}
/*---------------------------------------------------------------------------*
Name: LockHotSwRsc
Description: 共有ワークのリソースの排他制御用 lockを行う
*---------------------------------------------------------------------------*/
static void LockHotSwRsc(OSLockWord* word)
{
while(OS_TryLockByWord( s_RscLockID, word, NULL ) != OS_LOCK_SUCCESS){
OS_Sleep(1);
}
}
/*---------------------------------------------------------------------------*
Name: UnlockHotSwRsc
Description: 共有ワークのリソースの排他制御用 Unlockを行う
*---------------------------------------------------------------------------*/
static void UnlockHotSwRsc(OSLockWord* word)
{
OS_UnlockByWord( s_RscLockID, word, NULL );
}
/*---------------------------------------------------------------------------*
Name: HOTSW_IsCardExist
Description: SCFG_MC1のCDETフラグを見て、カードの存在判定を行う
*---------------------------------------------------------------------------*/
BOOL HOTSW_IsCardExist(void)
{
if( !(reg_MI_MC1 & REG_MI_MC_SL1_CDET_MASK) ){
return TRUE;
}
else{
return FALSE;
}
}
/*---------------------------------------------------------------------------*
Name: HOTSW_IsCardAccessible
Description: SCFG_MC1のCDETフラグとM(モード)を見て、カードスロットにアクセスできる状態か判定する
*---------------------------------------------------------------------------*/
BOOL HOTSW_IsCardAccessible(void)
{
if( HOTSW_IsCardExist() && (GetMcSlotMode() == SLOT_STATUS_MODE_10)){
return TRUE;
}
else{
return FALSE;
}
}
/*---------------------------------------------------------------------------*
Name: GetMcSlotMode
Description: スロットの現在のモードを返す
*---------------------------------------------------------------------------*/
static u32 GetMcSlotMode(void)
{
return reg_MI_MC1 & REG_MI_MC_SL1_MODE_MASK;
}
/*---------------------------------------------------------------------------*
Name: SetMcSlotMode
Description: カードスロットのモード設定
*---------------------------------------------------------------------------*/
static void SetMcSlotMode(u32 mode)
{
reg_MI_MC1 = (u32)((reg_MI_MC1 & ~REG_MI_MC_SL1_MODE_MASK) | mode);
}
/*---------------------------------------------------------------------------*
Name: McPowerOn
Description: スロット電源ON
*---------------------------------------------------------------------------*/
static void McPowerOn(void)
{
// Counter-Aカウンタ設定値到達まで待つ
while(GetMcSlotMode() == SLOT_STATUS_MODE_11){
OS_Sleep(1);
}
if(GetMcSlotMode() == SLOT_STATUS_MODE_00){
// 3DMのリセット待ち
OS_Sleep(1);
// SCFG_MC1 の Slot Status の M1,M0 を 01 にする
SetMcSlotMode(SLOT_STATUS_MODE_01);
// VDDの安定期間待ち
OS_Sleep(10);
// SCFG_MC1 の Slot Status の M1,M0 を 10 にする
SetMcSlotMode(SLOT_STATUS_MODE_10);
// RESBを上げるまでの待ち時間
OS_Sleep(27);
// リセットをhighに (RESB = 1にする)
reg_HOTSW_MCCNT1 = RESB_MASK;
// カードへ最初のコマンドを送るまでの待ち時間
OS_Sleep(120);
}
}
/*---------------------------------------------------------------------------*
Name: McPowerOff
Description: スロット電源OFF
*---------------------------------------------------------------------------*/
static void McPowerOff(void)
{
// Counter-Aカウンタ設定値到達まで待つ
while(GetMcSlotMode() == SLOT_STATUS_MODE_11){
OS_Sleep(1);
}
if(GetMcSlotMode() == SLOT_STATUS_MODE_10){
// SCFG_MC1 の Slot Status の M1,M0 を 11 にする
SetMcSlotMode(SLOT_STATUS_MODE_11);
// SCFG_MC1 の Slot Status の M1,M0 が 00 になるまでポーリング
while(GetMcSlotMode() != SLOT_STATUS_MODE_00){
OS_Sleep(1);
}
}
}
/*---------------------------------------------------------------------------*
Name: HOTSWi_TurnCardPowerOn
Description: デバッガ通信用にカードスロットの電源をONにする。
Arguments: None.
Returns: None.
*---------------------------------------------------------------------------*/
void HOTSWi_TurnCardPowerOn(u32 slot)
{
u32 shift;
u32 mask = slot >= 2 ? (u32)REG_MI_MC_SL2_CDET_MASK : (u32)REG_MI_MC_SL1_CDET_MASK;
// カードが差さっていなければONしない
if ( reg_MI_MC & mask )
{
return;
}
shift = slot >= 2 ? (u32)REG_MI_MC_SL2_MODE_SHIFT : (u32)REG_MI_MC_SL1_MODE_SHIFT;
mask = slot >= 2 ? (u32)REG_MI_MC_SL2_MODE_MASK : (u32)REG_MI_MC_SL1_MODE_MASK;
// 電源が落ちている最中なら待つ
if ( (reg_MI_MC & mask) == (0x3 << shift) )
{
OS_Sleep(1);
}
if ( (reg_MI_MC & mask) == (0x0 << shift) )
{
// 3DMのリセット待ち
OS_Sleep(1);
reg_MI_MC = (u16)((reg_MI_MC & ~mask) | (0x1 << shift));
// VDDの安定期間
OS_Sleep(10);
reg_MI_MC = (u16)((reg_MI_MC & ~mask) | (0x2 << shift));
// RESBのLow期間
OS_Sleep(27);
reg_MI_MCCNT1_B = REG_MI_MCCNT1_RESB_MASK;
// RESBのHigh期間
// カードへ最初のコマンドを送るまでの待ち時間
OS_Sleep(120);
}
}
/*---------------------------------------------------------------------------*
Name: SetMCSCR
Description: 符号生成回路初期値設定レジスタを設定する
※注この関数はセキュアモードで、sPNG_ONコマンドを実行してから呼び出してください。
*---------------------------------------------------------------------------*/
static void SetMCSCR(void)
{
static u32 pnbL = 0x879b9b05;
static u8 pnbH = 0x5c;
static u8 pnaL1 = 0x60;
static u8 pnaL0Table[8] = { 0xe8, 0x4d, 0x5a, 0xb1, 0x17, 0x8f, 0x99, 0xd5 };
u32 pnaL = s_cbData.vd << 15 | pnaL1 << 8 | pnaL0Table[(s_cbData.pBootSegBuf->rh.s.rom_type & 0x7)];
u8 pnaH = (u8)((s_cbData.vd >> 17) & 0x7f);
// SCR A
reg_HOTSW_MCSCR0 = pnaL;
// SCR B
reg_HOTSW_MCSCR1 = pnbL;
// [d0 -d6 ] -> SCR A
// [d16-d22] -> SCR B
reg_HOTSW_MCSCR2 = (u32)(pnaH | pnbH << 16);
// MCCNT1 レジスタ設定 (SCR = 1に)
reg_HOTSW_MCCNT1 = SCR_MASK;
}
/*---------------------------------------------------------------------------*
Name: HotSwThread
Description: カード抜け・挿し処理スレッド
*---------------------------------------------------------------------------*/
static void HotSwThread(void *arg)
{
#pragma unused( arg )
HotSwState retval;
HotSwMessageForArm7 *msg;
static BOOL card_exist = FALSE;
while(1){
OS_ReceiveMessage(&HotSwThreadData.hotswQueue, (OSMessage *)&msg, OS_MESSAGE_BLOCK);
SYSMi_GetWork()->flags.hotsw.isBusyHotSW = TRUE;
if( msg->ctrl == TRUE ) {
SYSMi_GetWork()->flags.hotsw.isEnableHotSW = msg->value;
s_pollingThreadSleepFlg = msg->value ? FALSE : TRUE;
if(msg->value){
s_isPulledOut = TRUE;
OS_SendMessage(&HotSwThreadData.hotswPollingCtrlQueue,
(OSMessage *)&HotSwThreadData.hotswPollingCtrlMsg[HotSwThreadData.idx_polling],
OS_MESSAGE_NOBLOCK);
HotSwThreadData.idx_polling = (HotSwThreadData.idx_polling+1) % HOTSW_POLLING_CTRL_BUFFER_NUM;
}
else{
if(msg->finalize == FALSE){
ClearCardFlgs();
}
}
}
if( msg->finalize == TRUE && msg->ctrl == FALSE) {
FinalizeHotSw( msg->state );
}
#ifdef USE_WRAM_LOAD
if( msg->read == TRUE ){
ReadCardData(SYSMi_GetWork()->cardReadParam.src,
SYSMi_GetWork()->cardReadParam.dest,
SYSMi_GetWork()->cardReadParam.size);
SYSMi_GetWork()->flags.hotsw.isBusyHotSW = FALSE;
continue;
}
if( msg->type == HOTSW_INSERT ){
SendPxiMessage(HOTSW_CARD_INSERT);
}
#endif
while(1){
if( !SYSMi_GetWork()->flags.hotsw.isEnableHotSW ) {
SYSMi_GetWork()->flags.hotsw.is1stCardChecked = TRUE;
OS_PutString("### HotSw is restrained...\n");
break;
}
if(HOTSW_IsCardExist()){
if(!s_isPulledOut){
if(GetMcSlotMode() == SLOT_STATUS_MODE_10){
if(!card_exist){
card_exist = TRUE;
LockHotSwRsc(&SYSMi_GetWork()->lockCardRsc);
SYSMi_GetWork()->flags.hotsw.isExistCard = TRUE;
SYSMi_GetWork()->flags.hotsw.isCardStateChanged = TRUE;
SYSMi_GetWork()->flags.hotsw.isCardLoadCompleted = TRUE;
#ifdef USE_WRAM_LOAD
SYSMi_GetWork()->flags.hotsw.isCardGameMode = TRUE;
#endif
UnlockHotSwRsc(&SYSMi_GetWork()->lockCardRsc);
#ifdef USE_WRAM_LOAD
SendPxiMessage(HOTSW_CHANGE_GAMEMODE);
#endif
OS_PutString("ok!\n");
}
break;
}
}
retval = LoadCardData();
DebugPrintErrorMessage(retval);
s_isPulledOut = FALSE;
// エラー処理
if(retval != HOTSW_SUCCESS || s_cbData.illegalCardFlg){
ClearCardFlgs();
McPowerOff();
s_isPulledOut = TRUE;
break;
}
}
// カードが抜けてたら
else{
card_exist = FALSE;
#ifdef USE_WRAM_LOAD
SendPxiMessage(HOTSW_CARD_PULLOUT);
#endif
ClearCardFlgs();
MI_CpuClear32(&s_cbData, sizeof(CardBootData));
MI_CpuClearFast(s_pBootSegBuffer, s_BootSegBufSize);
MI_CpuClearFast(s_pSecureSegBuffer, s_SecureSegBufSize);
MI_CpuClearFast((u32 *)SYSM_CARD_BANNER_BUF, sizeof(TWLBannerFile));
s_isPulledOut = TRUE;
// ワンセグのスリープ時シャットダウン対策を戻す
MCU_EnableDeepSleepToPowerLine( MCU_PWR_LINE_33, TRUE );
break;
}
} // Card Read while loop
SYSMi_GetWork()->flags.hotsw.is1stCardChecked = TRUE;
SYSMi_GetWork()->flags.hotsw.isBusyHotSW = FALSE;
} // while loop
}
/*---------------------------------------------------------------------------*
Name: ClearCardFlgs
Description: カードデータバッファのバッファとフラグの後始末
*---------------------------------------------------------------------------*/
static void ClearCardFlgs(void)
{
// フラグ処理
LockHotSwRsc(&SYSMi_GetWork()->lockHotSW);
SYSMi_GetWork()->flags.hotsw.isExistCard = FALSE;
SYSMi_GetWork()->flags.hotsw.isValidCardBanner = FALSE;
SYSMi_GetWork()->flags.hotsw.isCardStateChanged = TRUE;
SYSMi_GetWork()->flags.hotsw.isCardLoadCompleted = FALSE;
#ifdef USE_WRAM_LOAD
SYSMi_GetWork()->flags.hotsw.isCardGameMode = FALSE;
#endif
UnlockHotSwRsc(&SYSMi_GetWork()->lockHotSW);
}
/*---------------------------------------------------------------------------*
Name: FinalizeHotSw
Description: アプリ起動時に、活線挿抜関係の後始末を行う。
*---------------------------------------------------------------------------*/
static void FinalizeHotSw(HotSwCardState state)
{
ROM_Header* rh = (void*)SYSM_APP_ROM_HEADER_BUF;
static BOOL finalized = FALSE;
if(finalized){
return;
}
finalized = TRUE;
// カード挿入検出停止
(void)OS_DisableIrqMask( HOTSW_IF_CARD_DET );
// ポーリングスレッドを消去
OS_KillThread( &HotSwThreadData.monitorThread, NULL );
SYSMi_GetWork()->appCardID = 0;
// カードアクセスできないなら、(一応)スロット電源OFFしてレジスタクリア
if(!HOTSW_IsCardAccessible()){
McPowerOff();
ClearAllCardRegister();
goto final;
}
switch(state){
// Slot Power Off
case HOTSW_CARD_STATE_POWER_OFF:
McPowerOff();
break;
// Normalモードに移行
case HOTSW_CARD_STATE_NORMAL_MODE:
ForceNormalModeToFinalize();
break;
// Gameモードに移行
case HOTSW_CARD_STATE_GAME_MODE:
ForceNitroModeToFinalize();
break;
// 状態キープ
case HOTSW_CARD_STATE_KEEP:
SYSMi_GetWork()->appCardID = s_cbData.id_gam;
break;
// else
default:
ClearAllCardRegister();
McPowerOff();
}
final:
ClearCardIrq();
// デバッガではTWLカードスロットを電源ON
//既にONなら何もしない
// NANDアプリ起動時はデフォルトではカードI/FをOFFにするが、
// デバッガモニタではカードI/Fが必要なためスロットを使用
if ( SYSM_IsRunOnDebugger() )
{
HOTSWi_TurnCardPowerOn( 2 );
}
// 終了完了通知
SYSMi_GetWork()->gameCommondParam = s_cbData.gameCommondParam;
SYSMi_GetWork()->flags.hotsw.isFinalized = TRUE;
}
/*---------------------------------------------------------------------------*
Name: ForceNitroModeToFinalize
Description: Nitro互換のGame Modeに強制移行させる
*---------------------------------------------------------------------------*/
static void ForceNitroModeToFinalize(void)
{
s_cbData.id_gam = 0;
if(!ChangeGameMode()){
ClearAllCardRegister();
McPowerOff();
OS_PutString("Failed To Change Game Mode... Card Slot Power Off\n");
}
SYSMi_GetWork()->appCardID = s_cbData.id_gam;
}
/*---------------------------------------------------------------------------*
Name: ForceNormalModeToFinalize
Description: Normal Modeに強制移行させる
*---------------------------------------------------------------------------*/
static void ForceNormalModeToFinalize(void)
{
CARD_LockRom(s_CardLockID);
McPowerOff(); // 既にOFFになっているため実質的には無効
McPowerOn();
s_cbData.modeType = HOTSW_MODE2;
(void)LoadTable();
(void)ReadIDNormal(&s_cbData);
(void)ReadBootSegNormal(&s_cbData);
CARD_UnlockRom(s_CardLockID);
s_cbData.gameCommondParam = s_cbData.pBootSegBuf->rh.s.game_cmd_param & ~SCRAMBLE_MASK;
SYSMi_GetWork()->appCardID = s_cbData.id_nml;
OS_PutString("- game card on flg is TRUE : now Normal Mode\n");
}
/*---------------------------------------------------------------------------*
Name: ChangeGameMode
Description: Nitro互換のRomHeaderを読んで、Game Modeに移行させる
*---------------------------------------------------------------------------*/
static BOOL ChangeGameMode(void)
{
HotSwState state;
CARD_LockRom(s_CardLockID);
McPowerOff();
McPowerOn();
s_cbData.pBootSegBuf = s_pBootSegBuffer;
s_cbData.modeType = HOTSW_MODE1;
// ---------------------- Normal Mode ----------------------
state = LoadTable();
state = ReadIDNormal(&s_cbData);
state = ReadBootSegNormal(&s_cbData);
if(s_debuggerFlg){
s_cbData.cardType = ROM_EMULATION;
s_cbData.gameCommondParam = s_cbData.pBootSegBuf->rh.s.game_cmd_param & ~SCRAMBLE_MASK;
}
else{
s_cbData.cardType = (s_cbData.id_nml & HOTSW_ROMID_1TROM_MASK) ? DS_CARD_TYPE_2 : DS_CARD_TYPE_1;
s_cbData.gameCommondParam = s_cbData.pBootSegBuf->rh.s.game_cmd_param;
}
s_cbData.secureLatency = AddLatency2ToLatency1(s_cbData.pBootSegBuf->rh.s.secure_cmd_param);
MI_CpuClear32(&s_cbData.keyTable, sizeof(BLOWFISH_CTX));
MI_CpuClear32(s_cbData.keyBuf, sizeof(s_cbData.keyBuf));
MakeBlowfishTableDS(&s_cbData, 8);
GenVA_VB_VD();
state = ChangeModeNormal(&s_cbData);
// ---------------------- Secure Mode ----------------------
state = s_funcTable[s_debuggerFlg].SetPNG_S(&s_cbData);
SetMCSCR();
state = s_funcTable[s_debuggerFlg].ChangeMode_S(&s_cbData);
// ---------------------- Game Mode ----------------------
state = ReadIDGame(&s_cbData);
if(s_cbData.id_nml != s_cbData.id_gam){
state = HOTSW_ID_CHECK_ERROR;
}
OS_TPrintf("Card Normal ID : 0x%08x\n", s_cbData.id_nml);
OS_TPrintf("Card Game ID : 0x%08x\n", s_cbData.id_gam);
#ifdef USE_NEW_DMA
HOTSW_WaitNDmaCtrl(HOTSW_NDMA_NO);
#else
HOTSW_WaitDmaCtrl(HOTSW_DMA_NO);
#endif
HOTSW_WaitCardCtrl();
CARD_UnlockRom(s_CardLockID);
if(state == HOTSW_SUCCESS){
return TRUE;
}
else{
return FALSE;
}
}
/*---------------------------------------------------------------------------*
Name: SendPxiMessage
Description: ARM9にメッセージを送る
*---------------------------------------------------------------------------*/
#ifdef USE_WRAM_LOAD
static void SendPxiMessage(HotSwCallBackType type)
{
HotSwPxiMessageForArm9 msg;
MI_CpuClear8( &msg, sizeof(HotSwPxiMessageForArm9));
switch(type){
case HOTSW_CHANGE_GAMEMODE:
msg.msg.mode = TRUE;
break;
case HOTSW_CARD_INSERT:
msg.msg.insert = TRUE;
break;
case HOTSW_CARD_PULLOUT:
msg.msg.pullout = TRUE;
break;
default:
return;
}
while (PXI_SendWordByFifo(PXI_FIFO_TAG_HOTSW, msg.data, FALSE) != PXI_FIFO_SUCCESS)
{
// do nothing
}
}
#endif
/*---------------------------------------------------------------------------*
Name: ClearCardIrq
Description: カード関連の割り込みをクリアする
*---------------------------------------------------------------------------*/
#define REGCLEAR_16 0x0000
#define REGCLEAR_32 0x00000000UL
static void ClearCardIrq(void)
{
// HotSwで使っている割り込みを無効にする
OSIntrMode irq = OS_DisableInterrupts();
(void)OS_DisableIrqMask( HOTSW_IF_CARD_DET );
(void)OS_ResetRequestIrqMask( HOTSW_IF_CARD_DET );
(void)OS_RestoreInterrupts( irq );
}
/*---------------------------------------------------------------------------*
Name: ClearAllCardRegister
Description: カード関連の全てのレジスタをクリアする。
*---------------------------------------------------------------------------*/
static void ClearAllCardRegister(void)
{
ClearCardIrq();
// コマンド設定レジスタをクリア [各32bit]
reg_HOTSW_MCCMD0 = REGCLEAR_32;
reg_HOTSW_MCCMD1 = REGCLEAR_32;
// メモリカードイネーブルとか割り込みイネーブルとかをクリア [16bit中 d15-d8が関係あり]
reg_HOTSW_MCCNT0 &= HOTSW_E2PROM_CTRL_MASK;
// latencyとかstartフラグとかのレジスタをクリア [32bit]
reg_HOTSW_MCCNT1 = REGCLEAR_32;
// カードからのデータがたまるレジスタをクリア [32bit]
reg_HOTSW_MCD1 = REGCLEAR_32;
// 符号生成回路初期値設定レジスタをクリア [各32bit]
reg_HOTSW_MCSCR0 = REGCLEAR_32;
reg_HOTSW_MCSCR1 = REGCLEAR_32;
reg_HOTSW_MCSCR2 = REGCLEAR_32;
// Slot Status,SWPをクリア [d15-d0 Slot Status,SWP]
reg_MI_MC1 &= REG_MI_MC1_CC_MASK;
}
/*---------------------------------------------------------------------------*
Name: MonitorThread
Description: 実際のカード状態とHotSwThreadで状態を比べて、違いがあった場合は
メッセージを送る
s_isPulledOut : True -> カードなし HOTSW_IsCardExist : True -> カードあり
False -> カードあり False -> カードなし
*---------------------------------------------------------------------------*/
static void MonitorThread(void *arg)
{
#pragma unused( arg )
u32 count = 0;
BOOL isCardExist;
while(1){
// カードデータロード中は待機
do{
OS_Sleep(CARD_EXIST_CHECK_POLLING_TIME);
count++;
}
while(s_isHotSwBusy);
// ポーリングスレッド抑制フラグが上がってたら、スリープ。抑制フラグが下りたら起床。
if(s_pollingThreadSleepFlg){
OSMessage msg;
OS_ReceiveMessage(&HotSwThreadData.hotswPollingCtrlQueue, (OSMessage *)&msg, OS_MESSAGE_BLOCK);
}
isCardExist = HOTSW_IsCardExist();
CheckCardPullOut(isCardExist);
if(count >= CARD_INSERT_CHECK_INTERVAL){
CheckCardInsert(isCardExist);
count = 0;
}
}
}
/*---------------------------------------------------------------------------*
Name: CheckCardInsert
Description: カードは挿さっているのに、ランチャーが認識してなかったらメッセージを送る
*---------------------------------------------------------------------------*/
static void CheckCardInsert(BOOL cardExist)
{
if(cardExist && s_isPulledOut){
OSIntrMode enabled = OS_DisableInterrupts();
HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert].ctrl = FALSE;
HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert].value = 0;
HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert].type = HOTSW_INSERT;
// メッセージをキューの先頭に入れる
OS_JamMessage(&HotSwThreadData.hotswQueue, (OSMessage *)&HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert], OS_MESSAGE_NOBLOCK);
// メッセージインデックスをインクリメント
HotSwThreadData.idx_insert = (HotSwThreadData.idx_insert+1) % HOTSW_INSERT_MSG_NUM;
(void)OS_RestoreInterrupts( enabled );
}
}
/*---------------------------------------------------------------------------*
Name: CheckCardPullOut
Description: カードは抜かれているのに、ランチャーが認識していたらメッセージを送る
*---------------------------------------------------------------------------*/
static void CheckCardPullOut(BOOL cardExist)
{
if(!cardExist && !s_isPulledOut){
OSIntrMode enabled;
#ifndef HOTSW_DISABLE_FORCE_CARD_OFF
{
u32 mode = GetMcSlotMode();
if(mode == SLOT_STATUS_MODE_01 || mode == SLOT_STATUS_MODE_10){
SetMcSlotMode(SLOT_STATUS_MODE_11);
}
}
#endif
enabled = OS_DisableInterrupts();
HotSwThreadData.hotswPulledOutMsg[HotSwThreadData.idx_pulledOut].ctrl = FALSE;
HotSwThreadData.hotswPulledOutMsg[HotSwThreadData.idx_pulledOut].value = 0;
HotSwThreadData.hotswPulledOutMsg[HotSwThreadData.idx_pulledOut].type = HOTSW_PULLOUT;
// メッセージをキューの先頭に入れる
OS_JamMessage(&HotSwThreadData.hotswQueue, (OSMessage *)&HotSwThreadData.hotswPulledOutMsg[HotSwThreadData.idx_pulledOut], OS_MESSAGE_NOBLOCK);
// メッセージインデックスをインクリメント
HotSwThreadData.idx_pulledOut = (HotSwThreadData.idx_pulledOut+1) % HOTSW_PULLED_MSG_NUM;
(void)OS_RestoreInterrupts( enabled );
}
}
/*---------------------------------------------------------------------------*
Name: InterruptCallbackCardDet
Description: カードB挿し割り込みハンドラ
*---------------------------------------------------------------------------*/
static void InterruptCallbackCardDet(void)
{
HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert].ctrl = FALSE;
HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert].value = 0;
HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert].type = HOTSW_INSERT;
// メッセージ送信
OS_SendMessage(&HotSwThreadData.hotswQueue, (OSMessage *)&HotSwThreadData.hotswInsertMsg[HotSwThreadData.idx_insert], OS_MESSAGE_NOBLOCK);
// メッセージインデックスをインクリメント
HotSwThreadData.idx_insert = (HotSwThreadData.idx_insert+1) % HOTSW_INSERT_MSG_NUM;
OS_PutString("\n");
}
/*---------------------------------------------------------------------------*
Name: InterruptCallbackPxi
Description: PXI割り込みハンドラ
*---------------------------------------------------------------------------*/
static void InterruptCallbackPxi(PXIFifoTag tag, u32 data, BOOL err)
{
#pragma unused(tag)
#pragma unused(err)
HotSwPxiMessageForArm7 d;
d.data = data;
#ifndef USE_WRAM_LOAD
OS_TPrintf("... Pxi Message - value:%x ctrl:%x finalize:%x bootType:%x\n",
d.msg.value, d.msg.ctrl, d.msg.finalize, d.msg.cardState);
#else
OS_TPrintf("... Pxi Message - value:%x ctrl:%x finalize:%x read:%x bootType:%x\n",
d.msg.value, d.msg.ctrl, d.msg.finalize, d.msg.read, d.msg.cardState);
HotSwThreadData.hotswPxiMsg[HotSwThreadData.idx_ctrl].read = (d.msg.read) ? TRUE : FALSE;
#endif
HotSwThreadData.hotswPxiMsg[HotSwThreadData.idx_ctrl].ctrl = (d.msg.ctrl) ? TRUE : FALSE;
HotSwThreadData.hotswPxiMsg[HotSwThreadData.idx_ctrl].finalize = (d.msg.finalize) ? TRUE : FALSE;
HotSwThreadData.hotswPxiMsg[HotSwThreadData.idx_ctrl].value = d.msg.value;
HotSwThreadData.hotswPxiMsg[HotSwThreadData.idx_ctrl].state = (HotSwCardState)d.msg.cardState;
// メッセージ送信
OS_SendMessage(&HotSwThreadData.hotswQueue, (OSMessage *)&HotSwThreadData.hotswPxiMsg[HotSwThreadData.idx_ctrl], OS_MESSAGE_NOBLOCK);
// メッセージインデックスをインクリメント
HotSwThreadData.idx_ctrl = (HotSwThreadData.idx_ctrl+1) % HOTSW_CTRL_MSG_NUM;
}
/*---------------------------------------------------------------------------*
Name: InterruptCallbackCardData
Description: カードB データ転送終了割り込みハンドラ
*---------------------------------------------------------------------------*/
#ifndef USE_NEW_DMA
static void InterruptCallbackCardData(void)
{
// DMA強制終了
MI_StopDma(HOTSW_DMA_NO);
// メッセージ送信
OS_SendMessage(&HotSwThreadData.hotswDmaQueue, (OSMessage *)&HotSwThreadData.hotswDmaMsg[HotSwThreadData.idx_dma], OS_MESSAGE_NOBLOCK);
// メッセージインデックスをインクリメント
HotSwThreadData.idx_dma = (HotSwThreadData.idx_dma+1) % HOTSW_DMA_MSG_NUM;
}
#endif
/*---------------------------------------------------------------------------*
Name: SetInterruptCallback
SetInterruptCallbackEx
Description: 割り込みコールバック関数と割り込み許可の設定を行う
*---------------------------------------------------------------------------*/
static void SetInterruptCallback( OSIrqMask intr_bit, OSIrqFunction func )
{
(void)OS_SetIrqFunction(intr_bit, func);
(void)OS_EnableIrqMask(intr_bit);
}
static void SetInterruptCallbackEx( OSIrqMask intr_bit, void *func )
{
(void)OS_SetIrqFunctionEx(intr_bit, func);
(void)OS_EnableIrqMaskEx(intr_bit);
}
/*---------------------------------------------------------------------------*
Name: SetInterrupt
Description: 割り込みコールバック関数を一度に設定する関数
*---------------------------------------------------------------------------*/
static void SetInterrupt(void)
{
SetInterruptCallback( OS_IE_CARD_A_DET , InterruptCallbackCardDet );
#ifdef USE_NEW_DMA
(void)OS_EnableIrqMask(OS_IE_NDMA2);
#else
SetInterruptCallback( OS_IE_CARD_DATA , InterruptCallbackCardData );
#endif
}
/*---------------------------------------------------------------------------*
Name: CheckStaticModuleHash
Description: 常駐モジュールのハッシュチェックを行う
*---------------------------------------------------------------------------*/
#ifndef USE_WRAM_LOAD
#include <twl/os/common/systemCall.h>
static HotSwState CheckStaticModuleHash(void)
{
BOOL flg = TRUE;
// Arm9常駐モジュール Hash値のチェック
if(!CheckArm9HashValue()){
flg = FALSE;
OS_PutString("×Arm9 Static Module Hash Check Error...\n");
}
// Arm7常駐モジュール Hash値のチェック
if(!CheckArm7HashValue()){
flg = FALSE;
OS_PutString("×Arm7 Static Module Hash Check Error...\n");
}
// Arm9拡張常駐モジュール Hash値のチェック
if(!CheckExtArm9HashValue()){
flg = FALSE;
OS_PutString("×Arm9 Ltd Static Module Hash Check Error...\n");
}
// Arm7拡張常駐モジュール Hash値のチェック
if(!CheckExtArm7HashValue()){
flg = FALSE;
OS_PutString("×Arm7 Ltd Static Module Hash Check Error...\n");
}
if(flg){
OS_PutString("*** Static Module Load was Completed!!\n");
}
return flg ? HOTSW_SUCCESS : HOTSW_HASH_CHECK_ERROR;
}
#endif
/*---------------------------------------------------------------------------*
Name: CheckArm7HashValue
Description: Arm7常駐モジュールのハッシュチェック
*---------------------------------------------------------------------------*/
#ifndef USE_WRAM_LOAD
static BOOL CheckArm7HashValue(void)
{
u8 sha1data[DIGEST_SIZE_SHA1];
BOOL retval = TRUE;
// クリア
MI_CpuClear8(sha1data, sizeof(sha1data));
// ARM7常駐モジュールのHash値照合
SVC_CalcHMACSHA1( sha1data,
(u32 *)(s_cbData.arm7Stc),
s_cbData.pBootSegBuf->rh.s.sub_size,
s_digestDefaultKey,
sizeof(s_digestDefaultKey) );
return SVC_CompareSHA1( sha1data, s_cbData.pBootSegBuf->rh.s.sub_static_digest );
}
#endif
/*---------------------------------------------------------------------------*
Name: CheckArm9HashValue
Description: Arm9常駐モジュールのハッシュチェック
※ 先頭2Kの復号化が行われる前のデータのハッシュを比べる
*---------------------------------------------------------------------------*/
#ifndef USE_WRAM_LOAD
static BOOL CheckArm9HashValue(void)
{
u8 sha1data[DIGEST_SIZE_SHA1];
BOOL retval = TRUE;
SVCHMACSHA1Context hash;
// クリア
MI_CpuClear8(sha1data, sizeof(sha1data));
// ハッシュ初期化
SVC_HMACSHA1Init( &hash, s_digestDefaultKey, sizeof(s_digestDefaultKey) );
// セキュア領域分UpDate
SVC_HMACSHA1Update( &hash, s_cbData.pSecureSegBuf, SECURE_SEGMENT_SIZE );
// ゲーム領域分UpDate
SVC_HMACSHA1Update( &hash, (u32 *)(s_cbData.arm9Stc + SECURE_SEGMENT_SIZE), s_cbData.pBootSegBuf->rh.s.main_size - SECURE_SEGMENT_SIZE );
// Hash値取得
SVC_HMACSHA1GetHash( &hash, sha1data );
return SVC_CompareSHA1( sha1data, s_cbData.pBootSegBuf->rh.s.main_static_digest );
}
#endif
/*---------------------------------------------------------------------------*
Name: CheckExtArm7HashValue
Description: Arm7拡張常駐モジュールのハッシュチェック
*---------------------------------------------------------------------------*/
#ifndef USE_WRAM_LOAD
static BOOL CheckExtArm7HashValue(void)
{
u8 sha1data[DIGEST_SIZE_SHA1];
BOOL retval = TRUE;
// クリア
MI_CpuClear8(sha1data, sizeof(sha1data));
// ARM7常駐モジュールのHash値照合
SVC_CalcHMACSHA1( sha1data,
(u32 *)s_cbData.arm7Ltd,
s_cbData.pBootSegBuf->rh.s.sub_ltd_size,
s_digestDefaultKey,
sizeof(s_digestDefaultKey) );
return SVC_CompareSHA1( sha1data, s_cbData.pBootSegBuf->rh.s.sub_ltd_static_digest );
}
#endif
/*---------------------------------------------------------------------------*
Name: CheckExtArm9HashValue
Description: Arm9拡張常駐モジュールのハッシュチェック
*---------------------------------------------------------------------------*/
#ifndef USE_WRAM_LOAD
static BOOL CheckExtArm9HashValue(void)
{
u8 sha1data[DIGEST_SIZE_SHA1];
u32 size;
BOOL retval = TRUE;
SVCHMACSHA1Context hash;
// Arm9拡張常駐モジュールのセキュア領域分のサイズを取得
size = ( s_cbData.pBootSegBuf->rh.s.main_ltd_size < SECURE_SEGMENT_SIZE ) ?
s_cbData.pBootSegBuf->rh.s.main_ltd_size : SECURE_SEGMENT_SIZE;
// クリア
MI_CpuClear8(sha1data, sizeof(sha1data));
// ハッシュ初期化
SVC_HMACSHA1Init( &hash, s_digestDefaultKey, sizeof(s_digestDefaultKey) );
// セキュア領域分UpDate
SVC_HMACSHA1Update( &hash, (u32 *)SYSM_CARD_TWL_SECURE_BUF, size );
// ゲーム領域分UpDate (Arm9拡張常駐モジュールがSecure領域で収まってたらここは飛ばす)
if( s_cbData.pBootSegBuf->rh.s.main_ltd_size > SECURE_SEGMENT_SIZE ){
SVC_HMACSHA1Update( &hash, (u32 *)(s_cbData.arm9Ltd + SECURE_SEGMENT_SIZE), s_cbData.pBootSegBuf->rh.s.main_ltd_size - size );
}
// Hash値取得
SVC_HMACSHA1GetHash( &hash, sha1data );
return SVC_CompareSHA1( sha1data, s_cbData.pBootSegBuf->rh.s.main_ltd_static_digest );
}
#endif
/*---------------------------------------------------------------------------*
Name: HOTSWi_GetCardBootData
Description:
*---------------------------------------------------------------------------*/
void *HOTSWi_GetCardBootData(void)
{
return &s_cbData;
}
/*---------------------------------------------------------------------------*
Name: DebugPrintErrorMessage
Description:
*---------------------------------------------------------------------------*/
static void DebugPrintErrorMessage(HotSwState state)
{
switch(state){
case HOTSW_SUCCESS:
OS_PutString(" - Success\n");
break;
case HOTSW_TIME_OUT:
OS_PutString(" - Error 1 : TimeOut\n");
break;
case HOTSW_CARD_LOCK_ERROR:
OS_PutString(" - Error 2 : Slot Lock\n");
break;
case HOTSW_CRC_CHECK_ERROR:
OS_PutString(" - Error 3 : CRC Check\n");
break;
case HOWSW_REGION_CHECK_ERROR:
OS_PutString(" - Error 3 : Region Check\n");
break;
case HOTSW_HASH_CHECK_ERROR:
OS_PutString(" - Error 4 : Hash Check\n");
break;
case HOTSW_ID_CHECK_ERROR:
OS_PutString(" - Error 5 : ID Check\n");
break;
case HOTSW_PULLED_OUT_ERROR:
OS_PutString(" - Error 6 : Pulled Out\n");
break;
case HOTSW_DATA_DECRYPT_ERROR:
OS_PutString(" - Error 7 : Data Decrypt\n");
break;
case HOTSW_BUFFER_OVERRUN_ERROR:
OS_PutString(" - Error 8 : Buffer OverRun\n");
break;
case HOTSW_UNEXPECTED_ERROR:
OS_PutString(" - Error 9 : Unexpected\n");
break;
default :
OS_PutString(" - illigal Error\n");
break;
}
}