mirror of
https://github.com/rvtr/TwlIPL.git
synced 2025-10-31 06:01:12 -04:00
VCK および VCW タイトルのバックアップデータ検証を追加
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@3039 b08762b0-b915-fc4b-9d8c-17b2551a87ff
This commit is contained in:
parent
d434b48745
commit
06fa1b3700
@ -32,6 +32,9 @@ SRCS = sysmenu_lib.c \
|
|||||||
device.c \
|
device.c \
|
||||||
keys.c \
|
keys.c \
|
||||||
title.c \
|
title.c \
|
||||||
|
SaveDataChecker/lgy_SaveDataChecker.c \
|
||||||
|
SaveDataChecker/lgy_VCK.c \
|
||||||
|
SaveDataChecker/lgy_VCW.c \
|
||||||
fs_wram.c \
|
fs_wram.c \
|
||||||
../common/src/status.c \
|
../common/src/status.c \
|
||||||
../common/src/pxi.c \
|
../common/src/pxi.c \
|
||||||
|
|||||||
@ -0,0 +1,198 @@
|
|||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Project: Horizon
|
||||||
|
File: lgy_SaveDataChecker.cpp
|
||||||
|
|
||||||
|
Copyright (C)2009-2011 Nintendo Co., Ltd. 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.
|
||||||
|
|
||||||
|
$Rev$
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <twl.h>
|
||||||
|
|
||||||
|
#include "lgy_SaveDataChecker.h"
|
||||||
|
#include "lgy_VCK.h"
|
||||||
|
#include "lgy_VCW.h"
|
||||||
|
|
||||||
|
// title.c より定義を拝借
|
||||||
|
#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB
|
||||||
|
#ifdef USE_HYENA_COMPONENT
|
||||||
|
#define WRAM_SLOT_FOR_FS 5
|
||||||
|
#else
|
||||||
|
#define WRAM_SLOT_FOR_FS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum GameCodeList
|
||||||
|
{
|
||||||
|
TARGET_ROM_VCK = 0,
|
||||||
|
TARGET_ROM_VCW,
|
||||||
|
TARGET_ROM_MAX
|
||||||
|
}GameCodeList;
|
||||||
|
|
||||||
|
char *game_code_list[TARGET_ROM_MAX] = { "VCK", "VCW" };
|
||||||
|
|
||||||
|
|
||||||
|
BOOL CheckBackupData( TitleProperty *rhs)
|
||||||
|
{
|
||||||
|
u8 list_num;
|
||||||
|
char test[5];
|
||||||
|
|
||||||
|
{
|
||||||
|
char* n = (char*)&rhs->titleID;
|
||||||
|
test[0] = n[3];
|
||||||
|
test[1] = n[2];
|
||||||
|
test[2] = n[1];
|
||||||
|
test[3] = n[0];
|
||||||
|
test[4] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for( list_num = 0; list_num < TARGET_ROM_MAX; list_num++)
|
||||||
|
{
|
||||||
|
if( 0 == STD_CompareNString( test, game_code_list[list_num], 3))
|
||||||
|
{
|
||||||
|
switch( list_num)
|
||||||
|
{
|
||||||
|
case TARGET_ROM_VCK:
|
||||||
|
return checkVCK( rhs);
|
||||||
|
case TARGET_ROM_VCW:
|
||||||
|
if( test[3] == 'V')
|
||||||
|
{
|
||||||
|
return checkVCW( rhs, 0x00800354);
|
||||||
|
}
|
||||||
|
else if( test[3] == 'F')
|
||||||
|
{
|
||||||
|
return checkVCW( rhs, 0x00800355);
|
||||||
|
}
|
||||||
|
else if( test[3] == 'E')
|
||||||
|
{
|
||||||
|
return checkVCW( rhs, 0x00400810);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InitializeBackup( void)
|
||||||
|
{
|
||||||
|
u16 lock_id;
|
||||||
|
|
||||||
|
if( HOTSW_isEnableHotSW())
|
||||||
|
{
|
||||||
|
HOTSW_InvalidHotSW();
|
||||||
|
OS_TPrintf( "HOTSW is enable, so HOTSW_InvalidHotSW is done.\n");
|
||||||
|
}
|
||||||
|
OS_TPrintf( "ok, HOTSW is not enable.\n");
|
||||||
|
|
||||||
|
if( !HOTSW_isFinalized())
|
||||||
|
{
|
||||||
|
OS_TPrintf( "HOTSW is not Finalized!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OS_TPrintf( "ok, HOTSW is Finalized.\n");
|
||||||
|
}
|
||||||
|
if( !HOTSW_isCardLoadCompleted())
|
||||||
|
{
|
||||||
|
OS_TPrintf( "HOTSW is not card load completed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OS_TPrintf( "ok, HOTSW is is card load completed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !CARD_IsAvailable())
|
||||||
|
{
|
||||||
|
CARD_Init();
|
||||||
|
OS_TPrintf( "CARD is not available, CARD_Init() is done.\n");
|
||||||
|
}
|
||||||
|
if( !CARD_IsEnabled())
|
||||||
|
{
|
||||||
|
CARD_Enable( TRUE);
|
||||||
|
OS_TPrintf( "CARD is not enable, CARD_Enable() is done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_id = (u16)OS_GetLockID();
|
||||||
|
CARD_LockBackup( lock_id);
|
||||||
|
if( !CARD_IdentifyBackup( CARD_BACKUP_TYPE_EEPROM_64KBITS))
|
||||||
|
{
|
||||||
|
OS_TPrintf( "CARD_IdentifyBackup failed.\n");
|
||||||
|
}
|
||||||
|
CARD_UnlockBackup( lock_id);
|
||||||
|
OS_TPrintf( "InitializeBackup done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeBackup( void)
|
||||||
|
{
|
||||||
|
// while( 1) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL readEEPROM( u32 src, void *dst, u32 len)
|
||||||
|
{
|
||||||
|
BOOL result;
|
||||||
|
u16 lock_id;
|
||||||
|
|
||||||
|
lock_id = (u16)OS_GetLockID();
|
||||||
|
CARD_LockBackup( lock_id);
|
||||||
|
/* CARD_ReadEeprom() は、 一時バッファ(CARDi_backup_cache_page_buf)に読み出したデータを
|
||||||
|
A9-CPUでdstへコピーしてくれるので、dstのメモリ空間はA7から見えなくても良い */
|
||||||
|
result = CARD_ReadEeprom( src, dst, len);
|
||||||
|
if( !result)
|
||||||
|
{
|
||||||
|
OS_TPrintf( "CARD_ReadEeprom failed! err:%d\n", (int)CARD_GetResultCode());
|
||||||
|
}
|
||||||
|
CARD_UnlockBackup( lock_id);
|
||||||
|
|
||||||
|
DC_FlushRange( dst, len);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL writeEEPROM( u32 dst, const void *src, u32 len)
|
||||||
|
{
|
||||||
|
BOOL result;
|
||||||
|
u16 lock_id;
|
||||||
|
|
||||||
|
DC_FlushRange( src, len);
|
||||||
|
|
||||||
|
lock_id = (u16)OS_GetLockID();
|
||||||
|
CARD_LockBackup( lock_id);
|
||||||
|
/* CARD_WriteEeprom() は、 src上のデータをA9-CPUで一時バッファ(CARDi_backup_cache_page_buf)に
|
||||||
|
コピーした上でデバイスに書き込んでいるので、srcのメモリ空間はA7から見えなくても良い */
|
||||||
|
result = CARD_WriteEeprom( dst, src, len);
|
||||||
|
if( !result)
|
||||||
|
{
|
||||||
|
OS_TPrintf( "CARD_WriteEeprom failed! err:%d\n", (int)CARD_GetResultCode());
|
||||||
|
}
|
||||||
|
CARD_UnlockBackup( lock_id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL writeAndVerifyEEPROM( u32 dst, const void *src, u32 len)
|
||||||
|
{
|
||||||
|
BOOL result;
|
||||||
|
u16 lock_id;
|
||||||
|
|
||||||
|
DC_FlushRange( src, len);
|
||||||
|
|
||||||
|
lock_id = (u16)OS_GetLockID();
|
||||||
|
CARD_LockBackup( lock_id);
|
||||||
|
/* CARD_WriteAndVerifyEeprom() は、 src上のデータをA9-CPUで一時バッファ(CARDi_backup_cache_page_buf)に
|
||||||
|
コピーした上で処理しているので、srcのメモリ空間はA7から見えなくても良い */
|
||||||
|
result = CARD_WriteAndVerifyEeprom( dst, src, len);
|
||||||
|
if( !result)
|
||||||
|
{
|
||||||
|
OS_TPrintf( "CARD_WriteAndVerifyEeprom failed! err:%d\n", (int)CARD_GetResultCode());
|
||||||
|
}
|
||||||
|
CARD_UnlockBackup( lock_id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Project: Horizon
|
||||||
|
File: lgy_SaveDataChecker.cpp
|
||||||
|
|
||||||
|
Copyright (C)2009-2011 Nintendo Co., Ltd. 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.
|
||||||
|
|
||||||
|
$Rev$
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef __LGY_SAVEDATACHECKER_CPP__
|
||||||
|
#define __LGY_SAVEDATACHECKER_CPP__
|
||||||
|
|
||||||
|
#include <twl.h>
|
||||||
|
#include <sysmenu.h>
|
||||||
|
|
||||||
|
BOOL CheckBackupData( TitleProperty *rhs);
|
||||||
|
|
||||||
|
void InitializeBackup( void);
|
||||||
|
void FinalizeBackup( void);
|
||||||
|
BOOL readEEPROM( u32 src, void *dst, u32 len);
|
||||||
|
BOOL writeEEPROM( u32 dst, const void *src, u32 len);
|
||||||
|
BOOL writeAndVerifyEEPROM( u32 dst, const void *src, u32 len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// cardnor_NspiIfApi.cpp
|
||||||
|
namespace nn {
|
||||||
|
namespace drivers {
|
||||||
|
namespace cardnor {
|
||||||
|
namespace CTR {
|
||||||
|
namespace ARM946ES{
|
||||||
|
|
||||||
|
void InitializeTwlBackup( void);
|
||||||
|
nn::Result ReadTwlEEPROM(u32 address, u32* buffer, size_t size);
|
||||||
|
nn::Result WriteTwlEEPROM(u32 address, const u32* buffer, size_t size);
|
||||||
|
void FinalizeTwlBackup( void);
|
||||||
|
|
||||||
|
} // end of namespace ARM946ES
|
||||||
|
} // end of namespace CTR
|
||||||
|
} // end of namespace cardnor
|
||||||
|
} // end of namespace drivers
|
||||||
|
} // end of namespace nn
|
||||||
|
*/
|
||||||
|
|
||||||
|
//nn::Result ReadTwlEEPROM(u32 address, u32* buffer, size_t size);
|
||||||
|
//nn::Result WriteTwlEEPROM(u32 address, const u32* buffer, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,256 @@
|
|||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Project: Horizon
|
||||||
|
File: lgy_VCK.cpp
|
||||||
|
|
||||||
|
Copyright (C)2009-2011 Nintendo Co., Ltd. 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.
|
||||||
|
|
||||||
|
$Rev$
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <twl.h>
|
||||||
|
#include <sysmenu.h>
|
||||||
|
#include "lgy_VCK.h"
|
||||||
|
#include "lgy_SaveDataChecker.h"
|
||||||
|
|
||||||
|
// title.c より定義を拝借
|
||||||
|
#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB
|
||||||
|
#ifdef USE_HYENA_COMPONENT
|
||||||
|
#define WRAM_SLOT_FOR_FS 5
|
||||||
|
#else
|
||||||
|
#define WRAM_SLOT_FOR_FS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VCK_BACKUP_READ_SIZE (896)
|
||||||
|
//NN_COMPILER_ASSERT(VCK_BACKUP_READ_SIZE >= sizeof(VCK_SlotHeader) + sizeof(VCK_ProfileSlotBody));
|
||||||
|
//NN_COMPILER_ASSERT(VCK_BACKUP_READ_SIZE % 32 == 0);
|
||||||
|
|
||||||
|
// checksum を算出する
|
||||||
|
static u16 getChecksum( void* data);
|
||||||
|
// データが工場出荷状態か破壊されていれば TRUE を返す
|
||||||
|
static BOOL isFactoryOrBrokenForVCK( TitleProperty* tp, void* data, u16* ret_checksum);
|
||||||
|
// データが正常範囲内に収まっていれば TRUE を返す
|
||||||
|
static BOOL checkEepromRangeForVCK( void* data);
|
||||||
|
|
||||||
|
//using namespace nn::drivers::cardnor::CTR::ARM946ES;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct TitleID_num
|
||||||
|
{
|
||||||
|
u32 Lo;
|
||||||
|
u32 Hi;
|
||||||
|
}
|
||||||
|
TitleID_num;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// チェックAPI(VCK*タイトル起動前にこれを呼べばOK)
|
||||||
|
BOOL checkVCK( TitleProperty* tp)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u16 tick;
|
||||||
|
u32 *data;
|
||||||
|
VCK_SlotHeader *header;
|
||||||
|
VCK_ProfileSlotBody *body;
|
||||||
|
u8 *body_u8;
|
||||||
|
u16 S_checksum = 0;
|
||||||
|
u16 B_checksum;
|
||||||
|
u32 calculatedSha1[ MATH_SHA1_DIGEST_SIZE / sizeof(u32)];
|
||||||
|
MATHRandContext16 rc16;
|
||||||
|
u32 rseed;
|
||||||
|
|
||||||
|
OS_TPrintf("check VCK backup start.\n");
|
||||||
|
OS_TPrintf( "header size:0x%x, body size:0x%x\n", sizeof(VCK_SlotHeader), sizeof(VCK_ProfileSlotBody));
|
||||||
|
|
||||||
|
// EEPROM から読み出し
|
||||||
|
data = (u32*)(MI_AllocWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9));
|
||||||
|
OS_TPrintf("Buffer:0x%x\n", data);
|
||||||
|
|
||||||
|
InitializeBackup();
|
||||||
|
readEEPROM( 0, (u32*)data, VCK_BACKUP_READ_SIZE);//sizeof(VCK_SlotHeader) + sizeof(VCK_ProfileSlotBody)が32Bytesの倍数でないため
|
||||||
|
header = (VCK_SlotHeader*)data;
|
||||||
|
body = (VCK_ProfileSlotBody*)((u8*)data + sizeof(VCK_SlotHeader));
|
||||||
|
body_u8 = (u8*)body;
|
||||||
|
|
||||||
|
// 工場出荷状態またはデータ破壊状態かどうか確認
|
||||||
|
if( !isFactoryOrBrokenForVCK( tp, data, &S_checksum))
|
||||||
|
{
|
||||||
|
if( checkEepromRangeForVCK( data)) // データ範囲を確認
|
||||||
|
{
|
||||||
|
OS_TPrintf("VCK backup is correct.\n");
|
||||||
|
FinalizeBackup();
|
||||||
|
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !S_checksum)
|
||||||
|
{
|
||||||
|
S_checksum = getChecksum( body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checksumがBになるようにランダムな1箇所へ書き込み
|
||||||
|
tick = OS_GetTickLo();
|
||||||
|
#if 1
|
||||||
|
{
|
||||||
|
MATH_CalcSHA1( calculatedSha1, (const void*)data, sizeof(VCK_ProfileSlotBody));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
rseed = (u32)(OS_GetTick()) + *(u32*)(calculatedSha1);
|
||||||
|
MATH_InitRand16( &rc16, rseed);
|
||||||
|
for( i=0; i<sizeof(VCK_ProfileSlotBody); i++)
|
||||||
|
{
|
||||||
|
body_u8[i] = (u8)(MATH_Rand16( &rc16, 0xFF));
|
||||||
|
}
|
||||||
|
B_checksum = getChecksum( body);
|
||||||
|
// 書き込んだ後の checksum が、S_checksum でも マジコンヘッダのchecksum にもならないようにする
|
||||||
|
while( (B_checksum == S_checksum) ||
|
||||||
|
( B_checksum == (0xFFFF - (header->m_uniqueIdentifier) - (header->m_slotCheckSum))))
|
||||||
|
{
|
||||||
|
B_checksum -= body_u8[sizeof(VCK_ProfileSlotBody) - 1];
|
||||||
|
body_u8[sizeof(VCK_ProfileSlotBody) - 1]++;
|
||||||
|
B_checksum += body_u8[sizeof(VCK_ProfileSlotBody) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup デバイスへ反映
|
||||||
|
if( writeAndVerifyEEPROM( 0, data, VCK_BACKUP_READ_SIZE))
|
||||||
|
{
|
||||||
|
OS_TPrintf("launch ok.\n");
|
||||||
|
OS_TPrintf("ckecksum:0x%x, B_checksum:0x%x\n", getChecksum(body), B_checksum);
|
||||||
|
FinalizeBackup();
|
||||||
|
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
OS_TPrintf("launch NG.\n");
|
||||||
|
OS_TPrintf("S_checksum:0x%x, ckecksum:0x%x, B_checksum:0x%x\n", S_checksum, getChecksum(body), B_checksum);
|
||||||
|
FinalizeBackup();
|
||||||
|
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checksum を算出する
|
||||||
|
static u16 getChecksum( void* data)
|
||||||
|
{
|
||||||
|
u8 *data_u8;
|
||||||
|
u16 checksum = 0;
|
||||||
|
u16 i;
|
||||||
|
|
||||||
|
data_u8 = (u8*)data;
|
||||||
|
|
||||||
|
for( i=0; i<sizeof(VCK_ProfileSlotBody); ++i)
|
||||||
|
{
|
||||||
|
checksum += data_u8[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// データが工場出荷状態か破壊されていれば TRUE を返す
|
||||||
|
static BOOL isFactoryOrBrokenForVCK( TitleProperty* tp, void* data, u16* ret_checksum)
|
||||||
|
{
|
||||||
|
VCK_SlotHeader *header;
|
||||||
|
u8* body;
|
||||||
|
u16 checksum, i;
|
||||||
|
u8* pTitle_id;
|
||||||
|
u8* pIdentifier;
|
||||||
|
|
||||||
|
header = (VCK_SlotHeader*)data;
|
||||||
|
body = (u8*)data + sizeof(VCK_SlotHeader);
|
||||||
|
pTitle_id = (u8*)&(tp->titleID); // TWL:0x56434B45, CTR:0x454B4356
|
||||||
|
pIdentifier = (u8*)&(header->m_uniqueIdentifier); // 0x56434B45
|
||||||
|
|
||||||
|
/* 工場出荷状態のチェック */
|
||||||
|
#if 1
|
||||||
|
for( i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
if( pTitle_id[i] != pIdentifier[i])
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, factory.\n", __FUNCTION__);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OS_TPrintf("%s, not factory.\n", __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 破壊のチェック */
|
||||||
|
checksum = 0;
|
||||||
|
for( i=0; i<sizeof(VCK_ProfileSlotBody); i++)
|
||||||
|
{
|
||||||
|
checksum += body[i];
|
||||||
|
}
|
||||||
|
OS_TPrintf("%s : S_checksum:0x%x\n", __FUNCTION__, checksum);
|
||||||
|
*ret_checksum = checksum; // checksumを返す
|
||||||
|
checksum += (u16)(header->m_uniqueIdentifier);
|
||||||
|
checksum += header->m_slotCheckSum;
|
||||||
|
if( checksum != 0xFFFF)
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, broken.\n", __FUNCTION__);
|
||||||
|
return TRUE; // broken
|
||||||
|
}
|
||||||
|
|
||||||
|
OS_TPrintf("%s, not broken.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// データが正常範囲内に収まっていれば TRUE を返す
|
||||||
|
static BOOL checkEepromRangeForVCK( void* data)
|
||||||
|
{
|
||||||
|
VCK_ProfileSlotBody *buf;
|
||||||
|
buf = (VCK_ProfileSlotBody*)((u8*)data + sizeof(VCK_SlotHeader));
|
||||||
|
|
||||||
|
if( buf->m_playerName[10] != '\0')
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, playerName is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( (buf->m_averageCookingTime < -1) || (buf->m_averageCookingTime > 2))
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, cookingTime is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( (buf->m_culinaryLevel < -1) || (buf->m_culinaryLevel > 2))
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, culinaryLevel is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( (buf->m_costImportance < -1) || (buf->m_costImportance > 2))
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, costImportance is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( (buf->m_numberCalories < -1) || (buf->m_numberCalories > 2))
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, numberCalories is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( buf->m_ROTD_index > 9)
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, ROTD_index is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( buf->m_uBirthDate_Day >0x1F)
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, birthdate_day is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( buf->m_uBirthDate_Month > 0x0C)
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, birthdate_month is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if( buf->m_numServings > 8)
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, numServings is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
OS_TPrintf("%s, good range.\n", __FUNCTION__);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
@ -0,0 +1,159 @@
|
|||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Project: Horizon
|
||||||
|
File: lgy_VCK.h
|
||||||
|
|
||||||
|
Copyright (C)2009-2011 Nintendo Co., Ltd. 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.
|
||||||
|
|
||||||
|
$Rev$
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef __LGY_VCK_H__
|
||||||
|
#define __LGY_VCK_H__
|
||||||
|
|
||||||
|
#include <twl.h>
|
||||||
|
#include <sysmenu.h>
|
||||||
|
|
||||||
|
enum E_CookingCoachSavegameSlot
|
||||||
|
{
|
||||||
|
CCSS_ProfileSlot, // 0x0000~0x0377
|
||||||
|
CCSS_ShoppingListSlot, // 0x0378~0x0BCF
|
||||||
|
CCSS_CommentSlot1, // 0x0BD0~0x0F03
|
||||||
|
CCSS_CommentSlot2, // 0x0F04~0x1237
|
||||||
|
CCSS_PhotoSlot, // 0x1238~0x1F76
|
||||||
|
CCSS_SlotCount
|
||||||
|
};
|
||||||
|
|
||||||
|
#define C_PROFILENAME_MAXLENGTH 11 // Include \0 character at the end
|
||||||
|
#define DATASAVE_MAX_INGREDIENTS 8
|
||||||
|
#define DATASAVE_MAX_SHOPPINGLIST_CUSTOMITEMS 10
|
||||||
|
#define DATASAVE_MAX_SHOPPINGLIST_RECIPEITEMS 75
|
||||||
|
#define MAX_SHOPPING_LIST_RECIPES 6
|
||||||
|
#define DATASAVE_NUM_CALENDARRECIPES 50
|
||||||
|
#define DATASAVE_MAX_ROTD 10
|
||||||
|
#define DATASAVE_NUM_RECIPECOMMENTS_PER_SLOT 7
|
||||||
|
#define DATASAVE_RECIPECOMMENT_LENGTH 114
|
||||||
|
//the favorites are stored in an array of u32 used as a bitfield. each bit represents
|
||||||
|
//ONE recipe. Thus, the maximum number of recipes that can be remembered in this array
|
||||||
|
//is expressed by DATASAVE_FAVORITE_RECIPES_MAXNUMRECIPES
|
||||||
|
#define DATASAVE_FAVORITE_RECIPES_NB_U32 10
|
||||||
|
#define DATASAVE_FAVORITE_RECIPES_MAXNUMRECIPES (8*4*DATASAVE_FAVORITE_RECIPES_NB_U32)
|
||||||
|
#define QUANTITY_BUFFER_SIZE 20
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct VCK_SlotHeader
|
||||||
|
{
|
||||||
|
u32 m_uniqueIdentifier;
|
||||||
|
u16 m_slotCheckSum;
|
||||||
|
u8 m_status;
|
||||||
|
u8 struct_padding;
|
||||||
|
}
|
||||||
|
VCK_SlotHeader;
|
||||||
|
|
||||||
|
typedef struct CalendarRecipe
|
||||||
|
{
|
||||||
|
u32 m_uDay;
|
||||||
|
u16 m_uRecipeID;
|
||||||
|
u8 m_recipeState;
|
||||||
|
}
|
||||||
|
CalendarRecipe;
|
||||||
|
|
||||||
|
typedef struct RecipeOfTheDay
|
||||||
|
{
|
||||||
|
u32 m_recipeID;
|
||||||
|
s32 m_dayProposed;
|
||||||
|
}
|
||||||
|
RecipeOfTheDay;
|
||||||
|
|
||||||
|
|
||||||
|
//EntryData is the base class for the two "slots" that will be saved individually.=
|
||||||
|
//the structs are defined in the base class just in case some of them must be used in
|
||||||
|
//both derived classes.
|
||||||
|
typedef struct VCK_ProfileSlotBody
|
||||||
|
{
|
||||||
|
//TODO : optimize the size of the EntryData structure
|
||||||
|
char m_playerName[C_PROFILENAME_MAXLENGTH]; // 11(0x08~0x12)
|
||||||
|
// 1(0x13)
|
||||||
|
s32 m_averageCookingTime; // 4(0x14~0x17) [取り得る値は -1,0,1,2のどれか]
|
||||||
|
s32 m_culinaryLevel; // 4(0x18~0x1B) [取り得る値は -1,0,1,2のどれか]
|
||||||
|
s32 m_costImportance; // 4(0x1C~0x1F) [取り得る値は -1,0,1,2のどれか]
|
||||||
|
s32 m_numberCalories; // 4(0x20~0x23) [取り得る値は -1,0,1,2のどれか]
|
||||||
|
u32 m_ingredientsExcluded[DATASAVE_MAX_INGREDIENTS]; // 32(0x24~0x43)
|
||||||
|
u32 m_ingredientsPrefered[DATASAVE_MAX_INGREDIENTS]; // 32(0x44~0x63)
|
||||||
|
CalendarRecipe m_calendarRecipes[DATASAVE_NUM_CALENDARRECIPES]; //400(0x64~0x1F3)
|
||||||
|
u16 m_uNbCalendarRecipes; // 2(0x1F4~0x1F5)
|
||||||
|
|
||||||
|
RecipeOfTheDay m_recipeOfTheDay[DATASAVE_MAX_ROTD]; // 80(0x1F8~0x247)
|
||||||
|
u32 m_ROTD_index; // 4(0x248~0x24B)
|
||||||
|
|
||||||
|
//---Music
|
||||||
|
s32 m_musicStyle; // (0x24C~0x24F) 取り得る値は -1,0,1,2,3のどれか
|
||||||
|
u32 m_musicLocation; // (0x250~0x253) 取り得る値は 0,1,2のどちらか
|
||||||
|
|
||||||
|
//---FAVORITES BIT FIELDS
|
||||||
|
u32 m_favoriteRecipes[DATASAVE_FAVORITE_RECIPES_NB_U32]; // 40(0x254)
|
||||||
|
u32 m_firstSessionDateInDay; // 4(0x27C)
|
||||||
|
s32 m_lastSessionDateInDay; // 4(0x280)
|
||||||
|
|
||||||
|
u8 m_uBirthDate_Day; // 1(0x284) [取り得る値は 1~0x1F]
|
||||||
|
u8 m_uBirthDate_Month; // 1(0x285) [取り得る値は 1~0x0C]
|
||||||
|
|
||||||
|
// recipe quantity info (300 quantity info saved on 2 bits each)
|
||||||
|
u32 m_recipeQuantity[QUANTITY_BUFFER_SIZE]; // 80
|
||||||
|
|
||||||
|
|
||||||
|
// save kitchen profile
|
||||||
|
u8 m_unitsUsed; // 1
|
||||||
|
u8 m_numServings; // 1(0x2D9) 取り得る値は 2,4,6,8のどれか
|
||||||
|
|
||||||
|
BOOL m_hasOven :1; // 0x2DA
|
||||||
|
BOOL m_hasMixer :1;
|
||||||
|
BOOL m_hasBBQ :1;
|
||||||
|
BOOL m_hasFoodProcessor :1;
|
||||||
|
|
||||||
|
// tutorial completed?
|
||||||
|
BOOL m_tutorialSearchCompleted :1;
|
||||||
|
BOOL m_tutorialCriteriaSearchCompleted :1;
|
||||||
|
BOOL m_tutorialPrecookCompleted :1;
|
||||||
|
BOOL m_tutorialTimelineCompleted :1;
|
||||||
|
BOOL m_tutorialCookbookCompleted :1; // 0x2DB
|
||||||
|
BOOL m_tutorialShoppingCompleted :1;
|
||||||
|
BOOL m_tutorialManagementCompleted :1;
|
||||||
|
BOOL m_tutorialExtraInfoCompleted :1;
|
||||||
|
BOOL m_tutorialCalendarCompleted :1;
|
||||||
|
BOOL m_searchFirstDeleteCompleted :1;
|
||||||
|
// introduction completed?
|
||||||
|
BOOL m_introductionCompleted :1;
|
||||||
|
BOOL m_tutorialFoodProfileCompleted :1;
|
||||||
|
BOOL m_tutorialFoodProfileFirstDeleteCompleted :1; // 0x2DC
|
||||||
|
BOOL m_tutorialCookbookTimerCompleted :1;
|
||||||
|
|
||||||
|
//---OPTIONS
|
||||||
|
//---Voice
|
||||||
|
BOOL m_vocalCommandsActivated :1;
|
||||||
|
BOOL m_narrationActivated :1;
|
||||||
|
BOOL m_birthdayRecipeIsLocked :1;
|
||||||
|
//---Welcome
|
||||||
|
BOOL m_forceShowBirthday :1;
|
||||||
|
BOOL m_plannedARecipe :1;
|
||||||
|
BOOL m_usedFavorites :1;
|
||||||
|
|
||||||
|
u8 m_welcomeMsgAlreadyDisplayed; //BIT FIELDS with msg that must be display only once // 0x2DD
|
||||||
|
//check enum E_WelcomeMsg for bit order.
|
||||||
|
|
||||||
|
u8 m_language; // 0x2DE
|
||||||
|
u8 padding[0x95];
|
||||||
|
//CookingCoach::ShoppingListCustomItem m_shoppingListCustomItems[DATASAVE_MAX_SHOPPINGLIST_CUSTOMITEMS];
|
||||||
|
}
|
||||||
|
VCK_ProfileSlotBody;
|
||||||
|
|
||||||
|
|
||||||
|
// チェックAPI(VCK*タイトル起動前にこれを呼べばOK)
|
||||||
|
BOOL checkVCK( TitleProperty* tp);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,255 @@
|
|||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Project: Horizon
|
||||||
|
File: lgy_VCW.cpp
|
||||||
|
|
||||||
|
Copyright (C)2009-2011 Nintendo Co., Ltd. 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.
|
||||||
|
|
||||||
|
$Rev$
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <twl.h>
|
||||||
|
#include <sysmenu.h>
|
||||||
|
#include "lgy_VCW.h"
|
||||||
|
#include "lgy_SaveDataChecker.h"
|
||||||
|
|
||||||
|
// title.c より定義を拝借
|
||||||
|
#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB
|
||||||
|
#ifdef USE_HYENA_COMPONENT
|
||||||
|
#define WRAM_SLOT_FOR_FS 5
|
||||||
|
#else
|
||||||
|
#define WRAM_SLOT_FOR_FS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VCW_BACKUP_READ_SIZE (7808)
|
||||||
|
//NN_COMPILER_ASSERT(VCW_BACKUP_READ_SIZE >= ((sizeof(VCW_SavegameHeader) + sizeof(VCW_BodyForCheck)) * 2));
|
||||||
|
//NN_COMPILER_ASSERT(VCW_BACKUP_READ_SIZE % 32 == 0);
|
||||||
|
|
||||||
|
/* VCW メソッド */
|
||||||
|
static u16 VCW_HeaderChecksumToChecksum( VCW* vcw);
|
||||||
|
static void VCW_Initialize( VCW* vcw, void* buffer, u32 ggid);
|
||||||
|
static BOOL VCW_IsFactoryOrBroken( VCW* vcw);
|
||||||
|
static BOOL VCW_CheckRange( VCW* vcw);
|
||||||
|
static u16 VCW_Modify( VCW* vcw);
|
||||||
|
static BOOL VCW_IsModified( VCW* vcw);
|
||||||
|
static void VCW_UpdateChecksum( VCW* vcw);
|
||||||
|
static u16 VCW_GetChecksum( VCW* vcw);
|
||||||
|
static void VCW_Finalize( VCW* vcw);
|
||||||
|
|
||||||
|
//using namespace nn::drivers::cardnor::CTR::ARM946ES;
|
||||||
|
|
||||||
|
|
||||||
|
// チェックAPI(VCW*タイトル起動前にこれを呼べばOK)
|
||||||
|
BOOL checkVCW( TitleProperty* tp, u32 ggid)
|
||||||
|
{
|
||||||
|
#pragma unused( tp)
|
||||||
|
u32 i;
|
||||||
|
u32 *data;
|
||||||
|
u8 *buf;
|
||||||
|
u16 B_checksum[2];
|
||||||
|
VCW vcw[2];
|
||||||
|
|
||||||
|
OS_TPrintf("check VCW backup start.\n");
|
||||||
|
OS_TPrintf( "header size:0x%x, body size:0x%x\n", sizeof(VCW_SavegameHeader), sizeof(VCW_BodyForCheck));
|
||||||
|
|
||||||
|
// EEPROM から読み出し
|
||||||
|
// base = MI_AllocWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
|
||||||
|
data = (u32*)(MI_AllocWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9));
|
||||||
|
OS_TPrintf("Buffer:0x%x\n", data);
|
||||||
|
|
||||||
|
InitializeBackup();
|
||||||
|
readEEPROM( 0, (u32*)data, VCW_BACKUP_READ_SIZE);
|
||||||
|
|
||||||
|
buf = (u8*)data;
|
||||||
|
VCW_Initialize( &vcw[0], buf, ggid);
|
||||||
|
buf = (u8*)data + (sizeof(VCW_SavegameHeader) + sizeof(VCW_BodyForCheck));
|
||||||
|
VCW_Initialize( &vcw[1], buf, ggid);
|
||||||
|
|
||||||
|
|
||||||
|
for( i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 工場出荷状態またはデータ破壊状態かどうか確認
|
||||||
|
if( !VCW_IsFactoryOrBroken( &vcw[i]))
|
||||||
|
{
|
||||||
|
if( VCW_CheckRange( &vcw[i]))
|
||||||
|
{
|
||||||
|
OS_TPrintf("VCW backup is correct.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ランダムな位置に書き込み
|
||||||
|
B_checksum[i] = VCW_Modify( &vcw[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// バッファに書き込みしたならデバイスへの書き込みテストが必要
|
||||||
|
if( VCW_IsModified( &vcw[0]) || VCW_IsModified( &vcw[1]))
|
||||||
|
{
|
||||||
|
OS_TPrintf( "backup write testing..\n");
|
||||||
|
if( !writeAndVerifyEEPROM( 0, data, VCW_BACKUP_READ_SIZE))
|
||||||
|
{
|
||||||
|
OS_TPrintf("launch NG!\n");
|
||||||
|
VCW_Finalize( &vcw[0]);
|
||||||
|
VCW_Finalize( &vcw[1]);
|
||||||
|
FinalizeBackup();
|
||||||
|
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OS_TPrintf("launch ok.\n");
|
||||||
|
VCW_Finalize( &vcw[0]);
|
||||||
|
VCW_Finalize( &vcw[1]);
|
||||||
|
FinalizeBackup();
|
||||||
|
MI_FreeWramSlot( MI_WRAM_C, WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* VCWメソッド*/
|
||||||
|
static u16 VCW_HeaderChecksumToChecksum( VCW* vcw)
|
||||||
|
{
|
||||||
|
return (u16)(0xFFFF - (vcw->header->uniqueIdentifier) - (vcw->header->checkSum));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VCW_Initialize( VCW* vcw, void* buffer, u32 ggid)
|
||||||
|
{
|
||||||
|
vcw->buf = (u8*)buffer;
|
||||||
|
if( (u32)(vcw->buf) % 4)
|
||||||
|
{
|
||||||
|
OS_TPrintf( "Buffer alignment error!\n");
|
||||||
|
while( 1) {};
|
||||||
|
}
|
||||||
|
vcw->ggid = ggid;
|
||||||
|
vcw->header = (VCW_SavegameHeader*)(vcw->buf);
|
||||||
|
vcw->body = (VCW_BodyForCheck*)(vcw->buf + sizeof(VCW_SavegameHeader));
|
||||||
|
vcw->B_checksum = VCW_HeaderChecksumToChecksum( vcw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 工場出荷状態かデータ破壊状態なら TRUE を返す */
|
||||||
|
static BOOL VCW_IsFactoryOrBroken( VCW* vcw)
|
||||||
|
{
|
||||||
|
u16 checksum;
|
||||||
|
|
||||||
|
/**/
|
||||||
|
VCW_UpdateChecksum( vcw);
|
||||||
|
|
||||||
|
/* 工場出荷状態のチェック */
|
||||||
|
if( vcw->ggid != vcw->header->uniqueIdentifier) // VCWV:0x00800354, VCWF:0x00800355, VCWE:0x00400810
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, factory.\n", __FUNCTION__);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
OS_TPrintf("%s, not factory.\n", __FUNCTION__);
|
||||||
|
|
||||||
|
/* 破壊のチェック */
|
||||||
|
checksum = VCW_GetChecksum( vcw);
|
||||||
|
checksum += (u16)(vcw->ggid);
|
||||||
|
checksum += vcw->header->checkSum;
|
||||||
|
if( checksum != 0xFFFF)
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, broken.\n", __FUNCTION__);
|
||||||
|
return TRUE; // broken
|
||||||
|
}
|
||||||
|
|
||||||
|
OS_TPrintf("%s, not broken.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// データが正常範囲内に収まっていれば TRUE を返す
|
||||||
|
static BOOL VCW_CheckRange( VCW* vcw)
|
||||||
|
{
|
||||||
|
if( vcw->body->m_name[UBI_PLAYERINFO_NAME_LENGTH] != '\0')
|
||||||
|
{
|
||||||
|
OS_TPrintf("%s, playerName is out of range.\n", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
OS_TPrintf("%s, good range.\n", __FUNCTION__);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ランダムに一箇所書き換え、書き換え後のchecksumを返す */
|
||||||
|
static u16 VCW_Modify( VCW* vcw)
|
||||||
|
{
|
||||||
|
u16 S_checksum_tmp;
|
||||||
|
u32 i;
|
||||||
|
u16 tick;
|
||||||
|
u8* body_u8 = (u8*)(vcw->body);
|
||||||
|
u32 calculatedSha1[ MATH_SHA1_DIGEST_SIZE /sizeof(u32)];
|
||||||
|
MATHRandContext16 rc16;
|
||||||
|
u32 rseed;
|
||||||
|
|
||||||
|
S_checksum_tmp = VCW_GetChecksum( vcw);
|
||||||
|
|
||||||
|
// checksumがBになるようにランダムな1箇所へ書き込み
|
||||||
|
tick = OS_GetTickLo();
|
||||||
|
#if 1
|
||||||
|
{
|
||||||
|
MATH_CalcSHA1( calculatedSha1, (const void*)vcw->body, sizeof(VCW_BodyForCheck));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
rseed = (u32)(OS_GetTick()) + *(u32*)(calculatedSha1);
|
||||||
|
MATH_InitRand16( &rc16, rseed);
|
||||||
|
for( i=0; i<sizeof(VCW_BodyForCheck); i++)
|
||||||
|
{
|
||||||
|
body_u8[i] = (u8)(MATH_Rand16( &rc16, 0xFF));
|
||||||
|
}
|
||||||
|
VCW_UpdateChecksum( vcw);
|
||||||
|
vcw->B_checksum = VCW_GetChecksum( vcw);
|
||||||
|
// 書き込んだ後の checksum が、S_checksum でも マジコンヘッダのchecksum にもならないようにする
|
||||||
|
while( (vcw->B_checksum == S_checksum_tmp) ||
|
||||||
|
( vcw->B_checksum == VCW_HeaderChecksumToChecksum( vcw)))
|
||||||
|
{
|
||||||
|
vcw->B_checksum -= body_u8[sizeof(VCW_BodyForCheck) - 1];
|
||||||
|
body_u8[sizeof(VCW_BodyForCheck) - 1]++;
|
||||||
|
vcw->B_checksum += body_u8[sizeof(VCW_BodyForCheck) - 1];
|
||||||
|
}
|
||||||
|
OS_TPrintf( "S_checksum:0x%x, A_checksum:0x%x, B_checksum;0x%x\n",
|
||||||
|
S_checksum_tmp,
|
||||||
|
VCW_HeaderChecksumToChecksum( vcw),
|
||||||
|
vcw->B_checksum);
|
||||||
|
|
||||||
|
return vcw->B_checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modifyされたかどうかを返す */
|
||||||
|
static BOOL VCW_IsModified( VCW* vcw)
|
||||||
|
{
|
||||||
|
return ( vcw->B_checksum != VCW_HeaderChecksumToChecksum( vcw));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checksum をアップデートする */
|
||||||
|
static void VCW_UpdateChecksum( VCW* vcw)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u8* body_u8 = (u8*)vcw->body;
|
||||||
|
|
||||||
|
vcw->S_checksum = 0;
|
||||||
|
for( i=0; i<sizeof(VCW_BodyForCheck); ++i)
|
||||||
|
{
|
||||||
|
vcw->S_checksum += body_u8[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checksum を取得する */
|
||||||
|
static u16 VCW_GetChecksum( VCW* vcw)
|
||||||
|
{
|
||||||
|
return vcw->S_checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static void VCW_Finalize( VCW* vcw)
|
||||||
|
{
|
||||||
|
#pragma unused( vcw)
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,262 @@
|
|||||||
|
/*---------------------------------------------------------------------------*
|
||||||
|
Project: Horizon
|
||||||
|
File: lgy_VCW.h
|
||||||
|
|
||||||
|
Copyright (C)2009-2011 Nintendo Co., Ltd. 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.
|
||||||
|
|
||||||
|
$Rev$
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef __LGY_VCW_H__
|
||||||
|
#define __LGY_VCW_H__
|
||||||
|
|
||||||
|
#include <twl.h>
|
||||||
|
#include <sysmenu.h>
|
||||||
|
|
||||||
|
#define UBI_PLAYERINFO_TUTORIALSEENFLAG_SIZE 3
|
||||||
|
#define UBI_PLAYERINFO_NAME_LENGTH 12
|
||||||
|
#define UBI_PLAYERINFO_UNLOCK_LETTERMASK_COUNT 40 //1 for each alphabet letter, including accented letters
|
||||||
|
#define UBI_PLAYERINFO_UNLOCK_LETTERMASK_SIZE (UBI_PLAYERINFO_UNLOCK_LETTERMASK_COUNT/4)
|
||||||
|
#define UBI_PLAYERINFO_DATAITEM_MAXCOUNT 2900
|
||||||
|
#define UBI_PLAYERINFO_DATAITEM_SAVE_MAXSIZE (UBI_PLAYERINFO_DATAITEM_MAXCOUNT/2)
|
||||||
|
#define UBI_PLAYERINFO_THEMEDATAITEM_MAXCOUNT 160
|
||||||
|
#define UBI_PLAYERINFO_THEMEDATAITEM_SAVE_MAXSIZE (UBI_PLAYERINFO_THEMEDATAITEM_MAXCOUNT/2)
|
||||||
|
// defines for MWC2
|
||||||
|
#define UBI_PLAYERINFO_TOP_SCORE_NUM 4
|
||||||
|
#define UBI_PLAYERINFO_LAST_GAME_SCORES_NUM 5
|
||||||
|
#define UBI_PLAYERINFO_SESSION_STARS 100 // 100 is temp for now
|
||||||
|
#define UBI_PLAYERINFO_CROSSWORD_COUNT 20
|
||||||
|
#define UBI_PLAYERINFO_CROSSWORD_NO_SCORE 0xF
|
||||||
|
#define UBI_PLAYERINFO_CROSSWORD_MIN_RANK 10
|
||||||
|
|
||||||
|
#define GRID_SIZE 11
|
||||||
|
|
||||||
|
enum E_GameIDs
|
||||||
|
{
|
||||||
|
UBI_PLAYERINFO_GAMES_MISMATCH_ID = 0,
|
||||||
|
UBI_PLAYERINFO_GAMES_NETWORDER_ID, // 1
|
||||||
|
UBI_PLAYERINFO_GAMES_QUOTES_ID, // 2
|
||||||
|
UBI_PLAYERINFO_GAMES_IDIOMS_ID, // 3
|
||||||
|
UBI_PLAYERINFO_GAMES_TRACE_ID, // 4
|
||||||
|
UBI_PLAYERINFO_GAMES_RACE_ID, // 5
|
||||||
|
UBI_PLAYERINFO_GAMES_WORDFALL_ID, // 6
|
||||||
|
UBI_PLAYERINFO_GAMES_LADDER_ID, // 7
|
||||||
|
UBI_PLAYERINFO_GAMES_CROSSWORD_ID, // 8
|
||||||
|
UBI_PLAYERINFO_GAMES_HIDDENWORD_ID,// 9
|
||||||
|
UBI_PLAYERINFO_GAMES_BLUFF_ID, // 10
|
||||||
|
UBI_PLAYERINFO_GAMES_HANGMAN_ID, // 11
|
||||||
|
UBI_PLAYERINFO_GAMES_MUMBLE_ID, // 12
|
||||||
|
UBI_PLAYERINFO_GAMES_UNLOCK_ID, // 13
|
||||||
|
UBI_PLAYERINFO_GAMES_NUM, // 14
|
||||||
|
UBI_PLAYERINFO_GAMES_NONE_ID
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct VCW_SavegameHeader
|
||||||
|
{
|
||||||
|
u32 uniqueIdentifier;
|
||||||
|
u16 checkSum;
|
||||||
|
u8 m_status;
|
||||||
|
u8 padTemp;
|
||||||
|
}VCW_SavegameHeader;
|
||||||
|
|
||||||
|
struct ScoreInfo
|
||||||
|
{
|
||||||
|
u16 m_score; //represents either stars or points, whatever
|
||||||
|
u32 m_time; // could be u16
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ActivePassiveData
|
||||||
|
{
|
||||||
|
u16 m_activeWords;
|
||||||
|
u16 m_passiveWords;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnlockGameData
|
||||||
|
{
|
||||||
|
u16 m_availableGuesses;
|
||||||
|
u16 m_currentQuoteIndex;
|
||||||
|
u8 m_letterStateMask[UBI_PLAYERINFO_UNLOCK_LETTERMASK_SIZE];
|
||||||
|
u8 m_pad[2]; //for 32-bit alignment
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnlockData
|
||||||
|
{
|
||||||
|
u8 m_lockState;
|
||||||
|
u16 m_availableStars;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HiddenWordData
|
||||||
|
{
|
||||||
|
char gridLetters[11][11];
|
||||||
|
struct WordData
|
||||||
|
{
|
||||||
|
u16 m_posX : 4;
|
||||||
|
u16 m_posY : 4;
|
||||||
|
u16 m_length : 4;
|
||||||
|
u16 m_axis : 4;
|
||||||
|
}m_words[12];
|
||||||
|
|
||||||
|
// u8 wordsStartPos[12][2];
|
||||||
|
// u8 wordsLenght[12];
|
||||||
|
// u8 wordsAxis[12];
|
||||||
|
u8 amountOfWords;
|
||||||
|
u16 flagWordsFound; // The last bit (15) is used to show the presence of a hidden word save game.
|
||||||
|
u32 timeElapsed;
|
||||||
|
u8 hintsUsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used for dynamically generated crosswords
|
||||||
|
struct CrosswordData
|
||||||
|
{
|
||||||
|
u8 m_pregenGridId;
|
||||||
|
|
||||||
|
u8 m_helpUsed : 1;
|
||||||
|
u8 m_saveIsValid : 1;
|
||||||
|
u8 m_timerIndex : 6;
|
||||||
|
|
||||||
|
// Letter displayed in the grid cell, 1st bit is bool for Cheated ( or Not ).
|
||||||
|
char m_gridLetters[GRID_SIZE][GRID_SIZE]; // Upper Case Ascii value
|
||||||
|
|
||||||
|
// Add timer data
|
||||||
|
u32 m_elapsedTime; // In miliseconds
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_WORD_COUNT 30
|
||||||
|
|
||||||
|
struct DynamicCrosswordData
|
||||||
|
{
|
||||||
|
struct Word
|
||||||
|
{
|
||||||
|
u16 m_startPosX : 4;
|
||||||
|
u16 m_startPosY : 4;
|
||||||
|
u16 m_axis : 4;
|
||||||
|
u16 m_isSmallword : 4;
|
||||||
|
|
||||||
|
u16 m_wordId; // Id of the word in dictionary
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 m_wordCount;
|
||||||
|
|
||||||
|
// Used for generated grids.
|
||||||
|
u16 m_words[MAX_WORD_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VocabularyData
|
||||||
|
{
|
||||||
|
union StateBucket
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u8 m_state0 : 3; //word state (item 0)
|
||||||
|
u8 m_seen0 : 1; //seen flag (item 0)
|
||||||
|
u8 m_state1 : 3; //word state (item 1)
|
||||||
|
u8 m_seen1 : 1; //seen flag (item 1)
|
||||||
|
};
|
||||||
|
u8 m_wholeBucket;
|
||||||
|
}StateBucket;
|
||||||
|
|
||||||
|
u8 m_type;
|
||||||
|
u8 m_playerDl;
|
||||||
|
u8 m_selectionCount[4]; //LT_BasicCount
|
||||||
|
u32 m_newActiveCount;
|
||||||
|
u32 m_allTimeMaxActiveCount;
|
||||||
|
u8 m_lastAccuracy;
|
||||||
|
|
||||||
|
union StateBucket* m_itemStates;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MainVocabularyData
|
||||||
|
{
|
||||||
|
struct VocabularyData voc;
|
||||||
|
union StateBucket m_specificItemStates[UBI_PLAYERINFO_DATAITEM_SAVE_MAXSIZE]; //missing 2 for 32-bit alignment
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThemeVocabularyData
|
||||||
|
{
|
||||||
|
struct VocabularyData voc;
|
||||||
|
union StateBucket m_specificItemStates[UBI_PLAYERINFO_THEMEDATAITEM_SAVE_MAXSIZE]; //missing 2 for 32-bit alignment
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct PlayerData
|
||||||
|
{
|
||||||
|
char m_name[UBI_PLAYERINFO_NAME_LENGTH+1]; // 13 (0x08~0x0x14)
|
||||||
|
u8 m_dataState; // 1 (0x15)
|
||||||
|
u8 m_musicOff; // 1 (0x16)
|
||||||
|
u8 m_useWarmups; // 1 (0x17)
|
||||||
|
u8 m_lefty; // 1 (0x18)
|
||||||
|
u16 m_numSessions; // 2 (0x19~0x1A)
|
||||||
|
u16 m_seenRealLifeChallenges; // 2 (0x1B~0x1C)
|
||||||
|
f32 m_fReadingTimeMod; // 4 (0x1D~
|
||||||
|
f32 m_fReactionTimeModQuick; // 4
|
||||||
|
f32 m_fReactionTimeModSegment; // 4
|
||||||
|
|
||||||
|
u8 m_sessionStars; // 1
|
||||||
|
u8 m_sessionUnlockTry; // 1
|
||||||
|
u8 m_personalProgressSeen; // 1
|
||||||
|
u32 m_gameTracker; // 4
|
||||||
|
u8 m_hsGamesPlayed; // 1
|
||||||
|
u8 m_themeViewed; // 1
|
||||||
|
u8 m_themeUnlocked; // 1
|
||||||
|
u8 m_gameIntroViewed[UBI_PLAYERINFO_GAMES_NUM]; // 14
|
||||||
|
u16 m_gameLastSessionPlayed[UBI_PLAYERINFO_GAMES_NUM]; // 28
|
||||||
|
struct ScoreInfo m_topScores[UBI_PLAYERINFO_GAMES_NUM][UBI_PLAYERINFO_TOP_SCORE_NUM]; //
|
||||||
|
struct ScoreInfo m_lastScores[UBI_PLAYERINFO_GAMES_NUM][UBI_PLAYERINFO_LAST_GAME_SCORES_NUM];
|
||||||
|
u8 m_crosswordRanks[UBI_PLAYERINFO_CROSSWORD_COUNT];
|
||||||
|
|
||||||
|
struct ActivePassiveData m_activePassiveTotals;
|
||||||
|
struct UnlockGameData m_unlockGameData;
|
||||||
|
struct UnlockData m_unlockData;
|
||||||
|
|
||||||
|
struct MainVocabularyData m_mainVocabularyData; //
|
||||||
|
// struct ThemeVocabularyData m_themeVocabularyData[DICT_THEME_MAX_COUNT]; //
|
||||||
|
|
||||||
|
struct HiddenWordData m_hiddenWordData; // 153 ()
|
||||||
|
struct CrosswordData m_crossWordData; // 133 ()
|
||||||
|
struct DynamicCrosswordData m_dynamicCrossWordData; // 65 (~0xF37)
|
||||||
|
}
|
||||||
|
PlayerData;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct VCW_BodyForCheck
|
||||||
|
{
|
||||||
|
char m_name[UBI_PLAYERINFO_NAME_LENGTH+1]; // 13 (0x08~0x0x14)
|
||||||
|
u8 dummy[0xF38 - 8 - 13];
|
||||||
|
}
|
||||||
|
VCW_BodyForCheck;
|
||||||
|
//NN_COMPILER_ASSERT(0xF38 == sizeof(VCW_SavegameHeader) + sizeof(VCW_BodyForCheck));
|
||||||
|
|
||||||
|
/**/
|
||||||
|
BOOL checkVCW( TitleProperty* tp, u32 ggid);
|
||||||
|
|
||||||
|
|
||||||
|
/* TWLランチャにも移植するので Cでオブジェクトを定義する */
|
||||||
|
typedef struct VCW
|
||||||
|
{
|
||||||
|
u8* buf;
|
||||||
|
u32 ggid;
|
||||||
|
VCW_SavegameHeader *header;
|
||||||
|
VCW_BodyForCheck *body;
|
||||||
|
u16 S_checksum;
|
||||||
|
u16 B_checksum;
|
||||||
|
}VCW;
|
||||||
|
|
||||||
|
//static void VCW_Initialize( VCW* vcw, void* buffer, u32 ggid);
|
||||||
|
//static bool VCW_IsFactoryOrBroken( VCW* vcw);
|
||||||
|
//static bool VCW_CheckRange( VCW* vcw);
|
||||||
|
//static u16 VCW_Modify( VCW* vcw);
|
||||||
|
//static bool VCW_IsModified( VCW* vcw);
|
||||||
|
//static void VCW_UpdateChecksum( VCW* vcw);
|
||||||
|
//static u16 VCW_GetChecksum( VCW* vcw);
|
||||||
|
//static void VCW_Finalize( VCW* vcw);
|
||||||
|
/* オブジェクトここまで */
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -24,6 +24,7 @@
|
|||||||
#include "internal_api.h"
|
#include "internal_api.h"
|
||||||
#include "fs_wram.h"
|
#include "fs_wram.h"
|
||||||
#include <sysmenu/errorLog.h>
|
#include <sysmenu/errorLog.h>
|
||||||
|
#include "SaveDataChecker/lgy_SaveDataChecker.h"
|
||||||
|
|
||||||
// define data-----------------------------------------------------------------
|
// define data-----------------------------------------------------------------
|
||||||
|
|
||||||
@ -1816,7 +1817,19 @@ static BOOL SYSMi_AuthenticateTitleCore( TitleProperty *pBootTitle)
|
|||||||
return SYSMi_AuthenticateTWLTitle( pBootTitle );
|
return SYSMi_AuthenticateTWLTitle( pBootTitle );
|
||||||
case LAUNCHER_BOOTTYPE_ROM:
|
case LAUNCHER_BOOTTYPE_ROM:
|
||||||
OS_TPrintf( "Authenticate :TWL_ROM start.\n" );
|
OS_TPrintf( "Authenticate :TWL_ROM start.\n" );
|
||||||
return SYSMi_AuthenticateTWLTitle( pBootTitle );
|
if( SYSMi_AuthenticateTWLTitle( pBootTitle ))
|
||||||
|
{
|
||||||
|
if( CheckBackupData( pBootTitle)) // バックアップデータのチェック
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UTL_SetFatalError(FATAL_ERROR_BACKUP_DATA_CHECK_FAILED);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
case LAUNCHER_BOOTTYPE_TEMP:
|
case LAUNCHER_BOOTTYPE_TEMP:
|
||||||
OS_TPrintf( "Authenticate :TWL_TEMP start.\n" );
|
OS_TPrintf( "Authenticate :TWL_TEMP start.\n" );
|
||||||
if (!hs->permit_landing_tmp_jump)
|
if (!hs->permit_landing_tmp_jump)
|
||||||
|
|||||||
@ -85,6 +85,7 @@ typedef enum FatalErrorCode {
|
|||||||
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
|
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
|
||||||
FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗(フェーズ3)
|
FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗(フェーズ3)
|
||||||
FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗(フェーズ4)
|
FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗(フェーズ4)
|
||||||
|
FATAL_ERROR_BACKUP_DATA_CHECK_FAILED = 53, // バックアップデータの検証失敗
|
||||||
|
|
||||||
FATAL_ERROR_MAX = 53
|
FATAL_ERROR_MAX = 53
|
||||||
}FatalErrorCode;
|
}FatalErrorCode;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user