活栓挿抜用ソースを追加。未完成。

git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@160 b08762b0-b915-fc4b-9d8c-17b2551a87ff
This commit is contained in:
akabane_jumpei 2007-11-13 08:12:26 +00:00
parent d0d5e2d6e8
commit 3fb9f3bed2
7 changed files with 1685 additions and 0 deletions

View File

@ -0,0 +1,265 @@
/*---------------------------------------------------------------------------*
Project: TwlSDK
File: Card.h
*---------------------------------------------------------------------------*/
#ifndef __MY_CARD_H__
#define __MY_CARD_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <twl.h>
#include <twl/os/common/format_rom.h>
// Define -------------------------------------------------------------------
#define KEY_BUF_SIZE 3 // Blowfishキーのバッファサイズ
#define DMA_NO 2 //
#define BOOT_SEGMENT_SIZE 0x1000 // Boot Segment領域のサイズ
#define SECURE_SEGMENT_SIZE 0x4000 // Secure領域のサイズ
#define VAE_VALUE 0xaaaaaa // VAE (コマンド認証値(期待値))
#define VBI_VALUE 0xbbbbb // VBI (コマンドカウンタ 初期値)
#define VD_VALUE 0xdddddd // VD (PNジェネレータ 初期値)
#define PNA_BASE_VALUE 0x60e8 //
#define PNB_L_VALUE 0x879b9b05 //
#define PNB_H_VALUE 0x5c //
// コントロールレジスタ1 bit関連
#define START_FLG_MASK 0x80000000
#define READY_FLG_MASK 0x00800000
#define LATENCY1_SHIFT 0
#define LATENCY1_MASK 0x00001fff
#define DS_SHIFT 13
#define DS_MASK 0x00002000
#define SE_SHIFT 14
#define SE_MASK 0x00004000
#define SCR_SHIFT 15
#define SCR_MASK 0x00008000
#define LATENCY2_SHIFT 16
#define LATENCY2_MASK 0x003f0000
#define CS_SHIFT 22
#define CS_MASK 0x00400000
#define RDY_SHIFT 23
#define RDY_MASK 0x00800000
#define PC_SHIFT 24
#define PC_MASK 0x07000000
#define CT_SHIFT 27
#define CT_MASK 0x08000000
#define TRM_SHIFT 28
#define TRM_MASK 0x10000000
#define RESB_SHIFT 29
#define RESB_MASK 0x20000000
#define WR_SHIFT 30
#define WR_MASK 0x40000000
#define START_SHIFT 31
#define START_MASK 0x80000000
#define CNT1_FLD( start, wr, resb, rtm, ct, pc, rdy, cs, l2, scr, se, ds, l1 ) \
(u32)( \
((u32)(start)<< START_SHIFT) | \
((u32)(wr) << WR_SHIFT) | \
((u32)(resb) << RESB_SHIFT) | \
((u32)(rtm) << TRM_SHIFT) | \
((u32)(ct) << CT_SHIFT) | \
((u32)(pc) << PC_SHIFT) | \
((u32)(rdy) << RDY_SHIFT) | \
((u32)(cs) << CS_SHIFT) | \
((u32)(l2) << LATENCY2_SHIFT) | \
((u32)(scr) << SCR_SHIFT) | \
((u32)(se) << SE_SHIFT) | \
((u32)(ds) << DS_SHIFT) | \
((u32)(l1) << LATENCY1_SHIFT) \
)
#define CNT1_MSK( start, wr, resb, rtm, ct, pc, rdy, cs, l2, scr, se, ds, l1 ) \
(u32)( ((start) ? START_MASK : 0) | \
((wr) ? WR_MASK : 0) | \
((resb) ? RESB_MASK : 0) | \
((rtm) ? TRM_MASK : 0) | \
((ct) ? CT_MASK : 0) | \
((pc) ? PC_MASK : 0) | \
((rdy) ? RDY_MASK : 0) | \
((cs) ? CS_MASK : 0) | \
((l2) ? LATENCY2_MASK : 0)| \
((scr) ? SCR_MASK : 0) | \
((se) ? SE_MASK : 0) | \
((ds) ? DS_MASK : 0) | \
((l1) ? LATENCY1_MASK : 0))
//#define USE_SLOT_A
#ifdef USE_SLOT_A
// Slot A
#define SLOT_STATUS_MODE_SELECT_MSK 0x0c
#define SLOT_STATUS_MODE_01 0x04
#define SLOT_STATUS_MODE_10 0x08
#define SLOT_STATUS_MODE_11 0x0c
#define reg_MCCNT1 reg_MI_MCCNT1_A
#define reg_MCCMD0 reg_MI_MCCMD0_A
#define reg_MCCMD1 reg_MI_MCCMD1_A
#define reg_MCCNT0 reg_MI_MCCNT0_A
#define reg_MCCNT1 reg_MI_MCCNT1_A
#define reg_MCD1 reg_MI_MCD1_A
#define reg_MCSCR0 reg_MI_MCSCR0_A
#define reg_MCSCR1 reg_MI_MCSCR1_A
#define reg_MCSCR2 reg_MI_MCSCR2_A
#else
// Slot B
#define SLOT_STATUS_MODE_SELECT_MSK 0xc0
#define SLOT_STATUS_MODE_01 0x40
#define SLOT_STATUS_MODE_10 0x80
#define SLOT_STATUS_MODE_11 0xc0
#define reg_MCCNT1 reg_MI_MCCNT1_B
#define reg_MCCMD0 reg_MI_MCCMD0_B
#define reg_MCCMD1 reg_MI_MCCMD1_B
#define reg_MCCNT0 reg_MI_MCCNT0_B
#define reg_MCCNT1 reg_MI_MCCNT1_B
#define reg_MCD1 reg_MI_MCD1_B
#define reg_MCSCR0 reg_MI_MCSCR0_B
#define reg_MCSCR1 reg_MI_MCSCR1_B
#define reg_MCSCR2 reg_MI_MCSCR2_B
#endif
// Enum ---------------------------------------------------------------------
typedef enum NormalCommandType{
RD_ID = 0,
RD_BSEG,
CHG_MODE
}NormalCommandType;
typedef enum SecureCommandType{
S_RD_ID = 0,
S_RD_SEG,
S_PNG_ON,
S_PNG_OFF,
S_CHG_MODE
}SecureCommandType;
typedef enum GameCommandType{
G_RD_ID = 0,
G_RD_PAGE
}GameCommandType;
typedef enum CardType{
CARD_DS_TYPE1 = 0,
CARD_DS_TYPE2,
CARD_TWL
}CardType;
// union ---------------------------------------------------------------------
typedef union
{
u64 dw;
u8 b[8];
}
GCDCmd64;
// ブートセグメントデータ
typedef union BootSegmentData
{
ROM_Header rh;
u32 word[BOOT_SEGMENT_SIZE / sizeof(u32)];
}
BootSegmentData;
// struct -------------------------------------------------------------------
typedef struct BLOWFISH_CTX{
u32 P[16 + 2];
u32 S[4][256];
} BLOWFISH_CTX;
// カードブート時に必要な変数一式をまとめた構造体
typedef struct CardBootData{
u32 vae;
u32 vbi;
u32 vd;
u32 id_nml;
u32 id_scr;
u32 id_gam;
u32 arm9StaticSize;
u32 arm7StaticSize;
u32 arm9LtdSize;
u32 arm7LtdSize;
BOOL twlFlg;
u32 keyBuf[KEY_BUF_SIZE];
u64 secureSegNum;
BootSegmentData *pBootSegBuf;
u32 *pSecureSegBuf;
BLOWFISH_CTX keyTable;
}
CardBootData;
// カード起動用関数
typedef struct CardBootFunction {
void (*ReadID_N)(CardBootData *cbd);
void (*ReadBootSegment_N)(CardBootData *cbd);
void (*ChangeMode_N)(CardBootData *cbd);
void (*ReadID_S)(CardBootData *cbd);
void (*ReadSegment_S)(CardBootData *cbd);
void (*SetPNG_S)(CardBootData *cbd);
void (*ChangeMode_S)(CardBootData *cbd);
void (*ReadID_G)(CardBootData *cbd);
}
CardBootFunction;
// Function prototype -------------------------------------------------------
// 活栓挿抜処理の初期化
void Card_Init(void);
// カード起動。Normalモード→Secureモード→Gameモードを行う。
void Card_Boot(void);
// Boot Segment バッファの指定
void Card_SetBootSegmentBuffer(void* buf, u32 size);
// Secure Segment バッファの指定
void Card_SetSecureSegmentBuffer(void* buf, u32 size);
// Boot Segment を読み込む関数
BOOL Card_GetRomHeaderData(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // __MY_CARD_H__

View File

@ -0,0 +1,47 @@
/*---------------------------------------------------------------------------*
Project: TwlFirm - GCD - include
File: blowfish.h
Copyright 2007 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.
*---------------------------------------------------------------------------*/
#ifndef FIRM_GCD_BLOWFISH_H
#define FIRM_GCD_BLOWFISH_H
#include <twl/types.h>
#include "Card.h"
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************/
// 初期化テーブル
extern const BLOWFISH_CTX GCDi_BlowfishInitTableDS;
// Function Prototype ------------------------------------------------------------------------
// Blowfish 初期化
void InitBlowfish(BLOWFISH_CTX *ctx, const unsigned char *key, int keyLen);
// Blowfish 復号化
void EncryptByBlowfish(const BLOWFISH_CTX *ctx, u32 *xl, u32 *xr);
// Blowfish 暗号化
void DecryptByBlowfish(const BLOWFISH_CTX *ctx, u32 *xl, u32 *xr);
// Key Table の生成
void GCDm_MakeBlowfishTableDS(BLOWFISH_CTX *tableBufp, ROM_Header_Short *rhs, u32 *keyBufp, s32 keyLen);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // FIRM_GCD_BLOWFISH_H

View File

@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------*
Project: TwlSDK
File:
*---------------------------------------------------------------------------*/
#ifndef __DSCARD_TYPE1_H__
#define __DSCARD_TYPE1_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <twl.h>
#include "Card.h"
// ===========================================================================
// Function Describe
// ===========================================================================
// ■ ノーマルモードのコマンド ■
// DSカードType1のーマルモードのID読み込み
void ReadIDNormal_DSType1(CardBootData *cbd);
// DSカードType1のーマルモードのBoot Segment(4Kbyte)読み込み
void ReadBootSegNormal_DSType1(CardBootData *cbd);
// DSカードType1のーマルモードのモード変更
void ChangeModeNormal_DSType1(CardBootData *cbd);
// ■ セキュアモードのコマンド ■
// DSカードType1のセキュアモードのID読み込み
void ReadIDSecure_DSType1(CardBootData *cbd);
// DSカードType1のセキュアモードのSecure Segment(16Kbyte)読み込み
void ReadSegSecure_DSType1(CardBootData *cbd);
// DSカードType1のセキュアモードのPNジェネレータON
void SwitchONPNGSecure_DSType1(CardBootData *cbd);
// DSカードType1のセキュアモードのPNジェネレータOFF
void SwitchOFFPNGSecure_DSType1(CardBootData *cbd);
// DSカードType1のセキュアモードのモード変更
void ChangeModeSecure_DSType1(CardBootData *cbd);
// ■ ゲームモードのコマンド ■
// DSカードType1のゲームモードのID読み込み
void ReadIDGame_DSType1(CardBootData *cbd);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // __DSCARD_TYPE1_H__

View File

@ -0,0 +1,435 @@
/*---------------------------------------------------------------------------*
Project: TwlSDK
File: Card.c
Copyright 2007 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 <nitro/card/types.h>
#include "blowfish.h"
#include "Card.h"
#include "dsCardType1.h"
// define -------------------------------------------------------------------
#define STACK_SIZE 1024 // スタックサイズ
#define MC_THREAD_PRIO 11 // カード電源ON → ゲームモードのスレッド優先度
// Function prototype -------------------------------------------------------
static BOOL IsCardExist(void);
static void SetInterruptCallback( OSIrqMask intr_bit, OSIrqFunction func );
static void SetInterruptCallbackEx( OSIrqMask intr_bit, void *func );
static void SetInterrupt(void);
static void InterruptCallbackCard(void);
static void InterruptCallbackCardDet(void);
static void InterruptCallbackCardData(void);
static void McThread(void *arg);
static void McPowerOn(void);
static void SetMCSCR(void);
static void ShowRegisterData(void);
static void ShowRomHeaderData(void);
// Static Values ------------------------------------------------------------
static u64 s_MCStack[STACK_SIZE / sizeof(u64)];
static OSThread s_MCThread;
static u32 s_SecureSegBufSize, s_BootSegBufSize;
static u32 *s_pSecureSegBuffer; // カード抜けてもバッファの場所覚えとく
static BootSegmentData *s_pBootSegBuffer; // カード抜けてもバッファの場所覚えとく
static CardBootData s_cbData;
static CardBootFunction s_funcTable[] = {
{ReadIDNormal_DSType1, ReadBootSegNormal_DSType1, ChangeModeNormal_DSType1,
ReadIDSecure_DSType1, ReadSegSecure_DSType1, SwitchONPNGSecure_DSType1, ChangeModeSecure_DSType1,
ReadIDGame_DSType1}
};
// ===========================================================================
// Function Describe
// ===========================================================================
/*---------------------------------------------------------------------------*
Name: Card_Init
Arguments: None.
Returns: None.
*---------------------------------------------------------------------------*/
void Card_Init(void)
{
OS_InitTick();
OS_InitThread();
// 割り込みマスクの設定
SetInterrupt();
// 割り込みの有効化
(void)OS_EnableIrq();
(void)OS_EnableInterrupts();
#ifdef SDK_ARM7
// チャッタリングカウンタの値を設定
reg_MI_MC1 = (u32)((reg_MI_MC1 & 0xffff) | 0xfff0000);
// Counter-Aの値を設定
reg_MI_MC2 = 0xfff;
#endif
// カードブート用スレッドの生成
OS_CreateThread(&s_MCThread,
McThread,
NULL,
s_MCStack + STACK_SIZE / sizeof(u64),
STACK_SIZE,
MC_THREAD_PRIO
);
// スレッド起動
OS_WakeupThreadDirect(&s_MCThread);
// カードブート用構造体の初期化
MI_CpuClear32(&s_cbData, sizeof(CardBootData));
}
/* -----------------------------------------------------------------
* Card_Boot関数
*
*
*
* BootSegmentBuffer SecureSegmentBufferの設定を行ってから
*
* ----------------------------------------------------------------- */
void Card_Boot(void)
{
OS_TPrintf("---------------- Card Boot Start ---------------\n");
// カード電源ON
McPowerOn();
// VAE・VBI・VD値の設定
s_cbData.vae = VAE_VALUE;
s_cbData.vbi = VBI_VALUE;
s_cbData.vd = VD_VALUE;
// セキュア領域の読み込みセグメント先頭番号(Segment4 Segment 7)
s_cbData.secureSegNum = 4;
// バッファを設定
s_cbData.pBootSegBuf = s_pBootSegBuffer;
s_cbData.pSecureSegBuf = s_pSecureSegBuffer;
if(IsCardExist()){
// ---------------------- Normal Mode ----------------------
// カードID読み込み
s_funcTable[0].ReadID_N(&s_cbData);
// Boot Segment読み込み
s_funcTable[0].ReadBootSegment_N(&s_cbData);
// TWLカードかNTRカードか判定 (Platform code : bit0 : not support NTR, bit1 : support TWL)
if(s_cbData.pBootSegBuf->rh.s.platform_code & 0x02){
OS_TPrintf("TWL Card.\n");
s_cbData.twlFlg = TRUE;
}
// Key Table初期化
GCDm_MakeBlowfishTableDS(&s_cbData.keyTable, &s_pBootSegBuffer->rh.s, s_cbData.keyBuf, 8);
// セキュアモードに移行
s_funcTable[0].ChangeMode_N(&s_cbData);
// ---------------------- Secure Mode ----------------------
// PNG設定
s_funcTable[0].SetPNG_S(&s_cbData);
// DS側符号生成回路初期値設定 (レジスタ設定)
SetMCSCR();
// ID読み込み
s_funcTable[0].ReadID_S(&s_cbData);
// Secure領域のSegment読み込み
s_funcTable[0].ReadSegment_S(&s_cbData);
// ゲームモードに移行
s_funcTable[0].ChangeMode_S(&s_cbData);
// ---------------------- Game Mode ----------------------
// ID読み込み
s_funcTable[0].ReadID_G(&s_cbData);
OS_TPrintf("-----------------------------------------------\n\n");
}
else{
OS_TPrintf("Card Not Found\n");
}
}
/* -----------------------------------------------------------------
* IsCardExist関数
*
*
*
* SCFG_MC1のSlot B
*
* 10 ()
Slot A if((reg_MI_MC1 & 0x0c) == 0x08)
Slot B if((reg_MI_MC1 & 0xc0) == 0x80)
* ----------------------------------------------------------------- */
static BOOL IsCardExist(void)
{
if((reg_MI_MC1 & SLOT_STATUS_MODE_SELECT_MSK) == SLOT_STATUS_MODE_10){
return TRUE;
}
else{
return FALSE;
}
}
/* -----------------------------------------------------------------
* Card_SetBootSegmentBuffer関数
*
* Boot Segment
*
*
* ----------------------------------------------------------------- */
void Card_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);
}
/* -----------------------------------------------------------------
* Card_SetSecureSegmentBuffer関数
*
* Secure Segment
*
*
* ----------------------------------------------------------------- */
void Card_SetSecureSegmentBuffer(void* buf, u32 size)
{
SDK_ASSERT(size > SECURE_SEGMENT_SIZE);
s_pSecureSegBuffer = (u32 *)buf;
s_SecureSegBufSize = size;
s_cbData.pSecureSegBuf = s_pSecureSegBuffer;
// バッファの初期化
MI_CpuClear8(s_pSecureSegBuffer, size);
}
/* -----------------------------------------------------------------
* McThread B
* ----------------------------------------------------------------- */
static void McThread(void *arg)
{
#pragma unused( arg )
while(1){
OS_SleepThread(NULL);
// カードブート
Card_Boot();
}
}
/* -----------------------------------------------------------------
* McPowerOn関数
* ----------------------------------------------------------------- */
static void McPowerOn(void)
{
OSTick start;
// SCFG_MC1 の Slot2 Status の M1,M0 を 01 にする
reg_MI_MC1 = (u32)((reg_MI_MC1 & (~SLOT_STATUS_MODE_SELECT_MSK)) | SLOT_STATUS_MODE_01);
// 100ms待ち
start = OS_GetTick();
while(OS_TicksToMilliSeconds(OS_GetTick()-start) < 100){}
// SCFG_MC1 の Slot2 Status の M1,M0 を 10 にする
reg_MI_MC1 = (u32)((reg_MI_MC1 & (~SLOT_STATUS_MODE_SELECT_MSK)) | SLOT_STATUS_MODE_10);
// リセットをhighに (RESB = 1にする)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(1,1,0,1,1,1,1,1,1,1,1,1,1)) |
CNT1_FLD(0,0,1,0,0,0,0,0,0,0,0,0,0));
// 100ms待ち
start = OS_GetTick();
while(OS_TicksToMilliSeconds(OS_GetTick()-start) < 100){}
OS_TPrintf("MC Power ON\n");
}
/*---------------------------------------------------------------------------*
Name: SetMCSCR
Description:
sPNG_ONコマンドを実行してから呼び出してください
*---------------------------------------------------------------------------*/
static void SetMCSCR(void)
{
u32 pna_l = (u32)(PNA_BASE_VALUE | (s_cbData.vd << 15));
u32 pna_h = (u32)(s_cbData.vd >> 17);
// SCR A
reg_MCSCR0 = pna_l;
// SCR B
reg_MCSCR1 = PNB_L_VALUE;
// [d0 -d6 ] -> SCR A
// [d16-d22] -> SCR B
reg_MCSCR2 = (u32)(pna_h | PNB_H_VALUE << 16);
// MCCNT1 レジスタ設定 (SCR = 1に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(1,1,1,1, 1,1, 1,1, 1, 0,1,1, 1)) |
CNT1_FLD(0,0,0,0, 0,0, 0,0, 0, 1,0,0, 0));
}
/*---------------------------------------------------------------------------*
Name: InterruptCallbackCard
InterruptCallbackCardDet
InterruptCallbackCardData
Description:
*---------------------------------------------------------------------------*/
// カードB抜け
static void InterruptCallbackCard(void)
{
// Mを 10 から 11 に遷移
reg_MI_MC1 = (u32)((reg_MI_MC1 & (~SLOT_STATUS_MODE_SELECT_MSK)) | SLOT_STATUS_MODE_11);
// カードブート用構造体の初期化
MI_CpuClear32(&s_cbData, sizeof(CardBootData));
// バッファの初期化
MI_CpuClear8(s_pBootSegBuffer, s_BootSegBufSize);
MI_CpuClear8(s_pSecureSegBuffer, s_SecureSegBufSize);
// MC_CNT1を初期化
reg_MCCNT1 = 0x0;
#ifdef USE_SLOT_A
OS_SetIrqCheckFlagEx(OS_IE_CARD_A_IREQ);
#else
OS_SetIrqCheckFlagEx(OS_IE_CARD_B_IREQ);
#endif
}
// カードB挿し
static void InterruptCallbackCardDet(void)
{
// カードブートスレッドを起動する
OS_WakeupThreadDirect(&s_MCThread);
#ifdef USE_SLOT_A
OS_SetIrqCheckFlagEx(OS_IE_CARD_A_DET);
#else
OS_SetIrqCheckFlagEx(OS_IE_CARD_B_DET);
#endif
}
// カードB データ転送終了
static void InterruptCallbackCardData(void)
{
#ifdef USE_SLOT_A
OS_SetIrqCheckFlagEx(OS_IE_CARD_A_DATA);
#else
OS_SetIrqCheckFlagEx(OS_IE_CARD_B_DATA);
#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)
{
#ifdef USE_SLOT_A
SetInterruptCallback( OS_IE_CARD_A_IREQ , InterruptCallbackCard );
SetInterruptCallback( OS_IE_CARD_A_DET , InterruptCallbackCardDet );
SetInterruptCallback( OS_IE_CARD_A_DATA , InterruptCallbackCardData );
#else
SetInterruptCallback( OS_IE_CARD_B_IREQ , InterruptCallbackCard );
SetInterruptCallback( OS_IE_CARD_B_DET , InterruptCallbackCardDet );
SetInterruptCallback( OS_IE_CARD_B_DATA , InterruptCallbackCardData );
#endif
}
// **************************************************************************
//
// Debug用表示関数
//
// **************************************************************************
/*---------------------------------------------------------------------------*
Name: ShowRomHeaderData
Description:
*---------------------------------------------------------------------------*/
static void ShowRomHeaderData(void)
{
OS_TPrintf("Rom Header Data -------------------------------\n");
OS_TPrintf("titleName : %s\n", s_pBootSegBuffer->rh.s.title_name);
OS_TPrintf("initialCode : %x\n", *(u32 *)s_pBootSegBuffer->rh.s.game_code);
OS_TPrintf("-----------------------------------------------\n");
}
/*---------------------------------------------------------------------------*
Name: ShowRegisterData
Description:
*---------------------------------------------------------------------------*/
static void ShowRegisterData(void)
{
OS_TPrintf("----------------------------------------------------------\n");
OS_TPrintf("拡張機能制御レジスタ (MC_B(d24)) : %08x\n", reg_SCFG_EXT);
OS_TPrintf("MC I/F制御レジスタ (slot status) : %08x\n", reg_MI_MC1);
OS_TPrintf("MC I/F制御レジスタ (Counter-A) : %04x\n", reg_MI_MC2);
OS_TPrintf("MC コントロールレジスタ0 (SEL etc) : %04x\n", reg_MCCNT0);
OS_TPrintf("MC コントロールレジスタ1 (START etc) : %08x\n", reg_MCCNT1);
OS_TPrintf("----------------------------------------------------------\n");
}

View File

@ -0,0 +1,206 @@
/*---------------------------------------------------------------------------*
Project: TwlBrom - libraries - GCD
File: blowfish.c
Copyright 2007 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 "blowfish.h"
#define MAXKEYBYTES 56 /* 448 bits */
#define N 16
// Function Prototype -------------------------------------------------------
static u32 F(const BLOWFISH_CTX *ctx, u32 x);
static void GCDi_InitBlowfishKeyAndTableDS(BLOWFISH_CTX *ctx, u32 *keyBufp, s32 keyLen);
//*****************************************
//
// GCDm_MakeBlowfishTableDSŠÖ<C5A0>
//
//*****************************************
void GCDm_MakeBlowfishTableDS(BLOWFISH_CTX *tableBufp, ROM_Header_Short *rhs, u32 *keyBufp, s32 keyLen)
{
const BLOWFISH_CTX *blowfishInitTablep = &GCDi_BlowfishInitTableDS;
u32 blowfishedKey[2];
MI_CpuCopy32((void *)blowfishInitTablep, (void *)tableBufp, sizeof(BLOWFISH_CTX));
keyBufp[0] = *(u32 *)rhs->game_code;
keyBufp[1] = *(u32 *)rhs->game_code >> 1;
keyBufp[2] = *(u32 *)rhs->game_code << 1;
GCDi_InitBlowfishKeyAndTableDS(tableBufp, keyBufp, keyLen);
blowfishedKey[0] = (u32)rhs->ctrl_reserved_B[0];
blowfishedKey[1] = *(u32 *)&rhs->ctrl_reserved_B[4];
OS_TPrintf("Blowfish - key[0]:%d key[1]:%d\n",blowfishedKey[0],blowfishedKey[1]);
DecryptByBlowfish(tableBufp, &(blowfishedKey)[1], &(blowfishedKey)[0]);
GCDi_InitBlowfishKeyAndTableDS(tableBufp, keyBufp, keyLen);
}
//*****************************************
//
// GCDi_InitBlowfishKeyAndTableDSŠÖ<C5A0>
//
//*****************************************
static void GCDi_InitBlowfishKeyAndTableDS(BLOWFISH_CTX *ctx, u32 *keyBufp, s32 keyLen)
{
EncryptByBlowfish(ctx, &(keyBufp)[2], &(keyBufp)[1]);
EncryptByBlowfish(ctx, &(keyBufp)[1], &(keyBufp)[0]);
InitBlowfish(ctx, (u8 *)keyBufp, keyLen);
}
//*****************************************
//
// InitBlowfishŠÖ<C5A0>
//
//*****************************************
void InitBlowfish(BLOWFISH_CTX *ctx, const unsigned char *key, int keyLen)
{
int i, j, k;
u32 data, datal, datar;
j = 0;
for (i = 0; i < N + 2; ++i) {
data = 0x00000000;
for (k = 0; k < 4; ++k) {
data = (data << 8) | key[j];
j = j + 1;
if (j >= keyLen)
j = 0;
}
ctx->P[i] = ctx->P[i] ^ data;
}
datal = 0x00000000;
datar = 0x00000000;
for (i = 0; i < N + 2; i += 2) {
EncryptByBlowfish(ctx, &datal, &datar);
ctx->P[i] = datal;
ctx->P[i + 1] = datar;
}
for (i = 0; i < 4; ++i) {
for (j = 0; j < 256; j += 2) {
EncryptByBlowfish(ctx, &datal, &datar);
ctx->S[i][j] = datal;
ctx->S[i][j + 1] = datar;
}
}
}
//*****************************************
//
// EncryptByBlowfishŠÖ<C5A0>
//
//*****************************************
void EncryptByBlowfish(const BLOWFISH_CTX *ctx, u32 *xl, u32 *xr)
{
u32 Xl;
u32 Xr;
u32 temp;
int i;
Xl = *xl;
Xr = *xr;
for (i = 0; i < N; ++i) {
Xl = Xl ^ ctx->P[i];
Xr = F(ctx, Xl) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[N];
Xl = Xl ^ ctx->P[N + 1];
*xl = Xl;
*xr = Xr;
}
//*****************************************
//
// DecryptByBlowfishŠÖ<C5A0>
//
//*****************************************
void DecryptByBlowfish(const BLOWFISH_CTX *ctx, u32 *xl, u32 *xr)
{
u32 Xl;
u32 Xr;
u32 temp;
int i;
Xl = *xl;
Xr = *xr;
for (i = N + 1; i > 1; --i) {
Xl = Xl ^ ctx->P[i];
Xr = F(ctx, Xl) ^ Xr;
/* Exchange Xl and Xr */
temp = Xl;
Xl = Xr;
Xr = temp;
}
/* Exchange Xl and Xr */
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[1];
Xl = Xl ^ ctx->P[0];
*xl = Xl;
*xr = Xr;
}
//*****************************************
//
// FŠÖ<C5A0>
//
//*****************************************
static u32 F(const BLOWFISH_CTX *ctx, u32 x) {
u32 a, b, c, d;
u32 y;
d = x & 0x00FF;
x >>= 8;
c = x & 0x00FF;
x >>= 8;
b = x & 0x00FF;
x >>= 8;
a = x & 0x00FF;
y = ctx->S[0][a] + ctx->S[1][b];
y = y ^ ctx->S[2][c];
y = y + ctx->S[3][d];
return y;
}

View File

@ -0,0 +1,393 @@
/*---------------------------------------------------------------------------*
Project: TwlSDK
File:
*---------------------------------------------------------------------------*/
#include <twl.h>
#include "blowfish.h"
#include "Card.h"
#include "dsCardType1.h"
// Function prototype -------------------------------------------------------
static void SetSecureCommand(SecureCommandType type, CardBootData *cbd);
static void SetMCSCR(void);
// ===========================================================================
// Function Describe
// ===========================================================================
// ■--------------------------------------■
// ■ ノーマルモードのコマンド ■
// ■--------------------------------------■
/*---------------------------------------------------------------------------*
Name: ReadIDNormal_DSType1
Description: DSカードType1のーマルモードのID読み込み
*---------------------------------------------------------------------------*/
void ReadIDNormal_DSType1(CardBootData *cbd)
{
cbd->id_nml = 0;
// MCCMD レジスタ設定
reg_MCCMD0 = 0x00000090;
reg_MCCMD1 = 0x00000000;
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 0 PC = 111(ステータスリード) latency1 = 2320(必要ないけど) に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 0,0,0, 0)) |
CNT1_FLD(1,0,0,0, 0,7, 0,0, 0, 0,0,0, 2320));
// MCCNTレジスタのRDYフラグをポーリングして、フラグが立ったらデータをMCD1レジスタに再度セット。スタートフラグが0になるまでループ。
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
cbd->id_nml = reg_MCD1;
}
OS_TPrintf("Nml Card B ID : %08x\n", cbd->id_nml);
}
/*---------------------------------------------------------------------------*
Name: ReadBootSegNormal_DSType1
Description: DSカードType1のーマルモードのBoot Segment読み込み
*---------------------------------------------------------------------------*/
void ReadBootSegNormal_DSType1(CardBootData *cbd)
{
#pragma unused( cbd )
u32 i = 0;
// MCCMD レジスタ設定
reg_MCCMD0 = 0x00000000;
reg_MCCMD1 = 0x00000000;
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 0 PC = 100 (8ページリード) に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 0,0,0, 0)) |
CNT1_FLD(1,0,0,0, 0,4, 0,0, 0, 0,0,0, 2320));
// MCCNTレジスタのRDYフラグをポーリングして、フラグが立ったらデータをMCD1レジスタに再度セット。スタートフラグが0になるまでループ。
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
*(cbd->pBootSegBuf->word + i++) = reg_MCD1;
}
OS_TPrintf("GameTitle : %s\n", cbd->pBootSegBuf->rh.s.title_name);
}
/*---------------------------------------------------------------------------*
Name: ChangeModeNormal_DSType1
Description: DSカードType1のーマルモードのモード変更
*---------------------------------------------------------------------------*/
void ChangeModeNormal_DSType1(CardBootData *cbd)
{
GCDCmd64 tempCnd, cnd;
u64 vae64 = cbd->vae;
// リトルエンディアンで作って
tempCnd.dw = cbd->vbi << 8;
tempCnd.dw |= vae64 << 32;
tempCnd.dw |= 0x3c00000000000000;
// ビックエンディアンにする
cnd.b[0] = tempCnd.b[7];
cnd.b[1] = tempCnd.b[6];
cnd.b[2] = tempCnd.b[5];
cnd.b[3] = tempCnd.b[4];
cnd.b[4] = tempCnd.b[3];
cnd.b[5] = tempCnd.b[2];
cnd.b[6] = tempCnd.b[1];
cnd.b[7] = tempCnd.b[0];
// MCCMD レジスタ設定
reg_MCCMD0 = *(u32 *)cnd.b;
reg_MCCMD1 = *(u32 *)&cnd.b[4];
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 1 PC = 000 に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 0,0,0, 0)) |
CNT1_FLD(1,1,0,0, 0,0, 0,0, 0, 0,0,0, 2320));
// MCCNTレジスタのRDYフラグをポーリングして、フラグが立ったらデータをMCD1レジスタに再度セット。スタートフラグが0になるまでループ。
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
}
OS_TPrintf("Mode Changed\n");
}
// ■--------------------------------------■
// ■ セキュアモードのコマンド ■
// ■--------------------------------------■
/*---------------------------------------------------------------------------*
Name: SetSecureCommand
Description:
*---------------------------------------------------------------------------*/
static void SetSecureCommand(SecureCommandType type, CardBootData *cbd)
{
GCDCmd64 cndLE, cndBE;
u64 data;
data = (type == S_PNG_ON) ? (u64)cbd->vd : (u64)cbd->vae;
cndLE.dw = cbd->vbi;
cndLE.dw |= data << 20;
// comannd0部分
switch(type){
case S_RD_ID:
cndLE.dw |= 0x1000000000000000;
break;
case S_PNG_ON:
cndLE.dw |= 0x4000000000000000;
break;
case S_PNG_OFF:
cndLE.dw |= 0x6000000000000000;
break;
case S_CHG_MODE:
cndLE.dw |= 0xa000000000000000;
break;
}
// コマンドの暗号化
EncryptByBlowfish( &cbd->keyTable, (u32*)&cndLE.b[4], (u32*)cndLE.b );
// ビッグエンディアンに直す(暗号化後)
cndBE.b[7] = cndLE.b[0];
cndBE.b[6] = cndLE.b[1];
cndBE.b[5] = cndLE.b[2];
cndBE.b[4] = cndLE.b[3];
cndBE.b[3] = cndLE.b[4];
cndBE.b[2] = cndLE.b[5];
cndBE.b[1] = cndLE.b[6];
cndBE.b[0] = cndLE.b[7];
// MCCMD レジスタ設定
reg_MCCMD0 = *(u32*)cndBE.b;
reg_MCCMD1 = *(u32*)&cndBE.b[4];
}
/*---------------------------------------------------------------------------*
Name: ReadIDSecure_DSType1
Description:
*---------------------------------------------------------------------------*/
void ReadIDSecure_DSType1(CardBootData *cbd)
{
// コマンド作成・設定
SetSecureCommand(S_RD_ID, cbd);
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定
// (START = 1 W/R = 0 TRM = 1 PC = 111(ステータスリード) CS = 1 SE = 1 DS = 1 Latency1 = 2320(0x910)に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,1, 1, 0,0,0, 0)) |
CNT1_FLD(1,0,0,1, 1,7, 0,0, 0, 0,1,1, 2320));
// MCCNTレジスタのRDYフラグをポーリングして、フラグが立ったらデータをMCD1レジスタに再度セット。スタートフラグが0になるまでループ。
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
cbd->id_scr = reg_MCD1;
}
// コマンドカウンタインクリメント
cbd->vbi++;
OS_TPrintf("Scr Card B ID : %08x\n", cbd->id_scr);
}
/*---------------------------------------------------------------------------*
Name: ReadSegSecure_DSType1
Description:
*---------------------------------------------------------------------------*/
void ReadSegSecure_DSType1(CardBootData *cbd)
{
u32 i,j;
u64 segNum = 4;
u64 vae = cbd->vae;
GCDCmd64 cndLE, cndBE;
OSTick start;
for(i=0; i<4; i++){
MI_CpuClear8(&cndLE, sizeof(GCDCmd64));
cndLE.dw = cbd->vbi;
cndLE.dw |= vae << 20;
cndLE.dw |= segNum << 44;
cndLE.dw |= 0x2000000000000000;
// コマンドの暗号化
EncryptByBlowfish( &cbd->keyTable, (u32*)&cndLE.b[4], (u32*)cndLE.b );
// ビッグエンディアンに直す(暗号化後)
cndBE.b[7] = cndLE.b[0];
cndBE.b[6] = cndLE.b[1];
cndBE.b[5] = cndLE.b[2];
cndBE.b[4] = cndLE.b[3];
cndBE.b[3] = cndLE.b[4];
cndBE.b[2] = cndLE.b[5];
cndBE.b[1] = cndLE.b[6];
cndBE.b[0] = cndLE.b[7];
// MCCMD レジスタ設定
reg_MCCMD0 = *(u32*)cndBE.b;
reg_MCCMD1 = *(u32*)&cndBE.b[4];
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定
// (START = 1 W/R = 0 TRM = 1 PC = 100(8ページリード) CS = 1 Latency2 = 24(0x18) SE = 1 DS = 1 Latency1 = 2296(0x8f8)に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,1, 0, 0,0,0, 0)) |
CNT1_FLD(1,0,0,1, 1,4, 0,0, 24, 0,1,1, 2296));
// MCCNTレジスタのRDYフラグをポーリングして、フラグが立ったらデータをMCD1レジスタに再度セット。スタートフラグが0になるまでループ。
j = (u32)(1024*(segNum - 4));
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
*(cbd->pSecureSegBuf + j++) = reg_MCD1;
}
// 読み込みセグメント番号インクリメント
segNum++;
// コマンドカウンタインクリメント
cbd->vbi++;
// 100ms待ち
start = OS_GetTick();
while(OS_TicksToMilliSeconds(OS_GetTick()-start) < 100){}
}
OS_TPrintf("Read Scr Segment 16Kbyte\n");
}
/*---------------------------------------------------------------------------*
Name: SwitchONPNGSecure_DSType1
Description:
*---------------------------------------------------------------------------*/
void SwitchONPNGSecure_DSType1(CardBootData *cbd)
{
// コマンド作成・設定
SetSecureCommand(S_PNG_ON, cbd);
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 1 TRM = 1 PC = 000 Latency1 = 2320(0x910) に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 1,0,0, 0)) |
CNT1_FLD(1,1,0,1, 0,0, 0,0, 0, 0,1,1, 2320));
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
}
// コマンドカウンタインクリメント
cbd->vbi++;
OS_TPrintf("PN Generator ON\n");
}
/*---------------------------------------------------------------------------*
Name: SwitchOFFPNGSecure_DSType1
Description:
*---------------------------------------------------------------------------*/
void SwitchOFFPNGSecure_DSType1(CardBootData *cbd)
{
// コマンド作成・設定
SetSecureCommand(S_PNG_OFF, cbd);
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 1 TRM = 1 PC = 000 Latency1 = 2320(0x910) に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 1,0,0, 0)) |
CNT1_FLD(1,1,0,1, 0,0, 0,0, 0, 0,1,1, 2320));
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
}
// コマンドカウンタインクリメント
cbd->vbi++;
OS_TPrintf("PN Generator OFF\n");
}
/*---------------------------------------------------------------------------*
Name: ChangeModeSecure_DSType1
Description:
*---------------------------------------------------------------------------*/
void ChangeModeSecure_DSType1(CardBootData *cbd)
{
// コマンド作成・設定
SetSecureCommand(S_CHG_MODE, cbd);
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 1 TRM = 1 PC = 000 Latency1 = 2320(0x910) に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 1,0,0, 0)) |
CNT1_FLD(1,1,0,1, 0,0, 0,0, 0, 0,1,1, 2320));
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
}
// コマンドカウンタインクリメント
cbd->vbi++;
OS_TPrintf("Change Mode\n");
}
// ■------------------------------------■
// ■ ゲームモードのコマンド ■
// ■------------------------------------■
/*---------------------------------------------------------------------------*
Name: ReadIDGame_DSType1
Description: IDを読み込む
*---------------------------------------------------------------------------*/
void ReadIDGame_DSType1(CardBootData *cbd)
{
// MCCMD レジスタ設定
reg_MCCMD0 = 0x000000B8;
reg_MCCMD1 = 0x00000000;
// MCCNT0 レジスタ設定 (E = 1 I = 1 SEL = 0に)
reg_MCCNT0 = (u16)((reg_MCCNT0 & 0x0fff) | 0xc000);
// MCCNT1 レジスタ設定 (START = 1 W/R = 0 PC = 111(ステータスリード) CS = 1 SE = 1 DS = 1 latency1 = 2320(必要ないけど) に)
reg_MCCNT1 = (u32)((reg_MCCNT1 & CNT1_MSK(0,0,1,0, 0,0, 1,0, 0, 0,0,0, 0)) |
CNT1_FLD(1,0,0,0, 0,7, 0,1, 0, 0,1,1, 2320));
// MCCNTレジスタのRDYフラグをポーリングして、フラグが立ったらデータをMCD1レジスタに再度セット。スタートフラグが0になるまでループ。
while(reg_MCCNT1 & START_FLG_MASK){
while(!(reg_MCCNT1 & READY_FLG_MASK)){}
cbd->id_gam = reg_MCD1;
}
OS_TPrintf("Gme Card B ID : %08x\n", cbd->id_gam);
}

