TwlIPL/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_lib.c
yosiokat fd9112d120 ・カードレジスタのスワップとカードIDのシステム領域へのセットを、カードブートの時
のみ行うよう修正。
・アプリブート時のマウント情報設定への対応。
 ・ランチャーは、自身の起動時にマウント情報を自分でセットするようにする。
 ・暫定対策:全ドライブをRW可能にしている。
 ・暫定対策:FS不具合回避のため、"nand:"を'F'ドライブに設定。
 ・MachineSettingsとPictoChatでのnand_app_hack.hを使用したFSの暫定
  NAND対応を削除。
  これに伴い、nand_app_hack.hも削除。
・NANDアプリ読み込み時のリストバグ修正。


git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@272 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2007-11-27 13:06:08 +00:00

1023 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters

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

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

/*---------------------------------------------------------------------------*
Project: TwlIPL
File: SYSM_lib.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.
$Date:: $
$Rev$
$Author$
*---------------------------------------------------------------------------*/
#include <twl.h>
#include <sysmenu.h>
#include "sysmenu_define.h"
#include "spi.h"
// define data-----------------------------------------------------------------
#define CARD_BANNER_INDEX ( LAUNCHER_TITLE_LIST_NUM - 1 )
typedef struct BannerCheckParam {
u8 *pSrc;
u32 size;
}BannerCheckParam;
// extern data-----------------------------------------------------------------
extern void SYSMi_SetLauncherMountInfo( void );
extern void SYSM_SetBootAppMountInfo( NAMTitleId titleID ); // ƒ}ƒEƒ“ƒg<C692>î•ñ̃Zƒbƒg
// function's prototype-------------------------------------------------------
static TitleProperty *SYSMi_CheckShortcutBoot( void );
static BOOL SYSMi_IsDebuggerBannerViewMode( void );
static BOOL SYSMi_CheckTitlePointer( TitleProperty *pBootTitle );
static void SYSMi_WriteAdjustRTC( void );
static int SYSMi_IsValidCard( void );
static BOOL SYSMi_CheckEntryAddress( void );
static void SYSMi_CheckCardCloneBoot( void );
static void SYSMi_CheckRTC( void );
static s32 ReadFile(FSFile* pf, void* buffer, s32 size);
static void SYSMi_Relocate( void );
static BOOL SYSMi_ReadCardBannerFile( u32 bannerOffset, TWLBannerFile *pBanner );
static BOOL SYSMi_CheckBannerFile( NTRBannerFile *pBanner );
// global variable-------------------------------------------------------------
void *(*SYSM_Alloc)( u32 size );
void (*SYSM_Free )( void *ptr );
#ifdef SYSM_DEBUG_
SYSM_work *pSysm; // ƒfƒoƒbƒKÅÌSYSMƒ<4D><C692>[ƒÑEƒHƒbƒ`—p
#endif
// static variable-------------------------------------------------------------
static OSThread thread;
static TWLBannerFile s_bannerBuf[ LAUNCHER_TITLE_LIST_NUM ] ATTRIBUTE_ALIGN(32);
// const data------------------------------------------------------------------
#if 0
typedef enum RomSegmentName {
ROM_HEADER = 0,
ARM9_STATIC,
ARM7_STATIC,
ARM9_LTD_STATIC,
ARM7_LTD_STATIC
}RomSegmentName;
typedef struct RomSegmentRange {
u32 start;
u32 end;
}RomSegmentRange;
typedef struct RomReloadInfo {
void *pSrc;
void *pDst;
u32 length;
BOOL revCopy;
}RomReloadInfo;
static RomSegmentRange romSegmentRange[] = {
{ HW_TWL_ROM_HEADER_BUF, HW_TWL_ROM_HEADER_BUF_END },
{ SYSM_NTR_ARM9_LOAD_MMEM, SYSM_NTR_ARM9_LOAD_MMEM_END },
{ SYSM_NTR_ARM7_LOAD_MMEM, SYSM_NTR_ARM7_LOAD_MMEM_END },
{ SYSM_TWL_ARM9_LTD_LOAD_MMEM, SYSM_TWL_ARM9_LTD_LOAD_MMEM_END },
{ SYSM_TWL_ARM7_LTD_LOAD_MMEM, SYSM_TWL_ARM7_LTD_LOAD_MMEM_END },
};
static RomReloadInfo romReloadInfo[] = {
};
static BOOL SYSMi_OutOfRangeRomSegment( u32 start, u32 length, RomSegmentRange *pRange, ReloadInfo *pReload )
{
BOOL isReload = FALSE;
u32 end = (u32)start + length;
if( start < pRange->start ) {
if( end <= pRange->start ) {
isReload = TRUE;
pReload->revCopy = FALSE;
}else {
isReload = TRUE;
pReload->revCopy = TRUE;
}
}else if( start <= pRange->end ) {
if( end <= pRange->end ) {
if(u32)( pRange->start + length ) )
}else if( end > pRange->end ) {
isReload = TRUE;
pReload->revCopy = FALSE;
}
}else if( start > pRange->end ) {
isReload = TRUE;
}
if( isReload ) {
pReload->pDst = (void *)start;
pReload->pSrc = (void *)pRange->start;
pReload->length = length;
}
}
#endif
// ============================================================================
//
// <20>‰Šú‰»
//
// ============================================================================
// SystemMenuÌ<E2809A>‰Šú‰»
void SYSM_Init( void *(*pAlloc)(u32), void (*pFree)(void*) )
{
#ifdef SYSM_DEBUG_
pSysm = SYSMi_GetWork();
#endif /* SYSM_DEBUG_ */
// ƒ‰ƒ“ƒ`ƒƒ<C692>[‚̃}ƒEƒ“ƒg<C692>î•ñƒZƒbƒg
SYSMi_SetLauncherMountInfo();
// ARM7ƒRƒ“ƒ|<7C>[ƒlƒ“ƒg—pƒvƒ<76>ƒeƒNƒVƒ‡ƒ“ƒ†ƒjƒbƒg—̈æ•Ï<E280A2>X
OS_SetProtectionRegion( 2, SYSM_OWN_ARM7_MMEM_ADDR, 512KB );
// ARM9—pƒu<C692>[ƒgƒR<C692>[ƒh”zu̽ß<E2809A>AƒAƒŠ<C692>[ƒiHiˆÊuð‰º°é
OS_SetMainArenaHi( (void *)SYSM_OWN_ARM9_MMEM_ADDR_END );
SYSM_SetAllocFunc( pAlloc, pFree );
// WRAM<41>ÝèÍ¢é<E2809A>H
// MI_SetMainMemoryPriority(MI_PROCESSOR_ARM7);
// MI_SetWramBank(MI_WRAM_ARM7_ALL);
reg_OS_PAUSE |= REG_OS_PAUSE_CHK_MASK; // PAUSEƒŒƒWƒXƒ^‚̃`ƒFƒbƒNƒtƒ‰ƒÕZƒbƒg
}
// ƒVƒXƒeƒ€ƒ<E282AC>ƒjƒ…<C692>[ƒ‰ƒCƒuƒ‰ƒŠ—pƒ<70>ƒƒŠƒAƒ<41>ƒP<C692>[ƒ^Ì<E2809A>Ýè
void SYSM_SetAllocFunc( void *(*pAlloc)(u32), void (*pFree)(void*) )
{
SYSM_Alloc = pAlloc;
SYSM_Free = pFree;
}
// ============================================================================
//
// <20>î•ñŽæ“¾
//
// ============================================================================
// ƒpƒ‰ƒ<E280B0><C692>[ƒ^ƒŠ<C692>[ƒh
TitleProperty *SYSM_ReadParameters( void )
{
TitleProperty *pBootTitle = NULL;
// ARM7ÌƒŠƒZƒbƒgƒpƒ‰ƒ<E280B0><C692>[ƒ^Žæ“¾‚ªŠ®—¹‚·‚é‚Ì‚ð‘Ò‚Â
while( !SYSMi_GetWork()->isARM9Start ) {
SVC_WaitByLoop( 0x1000 );
}
#ifdef DEBUG_USED_CARD_SLOT_B_
while( !SYSMi_GetWork()->is1stCardChecked ) {
SVC_WaitByLoop( 0x1000 );
}
#endif
//-----------------------------------------------------
// ƒŠƒZƒbƒgƒpƒ‰ƒ<E280B0><C692>[ƒ^Ì”»è<E28099>iƒŠƒZƒbƒgƒpƒ‰ƒ<E280B0><C692>[ƒ^ª—LŒø©Ç¤©Í<E2809A>AARM7ÅâÁÄ­êÄ¢é<E2809A>j
//-----------------------------------------------------
{
if( SYSM_GetResetParamBody()->v1.flags.isLogoSkip || // ƒ<>ƒSƒfƒƒXƒLƒbƒv<C692>H
SYSMi_IsDebuggerBannerViewMode() ) {
SYSM_SetLogoDemoSkip( TRUE );
}
if( SYSM_GetResetParamBody()->v1.bootTitleID ) { // ƒAƒvƒŠ¼<E28099>ÚN“®ÌŽw誠Á½çƒ<C3A7>ƒSƒfƒð”òεĎwèƒAƒvƒŠN“®
pBootTitle = (TitleProperty *)&SYSM_GetResetParamBody()->v1;
}
}
//-----------------------------------------------------
// —ÊŽY<C5BD>Hö—pƒVƒ‡<C692>[ƒgƒJƒbƒgƒL<C692>[ or
// ŒŸ<C592>¸ƒJ<C692>[ƒhN“®
//-----------------------------------------------------
if( pBootTitle == NULL ) {
pBootTitle = SYSMi_CheckShortcutBoot();
}
//-----------------------------------------------------
// {Ì<E28098>Ýèƒf<C692>[ƒ^̃Š<C692>[ƒh
//-----------------------------------------------------
if( SYSM_ReadTWLSettingsFile() ) { // NAND©çTWL{Ì<E28098>Ýèƒf<C692>[ƒ^ðƒŠ<C692>[ƒh
SYSM_SetBackLightBrightness( (u8)TSD_GetBacklightBrightness() ); // “ÇÝ<E2809A>oµ½TWL{Ì<E28098>Ýèƒf<C692>[ƒ^ðàÆÉƒoƒbƒNƒ‰ƒCƒgP“x<E2809C>Ýè
SYSM_CaribrateTP(); // “ÇÝ<E2809A>oµ½TWL{Ì<E28098>Ýèƒf<C692>[ƒ^ðàÆÉTPƒLƒƒƒŠƒuƒŒ<C692>[ƒVƒ‡ƒ“<C692>B
}
// SYSM_ReadHWInfo(); // NAND©çHW<48>î•ñðƒŠ<C692>[ƒh
SYSMi_WriteAdjustRTC(); // RTCƒNƒ<4E>ƒbƒN•â<E280A2>³lðƒZƒbƒg<C692>B
SYSMi_CheckRTC();
SYSM_VerifyAndRecoveryNTRSettings(); // NTR<54>Ýèƒf<C692>[ƒ^ð“ÇÝ<E2809A>oµÄ<E2809A>ATWL<57>Ýèƒf<C692>[ƒ^ƃxƒŠƒtƒ@ƒCµ<E2809A>A•K—vÈ烊ƒJƒoƒŠ
// SYSMi_CheckCardCloneBoot(); // ƒJ<C692>[ƒhªƒNƒ<4E><C692>[ƒ“ƒu<C692>[ƒg©ƒ`ƒFƒbƒN
//NAMÌ<E2809A>‰Šú‰»
//NAM_Init(AllocForNAM,FreeForNAM);
return pBootTitle;
}
// ƒVƒ‡<C692>[ƒgƒJƒbƒgN“®Ìƒ`ƒFƒbƒN
static TitleProperty *SYSMi_CheckShortcutBoot( void )
{
#if 0 // <20>¦¢ŽÀ
static TitleProperty s_bootTitle;
MI_CpuClear8( &s_bootTitle, sizoef(TitleProperty) );
//-----------------------------------------------------
// —ÊŽY<C5BD>Hö—pƒVƒ‡<C692>[ƒgƒJƒbƒgƒL<C692>[ or
// ŒŸ<C592>¸ƒJ<C692>[ƒhN“®
//-----------------------------------------------------
if( SYSM_IsInspectCard() ||
( SYSM_IsExistCard() &&
( ( PAD_Read() & PAD_PRODUCTION_SHORTCUT_CARD_BOOT ) ==
PAD_PRODUCTION_SHORTCUT_CARD_BOOT ) )
) {
if( SYSM_GetCardTitleProperty( &s_bootTitle ) ) { // <20>¦¢ŽÀ
s_bootTitle.flags.isInitialShortcutSkip = TRUE; // <20>‰‰ñN“®ƒV<C692>[ƒPƒ“ƒXð”òη
s_bootTitle.flags.isLogoSkip = TRUE; // ƒ<>ƒSƒfƒð”òη
s_bootTitle.flags.media = TITLE_MEDIA_CARD;
s_bootTitle.flags.isValid = TRUE;
// titleIDÍ"0"<22>iƒJ<C692>[ƒh<C692>j
SYSM_SetLogoDemoSkip( TRUE );
return &s_bootTitle;
}
}
//-----------------------------------------------------
// TWL<57>Ýèƒf<C692>[ƒ^¢“ü—ÍŽžÌ<E2809A>‰‰ñN“®ƒV<C692>[ƒPƒ“ƒXN“®
//-----------------------------------------------------
#ifdef ENABLE_INITIAL_SETTINGS_
if( !TSD_IsSetTP() ||
!TSD_IsSetLanguage() ||
!TSD_IsSetDateTime() ||
!TSD_IsSetUserColor() ||
!TSD_IsSetNickname() ) {
s_bootTitle.titleID = TITLE_ID_MACHINE_SETTINGS;
s_bootTitle.flags.media = TITLE_MEDIA_NAND;
s_bootTitle.flags.isValid = TRUE;
return &s_bootTitle;
}
#endif // ENABLE_INITIAL_SETTINGS_
#endif // 0
return NULL; // <20>uƒu<C692>[ƒg“à—e¢è<E28099>vÅƒŠƒ^<5E>[ƒ“
}
// ƒJ<C692>[ƒhƒ^ƒCƒgƒÌŽæ“¾
BOOL SYSM_GetCardTitleList( TitleProperty *pTitleList_Card )
{
BOOL retval = FALSE;
if( SYSMi_GetWork()->isCardStateChanged ) {
MI_CpuClear32( pTitleList_Card, sizeof(TitleProperty) );
// ROMƒwƒbƒ_ƒoƒbƒtƒ@̃Rƒs<C692>[
if( SYSM_IsExistCard() ) {
u16 id = (u16)OS_GetLockID();
(void)OS_LockByWord( id, &SYSMi_GetWork()->lockCardRsc, NULL ); // ARM7Æ”r¼<E28098>§Œä·é
DC_InvalidateRange( (void *)SYSM_CARD_ROM_HEADER_BAK, SYSM_CARD_ROM_HEADER_SIZE ); // ƒLƒƒƒbƒVƒ…ƒPƒA
MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BAK, (void *)SYSM_CARD_ROM_HEADER_BUF, SYSM_CARD_ROM_HEADER_SIZE ); // ROMƒwƒbƒ_ƒRƒs<C692>[
SYSMi_GetWork()->cardHeaderCrc16 = SYSMi_GetWork()->cardHeaderCrc16; // ROMƒwƒbƒ_CRCƒRƒs<C692>[
SYSMi_GetWork()->isCardStateChanged = FALSE; // ƒJ<C692>[ƒh<C692>î•ñ<E280A2>X<EFBFBD>Vƒtƒ‰ƒOð—ŽÆ·
(void)OS_UnlockByWord( id, &SYSMi_GetWork()->lockCardRsc, NULL ); // ARM7Æ”r¼<E28098>§Œä·é
OS_ReleaseLockID( id );
pTitleList_Card->flags.isValid = TRUE;
pTitleList_Card->flags.isAppLoadCompleted = TRUE;
pTitleList_Card->flags.isAppRelocate = TRUE;
pTitleList_Card->pBanner = NULL;
// ƒoƒi<C692>[ƒf<C692>[ƒ^̃Š<C692>[ƒh
if( SYSM_GetCardRomHeader()->banner_offset &&
SYSMi_ReadCardBannerFile( SYSM_GetCardRomHeader()->banner_offset, &s_bannerBuf[ CARD_BANNER_INDEX ] ) ) {
pTitleList_Card->pBanner = &s_bannerBuf[ CARD_BANNER_INDEX ];
}else {
MI_CpuClearFast( &s_bannerBuf[ CARD_BANNER_INDEX ], sizeof(TWLBannerFile) );
}
}
retval = TRUE;
}
// ƒ^ƒCƒgƒ<C692>î•ñƒtƒ‰ƒÕZƒbƒg
pTitleList_Card->flags.media = TITLE_MEDIA_CARD;
pTitleList_Card->titleID = 0;
return retval;
}
// Žwèƒtƒ@ƒCƒƒŠ<C692>[ƒh
static s32 ReadFile(FSFile* pf, void* buffer, s32 size)
{
u8* p = (u8*)buffer;
s32 remain = size;
while( remain > 0 )
{
const s32 len = MATH_IMin(1024, remain);
const s32 readLen = FS_ReadFile(pf, p, len);
if( readLen < 0 )
{
return readLen;
}
if( readLen != len )
{
return size - remain + readLen;
}
remain -= readLen;
p += readLen;
}
return size;
}
#include <es.h>
ESTitleMeta dst[1];
// NANDƒ^ƒCƒgƒƒŠƒXƒg̎擾
int SYSM_GetNandTitleList( TitleProperty *pTitleList_Nand, int listNum )
{
// filter_flag : ALL, ALL_APP, SYS_APP, USER_APP, Data only, “™Ì<E2809A>ðŒ<C3B0>ðŽwèµÄƒ^ƒCƒgƒƒŠƒXƒgðŽæ“¾·é<E2809A>B
// Æè ¦¸ALL
int l;
int gotten;
NAMTitleId titleIdArray[ LAUNCHER_TITLE_LIST_NUM ];
if( listNum > LAUNCHER_TITLE_LIST_NUM ) {
OS_TPrintf( "Warning: TitleList_Nand num over LAUNCHER_TITLE_LIST_NUM(%d)\n", LAUNCHER_TITLE_LIST_NUM );
}
gotten = NAM_GetTitleList( &titleIdArray[ 0 ], LAUNCHER_TITLE_LIST_NUM - 1 );
for(l=0;l<gotten;l++)
{
//ƒwƒbƒ_©çƒoƒi<C692>[ð“ÇÝ<E2809A>žÞ
FSFile file[1];
BOOL bSuccess;
static const int PATH_LENGTH=1024;
char path[PATH_LENGTH];
static u8 header[HW_TWL_ROM_HEADER_BUF_SIZE] ATTRIBUTE_ALIGN(32);
s32 readLen;
s32 offset;
readLen = NAM_GetTitleBootContentPath(path, titleIdArray[l]);
if(readLen != NAM_OK){
OS_TPrintf("NAM_GetTitleBootContentPath failed %d,%lld,%d\n",l,titleIdArray[l],readLen);
}
bSuccess = FS_OpenFileEx(file, path, FS_FILEMODE_R);
if( ! bSuccess )
{
OS_TPrintf("SYSM_GetNandTitleList failed: cant open file %s\n",path);
return -1;
}
// ƒoƒi<C692>[ƒf<C692>[ƒ^ƒIƒtƒZƒbƒgð“ÇÝ<E2809A>žÞ
bSuccess = FS_SeekFile(file, 0x68, FS_SEEK_SET);
if( ! bSuccess )
{
OS_TPrintf("SYSM_GetNandTitleList failed: cant seek file(0)\n");
FS_CloseFile(file);
return -1;
}
readLen = FS_ReadFile(file, &offset, sizeof(offset));
if( readLen != sizeof(offset) )
{
OS_TPrintf("SYSM_GetNandTitleList failed: cant read file\n");
FS_CloseFile(file);
return -1;
}
bSuccess = FS_SeekFile(file, offset, FS_SEEK_SET);
if( ! bSuccess )
{
OS_TPrintf("SYSM_GetNandTitleList failed: cant seek file(offset)\n");
FS_CloseFile(file);
return -1;
}
readLen = ReadFile(file, &s_bannerBuf[l], (s32)sizeof(TWLBannerFile));
if( readLen != (s32)sizeof(TWLBannerFile) )
{
OS_TPrintf("SYSM_GetNandTitleList failed: cant read file2\n");
FS_CloseFile(file);
return -1;
}
FS_CloseFile(file);
}
for(l=gotten;l<LAUNCHER_TITLE_LIST_NUM;l++)
{
// ”O̽ß0ɃNƒŠƒA
titleIdArray[l] = 0;
}
// ƒJ<C692>[ƒhƒAƒvƒŠ•”•ªð<E2809A>œ¢½ƒŠƒXƒgƒNƒŠƒA
MI_CpuClearFast( &pTitleList_Nand[ 1 ], sizeof(TitleProperty) * ( listNum - 1 ) );
listNum = (gotten<listNum) ? gotten : listNum;
for(l=0;l<listNum;l++)
{
pTitleList_Nand[l+1].titleID = titleIdArray[l];
pTitleList_Nand[l+1].pBanner = &s_bannerBuf[l];
if( titleIdArray[l] ) {
pTitleList_Nand[l+1].flags.isValid = TRUE;
pTitleList_Nand[l+1].flags.media = TITLE_MEDIA_NAND;
}
}
// return : *TitleProperty Array
return listNum;
}
// ƒŠƒZƒbƒgƒpƒ‰ƒ<E280B0><C692>[ƒ^‚̎擾
const ResetParamBody *SYSM_GetResetParamBody( void )
{
return (const ResetParamBody *)&SYSMi_GetWork()->resetParam.body;
}
// ƒ<>ƒSƒfƒƒXƒLƒbƒv©Ç¤©ðƒZƒbƒg
void SYSM_SetLogoDemoSkip( BOOL skip )
{
SYSMi_GetWork()->isLogoSkip = skip;
}
// ƒ<>ƒSƒfƒƒXƒLƒbƒv©<E2809A>H
BOOL SYSM_IsLogoDemoSkip( void )
{
return SYSMi_GetWork()->isLogoSkip;
}
// ISƒfƒoƒbƒK̃oƒi<C692>[ƒrƒ…<C692><C692>[ƒhN“®©Ç¤©<E2809A>H
static BOOL SYSMi_IsDebuggerBannerViewMode( void )
{
#ifdef __IS_DEBUGGER_BUILD
return ( SYSMi_GetWork()->isOnDebugger &&
SYSMi_IsValidCard() &&
SYSM_GetCardRomHeader()->dbgRomSize == 0 ) ? TRUE : FALSE;
#else
return FALSE;
#endif // __IS_DEBUGGER_BUILD
}
// Žwèƒ^ƒCƒgƒªƒu<C692>[ƒg‰Â”\‚ȃ|ƒCƒ“ƒ^‚©ƒ`ƒFƒbƒN
static BOOL SYSMi_CheckTitlePointer( TitleProperty *pBootTitle )
{
#pragma unused( pBootTitle )
return TRUE;
}
// TPƒŠ<C692>[ƒh‰Â”\<5C>óÔ©<E2809A>H
BOOL SYSM_IsTPReadable( void )
{
return TRUE;
}
// TSD—LŒø/³ŒøðƒZƒbƒg
void SYSM_SetValidTSD( BOOL valid )
{
SYSMi_GetWork()->isValidTSD = valid;
}
// TSD—LŒø<C592>H
BOOL SYSM_IsValidTSD( void )
{
return SYSMi_GetWork()->isValidTSD;
}
// ============================================================================
//
// ƒAƒvƒŠN“®
//
// ============================================================================
static void SYSMi_LoadTitleThreadFunc( TitleProperty *pBootTitle )
{ enum
{
region_header,
region_arm9_ntr,
region_arm7_ntr,
region_arm9_twl,
region_arm7_twl,
region_max
};
// ƒ<>ƒCƒ“ƒ<E2809C>ƒƒŠÌƒNƒŠƒA
// DSƒ_ƒEƒ“ƒ<E2809C><C692>[ƒhƒvƒŒƒCÌŽžÍ<E2809A>AROMƒwƒbƒ_ðÞ”ð·é
// ƒAƒvƒŠƒ<C5A0><C692>[ƒh
// ƒAƒvƒŠ”F<E2809D>Ø
// ƒ<><C692>[ƒh
char path[256];
FSFile file[1];
BOOL bSuccess;
NAM_GetTitleBootContentPath(path, pBootTitle->titleID);
bSuccess = FS_OpenFileEx(file, path, FS_FILEMODE_R);
if( ! bSuccess )
{
OS_TPrintf("RebootSystem failed: cant open file\n");
return;
}
{
int i;
u32 source[region_max];
u32 length[region_max];
u32 destaddr[region_max];
static u8 header[HW_TWL_ROM_HEADER_BUF_SIZE] ATTRIBUTE_ALIGN(32);
s32 readLen;
// ܸROMƒwƒbƒ_ð“ÇÝ<E2809A>žÞ
// ({—ˆÈç±±ÅSRLÌ<E2809A>³“<E2809C>«”»è)
bSuccess = FS_SeekFile(file, 0x00000000, FS_SEEK_SET);
if( ! bSuccess )
{
OS_TPrintf("RebootSystem failed: cant seek file(0)\n");
FS_CloseFile(file);
return;
}
readLen = ReadFile(file, header, (s32)sizeof(header));
if( readLen != (s32)sizeof(header) )
{
OS_TPrintf("RebootSystem failed: cant read file(%p, %d, %d, %d)\n", header, 0, sizeof(header), readLen);
FS_CloseFile(file);
return;
}
if( header[0x15C] != 0x56 || header[0x15D] != 0xCF )
{
int i, j;
for( i = 0; i < 0x20; ++i )
{
for( j = 0; j < 0x10; ++j )
{
OS_TPrintf("%02X ", header[i * 0x10 + j]);
}
OS_TPrintf("\n");
}
OS_TPrintf("RebootSystem failed: logo CRC error\n");
FS_CloseFile(file);
return;
}
// Še—̈æð“ÇÝ<E2809A>žÞ
source [region_header ] = 0x00000000;
length [region_header ] = HW_TWL_ROM_HEADER_BUF_SIZE;
destaddr[region_header ] = HW_TWL_ROM_HEADER_BUF;
source [region_arm9_ntr] = *(const u32*)&header[0x020];
length [region_arm9_ntr] = *(const u32*)&header[0x02C];
destaddr[region_arm9_ntr] = *(const u32*)&header[0x028];
source [region_arm7_ntr] = *(const u32*)&header[0x030];
length [region_arm7_ntr] = *(const u32*)&header[0x03C];
destaddr[region_arm7_ntr] = *(const u32*)&header[0x038];
source [region_arm9_twl] = *(const u32*)&header[0x1C0];
length [region_arm9_twl] = *(const u32*)&header[0x1CC];
destaddr[region_arm9_twl] = *(const u32*)&header[0x1C8];
source [region_arm7_twl] = *(const u32*)&header[0x1D0];
length [region_arm7_twl] = *(const u32*)&header[0x1DC];
destaddr[region_arm7_twl] = *(const u32*)&header[0x1D8];
for (i = region_header; i < region_max; ++i)
{
u32 len = length[i];
bSuccess = FS_SeekFile(file, (s32)source[i], FS_SEEK_SET);
if( ! bSuccess )
{
OS_TPrintf("RebootSystem failed: cant seek file(%d)\n", source[i]);
FS_CloseFile(file);
return;
}
readLen = ReadFile(file, (void *)destaddr[i], (s32)len);
if( readLen != (s32)len )
{
OS_TPrintf("RebootSystem failed: cant read file(%d, %d)\n", source[i], len);
FS_CloseFile(file);
return;
}
}
(void)FS_CloseFile(file);
}
// ROMƒwƒbƒ_ƒoƒbƒtƒ@ðƒRƒs<C692>[
MI_CpuCopy32( (void *)HW_TWL_ROM_HEADER_BUF, (void *)HW_ROM_HEADER_BUF, HW_ROM_HEADER_BUF_END - HW_ROM_HEADER_BUF );
SYSMi_GetWork()->isLoadSucceeded = TRUE;
}
// Žwèƒ^ƒCƒgƒð•ʃXƒŒƒbƒhŃ<C385><C692>[ƒhŠJŽn·é
void SYSM_StartLoadTitle( TitleProperty *pBootTitle )
{
#define THREAD_PRIO 17
#define STACK_SIZE 0xc00
static u64 stack[ STACK_SIZE / sizeof(u64) ];
// ƒAƒvƒŠ¢ƒ<C2A2><C692>[ƒh<C692>óÔÈç<E2809A><41><C692>[ƒhŠJŽn
if( !pBootTitle->flags.isAppLoadCompleted ) {
SYSMi_GetWork()->isLoadSucceeded = FALSE;
OS_InitThread();
OS_CreateThread( &thread, (void (*)(void *))SYSMi_LoadTitleThreadFunc, (void*)pBootTitle, stack+STACK_SIZE/sizeof(u64), STACK_SIZE,THREAD_PRIO );
OS_WakeupThreadDirect( &thread );
}else if( pBootTitle->flags.isAppRelocate ) {
// ƒAƒvƒŠƒ<C5A0><C692>[ƒh<C692>ÏÝÅ<E2809A>A<EFBFBD>Ä”zu—v<76> èÈç<E2809A>A<EFBFBD>Ä”zu
SYSMi_Relocate();
SYSMi_GetWork()->isLoadSucceeded = TRUE;
}
if( pBootTitle->flags.media == TITLE_MEDIA_CARD ) {
SYSMi_GetWork()->isCardBoot = TRUE;
}
}
// ƒJ<C692>[ƒhƒAƒvƒŠƒP<C692>[ƒVƒ‡ƒ“Ì<E2809A>Ä”zu
static void SYSMi_Relocate( void )
{
u32 size;
// NTRƒZƒLƒ…ƒA—̈æÌ<E2809A>Ä”zu
DC_InvalidateRange( (void *)SYSM_CARD_NTR_SECURE_BUF, SECURE_AREA_SIZE ); // ƒLƒƒƒbƒVƒ…ƒPƒA
size = ( SYSM_GetCardRomHeader()->main_size < SECURE_AREA_SIZE ) ?
SYSM_GetCardRomHeader()->main_size : SECURE_AREA_SIZE;
MI_CpuCopyFast( (void *)SYSM_CARD_NTR_SECURE_BUF, SYSM_GetCardRomHeader()->main_ram_address, size );
if( SYSM_GetCardRomHeader()->platform_code & PLATFORM_CODE_FLAG_TWL ) {
// TWLƒZƒLƒ…ƒA—̈æÌ<E2809A>Ä”zu
DC_InvalidateRange( (void *)SYSM_CARD_TWL_SECURE_BUF, SECURE_AREA_SIZE ); // ƒLƒƒƒbƒVƒ…ƒPƒA
size = ( SYSM_GetCardRomHeader()->main_ltd_size < SECURE_AREA_SIZE ) ?
SYSM_GetCardRomHeader()->main_ltd_size : SECURE_AREA_SIZE;
MI_CpuCopyFast( (void *)SYSM_CARD_TWL_SECURE_BUF, SYSM_GetCardRomHeader()->main_ltd_ram_address, size );
// TWL-ROMƒwƒbƒ_<C692>î•ñÌ<E2809A>Ä”zu
MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BUF, (void *)HW_TWL_ROM_HEADER_BUF, SYSM_CARD_ROM_HEADER_SIZE );
MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BUF, (void *)HW_ROM_HEADER_BUF, HW_ROM_HEADER_BUF_END - HW_ROM_HEADER_BUF );
}else {
// NTR-ROMƒwƒbƒ_<C692>î•ñÌ<E2809A>Ä”zu
MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BUF, (void *)0x027ffe00, HW_ROM_HEADER_BUF_END - HW_ROM_HEADER_BUF ); // 8M̃PƒcÖ<E2809A>iTWLƒfƒoƒbƒKÅÌNTRƒ<C692>[ƒhƒfƒoƒbƒO—p<E28094>j
MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BUF, (void *)0x023ffe00, HW_ROM_HEADER_BUF_END - HW_ROM_HEADER_BUF ); // 4M̃PƒcÖ
}
}
// ƒAƒvƒŠƒ<C5A0><C692>[ƒh<C692>ÏÝ<E2809A>H
BOOL SYSM_IsLoadTitleFinished( TitleProperty *pBootTitle )
{
if( pBootTitle->flags.isAppLoadCompleted ) {
return TRUE;
}
return OS_IsThreadTerminated( &thread );
}
// ƒ<><C692>[ƒh<C692>ÏÝÌŽwèƒ^ƒCƒgƒÌ”F<E2809D>ØÆƒu<C692>[ƒgð<E2809A>s¤
AuthResult SYSM_AuthenticateTitle( TitleProperty *pBootTitle )
{
// ƒ<><C692>[ƒh
if( !SYSM_IsLoadTitleFinished( pBootTitle ) ) {
return AUTH_RESULT_PROCESSING;
}
// ƒ<><C692>[ƒh<C692>¬Œ÷<C592>H
if( SYSMi_GetWork()->isLoadSucceeded == FALSE )
{
return AUTH_RESULT_TITLE_LOAD_FAILED;
}
// ƒpƒ‰ƒ<E280B0><C692>[ƒ^ƒ`ƒFƒbƒN
if( !SYSMi_CheckTitlePointer( pBootTitle ) ) {
return AUTH_RESULT_TITLE_POINTER_ERROR;
}
#if 0
// ƒGƒ“ƒgƒŠƒAƒhƒŒƒXÌ<E2809A>³“<E2809C>«ðƒ`ƒFƒbƒN
if( !SYSMi_CheckEntryAddress() ) {
return AUTH_RESULT_ENTRY_ADDRESS_ERROR;
}
#endif
// <20>¦ROMƒwƒbƒ_”F<E2809D>Ø
// ƒ}ƒEƒ“ƒg<C692>î•ñÌ“o˜^
SYSM_SetBootAppMountInfo ( pBootTitle->titleID );
BOOT_Ready(); // never return.
return AUTH_RESULT_SUCCEEDED;
}
#if 0
// Žwèƒ^ƒCƒgƒÌ”F<E2809D>Ø<EFBFBD>•ƒ<E280A2><C692>[ƒh<C692>@<40>¦PƒtƒŒ<C692>[ƒ€á<E2809A>Iíçñ<E2809A>B
// ൩·éÆŽgíÈ¢©à
void SYSM_LoadAndAuthenticateTitleThread( TitleProperty *pBootTitle )
{
SYSMi_LoadTitleThreadFunc( pBootTitle );
OS_JoinThread(&thread);
// ”F<E2809D>Ø
return SYSM_AuthenticateTitle( pBootTitle );
}
#endif
// ============================================================================
//
// ƒfƒoƒCƒX<C692>§Œä
//
// ============================================================================
// ƒoƒbƒNƒ‰ƒCƒgP“x²<E28099>®
void SYSM_SetBackLightBrightness( u8 brightness )
{
if( brightness > TWL_BACKLIGHT_LEVEL_MAX ) {
OS_Panic( "Backlight brightness over : %d\n", brightness );
}
( void )PMi_WriteRegister( 0x20, (u16)brightness );
TSD_SetBacklightBrightness( brightness );
// [TODO:] ƒoƒbƒNƒ‰ƒCƒgP“x͈‰ñƒZ<C692>[ƒu¹¸É<E2809A>AƒAƒvƒŠN“®âƒŠƒZƒbƒg<C692>A“dŒ¹OFFŽžÉlª•ÏíÁÄ¢½çƒZ<C692>[ƒu·éæ¤É·é<E2809A>B
SYSM_WriteTWLSettingsFile();
}
// ƒ^ƒbƒ`ƒpƒlƒƒLƒƒƒŠƒuƒŒ<C692>[ƒVƒ‡ƒ“
void SYSM_CaribrateTP( void )
{
#ifndef __TP_OFF
TPCalibrateParam calibrate;
( void )TP_CalcCalibrateParam( &calibrate, // ƒ^ƒbƒ`ƒpƒlƒ<C692>‰Šú‰»
GetTSD()->tp.data.raw_x1, GetTSD()->tp.data.raw_y1, (u16)GetTSD()->tp.data.dx1, (u16)GetTSD()->tp.data.dy1,
GetTSD()->tp.data.raw_x2, GetTSD()->tp.data.raw_y2, (u16)GetTSD()->tp.data.dx2, (u16)GetTSD()->tp.data.dy2 );
TP_SetCalibrateParam( &calibrate );
OS_Printf("TP_calib: %4d %4d %4d %4d %4d %4d\n",
GetTSD()->tp.data.raw_x1, GetTSD()->tp.data.raw_y1, (u16)GetTSD()->tp.data.dx1, (u16)GetTSD()->tp.data.dy1,
GetTSD()->tp.data.raw_x2, GetTSD()->tp.data.raw_y2, (u16)GetTSD()->tp.data.dx2, (u16)GetTSD()->tp.data.dy2 );
#endif
}
// RTCƒNƒ<4E>ƒbƒN•â<E280A2>³lðƒZƒbƒg
static void SYSMi_WriteAdjustRTC( void )
{
// <20>¦TWLÌŽžÍ<E2809A>ANANDÌ"/sys/HWINFO.dat"ƒtƒ@ƒCƒ©çŠY“·é<E2809A>î•ñðŽæ“¾·é<E2809A>B
#if 0
FS_OpenFile( "/sys/HWINFO.dat" );
FS_ReadFile( xxxx );
raw = xxxx.rtcRaw;
( void )RTCi_SetRegAdjust( &raw );
#endif
#ifndef __IS_DEBUGGER_BUILD // ƒfƒoƒbƒK—pƒrƒƒhŽžÍ•â<E280A2>³µÈ¢<E2809A>B
RTCRawAdjust raw;
raw.adjust = 0;
// raw.adjust = GetTSD()->rtcClockAdjust; // isValidTSDŽžÉÍrtcClockAdjustÍ
// 0ƒNƒŠƒA³êÄ¢é½ß•â<E280A2>³@”\ÍŽg—p³êÈ¢
( void )RTCi_SetRegAdjust( &raw );
#endif /* __IS_DEBUGGER_BUILD */
}
// ============================================================================
//
// ƒoƒi<C692>[
//
// ============================================================================
// ƒoƒi<C692>[ƒtƒ@ƒCƒÌ“ÇÝ<E2809A>žÝÌŽÀÌ
static BOOL SYSMi_ReadCardBannerFile( u32 bannerOffset, TWLBannerFile *pBanner )
{
#ifndef DEBUG_USED_CARD_SLOT_B_
// <20>¦ƒXƒ<58>ƒbƒgA©ç̃Š<C692>[ƒhÈçâèÈ¢ª<E2809A>AƒXƒ<58>ƒbƒgB©çͼ<E28099>Ú“ÇßÈ¢ÌÅ
BOOL isRead;
u16 id = (u16)OS_GetLockID();
// ROMƒJ<C692>[ƒh©ç̃oƒi<C692>[ƒf<C692>[ƒ^̃Š<C692>[ƒh
DC_FlushRange( pBanner, sizeof(TWLBannerFile) );
CARD_LockRom( id );
CARD_ReadRom( 4, (void *)bannerOffset, pBanner, sizeof(TWLBannerFile) );
CARD_UnlockRom( id );
OS_ReleaseLockID( id );
isRead = SYSMi_CheckBannerFile( (NTRBannerFile *)pBanner );
if( !isRead ) {
MI_CpuClearFast( pBanner, sizeof(TWLBannerFile) );
}
return isRead;
#else
#pragma unused(bannerOffset)
if( SYSMi_GetWork()->isValidCardBanner ) {
DC_InvalidateRange( (void *)SYSM_CARD_BANNER_BUF, 0x3000 );
MI_CpuCopyFast( (void *)SYSM_CARD_BANNER_BUF, pBanner, sizeof(TWLBannerFile) );
}
return SYSMi_GetWork()->isValidCardBanner;
#endif
}
// ƒoƒi<C692>[ƒf<C692>[ƒ^Ì<E2809A>³Œëƒ`ƒFƒbƒN
static BOOL SYSMi_CheckBannerFile( NTRBannerFile *pBanner )
{
int i;
BOOL retval = TRUE;
u16 calc_crc = 0xffff;
u16 *pHeaderCRC = (u16 *)&pBanner->h.crc16_v1;
BannerCheckParam bannerCheckList[ NTR_BNR_VER_MAX ];
BannerCheckParam *pChk = &bannerCheckList[ 0 ];
bannerCheckList[ 0 ].pSrc = (u8 *)&( pBanner->v1 );
bannerCheckList[ 0 ].size = sizeof( BannerFileV1 );
bannerCheckList[ 1 ].pSrc = (u8 *)&( pBanner->v2 );
bannerCheckList[ 1 ].size = sizeof( BannerFileV2 );
bannerCheckList[ 2 ].pSrc = (u8 *)&( pBanner->v3 );
bannerCheckList[ 2 ].size = sizeof( BannerFileV3 );
for( i = 0; i < NTR_BNR_VER_MAX; i++ ) {
if( i < pBanner->h.version ) {
calc_crc = SVC_GetCRC16( calc_crc, pChk->pSrc, pChk->size );
if( calc_crc != *pHeaderCRC++ ) {
retval = FALSE;
break;
}
}else {
MI_CpuClear16( pChk->pSrc, pChk->size );
}
pChk++;
}
return retval;
}
//======================================================================
//
// ŠeŽíƒ`ƒFƒbƒN
//
//======================================================================
// —LŒøÈTWL/NTRƒJ<C692>[ƒhª<E2809A>·³ÁÄ¢é©<E2809A>H
BOOL SYSM_IsExistCard( void )
{
return SYSMi_GetWork()->isExistCard;
}
// ŒŸ<C592>¸—pƒJ<C692>[ƒhª<E2809A>·³ÁÄ¢é©<E2809A>H
BOOL SYSM_IsInspectCard( void )
{
return ( SYSM_IsExistCard() && SYSM_GetCardRomHeader()->inspect_card );
}
// —LŒøÈTWLƒJ<C692>[ƒhª<E2809A>·³ÁÄ¢é©<E2809A>H
BOOL SYSM_IsTWLCard( void );
BOOL SYSM_IsTWLCard( void )
{
return ( SYSM_IsExistCard() && ( SYSM_GetCardRomHeader()->platform_code & PLATFORM_CODE_FLAG_TWL ) );
}
// —LŒøÈNTRƒJ<C692>[ƒhª<E2809A>·³ÁÄ¢é©<E2809A>H
BOOL SYSM_IsNTRCard( void );
BOOL SYSM_IsNTRCard( void )
{
return ( SYSM_IsExistCard() && ( SYSM_GetCardRomHeader()->platform_code == PLATFORM_CODE_NTR ) );
}
// NTR,TWLƒJ<C692>[ƒh<E28098>݃`ƒFƒbƒN <09>uƒŠƒ^<5E>[ƒ“<C692>@1<>FƒJ<C692>[ƒh”Fޝ<C5BD>@0<>FƒJ<C692>[ƒhȵ<E2809A>v
static int SYSMi_IsValidCard( void )
{
if( ( SYSM_GetCardRomHeader()->nintendo_logo_crc16 == 0xcf56 ) &&
( SYSM_GetCardRomHeader()->header_crc16 == SYSMi_GetWork()->cardHeaderCrc16 ) ) {
return TRUE; // NTR,TWLƒJ<C692>[ƒh è<E2809A>iNintendoƒ<6F>ƒSCRC<52>AƒJ<C692>[ƒhƒwƒbƒ_CRCª<E2809A>³µ¢<E2809A>ê<EFBFBD><EFBFBD>j
// <20>¦Nintendoƒ<6F>ƒSƒf<C692>[ƒ^‚̃`ƒFƒbƒNÍ<E2809A>A“ÁÌ“s<E2809C><EFBFBD>ã<EFBFBD><41>ƒS•\ަƒ<C692>[ƒ`ƒ“N“®ŒãÉ<E2809A>s¢Ü·<E2809A>B
}else {
return FALSE; // NTR,TWLƒJ<C692>[ƒhȵ
}
}
// ƒGƒ“ƒgƒŠƒAƒhƒŒƒXÌ<E2809A>³“<E2809C>«ƒ`ƒFƒbƒN
static BOOL SYSMi_CheckEntryAddress( void )
{
// ƒGƒ“ƒgƒŠƒAƒhƒŒƒXªROM“à“o˜^ƒGƒŠƒA©AGBƒJ<C692>[ƒgƒŠƒbƒWƒGƒŠƒAÈç<E2809A>A³ŒÀƒ<C692>[ƒvÉ“üé<E2809A>B
if( !( ( (u32)SYSM_GetCardRomHeader()->main_entry_address >= HW_MAIN_MEM ) &&
( (u32)SYSM_GetCardRomHeader()->main_entry_address < SYSM_ARM9_MMEM_ENTRY_ADDR_LIMIT )
) ||
!( ( ( (u32)SYSM_GetCardRomHeader()->sub_entry_address >= HW_MAIN_MEM ) &&
( (u32)SYSM_GetCardRomHeader()->sub_entry_address < SYSM_ARM7_LOAD_MMEM_LAST_ADDR ) ) ||
( ( (u32)SYSM_GetCardRomHeader()->sub_entry_address >= HW_WRAM ) &&
( (u32)SYSM_GetCardRomHeader()->sub_entry_address < SYSM_ARM7_LOAD_WRAM_LAST_ADDR ) )
)
) {
OS_TPrintf("entry address invalid.\n");
#ifdef __DEBUG_SECURITY_CODE
DispSingleColorScreen( SCREEN_YELLOW );
#endif
return FALSE;
}
OS_TPrintf("entry address valid.\n");
return TRUE;
}
// ƒNƒ<4E><C692>[ƒ“ƒu<C692>[ƒg”»è
static void SYSMi_CheckCardCloneBoot( void )
{
#if 0
u8 *buffp = (u8 *)&pTempBuffer;
u32 total_rom_size = SYSM_GetCardRomHeader()->rom_valid_size ? SYSM_GetCardRomHeader()->rom_valid_size : 0x01000000;
u32 file_offset = total_rom_size & 0xFFFFFE00;
if( !SYSMi_IsValidCard() ) {
return;
}
DC_FlushRange( buffp, BNR_IMAGE_SIZE );
CARD_ReadRom( 4, (void *)file_offset, buffp, BNR_IMAGE_SIZE );
buffp += total_rom_size & 0x000001FF;
if( *buffp++ == 'a' && *buffp == 'c' ) {
SYSMi_GetWork()->cloneBootMode = CLONE_BOOT_MODE;
}else {
SYSMi_GetWork()->cloneBootMode = OTHER_BOOT_MODE;
}
#endif
}
// N“®ŽžÌRTCƒ`ƒFƒbƒN
static void SYSMi_CheckRTC( void )
{
RTCDate date;
RTCTime time;
// RTCÌƒŠƒZƒbƒg or ¨©µ¢lðŒŸ<C592>oµ½<E2809A>ê<EFBFBD>Í<E2809A>‰‰ñN“®ƒV<C692>[ƒPƒ“ƒXÖ<E2809A>B
( void )RTC_GetDateTime( &date, &time );
if( !SYSM_CheckRTCDate( &date ) ||
!SYSM_CheckRTCTime( &time )
#ifndef __IS_DEBUGGER_BUILD // <20>ƒfƒoƒbƒKÅÍRTCÌ“drªÈ¢ÌÅ<E2809A>Aˆ‰ñ±±ÉÐÁ©©ÁÄ<E2809A>Ýèƒf<C692>[ƒ^ª•ЕûƒNƒŠƒA³êĵܤ<E2809A>B±êðh®ƒXƒCƒbƒ`<60>B
||
( SYSMi_GetWork()->rtcStatus & 0x01 )
#endif
) { // RTC̈Ù<CB86>íðŒŸ<C592>oµ½ç<E2809A>Artc“ü—̓tƒ‰ƒO<C692>•rtcOffsetð0ɵÄNVRAMÉ<E2809A>«<E2809A>žÝ<E2809A>B
OS_TPrintf("\"RTC reset\" or \"Illegal RTC data\" detect!\n");
GetTSD()->flags.isSetDateTime = 0;
GetTSD()->rtcOffset = 0;
GetTSD()->rtcLastSetYear = 0;
// <20>¦<EFBFBD>¦ƒ‰ƒCƒg·é<E2809A>H
SYSM_WriteTWLSettingsFile();
}
}
//======================================================================
// ƒfƒoƒbƒO
//======================================================================