View File

@ -0,0 +1,283 @@
/*---------------------------------------------------------------------------*
Project: TwlBrom - libraries - GCD
File: ds_blowfish_table.c
Copyright 2007 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 "blowfish.h"
const BLOWFISH_CTX GCDi_BlowfishInitTableDS = {
0x5f20d599, 0xb9f54457, 0xd9a4196e, 0x945a6a9e,
0xebf1aed8, 0x3ae27541, 0x32d08293, 0xd531ee33,
0x9a6157cc, 0x1ba20637, 0xf5723979, 0xbef6ae55,
0xfb691b5f, 0xe9f19de5, 0xa1d92cce, 0xe605325e,
0xcffed3fe, 0x0d0462d4 ,
0xb7ecf58b, 0xbb79602b, 0x0d319512, 0x2bda3f6e,
0xf1f08488, 0x257e123d, 0xbbf12245, 0x061a0624,
0x28dfad11, 0x3481648b, 0x2933eb2b, 0xbdf2aa99,
0x9d95149c, 0x8cf5f79f, 0x29a19772, 0xcf5fd19d,
0x1a074d66, 0x4b4ad3de, 0xa3a7c985, 0x3a059517,
0xbf0a493d, 0xa28b890a, 0xdd49824a, 0x0bf19027,
0x6a1cebe9, 0x05457683, 0x617081ba, 0xde4b3f17,
0x39abcfae, 0x563af257, 0x8aad1148, 0x3f45e140,
0x54029bfa, 0xfb93a6ca, 0x6ffe4def, 0x9c87d8a3,
0x48d5ba08, 0xfd2d8d6a, 0x74f8156e, 0x8b52bebd,
0x9e8a2218, 0x073774fb, 0x4a6c361b, 0x6242ba19,
0x109179b9, 0x9665677b, 0xe82302fe, 0x778c99ee,
0x64865c3e, 0x86786d4d, 0xe2654fa5, 0x5adfb21e,
0x087ed00a, 0xac71b014, 0x1c83dbbd, 0x62a1d7b9,
0x7c63c6cd, 0xe6c36952, 0x12ce75bf, 0x04215d44,
0x3cd3fbfa, 0xd4631138, 0x49418595, 0x08f20946,
0x1fdc1143, 0x6d15c076, 0x70633c1f, 0x6c8087ea,
0x8b63bdc3, 0x372137c2, 0x2309eedc, 0x4d6a372e,
0x50f79073, 0x921cac30, 0x91231004, 0xaa07d24f,
0x9a4f3e68, 0x6a6064c9, 0xf32114c8, 0x124122d6,
0xe6cf2444, 0x0ddd568a, 0x85e14d53, 0x5a528c1e,
0xc284199c, 0x6ff15703, 0x58be00e3, 0xd5ed4cf6,
0x1f9c6421, 0x3c0355be, 0xaaffdc4a, 0x5de0dac9,
0xdee6bf5e, 0xf8b1d8f5, 0xb9b336ff, 0xdb956762,
0xed375f31, 0x9967704c, 0x3118b590, 0x99993d6c,
0xd3da42e4, 0xa0134225, 0x6c70d7ae, 0xc7cf55b1,
0x43d546d7, 0x443d1761, 0x8533e928, 0x93a2d0d5,
0x1f1225aa, 0x460bc5fb, 0x567697f5, 0x87bea645,
0xe86b94b1, 0x9933feb1, 0x6c3e1fae, 0x091d7139,
0xe4379000, 0x74753e10, 0x3b838cff, 0xf9b0f1b0,
0x42470501, 0xacd6f195, 0x9ee6387e, 0x3f267495,
0x185068b4, 0xb43043d0, 0x68e34b4c, 0xb64de5bf,
0xa00a8b95, 0x77322574, 0x2cf7a1cf, 0x5a1371d8,
0x51c9eaab, 0xefee0de8, 0x197e93e9, 0x38431ea7,
0xa12c1681, 0xcc73e348, 0xd36c2129, 0xd9a0ce5d,
0xa0437161, 0x64b51315, 0x192acf92, 0xa5b7addc,
0xf865869f, 0xfbe79f1a, 0x13b8fdf7, 0x6fdb276c,
0xf71c35df, 0x9b5b2c8d, 0x6438ab12, 0x31decc06,
0x11754ee8, 0xeafae364, 0xc25434eb, 0xeb343fad,
0x267d2c93, 0xf3569d36, 0xb3f6e15a, 0x9e4a6398,
0x9ae48332, 0x907d6084, 0xee0e132e, 0xa2364b93,
0x3816ec85, 0x020688e8, 0x3aa0f0bf, 0x9a6ad7ed,
0xcf57e173, 0xdcb844f8, 0xd159232e, 0x715295df,
0x4ba06199, 0x786e7fd5, 0x30c5a9ba, 0x328640d3,
0x9c0c329d, 0x2f02b737, 0xa99854ba, 0xc90413c4,
0xe7c8be8d, 0x2e50975d, 0x5922d693, 0x22bc270c,
0x20a7e092, 0x7f6f930f, 0xb5d39f4c, 0x740b2aa6,
0x107d4967, 0xc5d1cb26, 0x8ce77186, 0x5be99ca0,
0x01f61ab2, 0x5e9e8cee, 0xdb1af283, 0x84eae5e6,
0x7cd27659, 0x49a58df6, 0x16c24836, 0xa383bb52,
0x0c07b974, 0x2861ff3b, 0xe4e961e1, 0xaa156eef,
0x5de8ba4e, 0x32bb9605, 0x72fbb056, 0xc80e0f52,
0x76652542, 0xdef2af89, 0x01f02710, 0x97a7744b,
0x5426d507, 0x821f0954, 0x307d860a, 0x26b30e39,
0xbb570b9b, 0xaf310636, 0xd9fc79fd, 0x0c2b1030,
0xd79be1b3, 0xef5fdc7b, 0x4513f8d2, 0xbd75474d,
0x7e3c9646, 0xb53ef375, 0x3b9ac567, 0x6b295bb0,
0xc85b80de, 0x31b10515, 0xdd49ceb6, 0xaeb584ad,
0x3167dc60, 0x4efe3034, 0xa62f80bd, 0x213963bf,
0x7f35d986, 0x05226816, 0x2690e954, 0x516c078c,
0xd75531a4, 0x3ea80709, 0xc166532e, 0xc47bf2f8,
0xf1cf58f2, 0xe7a2c587, 0x87308f27, 0x6264a058,
0x88b91823, 0xc4cefa7c, 0x17adae98, 0xf35b4acc,
0x56d548e9, 0xc8f20dd3, 0xdb8c7392, 0xac562fd7,
0x6992f981, 0xf632c64d, 0x218dc0e6, 0x618076e2,
0x6cdcbc11, 0x6919af93, 0xb9bfd09b, 0x67029f31,
0x83ee51a3, 0x0c7b2206, 0x404249ab, 0x7d01d5b8,
0x55f75ece, 0x99c53953, 0x9f87d846, 0xb464f7ba,
0xa1fa9ae3, 0x1068906d, 0x548aca30, 0xc3609fa7,
0x0d6bf519, 0xe698517a, 0xb4514398, 0x4fe935d6,
0x7b0fdfc3, 0xbd5c2fd6, 0x1961153a, 0xaacb4bf1,
0xc9646ddc, 0x561ec6d3, 0x504c38ef, 0xcc758671,
0xe94e0d0d, 0x5d06f628, 0xd3aa1b70, 0x39a8cf45,
0x2ea695ac, 0xd422e4b4, 0x5f37a874, 0xcc047a48,
0xd8404ca5, 0x0828b428, 0x52721c0d, 0x477df041,
0x4e533a19, 0x6b628458, 0x818ab593, 0xdc0d4e21,
0xc6a23fb4, 0x402bc9fc, 0xe90438da, 0x6b865a5e,
0x8525220c, 0x7c8d1168, 0x55951d92, 0xbb8eab4d,
0xb7e6a6da, 0x5a32b651, 0x05dd4105, 0x50560a2a,
0xcc471791, 0xb57ee6c9, 0x73db4a61, 0x33c85167,
0x746edaf5, 0x37c3542e, 0x08af6d0d, 0x5f8a15e8,
0xcd2159e2, 0x060cdea8, 0x5f6b775a, 0x3e6518db,
0x78de50c8, 0xb382b8e0, 0x32724e5d, 0x34c14f07,
0xb796ba23, 0x28a44e67, 0xeb62341e, 0xe9706a2d,
0x70c4422f, 0x9c315a4e, 0x28475bf9, 0x6f71daaa,
0x78b31f38, 0x1c6b92c4, 0x9a35f69e, 0xbf0e4db7,
0x412918cc, 0x5d354803, 0xc62bd055, 0x605caf29,
0x5e8e6974, 0xbdd47c9b, 0x7d64447b, 0x695d923f,
0x4b001fb6, 0xcf3583d4, 0x174e647e, 0x2ed58dae,
0x4e12289a, 0x08492b2e, 0x46c6ae5c, 0x6141ae85,
0xd2826f1e, 0x1f163751, 0xa459f60b, 0xaf5aca9a,
0x8b33d40d, 0x84f16320, 0xcfcb5c80, 0xd3b9b408,
0x62bd0516, 0x569b3183, 0xba9f9851, 0xb2aa5bb2,
0xb52c6b22, 0x63fa48d4, 0xfa585f2b, 0x0964fa61,
0xb8e038bb, 0xa860929d, 0x0e6f670d, 0x010df537,
0xd477c29f, 0x73f1ecfe, 0x7de03930, 0xe49861f5,
0x0455282c, 0x2fdb5556, 0x58e5ec6b, 0x8064b606,
0x4e1a2a6a, 0xc4d80f5b, 0x19522e0a, 0x30f562d9,
0x7b8cbe48, 0xa29b384f, 0xd3c9afc3, 0x4162c1c7,
0x2161b986, 0x4f996f57, 0x7bcebac1, 0x5e4d3bb5,
0x57448b8a, 0x705f135f, 0x47295b6d, 0xece238dc,
0x12655504, 0x4317e82a, 0x2add8ee1, 0xf794e2b3,
0xe65c6e09, 0x6df88aeb, 0x48544989, 0xbfad2ff5,
0xca4b94ea, 0x828739fc, 0xf2018a5f, 0x71e6f275,
0xde42d8d6, 0x281d2df1, 0xa37e88a6, 0x301d47a0,
0xdf71a3d9, 0x01cb1c49, 0xf2b136f8, 0x5d5822f0,
0xa0bd6b45, 0x4288b2bb, 0xce288cc7, 0x6390e893,
0x897c9008, 0xb77df53c, 0x554f2d04, 0x7efd1651,
0xc1bee879, 0xf8d412f2, 0x230584b4, 0x2bd2cca0,
0xadabe1fd, 0x6c55d10d, 0x4d944123, 0x054f3777,
0x17bf0c28, 0x6c6712b3, 0xf75ac38c, 0x6d2a8441,
0x271294d0, 0x9cedb42c, 0x8247ec4d, 0xb967d597,
0x55c09d1b, 0x8ee57e07, 0x3ee7a8e2, 0x3a0ee412,
0x3455452a, 0x5a2df9a2, 0x7c52ab1b, 0x555f1083,
0x435af1d2, 0xa4a7c62b, 0xe8951589, 0xf89d4bb4,
0x609fe375, 0xe6d65b78, 0x21e6440d, 0x2247bd06,
0xad00a453, 0x8513438d, 0xfcaaf739, 0xed7baf38,
0x542be4fc, 0xfc4c9850, 0xdff78085, 0xe122803c,
0x24deda94, 0x397ab0c6, 0xa10fdc38, 0x6ff9f4a7,
0x8b571863, 0x2e2a4184, 0xd9f253d4, 0xddd00f00,
0xa6196e99, 0x5becd00a, 0xc0ab2458, 0xec6506cb,
0x9438131a, 0x2f03670a, 0x77e3f73f, 0xc6337744,
0xe3d03914, 0x7908a2c0, 0x579940bb, 0x90010b41,
0x48cce1cd, 0xafb3db67, 0x4cf37488, 0xb1728f82,
0xc42923b5, 0xfc196c12, 0x9ca4468e, 0x876525c4,
0x8abe6dd3, 0x38031193, 0xf32b83ed, 0xea93a446,
0x1d85533b, 0x08f1d4ce, 0xfced2783, 0xbc181a9b,
0xdcae8bf9, 0x3850ab24, 0x104b72e9, 0x467b1722,
0x6459ab5d, 0xf8ae40f3, 0xf9c8e5bb, 0x554e0326,
0xfeebeb7d, 0xe0e639f7, 0x2ebe110a, 0xed98ff28,
0x5642c9c0, 0x00fdc342, 0xa287aff6, 0x323f015b,
0x9a954792, 0x3d32a572, 0x9bd06bae, 0x9249d207,
0xfa4a78e3, 0xf27d06a1, 0x7477cf41, 0x0cb21404,
0x16648486, 0xa151bbd5, 0xd1f16fe5, 0x5ff7e2f2,
0xb84d2058, 0xddcfc757, 0x76bed8c5, 0x7e5ff63d,
0x888b2ae7, 0x3f381b24, 0x7723410e, 0xd44bf0f5,
0xa4fa1f0c, 0xcf5f800b, 0xdae0f645, 0x5359342f,
0x523c20fb, 0xb5355e62, 0x608bfe62, 0x5a86e363,
0xd16e1a15, 0x32bc4547, 0x3867ebb4, 0x336ee4ab,
0xa3edb53a, 0x4ee067ad, 0x62ee9541, 0x1d267162,
0x3062ef31, 0xac82d7af, 0x0405dcc2, 0xbf0797f5,
0x07235911, 0xe80264c0, 0xaf3ee597, 0xa659ac18,
0x90334a8b, 0x9c7c6e1c, 0x3c4c7e20, 0xbb64613e,
0x7e7c6bc5, 0x4cc59f3e, 0xf573ea9f, 0x4cc089d7,
0x2df4fbf4, 0x511b14ec, 0xc812c1d5, 0x4a0bdf10,
0x93bc9c8b, 0x3e3e6a45, 0xbaa9c17d, 0x07b4c1cd,
0x8668e1e4, 0x386db243, 0x5c0cfbf3, 0xde713766,
0xa06eef56, 0xa7654010, 0xbed0f798, 0x3637c80e,
0x7cca10ec, 0x1e84ab9c, 0x02761705, 0xaa524f1c,
0xa0c6c15f, 0x04d8b956, 0xa74d4484, 0x60ded859,
0x050e38e6, 0x3be1038f, 0x3304816d, 0xce0b306f,
0x33210569, 0x89bb26fb, 0x87aeb67d, 0xe007517e,
0x0a96f7ac, 0x5cc4f96b, 0x4744e41d, 0xe3fa5eb8,
0x42558478, 0xf75e484b, 0x8635477d, 0x05432b1d,
0xb88aec03, 0x763c061e, 0x431a480c, 0xed8ab7a7,
0x43c6131e, 0xdbef10ee, 0x833cfbec, 0xef4495b2,
0x4e5154d8, 0x1d44112d, 0x1e5936fb, 0xc3c1347a,
0x610057ca, 0x16a567ea, 0x55d0559b, 0x36d97fe1,
0xae7640d2, 0xb0ce01dc, 0xcbd5837a, 0x6bec9820,
0x349272c1, 0x375782f3, 0x36328a62, 0xae43900c,
0x789b5cae, 0x0265138e, 0xc17168fd, 0xa031b0fe,
0xc3b08224, 0xa76979b1, 0xd0ebd2f5, 0xdc32c082,
0x3c26c79e, 0xc1988d6d, 0xd0d422bb, 0x3eec330f,
0xdce1ccb9, 0x36774c6a, 0xbff91c14, 0x5f289f81,
0x29328571, 0xc4487590, 0xd8ce4ab3, 0x2f148f44,
0xef5740fd, 0xd97508aa, 0x6ed6d146, 0xc31f5532,
0x1f84fe18, 0xffd584fc, 0x481b5e71, 0x0e9586c3,
0xd3270828, 0x7b718338, 0x5463804c, 0xacb0569a,
0x31ca80cf, 0xf3feef09, 0x7e24afbe, 0x3f53fea6,
0x334a8dc2, 0xa622d168, 0xea7bad66, 0xb043b6de,
0x009525a1, 0x46753fa3, 0xec441114, 0x92bc95d7,
0x16a94ff0, 0x60976253, 0xf1410f2a, 0xeebe2471,
0xcd087f94, 0x85b39360, 0x3f00075b, 0x83280fd8,
0x9f69d19a, 0xc32edad1, 0xb9a20190, 0x662a4e6b,
0xa6aeda9d, 0x68d32aea, 0x9c0c0c2f, 0xed4a8cd2,
0x65579ee2, 0xa387099d, 0x5d32c4b4, 0x2b32d4c9,
0x1e71e0b1, 0x90e64d64, 0x401ee371, 0x84f37ded,
0x78c8ed0e, 0x71c0ae76, 0x05bb7227, 0xfb6402ea,
0xb56b48f3, 0xed3f9342, 0xd253139f, 0xec2afef7,
0xdb25471d, 0xc686913c, 0xfd11f08e, 0xf7367423,
0x7a9ef5a4, 0x4450537e, 0xd3ca47d4, 0xe66d38eb,
0x7f9471d9, 0x4b69c64a, 0xea52f411, 0xb08afe22,
0x598b6736, 0x2a80e6e8, 0x130465eb, 0x9edcecee,
0x05ecb15f, 0x9fe6596a, 0x896b595e, 0xca1af7bf,
0x6a5bf944, 0xe4038571, 0x70e06229, 0xcfc4416f,
0xe3ccb1b2, 0xa807a67e, 0x847fe787, 0x4b52db93,
0xdd7eec6c, 0x104824d4, 0x60049f69, 0x1848e674,
0xb92ce4f3, 0x7a502e4f, 0x6954d4df, 0xf3a78b2b,
0xf31fffce, 0x3901263e, 0x89849517, 0x4b4cf0b0,
0xc49f9182, 0xa59dac4b, 0x2517af74, 0xd332cac9,
0x848a89bc, 0xae0dcc89, 0x9cdba27c, 0xee91786a,
0x4e5d76ea, 0x69f56087, 0x02d46715, 0x3648afcf,
0x6fbfea07, 0x8f062d66, 0xf9fe9ac4, 0x758790f6,
0x0fadf7b8, 0x3d5a1076, 0xb32eb059, 0xcc2c35c7,
0xcb2b5670, 0xc59637e3, 0x8a1b462f, 0x88c74622,
0x983226a7, 0x2286df61, 0x2f1cf48a, 0xaa09a187,
0xd3aea9cc, 0x1c4500bd, 0x8687549a, 0xffef8752,
0x8fa18f1e, 0x355c89c1, 0x3a2dda1b, 0xc2b2162c,
0x78e256f1, 0x97636bc1, 0xc98f56c5, 0xaa2c7f32,
0xaca8a6af, 0x88229120, 0x8b60e4de, 0x25424bf9,
0x9c7fe31a, 0x3a89192c, 0x36d4057e, 0xc25869cc,
0x2f8b32c1, 0x7aeb8590, 0xa1a55039, 0x66c59227,
0x584f20b0, 0x4383557e, 0x9ce2452b, 0x9012d8e4,
0x5683162c, 0xb3037916, 0x18612dad, 0x371f131a,
0x739ce1e2, 0xfdd5807b, 0xfc87512d, 0x1fd7aa7b,
0xaf8e7a2c, 0xcdbb8df4, 0x727c1195, 0xe26fee0b,
0x37deafb9, 0x8d8cde83, 0xb7670562, 0x568dc696,
0x62d70db6, 0x3646d6ba, 0xe6c88ebd, 0x106c2aea,
0x5b6bff14, 0x463c82fa, 0x464330b1, 0x9b7d8a51,
0x79833e92, 0xb25d555b, 0x90ce5e6c, 0x98538e62,
0xe56d0dc9, 0xc5cd572d, 0xe1ba5781, 0x728fb8e8,
0xdc134fe5, 0x15719dea, 0x8811b210, 0x7fd409d5,
0x2c7f655b, 0x114c383b, 0xfb8d5068, 0xbf59b09e,
0x4a898094, 0x12181ac5, 0x4ad15389, 0x8ce82910,
0xeab6ec1c, 0x8b17c746, 0xa8311525, 0xb1436ba2,
0x0bdbe29d, 0x11b09b87, 0xd2710e04, 0x82897729,
0x7f41660a, 0xff480b1d, 0xfd24bb72, 0x9ba148c2,
0xce7f7bfe, 0xd986db88, 0xb01c3b85, 0x0733a8dc,
0xe32e51bf, 0x97009a0e, 0x97c0061e, 0xb6d89d43,
0x6786c445, 0x88f8005f, 0x9e52a49a, 0x838aaac7,
0x18c5ec75, 0x2fc3ceae, 0x18f92b1a, 0xf51aaeff,
0x33b50b53, 0xe8fda751, 0x64a2e1a8, 0x431722b6,
0xd80acc80, 0x40ba3bae, 0x4a92d9d7, 0x1004df89,
0x2b189bee, 0x8a69776a, 0xb9f9f468, 0x6e1521a2,
0x033b1ee6, 0x609b3062, 0x9b257e41, 0x52c58f9e,
0xc2f80810, 0x1121a169, 0x795e3788, 0x10ff6635,
0xed6e1842, 0x1c6bb697, 0x6de5364e, 0xbfe4b47d,
0x05e0b920, 0xb8d5693a, 0xe0dcd5e3, 0x3e53acb9,
0xad57a407, 0x1848ff77, 0x49ac2a76, 0x75478e2a,
0x63679f6d, 0x398c3530, 0x6fd53905, 0xad5b3a64,
0x82bb0bca, 0xb1459952, 0x99363693, 0x442013af,
0x4402d836, 0x85923909, 0x974a4aff, 0xd763a687,
0x24b5b5c7, 0x6fb40fed, 0x1452580c, 0xd37ba6d9,
0x5838bc79, 0x843bbda1, 0x061ad806, 0xeaa86bfd,
0x0428694b, 0x9982ad37, 0x851b0efb, 0x735da8bd,
0x7558dccd, 0x6c63be0a, 0xe44ce748, 0x60042b30,
0xdad815b9, 0x8f758186, 0x1c8dd496, 0x7c85705d,
0xd57b671c, 0xcea66708, 0x70660a4b, 0xd463e5b7,
0xea828a5b, 0xe2ca6710, 0x8517eff4, 0x8a5f2a2f,
0x6af88297, 0xea1034d6, 0x3c5cc9eb, 0x46f849e1,
0xf6bddeeb, 0xaaf192a9, 0xb018a0a6, 0x1f0fd33a,
0x31ff6ff3, 0xd3444345, 0x88f79a50, 0xcec19609,
0x2cf2cc76, 0x82adba2c, 0x84188f77, 0x9c07d2c0,
0x4e839036, 0x434fa50b, 0x78ab043e, 0x09fbd64f,
0xda902401, 0x613a3c6f, 0x4a697f0d, 0x02302beb,
0x84e0dbb4, 0x35d7eca9, 0x857d37bf, 0x4ea9ce58,
0xa8c780e4, 0x486730d3, 0x2faf29eb, 0xa7b46a74,
0x923f0f3f, 0xaccaf3af, 0x94d94baf, 0x81ca43c0,
0xa1482f0d, 0xd2d527b0, 0x85054bef, 0x934ddea3,
0xbbf03c30, 0x27308f4a, 0x3ee3eb4c, 0x2f9aed64,
0xf082f13b, 0x7fcff4ba, 0xe1b0cb40, 0x57aabc7f,
0xf274c9d3, 0x220d43fa, 0x4e77f4d0, 0x7085d793,
0xb6bf991f, 0x30f135de, 0xf0715ea7, 0x7b2d016b,
0x5333f064, 0xf388390a, 0x6ba63a6b, 0x432fd235,
0xb5fd02cd, 0xaa5bbce9, 0x7e19a4d8, 0x81945d0e,
0xad776f9e, 0x93740ed6, 0x18c4e796, 0x19f5ad5f
};