From a938401b08d113d649e1504e043c58867d408e0e Mon Sep 17 00:00:00 2001 From: yutaka Date: Wed, 25 Mar 2009 12:00:30 +0000 Subject: [PATCH] =?UTF-8?q?=E3=83=9B=E3=83=AF=E3=82=A4=E3=83=88=E3=83=AA?= =?UTF-8?q?=E3=82=B9=E3=83=88phase3,=20phase4=E5=AE=9F=E8=A3=85=E3=80=81?= =?UTF-8?q?=20=E4=BB=AE=E3=83=87=E3=83=BC=E3=82=BF=E3=83=99=E3=83=BC?= =?UTF-8?q?=E3=82=B9=E7=99=BB=E9=8C=B2=20(2009/03/25=E6=99=82=E7=82=B9?= =?UTF-8?q?=E3=81=A7=E6=9C=AC=E7=89=A9)=20SYSM=5FIGNORE=5FDHT=5FPHASE3?= =?UTF-8?q?=E3=81=AF=E3=83=90=E3=83=8A=E3=83=BC=E3=83=81=E3=82=A7=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=81=A7=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=80=81=20SYSM=5FIGNORE=5FDHT=5FEX=5FNOT=5F?= =?UTF-8?q?FOUND=E3=81=AF=E6=97=A7=E3=83=87=E3=83=BC=E3=82=BF=E3=83=99?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=81=A7=E3=82=82=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=AA=E3=81=84=E3=80=81=20=E3=81=A8?= =?UTF-8?q?=E3=81=84=E3=81=86=E6=84=8F=E5=91=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2767 b08762b0-b915-fc4b-9d8c-17b2551a87ff --- build/buildtools/commondefs | 2 + build/libraries_sysmenu/dht/common/src/dht.c | 373 +- build/libraries_sysmenu/sysmenu/ARM9/Makefile | 10 + .../sysmenu/ARM9/src/title.c | 3319 +++++++++-------- .../DSHashTable/DSHashTableAdHoc.bin | Bin 0 -> 412 bytes .../DSHashTable/DSHashTableEx.bin | Bin 0 -> 160156 bytes build/systemMenu_RED/DSHashTable/Makefile | 6 +- .../DSHashTable/commondefs.DSHashTable | 6 +- build/systemMenu_RED/Launcher/ARM9/src/main.c | 612 +-- docs/メモリマップ_NANDファーム.vsd | Bin 78336 -> 78336 bytes include/sysmenu/dht/dht.h | 153 +- include/sysmenu/dht/dht_format.h | 64 +- include/sysmenu/util.h | 156 +- 13 files changed, 2764 insertions(+), 1937 deletions(-) create mode 100644 build/systemMenu_RED/DSHashTable/DSHashTableAdHoc.bin create mode 100644 build/systemMenu_RED/DSHashTable/DSHashTableEx.bin diff --git a/build/buildtools/commondefs b/build/buildtools/commondefs index f8ea3c53..9bfa8118 100644 --- a/build/buildtools/commondefs +++ b/build/buildtools/commondefs @@ -21,6 +21,8 @@ TWL_IPL_COMMONDEFS_ = TRUE #FIRM_USE_PRODUCT_KEYS = TRUE #SYSM_BUILD_FOR_DEBUGGER = TRUE SYSM_DEV_WHITELIST_CHECK_SKIP ?= TRUE +#SYSM_IGNORE_DHT_PHASE_3 = TRUE +SYSM_IGNORE_DHT_EX_NOT_FOUND ?= TRUE ifeq ($(TARGET_FIRM),SYSTEMMENU) include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs.sysmenu diff --git a/build/libraries_sysmenu/dht/common/src/dht.c b/build/libraries_sysmenu/dht/common/src/dht.c index b968fe2f..6da8cd33 100644 --- a/build/libraries_sysmenu/dht/common/src/dht.c +++ b/build/libraries_sysmenu/dht/common/src/dht.c @@ -49,7 +49,8 @@ static const u8 g_pubkey_DER[ 0xa2 ] = { 0x00, 0x01 }; -static const u8 hmac_key[] = DHT_HMAC_KEY; +static const u8 hmac_key[] = DHT_HMAC_KEY; // for phase1, phase2 +static const u8 hmac_key2[] = DHT_HMAC_KEY2; // for phase3, phase4 static DHTReadFunc imageReadFunc; static void* imageBuffer; @@ -114,6 +115,25 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT) } return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase); } +u32 DHT_GetDatabaseExLength(const DHTFileEx* pDHT) +{ + if ( pDHT->header.magic_code != DHT_MAGIC_CODE_EX ) // magic code`FbN + { + OS_TPrintf("Invalid magic code (magic=0x%08X) [EX].\n", pDHT->header.magic_code); + return 0; + } + return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabaseEx); +} +u32 DHT_GetDatabaseAdHocLength(const DHTFileAdHoc* pDHT) +{ + if ( pDHT->header.magic_code != DHT_MAGIC_CODE_ADHOC ) // magic code`FbN + { + OS_TPrintf("Invalid magic code (magic=0x%08X) [AdHoc].\n", pDHT->header.magic_code); + return 0; + } + return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabaseAdHoc); +} + static BOOL DHT_CheckDatabase(const DHTFile* pDHT) { SVCSignHeapContext pool; @@ -216,6 +236,219 @@ const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* #endif return db; } +/* +gf[^x[Xǂݍ (O) +*/ + +static BOOL DHT_CheckDatabaseEx(const DHTFileEx* pDHT) +{ + SVCSignHeapContext pool; + static u8 heap[4*1024]; // avoid stack overflow + u8 md1[20]; + u8 md2[20]; + s32 result; + // t@Co + SVC_InitSignHeap(&pool, heap, sizeof(heap)); + SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]); + // nbVvZ + SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE_EX(&pDHT->header)); + // + result = SVC_CompareSHA1(md1, md2); + if ( !result ) + { + OS_TPrintf("\n"); + OS_TPrintfEx("SIGN = % 20B [EX]\n", md1); + OS_TPrintfEx("HASH = % 20B [EX]\n", md2); + OS_TPrintf("Signature is not valid. [EX]\n"); + return FALSE; + } + return TRUE; +} + +BOOL DHT_PrepareDatabaseEx(DHTFileEx* pDHT, FSFile* fp) +{ + s32 result; + s32 length; + PROFILE_INIT(); + + if ( fp ) + { + // wb_ǂݍ + PROFILE_COUNT(); + result = FS_ReadFile(fp, &pDHT->header, sizeof(DHTHeader)); + if ( result != sizeof(DHTHeader) ) + { + OS_TPrintf("Cannot read the DHT header (result=%d). [EX]\n", result); + return FALSE; + } + // gf[^x[Xǂݍ + PROFILE_COUNT(); + length = (s32)DHT_GetDatabaseExLength(pDHT) - (s32)sizeof(DHTHeader); // wb_ + if ( length < 0 ) + { + OS_TPrintf("Invalid DHT header. [EX]\n"); + return FALSE; + } + result = FS_ReadFile(fp, pDHT->database, length); + if ( result != length ) + { + OS_TPrintf("Cannot read the DHT database (result=%d). [EX]\n", result); + return FALSE; + } + } + else + { + PROFILE_COUNT(); + PROFILE_COUNT(); + } + + // gf[^x[X̌ + PROFILE_COUNT(); + result = DHT_CheckDatabaseEx(pDHT); + + // ʕ +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to prepare the database. [EX]\n"); + OS_TPrintf("%10d msec for reading header. [EX]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for reading database. [EX]\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for comparing hash. [EX]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("\nTotal: %10d msec. [EX]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0])); +#endif + return result; +} + +/* +ROMwb_ɑΉgf[^x[Xɓ +*/ +const DHTDatabaseEx* DHT_GetDatabaseEx(const DHTFileEx* pDHT, const ROM_Header_Short* pROMHeader) +{ + u8 data[5]; + DHTDatabaseEx* db; + PROFILE_INIT(); + + // + PROFILE_COUNT(); + MI_CpuCopy8( pROMHeader->game_code, data, 4 ); + data[4] = pROMHeader->rom_version; + db = (DHTDatabaseEx*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabaseEx), CompareGameCodeAndVersion); + if ( !db ) + { + OS_TPrintf("Cannot find the database. [EX]\n"); + } +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("%10d msec for searching database. [EX]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); +#endif + return db; +} +/* +•ʑΉf[^x[Xǂݍ (O) +*/ + +static BOOL DHT_CheckDatabaseAdHoc(const DHTFileAdHoc* pDHT) +{ + SVCSignHeapContext pool; + static u8 heap[4*1024]; // avoid stack overflow + u8 md1[20]; + u8 md2[20]; + s32 result; + // t@Co + SVC_InitSignHeap(&pool, heap, sizeof(heap)); + SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]); + // nbVvZ + SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE_EX(&pDHT->header)); + // + result = SVC_CompareSHA1(md1, md2); + if ( !result ) + { + OS_TPrintf("\n"); + OS_TPrintfEx("SIGN = % 20B [AdHoc]\n", md1); + OS_TPrintfEx("HASH = % 20B [AdHoc]\n", md2); + OS_TPrintf("Signature is not valid. [AdHoc]\n"); + return FALSE; + } + return TRUE; +} + +BOOL DHT_PrepareDatabaseAdHoc(DHTFileAdHoc* pDHT, FSFile* fp) +{ + s32 result; + s32 length; + PROFILE_INIT(); + + if ( fp ) + { + // wb_ǂݍ + PROFILE_COUNT(); + result = FS_ReadFile(fp, &pDHT->header, sizeof(DHTHeader)); + if ( result != sizeof(DHTHeader) ) + { + OS_TPrintf("Cannot read the DHT header (result=%d). [AdHoc]\n", result); + return FALSE; + } + // gf[^x[Xǂݍ + PROFILE_COUNT(); + length = (s32)DHT_GetDatabaseAdHocLength(pDHT) - (s32)sizeof(DHTHeader); // wb_ + if ( length < 0 ) + { + OS_TPrintf("Invalid DHT header. [AdHoc]\n"); + return FALSE; + } + result = FS_ReadFile(fp, pDHT->database, length); + if ( result != length ) + { + OS_TPrintf("Cannot read the DHT database (result=%d). [AdHoc]\n", result); + return FALSE; + } + } + else + { + PROFILE_COUNT(); + PROFILE_COUNT(); + } + + // gf[^x[X̌ + PROFILE_COUNT(); + result = DHT_CheckDatabaseAdHoc(pDHT); + + // ʕ +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to prepare the database. [AdHoc]\n"); + OS_TPrintf("%10d msec for reading header. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for reading database. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for comparing hash. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("\nTotal: %10d msec. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0])); +#endif + return result; +} + +/* +ROMwb_ɑΉgf[^x[Xɓ +*/ +static const DHTDatabaseAdHoc* DHT_GetDatabaseAdHoc(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader) +{ + u8 data[5]; + DHTDatabaseAdHoc* db; + PROFILE_INIT(); + + // + PROFILE_COUNT(); + MI_CpuCopy8( pROMHeader->game_code, data, 4 ); + data[4] = pROMHeader->rom_version; + db = (DHTDatabaseAdHoc*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabaseAdHoc), CompareGameCodeAndVersion); + if ( !db ) + { + OS_TPrintf("Cannot find the database. [AdHoc]\n"); + } +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("%10d msec for searching database. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); +#endif + return db; +} + /* nbVvZ (1) ǂݍݍς݃f[^`FbN @@ -468,3 +701,141 @@ void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 l SVC_HMACSHA1Update(ctx, ptr, (u32)length); } } + +/* +nbVvZ (3) +oi[f[^`FbN +*/ +BOOL DHT_CheckHashPhase3(const u8 *hash, const NTRBannerFile* pBanner) +{ + SVCHMACSHA1Context ctx; + u8 md[20]; + + PROFILE_INIT(); + PROFILE_COUNT(); + SVC_HMACSHA1Init(&ctx, hmac_key2, sizeof(hmac_key2)); + + // oi[̓ǂݍ (wb_) + PROFILE_COUNT(); + SVC_HMACSHA1Update(&ctx, &pBanner->h, sizeof(BannerHeader)); + + // oi[̓ǂݍ ({fB) + if (pBanner->h.version == 0) + { + OS_TPrintf("Invalid banner format.\n"); + return FALSE; + } + PROFILE_COUNT(); + if ( pBanner->h.version >= 1 ) + { + SVC_HMACSHA1Update(&ctx, &pBanner->v1, sizeof(BannerFileV1)); + } + PROFILE_COUNT(); + if ( pBanner->h.version >= 2 ) + { + SVC_HMACSHA1Update(&ctx, &pBanner->v2, sizeof(BannerFileV2)); + } + PROFILE_COUNT(); + if ( pBanner->h.version >= 3 ) + { + SVC_HMACSHA1Update(&ctx, &pBanner->v3, sizeof(BannerFileV3)); + } + + // + PROFILE_COUNT(); + SVC_HMACSHA1GetHash(&ctx, md); + if ( !SVC_CompareSHA1(md, hash) ) + { + OS_TPrintf("\n"); + OS_TPrintfEx("DB = % 20B\n", hash); + OS_TPrintfEx("HASH = % 20B\n", md); + OS_TPrintf("%s: banner_hash is not valid.\n", __func__); + return FALSE; + } + // ʕ +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to check the hash (phase 3).\n"); + OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for scanning header.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for scanning V1 body.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("%10d msec for scanning V2 body.\n", (int)OS_TicksToMilliSeconds(profile[4]-profile[3])); + OS_TPrintf("%10d msec for scanning V3 body.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[4])); + OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[5])); + OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[0])); +#endif + return TRUE; +} + +/* +nbVvZ (4) +•ʑΉ +*/ +BOOL DHT_CheckHashPhase4(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTPhase4Work* work, DHTReadFunc func, void* arg) +{ + imageBuffer = work->buffer; + imageReadFunc = func; + return DHT_CheckHashPhase4Ex(pDHT, pROMHeader, ImageHMACSHA1Update, arg); +} + +BOOL DHT_CheckHashPhase4Ex(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTReadFuncEx funcEx, void* arg) +{ + const DHTDatabaseAdHoc* plist; + SVCHMACSHA1Context ctx; + int i; + u8 md[20]; + PROFILE_INIT(); + + if ( !funcEx || !pDHT || !pROMHeader ) + { + return FALSE; + + } + + plist = DHT_GetDatabaseAdHoc(pDHT, pROMHeader); + + if ( !plist ) + { + return TRUE; // not found in individual list + } + + // + PROFILE_COUNT(); + SVC_HMACSHA1Init(&ctx, hmac_key2, sizeof(hmac_key2)); + + for (i = 0; i < DHT_INDIVIDUAL_ENTRY_MAX; i++) + { + if (plist->entry[i].offset == 0) + { + break; + } + if ( !funcEx(&ctx, (s32)plist->entry[i].offset, (s32)plist->entry[i].length, arg) ) + { + OS_TPrintf("Cannot read the phase 3 for %.4s(%x).\n", pROMHeader->game_code, pROMHeader->rom_version); + return FALSE; + } + } + // + PROFILE_COUNT(); + SVC_HMACSHA1GetHash(&ctx, md); + + if ( !SVC_CompareSHA1(md, plist->hash) ) + { + OS_TPrintf("\n"); + OS_TPrintfEx("DB = % 20B\n", plist->hash); + OS_TPrintfEx("HASH = % 20B\n", md); + OS_TPrintf("%s: phase4list->hash is not valid.\n", __func__); + return FALSE; + } + // ʕ +#ifdef PRINT_PROFILE + PROFILE_COUNT(); + OS_TPrintf("\nDone to check the hash (phase 3).\n"); + OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0])); + OS_TPrintf("%10d msec for scanning regions.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1])); + OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2])); + OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0])); +#endif + return TRUE; +} + diff --git a/build/libraries_sysmenu/sysmenu/ARM9/Makefile b/build/libraries_sysmenu/sysmenu/ARM9/Makefile index a0c019ee..e51b3d6e 100644 --- a/build/libraries_sysmenu/sysmenu/ARM9/Makefile +++ b/build/libraries_sysmenu/sysmenu/ARM9/Makefile @@ -62,6 +62,16 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs ifeq ($(SYSM_DEV_WHITELIST_CHECK_SKIP),TRUE) MACRO_FLAGS += -DDEV_WHITELIST_CHECK_SKIP +else + +ifeq ($(SYSM_IGNORE_DHT_PHASE_3),TRUE) +MACRO_FLAGS += -DSYSM_IGNORE_DHT_PHASE_3 +endif + +ifeq ($(SYSM_IGNORE_DHT_EX_NOT_FOUND),TRUE) +MACRO_FLAGS += -DSYSM_IGNORE_DHT_EX_NOT_FOUND +endif + endif INSTALL_TARGETS = $(TARGETS) diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/title.c b/build/libraries_sysmenu/sysmenu/ARM9/src/title.c index 3676ee5c..b319ae54 100644 --- a/build/libraries_sysmenu/sysmenu/ARM9/src/title.c +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/title.c @@ -29,60 +29,60 @@ #define MEASURE_MAKELIST_TIME 0 -#define CARD_BANNER_INDEX ( LAUNCHER_TITLE_LIST_NUM - 1 ) +#define CARD_BANNER_INDEX ( LAUNCHER_TITLE_LIST_NUM - 1 ) -#define LAUNCHER_KEY_INDEX 0 // t@[瑗Ă錮̂LauncherL[̃CfbNX -#define SYSTEM_APP_KEY_INDEX 1 // t@[瑗ĂSYSTEMAvL[̃CfbNX -#define SECURE_APP_KEY_INDEX 2 // t@[瑗ĂSECUREAvL[̃CfbNX -#define USER_APP_KEY_INDEX 3 // t@[瑗ĂUSERAvL[̃CfbNX +#define LAUNCHER_KEY_INDEX 0 // t@[瑗Ă錮̂LauncherL[̃CfbNX +#define SYSTEM_APP_KEY_INDEX 1 // t@[瑗ĂSYSTEMAvL[̃CfbNX +#define SECURE_APP_KEY_INDEX 2 // t@[瑗ĂSECUREAvL[̃CfbNX +#define USER_APP_KEY_INDEX 3 // t@[瑗ĂUSERAvL[̃CfbNX -#define ROM_HEADER_HASH_OFFSET (0x0) // ROMwb_nbVo߂̃ItZbg +#define ROM_HEADER_HASH_OFFSET (0x0) // ROMwb_nbVo߂̃ItZbg -#define SIGN_HEAP_ADDR 0x023c0000 // vẐ߂̃q[v̈JnAhX -#define SIGN_HEAP_SIZE 0x1000 // vẐ߂̃q[vTCY -#define ARM9_ENCRYPT_DEF_SIZE 0x800 // ARM9FLX̐擪Í̃TCY +#define SIGN_HEAP_ADDR 0x023c0000 // vẐ߂̃q[v̈JnAhX +#define SIGN_HEAP_SIZE 0x1000 // vẐ߂̃q[vTCY +#define ARM9_ENCRYPT_DEF_SIZE 0x800 // ARM9FLX̐擪Í̃TCY -#define DIGEST_HASH_BLOCK_SIZE_SHA1 (512/8) -#define TWL_ROM_HEADER_HASH_CALC_DATA_LEN 0xe00 // ROMwb_̃nbVvZ镔̒TWL -#define NTR_ROM_HEADER_HASH_CALC_DATA_LEN 0x160 // ROMwb_̃nbVvZ镔̒DS +#define DIGEST_HASH_BLOCK_SIZE_SHA1 (512/8) +#define TWL_ROM_HEADER_HASH_CALC_DATA_LEN 0xe00 // ROMwb_̃nbVvZ镔̒TWL +#define NTR_ROM_HEADER_HASH_CALC_DATA_LEN 0x160 // ROMwb_̃nbVvZ镔̒DS #define AUTH_KEY_BUFFER_LEN 128 -#define MB_AUTH_SIGN_SIZE (128) /* digital sign size */ +#define MB_AUTH_SIGN_SIZE (128) /* digital sign size */ -#define THREAD_PRIO_FS_WRAM 3 -#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB +#define THREAD_PRIO_FS_WRAM 3 +#define WRAM_SIZE_FOR_FS MI_WRAM_SIZE_96KB #ifdef USE_HYENA_COMPONENT -#define WRAM_SLOT_FOR_FS 5 +#define WRAM_SLOT_FOR_FS 5 #else -#define WRAM_SLOT_FOR_FS 0 +#define WRAM_SLOT_FOR_FS 0 #endif #include -#define DS_HASH_TABLE_SIZE (256*1024) +#define DS_HASH_TABLE_SIZE (512*1024) -#define SYSM_TITLE_MESSAGE_ARRAY_MAX 1 +#define SYSM_TITLE_MESSAGE_ARRAY_MAX 1 -#define SIZE_16KB ( 16 * 1024 ) +#define SIZE_16KB ( 16 * 1024 ) -typedef struct MbAuthCode +typedef struct MbAuthCode { - char magic_code[2]; // }WbNio[ - u16 version; // o[W - u8 sign[MB_AUTH_SIGN_SIZE]; // - u32 serial_number; // VAԍ -} MbAuthCode; // 16byte + char magic_code[2]; // }WbNio[ + u16 version; // o[W + u8 sign[MB_AUTH_SIGN_SIZE]; // + u32 serial_number; // VAԍ +} MbAuthCode; // 16byte typedef struct CalcHMACSHA1CallbackArg { - SVCHMACSHA1Context ctx; - u32 hash_length; + SVCHMACSHA1Context ctx; + u32 hash_length; } CalcHMACSHA1CallbackArg; typedef struct CalcSHA1CallbackArg { - SVCSHA1Context ctx; - u32 hash_length; + SVCSHA1Context ctx; + u32 hash_length; } CalcSHA1CallbackArg; // extern data----------------------------------------------------------------- @@ -101,18 +101,18 @@ static void SYSMi_CpuClearFast( void *dest, u32 size ); // global variable------------------------------------------------------------- // static variable------------------------------------------------------------- -static OSThread s_thread; -static OSThread s_auth_thread; -static TWLBannerFile s_card_bannerBuf; +static OSThread s_thread; +static OSThread s_auth_thread; +static TWLBannerFile s_card_bannerBuf; static MbAuthCode s_authcode; -static BOOL s_loadstart = FALSE; +static BOOL s_loadstart = FALSE; -static BOOL s_loadPaused = FALSE; +static BOOL s_loadPaused = FALSE; -static OSMessageQueue s_msgQ; -static OSMessage s_msgArray[SYSM_TITLE_MESSAGE_ARRAY_MAX]; +static OSMessageQueue s_msgQ; +static OSMessage s_msgArray[SYSM_TITLE_MESSAGE_ARRAY_MAX]; static int s_listLength = 0; @@ -120,21 +120,29 @@ static u8 *s_calc_hash = NULL; static BOOL s_b_dev = FALSE; static BOOL s_result_phase1 = FALSE; -static DHTFile *dht = NULL; -static const u8* hash0 = NULL; -static const u8* hash1 = NULL; +static struct +{ + void* buffer; + DHTFile* dht; // in buffer + DHTFileEx* dhtex; // in buffer + DHTFileAdHoc* dhtah; // in buffer + const u8* hash1; + const u8* hash2; + const u8* hash3; +} +s_dht; // const data------------------------------------------------------------------ static const OSBootType s_launcherToOSBootType[ LAUNCHER_BOOTTYPE_MAX ] = { - OS_BOOTTYPE_ILLEGAL, // ILLEGAL - OS_BOOTTYPE_ROM, // ROM - OS_BOOTTYPE_NAND, // TEMP - OS_BOOTTYPE_NAND, // NAND - OS_BOOTTYPE_MEMORY, // MEMORY + OS_BOOTTYPE_ILLEGAL, // ILLEGAL + OS_BOOTTYPE_ROM, // ROM + OS_BOOTTYPE_NAND, // TEMP + OS_BOOTTYPE_NAND, // NAND + OS_BOOTTYPE_MEMORY, // MEMORY }; // HMAC_SHA1p -static const u8 s_digestDefaultKey[ DIGEST_HASH_BLOCK_SIZE_SHA1 ] = +static const u8 s_digestDefaultKey[ DIGEST_HASH_BLOCK_SIZE_SHA1 ] = { 0x21, 0x06, 0xc0, 0xde, 0xba, 0x98, 0xce, 0x3f, @@ -218,42 +226,166 @@ static BOOL GetDatabaseFilepath(char *path) return TRUE; } -static void PrepareDHTDatabase(void) +// open and read every database (tF[Y4̂ŏɎs邱) +static BOOL PrepareDHTDatabase(void) { char path[256]; - if ( GetDatabaseFilepath( path ) ) + int length; + FSFile file; + + if ( s_dht.buffer ) { - FSFile file; - if ( FS_OpenFileEx(&file, path, FS_FILEMODE_R) ) - { -#if 0 // 1 if using attach_dummyromheader - if ( FS_SeekFile(&file, sizeof(ROM_Header), FS_SEEK_SET) ) -#endif - { - dht = SYSM_Alloc( DS_HASH_TABLE_SIZE ); - if( dht != NULL ) - { - if( DHT_PrepareDatabase(dht, &file) ) - { - DC_FlushRange(dht, DHT_GetDatabaseLength(dht)); - FS_CloseFile(&file); - return; - } - } - } - FS_CloseFile(&file); - } + return TRUE; // already done !? } - - MI_CpuClear8(dht, sizeof(DHTHeader)); - dht = NULL; + + if ( !GetDatabaseFilepath( path ) ) + { + OS_TPrintf("PrepareDHTDatabase failed: DHT file is not found.\n"); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file is not found.\n" ); + } + return FALSE; // database was not found + } + if ( !FS_OpenFileEx(&file, path, FS_FILEMODE_R) ) + { + OS_TPrintf("PrepareDHTDatabase failed: DHT file cannot open.\n"); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file cannot open.\n" ); + } + return FALSE; // cannot open the file + } + length = (int)FS_GetFileLength(&file); + if ( length > DS_HASH_TABLE_SIZE ) + { + OS_TPrintf("PrepareDHTDatabase failed: DHT file size (%d) is too large.\n", length ); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file size (%d) is too large.\n", length ); + } + FS_CloseFile(&file); + return FALSE; // too large + } + +#if 0 // 1 if using attach_dummyromheader + if ( FS_SeekFile(&file, sizeof(ROM_Header), FS_SEEK_SET) ) + { + OS_TPrintf("PrepareDHTDatabase failed: DHT file size (%d) is too small.\n", length ); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file size (%d) is too small.\n", length ); + } + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + FS_CloseFile(&file); + return FALSE; + } +#endif + + s_dht.buffer = SYSM_Alloc( (u32)length ); + if ( !s_dht.buffer ) + { + OS_TPrintf("PrepareDHTDatabase failed: cannot allocate %d bytes for buffer.\n", length ); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot allocate %d bytes for buffer.\n", length ); + } + FS_CloseFile(&file); + return FALSE; // cannot allocate the memory + } + // {f[^x[X + s_dht.dht = s_dht.buffer; + if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dht->header, sizeof(DHTHeader)) ) + { + OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 1/2.\n" ); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 1/2.\n" ); + } + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + FS_CloseFile(&file); + return FALSE; // cannot read the file + } + length = (int)DHT_GetDatabaseLength(s_dht.dht) - (int)sizeof(DHTHeader); + if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dht->database, length) ) + { + OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabase for phase 1/2.\n" ); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabase for phase 1/2.\n" ); + } + s_dht.dht = NULL; + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + FS_CloseFile(&file); + return FALSE; // cannot read the file + } + // gf[^x[X + s_dht.dhtex = (void*)((u32)s_dht.buffer + DHT_GetDatabaseLength(s_dht.dht)); + if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dhtex->header, sizeof(DHTHeader)) ) + { + s_dht.dhtex = NULL; + OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 3.\n" ); + FS_CloseFile(&file); +#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 3.\n" ); + } + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + return FALSE; // cannot read the file +#else + return TRUE; +#endif + } + length = (int)DHT_GetDatabaseExLength(s_dht.dhtex) - (int)sizeof(DHTHeader); + if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dhtex->database, length) ) + { + s_dht.dhtex = NULL; + OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabaseEx for phase 3.\n" ); + FS_CloseFile(&file); +#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabaseEx for phase 3.\n" ); + } + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + return FALSE; // cannot read the file +#else + return TRUE; +#endif + } + // •ʑΉf[^x[X + s_dht.dhtah = (void*)((u32)s_dht.buffer + DHT_GetDatabaseExLength(s_dht.dhtex)); + if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dhtah->header, sizeof(DHTHeader)) ) + { + s_dht.dhtah = NULL; + OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 4.\n" ); + FS_CloseFile(&file); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 4.\n" ); + } + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + return FALSE; // phase 3ǂ߂phase4ǂ߂ȂƂ͂蓾Ȃ + } + length = (int)DHT_GetDatabaseAdHocLength(s_dht.dhtah) - (int)sizeof(DHTHeader); + if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dhtah->database, length) ) + { + s_dht.dhtah = NULL; + OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabaseAdHoc for phase 4.\n" ); + FS_CloseFile(&file); + if(!s_b_dev) { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabaseAdHoc for phase 4.\n" ); + } + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + return FALSE; // phase 3ǂ߂phase4ǂ߂ȂƂ͂蓾Ȃ + } + FS_CloseFile(&file); + return TRUE; } static BOOL WrapperFunc_ReadCardData(void* dest, s32 offset, s32 length, void* arg) { #pragma unused(arg) - HOTSW_ReadCardData( (void *)offset, dest, (u32)length); - return TRUE; + HOTSW_ReadCardData( (void *)offset, dest, (u32)length); + return TRUE; } @@ -272,7 +404,7 @@ static BOOL WrapperFunc_ReadCardData(void* dest, s32 offset, s32 length, void* a // SharedArea Access ver. static inline u16 SCFG_GetBondingOption(void) { - return (u16)(*(u8*)(HW_SYS_CONF_BUF+HWi_WSYS08_OFFSET) & HWi_WSYS08_OP_OPT_MASK); + return (u16)(*(u8*)(HW_SYS_CONF_BUF+HWi_WSYS08_OFFSET) & HWi_WSYS08_OP_OPT_MASK); } @@ -287,122 +419,122 @@ static inline u16 SCFG_GetBondingOption(void) // J[h^Cg̎擾 TitleProperty *SYSM_GetCardTitleList( BOOL *changed ) { - TitleProperty *pTitleList_Card = AMN_getTitlePropertyList(); - if(changed) *changed = FALSE; - - if(s_loadstart) - { - // [hJnĂAwb_^Cg͕ύXȂ - return pTitleList_Card; - } - - if( SYSMi_GetWork()->flags.hotsw.isCardStateChanged ) { - u16 id = (u16)OS_GetLockID(); - const ROM_Header_Short *pROMH_bak = (ROM_Header_Short *)SYSM_CARD_ROM_HEADER_BAK; - - MI_CpuClear32( pTitleList_Card, sizeof(TitleProperty) ); - - (void)OS_LockByWord( id, &SYSMi_GetWork()->lockCardRsc, NULL ); // ARM7Ɣr䂷 - - // ROMwb_obt@̃Rs[ - if( SYSM_IsExistCard() ) { - if( ( pROMH_bak->platform_code & PLATFORM_CODE_FLAG_TWL ) && !UTL_CheckAppRegion( pROMH_bak->card_region_bitmap ) ) { - // TWLAvŃJ[h[W{̂ƈvȂ̂́AJ[hFȂB - OS_TPrintf( "Region Check NG : %llx\n", pROMH_bak->titleID ); - MI_CpuClearFast( (void *)SYSM_APP_ROM_HEADER_BUF, SYSM_APP_ROM_HEADER_SIZE ); // ROMwb_̃NA - MI_CpuClearFast( &s_card_bannerBuf, sizeof(TWLBannerFile) ); // oi[f[^̃NA - }else { - // ROMwb_̃[h - (void)SYSMi_CopyCardRomHeader(); - // oi[f[^̃[h - (void)SYSMi_CopyCardBanner(); - - pTitleList_Card->pBanner = &s_card_bannerBuf; - AMN_stepBannerAnime(0, TRUE); // oi[JE^ZbgȂ - pTitleList_Card->flags.isValid = TRUE; - pTitleList_Card->flags.isAppLoadCompleted = FALSE; - pTitleList_Card->flags.isAppRelocate = TRUE; - MI_CpuCopy8( SYSM_GetCardRomHeader(), AMN_getRomHeaderList(), sizeof(ROM_Header_Short) ); - } - }else { - MI_CpuClearFast( (void *)SYSM_APP_ROM_HEADER_BUF, SYSM_APP_ROM_HEADER_SIZE ); // ROMwb_̃NA - MI_CpuClearFast( &s_card_bannerBuf, sizeof(TWLBannerFile) ); // oi[f[^̃NA - } - - SYSMi_GetWork()->flags.hotsw.isCardStateChanged = FALSE; // J[hXVtO𗎂Ƃ - (void)OS_UnlockByWord( id, &SYSMi_GetWork()->lockCardRsc, NULL ); // ARM7Ɣr䂷 - OS_ReleaseLockID( id ); - - // ^CgtÕZbg - pTitleList_Card->flags.bootType = LAUNCHER_BOOTTYPE_ROM; - - if( SYSM_GetCardRomHeader()->platform_code & PLATFORM_CODE_FLAG_TWL ) { - // TWLAv̎́ATitleID̂܂܃Zbg - pTitleList_Card->titleID = *(u64 *)( &SYSM_GetCardRomHeader()->titleID_Lo ); - }else { - // NTRAv̎́ATitleIDȂ̂ŁAGameCodeċ[ITitleIDƂB - pTitleList_Card->titleID = (u64)( ( SYSM_GetCardRomHeader()->game_code[ 3 ] << 0 ) | - ( SYSM_GetCardRomHeader()->game_code[ 2 ] << 8 ) | - ( SYSM_GetCardRomHeader()->game_code[ 1 ] << 16 ) | - ( SYSM_GetCardRomHeader()->game_code[ 0 ] << 24 ) ); - } - if(changed) *changed = TRUE; - } - - return pTitleList_Card; + TitleProperty *pTitleList_Card = AMN_getTitlePropertyList(); + if(changed) *changed = FALSE; + + if(s_loadstart) + { + // [hJnĂAwb_^Cg͕ύXȂ + return pTitleList_Card; + } + + if( SYSMi_GetWork()->flags.hotsw.isCardStateChanged ) { + u16 id = (u16)OS_GetLockID(); + const ROM_Header_Short *pROMH_bak = (ROM_Header_Short *)SYSM_CARD_ROM_HEADER_BAK; + + MI_CpuClear32( pTitleList_Card, sizeof(TitleProperty) ); + + (void)OS_LockByWord( id, &SYSMi_GetWork()->lockCardRsc, NULL ); // ARM7Ɣr䂷 + + // ROMwb_obt@̃Rs[ + if( SYSM_IsExistCard() ) { + if( ( pROMH_bak->platform_code & PLATFORM_CODE_FLAG_TWL ) && !UTL_CheckAppRegion( pROMH_bak->card_region_bitmap ) ) { + // TWLAvŃJ[h[W{̂ƈvȂ̂́AJ[hFȂB + OS_TPrintf( "Region Check NG : %llx\n", pROMH_bak->titleID ); + MI_CpuClearFast( (void *)SYSM_APP_ROM_HEADER_BUF, SYSM_APP_ROM_HEADER_SIZE ); // ROMwb_̃NA + MI_CpuClearFast( &s_card_bannerBuf, sizeof(TWLBannerFile) ); // oi[f[^̃NA + }else { + // ROMwb_̃[h + (void)SYSMi_CopyCardRomHeader(); + // oi[f[^̃[h + (void)SYSMi_CopyCardBanner(); + + pTitleList_Card->pBanner = &s_card_bannerBuf; + AMN_stepBannerAnime(0, TRUE); // oi[JE^ZbgȂ + pTitleList_Card->flags.isValid = TRUE; + pTitleList_Card->flags.isAppLoadCompleted = FALSE; + pTitleList_Card->flags.isAppRelocate = TRUE; + MI_CpuCopy8( SYSM_GetCardRomHeader(), AMN_getRomHeaderList(), sizeof(ROM_Header_Short) ); + } + }else { + MI_CpuClearFast( (void *)SYSM_APP_ROM_HEADER_BUF, SYSM_APP_ROM_HEADER_SIZE ); // ROMwb_̃NA + MI_CpuClearFast( &s_card_bannerBuf, sizeof(TWLBannerFile) ); // oi[f[^̃NA + } + + SYSMi_GetWork()->flags.hotsw.isCardStateChanged = FALSE; // J[hXVtO𗎂Ƃ + (void)OS_UnlockByWord( id, &SYSMi_GetWork()->lockCardRsc, NULL ); // ARM7Ɣr䂷 + OS_ReleaseLockID( id ); + + // ^CgtÕZbg + pTitleList_Card->flags.bootType = LAUNCHER_BOOTTYPE_ROM; + + if( SYSM_GetCardRomHeader()->platform_code & PLATFORM_CODE_FLAG_TWL ) { + // TWLAv̎́ATitleID̂܂܃Zbg + pTitleList_Card->titleID = *(u64 *)( &SYSM_GetCardRomHeader()->titleID_Lo ); + }else { + // NTRAv̎́ATitleIDȂ̂ŁAGameCodeċ[ITitleIDƂB + pTitleList_Card->titleID = (u64)( ( SYSM_GetCardRomHeader()->game_code[ 3 ] << 0 ) | + ( SYSM_GetCardRomHeader()->game_code[ 2 ] << 8 ) | + ( SYSM_GetCardRomHeader()->game_code[ 1 ] << 16 ) | + ( SYSM_GetCardRomHeader()->game_code[ 0 ] << 24 ) ); + } + if(changed) *changed = TRUE; + } + + return pTitleList_Card; } // J[hROMwb_ARM7obt@ARM9obt@ւ̃Rs[ BOOL SYSMi_CopyCardRomHeader( void ) { - BOOL retval = FALSE; + BOOL retval = FALSE; - if( SYSM_IsExistCard() ) { - // ROMwb_̃[h - DC_InvalidateRange( (void *)SYSM_CARD_ROM_HEADER_BAK, SYSM_APP_ROM_HEADER_SIZE ); // LbVPA - MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BAK, (void *)SYSM_APP_ROM_HEADER_BUF, SYSM_APP_ROM_HEADER_SIZE ); // ROMwb_Rs[ + if( SYSM_IsExistCard() ) { + // ROMwb_̃[h + DC_InvalidateRange( (void *)SYSM_CARD_ROM_HEADER_BAK, SYSM_APP_ROM_HEADER_SIZE ); // LbVPA + MI_CpuCopyFast( (void *)SYSM_CARD_ROM_HEADER_BAK, (void *)SYSM_APP_ROM_HEADER_BUF, SYSM_APP_ROM_HEADER_SIZE ); // ROMwb_Rs[ - retval = TRUE; - } + retval = TRUE; + } - return retval; + return retval; } // J[hoi[ARM7obt@ARM9obt@ւ̃Rs[ BOOL SYSMi_CopyCardBanner( void ) { - BOOL retval = FALSE; + BOOL retval = FALSE; - if( SYSM_IsExistCard() ) { - // oi[f[^̃Rs[ - TWLBannerFile *pBanner = &s_card_bannerBuf; - if( SYSMi_GetWork()->flags.hotsw.isValidCardBanner ) { - DC_InvalidateRange( (void *)SYSM_CARD_BANNER_BUF, 0x3000 ); - MI_CpuCopyFast( (void *)SYSM_CARD_BANNER_BUF, pBanner, sizeof(TWLBannerFile) ); - } - retval = AMN_checkBannerFile( pBanner ); - - if( !retval ) { - MI_CpuClearFast( pBanner, sizeof(TWLBannerFile) ); - } - } + if( SYSM_IsExistCard() ) { + // oi[f[^̃Rs[ + TWLBannerFile *pBanner = &s_card_bannerBuf; + if( SYSMi_GetWork()->flags.hotsw.isValidCardBanner ) { + DC_InvalidateRange( (void *)SYSM_CARD_BANNER_BUF, 0x3000 ); + MI_CpuCopyFast( (void *)SYSM_CARD_BANNER_BUF, pBanner, sizeof(TWLBannerFile) ); + } + retval = AMN_checkBannerFile( pBanner ); - return retval; + if( !retval ) { + MI_CpuClearFast( pBanner, sizeof(TWLBannerFile) ); + } + } + + return retval; } void SYSM_InitTitleList( void ) { - AMN_init( SYSM_Alloc, SYSM_Free ); + AMN_init( SYSM_Alloc, SYSM_Free ); } // SYSM_InitTitleListOɌĂԕKv void SYSM_MakeNandTitleListMakerInfo( void ) { - AMN_restartWithReadNandTitleHeaderShort(); - while (!AMN_isNandTitleListReady()) { - OS_Sleep(1); - } + AMN_restartWithReadNandTitleHeaderShort(); + while (!AMN_isNandTitleListReady()) { + OS_Sleep(1); + } } // [`ΏۂƂȂNAND^CgXg̎擾 @@ -410,33 +542,33 @@ void SYSM_MakeNandTitleListMakerInfo( void ) // return:TitleXg̃|C^ TitleProperty *SYSM_GetNandTitleList( void ) { - // filter_flag : ALL, ALL_APP, SYS_APP, USER_APP, Data only, ̏w肵ă^CgXg擾B - AMN_restartWithReadNandTitle(); - while (!AMN_isNandTitleListReady()) { - OS_Sleep(1); - } - return AMN_getTitlePropertyList(); + // filter_flag : ALL, ALL_APP, SYS_APP, USER_APP, Data only, ̏w肵ă^CgXg擾B + AMN_restartWithReadNandTitle(); + while (!AMN_isNandTitleListReady()) { + OS_Sleep(1); + } + return AMN_getTitlePropertyList(); } // SYSM_InitTitleListOɌĂԕKv void SYSM_MakeNandTitleListMakerInfoAsync( void ) { - AMN_restartWithReadNandTitleHeaderShort(); + AMN_restartWithReadNandTitleHeaderShort(); } void SYSM_MakeNandTitleListAsync( void ) { - AMN_restartWithReadNandTitle(); + AMN_restartWithReadNandTitle(); } BOOL SYSM_isNandTitleListReady( void ) { - return AMN_isNandTitleListReady(); + return AMN_isNandTitleListReady(); } TitleProperty *SYSM_GetTitlePropertyList( void ) { - return AMN_getTitlePropertyList(); + return AMN_getTitlePropertyList(); } // ============================================================================ @@ -449,142 +581,142 @@ TitleProperty *SYSM_GetTitlePropertyList( void ) static void CallbackSub_DecryptAES(const void* addr, const void* orig_addr, u32 len, MIWramPos wram, s32 slot) { - OSIntrMode enabled = OS_DisableInterrupts();// WRAM؂ւrŊ荞ݔʃXbhWRAM؂ւS̉”\̂ŎbΉ - MI_SwitchWramSlot( wram, slot, MI_WRAM_SIZE_32KB, MI_WRAM_ARM9, MI_WRAM_ARM7 );// Wram7ɃXCb` - SYSM_StartDecryptAESRegion_W( addr, orig_addr, len ); // AES̈fNvg - MI_SwitchWramSlot( wram, slot, MI_WRAM_SIZE_32KB, MI_WRAM_ARM7, MI_WRAM_ARM9 );// Wram7ɃXCb`Ă܂Ă̂Ŗ߂ - OS_RestoreInterrupts(enabled);// 荞݋ + OSIntrMode enabled = OS_DisableInterrupts();// WRAM؂ւrŊ荞ݔʃXbhWRAM؂ւS̉”\̂ŎbΉ + MI_SwitchWramSlot( wram, slot, MI_WRAM_SIZE_32KB, MI_WRAM_ARM9, MI_WRAM_ARM7 );// Wram7ɃXCb` + SYSM_StartDecryptAESRegion_W( addr, orig_addr, len ); // AES̈fNvg + MI_SwitchWramSlot( wram, slot, MI_WRAM_SIZE_32KB, MI_WRAM_ARM7, MI_WRAM_ARM9 );// Wram7ɃXCb`Ă܂Ă̂Ŗ߂ + OS_RestoreInterrupts(enabled);// 荞݋ } static void SYSMi_CalcHMACSHA1Callback(const void* addr, const void* orig_addr, u32 len, MIWramPos wram, s32 slot, void* arg) { - CalcHMACSHA1CallbackArg *cba = (CalcHMACSHA1CallbackArg *)arg; - u32 calc_len = ( cba->hash_length < len ? cba->hash_length : len ); - CallbackSub_DecryptAES( addr, orig_addr, len, wram, slot ); - if( calc_len == 0 ) return; - cba->hash_length -= calc_len; - SVC_HMACSHA1Update( &cba->ctx, addr, calc_len ); + CalcHMACSHA1CallbackArg *cba = (CalcHMACSHA1CallbackArg *)arg; + u32 calc_len = ( cba->hash_length < len ? cba->hash_length : len ); + CallbackSub_DecryptAES( addr, orig_addr, len, wram, slot ); + if( calc_len == 0 ) return; + cba->hash_length -= calc_len; + SVC_HMACSHA1Update( &cba->ctx, addr, calc_len ); } static void SYSMi_CalcSHA1Callback(const void* addr, const void* orig_addr, u32 len, MIWramPos wram, s32 slot, void* arg) { - CalcSHA1CallbackArg *cba = (CalcSHA1CallbackArg *)arg; - u32 calc_len = ( cba->hash_length < len ? cba->hash_length : len ); - CallbackSub_DecryptAES( addr, orig_addr, len, wram, slot ); - if( calc_len == 0 ) return; - cba->hash_length -= calc_len; - SVC_SHA1Update( &cba->ctx, addr, calc_len ); + CalcSHA1CallbackArg *cba = (CalcSHA1CallbackArg *)arg; + u32 calc_len = ( cba->hash_length < len ? cba->hash_length : len ); + CallbackSub_DecryptAES( addr, orig_addr, len, wram, slot ); + if( calc_len == 0 ) return; + cba->hash_length -= calc_len; + SVC_SHA1Update( &cba->ctx, addr, calc_len ); } static void SYSMi_DHTPhase1Callback(const void* addr, const void* orig_addr, u32 len, MIWramPos wram, s32 slot, void* arg) { - CalcHMACSHA1CallbackArg *cba = (CalcHMACSHA1CallbackArg *)arg; - u32 calc_len = ( cba->hash_length < len ? cba->hash_length : len ); - CallbackSub_DecryptAES( addr, orig_addr, len, wram, slot ); - if( calc_len == 0 ) return; - cba->hash_length -= calc_len; - DHT_CheckHashPhase1Update( &cba->ctx, addr, (s32)calc_len ); + CalcHMACSHA1CallbackArg *cba = (CalcHMACSHA1CallbackArg *)arg; + u32 calc_len = ( cba->hash_length < len ? cba->hash_length : len ); + CallbackSub_DecryptAES( addr, orig_addr, len, wram, slot ); + if( calc_len == 0 ) return; + cba->hash_length -= calc_len; + DHT_CheckHashPhase1Update( &cba->ctx, addr, (s32)calc_len ); } static void SYSMi_FinalizeHotSWAsync( TitleProperty *pBootTitle, ROM_Header *head ) { - HotSwCardState card_state; + HotSwCardState card_state; ROM_Header* rh = (void*)SYSM_APP_ROM_HEADER_BUF; - DC_StoreRange( head, sizeof(ROM_Header) ); + DC_StoreRange( head, sizeof(ROM_Header) ); - switch( pBootTitle->flags.bootType ) - { - case LAUNCHER_BOOTTYPE_NAND: - case LAUNCHER_BOOTTYPE_TEMP: - // ROMwb_̃ANZXRg[ƂɃJ[hԂ𐧌䂷̂ "NAND/TMPu[gTWL-LTD" Av̂ - if ( ( head->s.platform_code & PLATFORM_CODE_TWL_LIMITED ) == PLATFORM_CODE_TWL_LIMITED ) - { - if(rh->s.access_control.game_card_nitro_mode){ - card_state = HOTSW_CARD_STATE_GAME_MODE; - } + switch( pBootTitle->flags.bootType ) + { + case LAUNCHER_BOOTTYPE_NAND: + case LAUNCHER_BOOTTYPE_TEMP: + // ROMwb_̃ANZXRg[ƂɃJ[hԂ𐧌䂷̂ "NAND/TMPu[gTWL-LTD" Av̂ + if ( ( head->s.platform_code & PLATFORM_CODE_TWL_LIMITED ) == PLATFORM_CODE_TWL_LIMITED ) + { + if(rh->s.access_control.game_card_nitro_mode){ + card_state = HOTSW_CARD_STATE_GAME_MODE; + } else if(rh->s.access_control.game_card_on){ - card_state = HOTSW_CARD_STATE_NORMAL_MODE; - }else - { - card_state = HOTSW_CARD_STATE_POWER_OFF; - } - } - // ȊO͋INTR݊GamëɃANZX”\ȏԂƂȂiDS_E[hvC܂ށj - else - { - card_state = HOTSW_CARD_STATE_GAME_MODE; - } - break; - case LAUNCHER_BOOTTYPE_ROM: - default: - card_state = HOTSW_CARD_STATE_KEEP; - break; - } + card_state = HOTSW_CARD_STATE_NORMAL_MODE; + }else + { + card_state = HOTSW_CARD_STATE_POWER_OFF; + } + } + // ȊO͋INTR݊GamëɃANZX”\ȏԂƂȂiDS_E[hvC܂ށj + else + { + card_state = HOTSW_CARD_STATE_GAME_MODE; + } + break; + case LAUNCHER_BOOTTYPE_ROM: + default: + card_state = HOTSW_CARD_STATE_KEEP; + break; + } - HOTSW_FinalizeHotSWAsync( card_state ); + HOTSW_FinalizeHotSWAsync( card_state ); } static void SYSMi_LoadTitleThreadFunc( TitleProperty *pBootTitle ) { - enum - { - region_header = 0, - region_arm9_ntr, - region_arm7_ntr, - region_arm9_twl, - region_arm7_twl, - region_max - }; - // DS_E[hvCpictochatNTRgNANDAv̎́AROMwb_ޔ - // ANTR-ROMwb_͋pb`ƃfobKpb`𓖂ĂKv邽߁AĔzurebootCuōsB - - // [h + enum + { + region_header = 0, + region_arm9_ntr, + region_arm7_ntr, + region_arm9_twl, + region_arm7_twl, + region_max + }; + // DS_E[hvCpictochatNTRgNANDAv̎́AROMwb_ޔ + // ANTR-ROMwb_͋pb`ƃfobKpb`𓖂ĂKv邽߁AĔzurebootCuōsB + + // [h char path[256]; FSFile file[1]; BOOL bSuccess; BOOL isTwlApp = TRUE; BOOL isCardApp = FALSE; - - switch( pBootTitle->flags.bootType ) - { - case LAUNCHER_BOOTTYPE_NAND: - // NAND - NAM_GetTitleBootContentPathFast(path, pBootTitle->titleID); - break; - case LAUNCHER_BOOTTYPE_ROM: - // CARD - isCardApp = TRUE; - break; - case LAUNCHER_BOOTTYPE_TEMP: - // tmptH_ - STD_TSNPrintf( path, 256, OS_TMP_APP_PATH, pBootTitle->titleID ); - break; - default: - // unknown - UTL_SetFatalError(FATAL_ERROR_LOAD_UNKNOWN_BOOTTYPE); - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "TitleID : %016llx \n", pBootTitle->titleID ); - ERRORLOG_Printf( "flags.isValid : %d\n", pBootTitle->flags.isValid ); - ERRORLOG_Printf( "flags.bootType : %d\n", pBootTitle->flags.bootType ); - ERRORLOG_Printf( "isAppLoadCompl : %d\n", pBootTitle->flags.isAppLoadCompleted ); - return; - } - if(!isCardApp) - { - FS_InitFile( file ); - bSuccess = FS_OpenFileEx(file, path, FS_FILEMODE_R); + switch( pBootTitle->flags.bootType ) + { + case LAUNCHER_BOOTTYPE_NAND: + // NAND + NAM_GetTitleBootContentPathFast(path, pBootTitle->titleID); + break; + case LAUNCHER_BOOTTYPE_ROM: + // CARD + isCardApp = TRUE; + break; + case LAUNCHER_BOOTTYPE_TEMP: + // tmptH_ + STD_TSNPrintf( path, 256, OS_TMP_APP_PATH, pBootTitle->titleID ); + break; + default: + // unknown + UTL_SetFatalError(FATAL_ERROR_LOAD_UNKNOWN_BOOTTYPE); + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "TitleID : %016llx \n", pBootTitle->titleID ); + ERRORLOG_Printf( "flags.isValid : %d\n", pBootTitle->flags.isValid ); + ERRORLOG_Printf( "flags.bootType : %d\n", pBootTitle->flags.bootType ); + ERRORLOG_Printf( "isAppLoadCompl : %d\n", pBootTitle->flags.isAppLoadCompleted ); + return; + } + + if(!isCardApp) + { + FS_InitFile( file ); + bSuccess = FS_OpenFileEx(file, path, FS_FILEMODE_R); }else { - bSuccess = TRUE; - } + bSuccess = TRUE; + } if( ! bSuccess ) { OS_TPrintf("RebootSystem failed: cant open file\n"); - UTL_SetFatalError(FATAL_ERROR_LOAD_OPENFILE_FAILED); - goto ERROR; + UTL_SetFatalError(FATAL_ERROR_LOAD_OPENFILE_FAILED); + goto ERROR; } { @@ -597,63 +729,63 @@ OS_TPrintf("RebootSystem failed: cant open file\n"); ROM_Header *head = (ROM_Header *)header; CalcHMACSHA1CallbackArg dht_arg; - // WRAMpRead֐̏A - // gpR|[lgɉāAWRAM̃XbgĂ - // hyena : WRAM_C slot 5-7 - // jackal : WRAM_C slot 0-2 - FS_InitWramTransfer( THREAD_PRIO_FS_WRAM ); - MI_FreeWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM7 ); - MI_FreeWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9 ); - MI_FreeWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_DSP ); - MI_CancelWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM7 ); - MI_CancelWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9 ); - MI_CancelWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_DSP ); - - // nbVi[pobt@iq[vĂ邯ǕύX邩j - s_calc_hash = SYSM_Alloc( region_max * SVC_SHA1_DIGEST_SIZE ); - if(!s_calc_hash) - { + // WRAMpRead֐̏A + // gpR|[lgɉāAWRAM̃XbgĂ + // hyena : WRAM_C slot 5-7 + // jackal : WRAM_C slot 0-2 + FS_InitWramTransfer( THREAD_PRIO_FS_WRAM ); + MI_FreeWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM7 ); + MI_FreeWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9 ); + MI_FreeWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_DSP ); + MI_CancelWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM7 ); + MI_CancelWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_ARM9 ); + MI_CancelWramSlot_C( WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, MI_WRAM_DSP ); + + // nbVi[pobt@iq[vĂ邯ǕύX邩j + s_calc_hash = SYSM_Alloc( region_max * SVC_SHA1_DIGEST_SIZE ); + if(!s_calc_hash) + { OS_TPrintf("RebootSystem failed: Alloc Failed.\n"); - UTL_SetFatalError(FATAL_ERROR_LOAD_MEMALLOC_FAILED); - goto ERROR; - } + UTL_SetFatalError(FATAL_ERROR_LOAD_MEMALLOC_FAILED); + goto ERROR; + } // ܂ROMwb_ǂݍ if(!isCardApp) { - bSuccess = FS_SeekFile(file, 0x00000000, FS_SEEK_SET); - }else - { - bSuccess = TRUE; - } + bSuccess = FS_SeekFile(file, 0x00000000, FS_SEEK_SET); + }else + { + bSuccess = TRUE; + } if( ! bSuccess ) { OS_TPrintf("RebootSystem failed: cant seek file(0)\n"); - UTL_SetFatalError(FATAL_ERROR_LOAD_SEEKFILE_FAILED); - goto ERROR; + UTL_SetFatalError(FATAL_ERROR_LOAD_SEEKFILE_FAILED); + goto ERROR; } - //wb_ǂݍ݂ƓɊenbVvZccłȂiNTRTWLʂłȂ߁ĵœǂݍ݂̂ - { + //wb_ǂݍ݂ƓɊenbVvZccłȂiNTRTWLʂłȂ߁ĵœǂݍ݂̂ + { BOOL result; u32 len = MATH_ROUNDUP( (s32)sizeof(header), SYSM_ALIGNMENT_LOAD_MODULE ); if(!isCardApp) - { - result = FS_ReadFileViaWram(file, (void *)header, (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, NULL, NULL ); - }else - { - result = HOTSW_ReadCardViaWram((void*) 0, (void*)header, (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, NULL, NULL ); - } - if ( !result ) - { + { + result = FS_ReadFileViaWram(file, (void *)header, (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, NULL, NULL ); + }else + { + result = HOTSW_ReadCardViaWram((void*) 0, (void*)header, (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, NULL, NULL ); + } + if ( !result ) + { OS_TPrintf("RebootSystem failed: cant read file(%d, %d)\n", 0, len); - UTL_SetFatalError(FATAL_ERROR_LOAD_READHEADER_FAILED); - goto ERROR; - } - } + UTL_SetFatalError(FATAL_ERROR_LOAD_READHEADER_FAILED); + goto ERROR; + } + } if( head->s.nintendo_logo_crc16 != 0xCF56 ) { @@ -667,301 +799,301 @@ OS_TPrintf("%02X ", header[i * 0x10 + j]); OS_TPrintf("\n"); } OS_TPrintf("RebootSystem failed: logo CRC error\n"); - UTL_SetFatalError(FATAL_ERROR_LOAD_LOGOCRC_ERROR); - goto ERROR; + UTL_SetFatalError(FATAL_ERROR_LOAD_LOGOCRC_ERROR); + goto ERROR; } - + if( !(head->s.platform_code & PLATFORM_CODE_FLAG_TWL) ) { - //NTRpROM or NTR TWLΉ̃Av - isTwlApp = FALSE; - if( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_TEMP) - { - // NTR-DLAv̏ꍇDLAvf[^擾Ă - u32 valid_size = ( head->s.rom_valid_size ? head->s.rom_valid_size : 0x01000000 ); + //NTRpROM or NTR TWLΉ̃Av + isTwlApp = FALSE; + if( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_TEMP) + { + // NTR-DLAv̏ꍇDLAvf[^擾Ă + u32 valid_size = ( head->s.rom_valid_size ? head->s.rom_valid_size : 0x01000000 ); - bSuccess = FS_SeekFile(file, (s32)valid_size, FS_SEEK_SET); + bSuccess = FS_SeekFile(file, (s32)valid_size, FS_SEEK_SET); - if( ! bSuccess ) - { + if( ! bSuccess ) + { OS_TPrintf("RebootSystem failed: cant seek file(0)\n"); - UTL_SetFatalError(FATAL_ERROR_LOAD_SEEKFILE_FAILED); - goto ERROR; - } - readLen = FS_ReadFile(file, &s_authcode, (s32)sizeof(s_authcode)); - if( readLen != (s32)sizeof(s_authcode) ) - { + UTL_SetFatalError(FATAL_ERROR_LOAD_SEEKFILE_FAILED); + goto ERROR; + } + readLen = FS_ReadFile(file, &s_authcode, (s32)sizeof(s_authcode)); + if( readLen != (s32)sizeof(s_authcode) ) + { OS_TPrintf("RebootSystem failed: cant read file(%p, %d, %d, %d)\n", &s_authcode, 0, sizeof(s_authcode), readLen); - UTL_SetFatalError(FATAL_ERROR_LOAD_READDLSIGN_FAILED); - goto ERROR; - } - } - } - - // wb_̃nbVvZ - SVC_CalcSHA1( s_calc_hash, header, (u32)( ( isTwlApp || ( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND ) || head->s.exFlags.enable_nitro_whitelist_signature ) ? - TWL_ROM_HEADER_HASH_CALC_DATA_LEN : NTR_ROM_HEADER_HASH_CALC_DATA_LEN )); - - //̎_Ńwb_̐ - // ROMwb_F - if( !SYSMi_AuthenticateHeader( pBootTitle, head ) ) - { - UTL_SetFatalError(FATAL_ERROR_LOAD_AUTH_HEADER_FAILED); - goto ERROR; - } - - // ̌؂ꂽwb_A{̃wb_obt@փRs[ - MI_CpuCopy8( head, (void*)SYSM_APP_ROM_HEADER_BUF, HW_TWL_ROM_HEADER_BUF_SIZE ); - - // NTRJ[hAvDHTPhase1̂߂̌vZKv - if( !isTwlApp && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) - { - DHT_CheckHashPhase1Init(&dht_arg.ctx, &head->s); - } - - // wb_ǂݍ݊̏ - // wb_ǂݍ݊tO𗧂Ă - SYSM_SetHeaderLoadCompleted(TRUE); - - // HOTSWIL - SYSMi_FinalizeHotSWAsync( pBootTitle, (void*)SYSM_APP_ROM_HEADER_BUF ); - + UTL_SetFatalError(FATAL_ERROR_LOAD_READDLSIGN_FAILED); + goto ERROR; + } + } + } + + // wb_̃nbVvZ + SVC_CalcSHA1( s_calc_hash, header, (u32)( ( isTwlApp || ( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND ) || head->s.exFlags.enable_nitro_whitelist_signature ) ? + TWL_ROM_HEADER_HASH_CALC_DATA_LEN : NTR_ROM_HEADER_HASH_CALC_DATA_LEN )); + + //̎_Ńwb_̐ + // ROMwb_F + if( !SYSMi_AuthenticateHeader( pBootTitle, head ) ) + { + UTL_SetFatalError(FATAL_ERROR_LOAD_AUTH_HEADER_FAILED); + goto ERROR; + } + + // ̌؂ꂽwb_A{̃wb_obt@փRs[ + MI_CpuCopy8( head, (void*)SYSM_APP_ROM_HEADER_BUF, HW_TWL_ROM_HEADER_BUF_SIZE ); + + // NTRJ[hAvDHTPhase1̂߂̌vZKv + if( !isTwlApp && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) + { + DHT_CheckHashPhase1Init(&dht_arg.ctx, &head->s); + } + + // wb_ǂݍ݊̏ + // wb_ǂݍ݊tO𗧂Ă + SYSM_SetHeaderLoadCompleted(TRUE); + + // HOTSWIL + SYSMi_FinalizeHotSWAsync( pBootTitle, (void*)SYSM_APP_ROM_HEADER_BUF ); + // ëǂݍ source [region_arm9_ntr] = head->s.main_rom_offset; length [region_arm9_ntr] = head->s.main_size; destaddr[region_arm9_ntr] = (u32)head->s.main_ram_address; - + source [region_arm7_ntr] = head->s.sub_rom_offset; length [region_arm7_ntr] = head->s.sub_size; destaddr[region_arm7_ntr] = (u32)head->s.sub_ram_address; - - if( isTwlApp ) - { - source [region_arm9_twl] = head->s.main_ltd_rom_offset; - length [region_arm9_twl] = head->s.main_ltd_size; - destaddr[region_arm9_twl] = (u32)head->s.main_ltd_ram_address; - - source [region_arm7_twl] = head->s.sub_ltd_rom_offset; - length [region_arm7_twl] = head->s.sub_ltd_size; - destaddr[region_arm7_twl] = (u32)head->s.sub_ltd_ram_address; + + if( isTwlApp ) + { + source [region_arm9_twl] = head->s.main_ltd_rom_offset; + length [region_arm9_twl] = head->s.main_ltd_size; + destaddr[region_arm9_twl] = (u32)head->s.main_ltd_ram_address; + + source [region_arm7_twl] = head->s.sub_ltd_rom_offset; + length [region_arm7_twl] = head->s.sub_ltd_size; + destaddr[region_arm7_twl] = (u32)head->s.sub_ltd_ram_address; } - + // ̈ǂݍݐ̃`FbNyэĔzuf[^̍쐬 // Q[J[h̍Ĕzu񂪏܂Ă̂ŁAnandAv[hOɈUNA MI_CpuClearFast(SYSMi_GetWork()->romRelocateInfo, sizeof(Relocate_Info) * RELOCATE_INFO_NUM); - for( i=0; i= ARM9_LTD_STATIC ) continue;// nitroł͓ǂݍ܂Ȃ̈ - if ( !SYSM_CheckLoadRegionAndSetRelocateInfo( (RomSegmentName)i, &(destaddr[i+region_arm9_ntr]), length[i+region_arm9_ntr], - &(SYSMi_GetWork()->romRelocateInfo[i]), isTwlApp ) ) - { - OS_TPrintf("RebootSystem failed: ROM Load Region error\n"); - UTL_SetFatalError(FATAL_ERROR_LOAD_RELOCATEINFO_FAILED); - goto ERROR; - } - } - - // AESiwb_ƍĔzu񂪂Ăj - (void)SYSM_InitDecryptAESRegion_W( (ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF ); + for( i=0; i= ARM9_LTD_STATIC ) continue;// nitroł͓ǂݍ܂Ȃ̈ + if ( !SYSM_CheckLoadRegionAndSetRelocateInfo( (RomSegmentName)i, &(destaddr[i+region_arm9_ntr]), length[i+region_arm9_ntr], + &(SYSMi_GetWork()->romRelocateInfo[i]), isTwlApp ) ) + { + OS_TPrintf("RebootSystem failed: ROM Load Region error\n"); + UTL_SetFatalError(FATAL_ERROR_LOAD_RELOCATEINFO_FAILED); + goto ERROR; + } + } + + // AESiwb_ƍĔzu񂪂Ăj + (void)SYSM_InitDecryptAESRegion_W( (ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF ); for (i = region_arm9_ntr; i < region_max; ++i) { - BOOL result; - + BOOL result; + u32 len = MATH_ROUNDUP( length[i], SYSM_ALIGNMENT_LOAD_MODULE );// AESDMA]TCY̎dlŁA[hTCY32oCgACgɕ␳ - + if ( !isTwlApp && i >= region_arm9_twl ) continue;// nitroł͓ǂݍ܂Ȃ̈ - if(!isCardApp) - { - bSuccess = FS_SeekFile(file, (s32)source[i], FS_SEEK_SET); + if(!isCardApp) + { + bSuccess = FS_SeekFile(file, (s32)source[i], FS_SEEK_SET); }else { - bSuccess = TRUE; - } + bSuccess = TRUE; + } if( ! bSuccess ) { OS_TPrintf("RebootSystem failed: cant seek file(%d)\n", source[i]); - UTL_SetFatalError(FATAL_ERROR_LOAD_SEEKFILE_FAILED); - goto ERROR; + UTL_SetFatalError(FATAL_ERROR_LOAD_SEEKFILE_FAILED); + goto ERROR; } OS_TPrintf("RebootSystem : Load VIA WRAM %d.\n", i); // Ń[hƓɃnbVvZAESĂ܂ // ʃXbhœWRAMgƂƑRP̂Œ - + // R[obN֐ɗ^Read if( !isTwlApp && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_TEMP ) { - // NTR_E[hAṽW[ - CalcSHA1CallbackArg arg; - SVC_SHA1Init( &arg.ctx ); - arg.hash_length = (u32)length[i]; - if(!isCardApp) - { - result = FS_ReadFileViaWram(file, (void *)destaddr[i], (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcSHA1Callback, &arg ); - }else - { - result = HOTSW_ReadCardViaWram((void *)source[i], (void *)destaddr[i], (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcSHA1Callback, &arg ); - } - SVC_SHA1GetHash( &arg.ctx, &s_calc_hash[i * SVC_SHA1_DIGEST_SIZE] ); - }else if( !isTwlApp && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) - { - // NTRJ[hAvDHTPhase1̂߂̌vZKv - // DHT`FbNphase1p̃nbVvZiDHT_CheckHashPhase1Update ֐jAʂ܂ŏoĂ - dht_arg.hash_length = (u32)length[i]; - result = HOTSW_ReadCardViaWram((void *)source[i], (void *)destaddr[i], (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_DHTPhase1Callback, &dht_arg ); - }else - { - // ȊO - CalcHMACSHA1CallbackArg arg; - SVC_HMACSHA1Init( &arg.ctx, (void *)s_digestDefaultKey, DIGEST_HASH_BLOCK_SIZE_SHA1 ); - arg.hash_length = length[i]; - if(!isCardApp) - { - result = FS_ReadFileViaWram(file, (void *)destaddr[i], (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcHMACSHA1Callback, &arg ); - }else - { - result = HOTSW_ReadCardViaWram((void *)source[i], (void *)destaddr[i], (s32)len, MI_WRAM_C, - WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcHMACSHA1Callback, &arg ); - //speed test code - /* - HOTSW_ReadCardData((void *)source[i], (void *)destaddr[i], (u32)len); - SVC_HMACSHA1Update( &arg.ctx, (void *)destaddr[i], length[i] ); - */ - } - SVC_HMACSHA1GetHash( &arg.ctx, &s_calc_hash[i * SVC_SHA1_DIGEST_SIZE] ); - } - if ( !result ) - { + // NTR_E[hAṽW[ + CalcSHA1CallbackArg arg; + SVC_SHA1Init( &arg.ctx ); + arg.hash_length = (u32)length[i]; + if(!isCardApp) + { + result = FS_ReadFileViaWram(file, (void *)destaddr[i], (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcSHA1Callback, &arg ); + }else + { + result = HOTSW_ReadCardViaWram((void *)source[i], (void *)destaddr[i], (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcSHA1Callback, &arg ); + } + SVC_SHA1GetHash( &arg.ctx, &s_calc_hash[i * SVC_SHA1_DIGEST_SIZE] ); + }else if( !isTwlApp && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) + { + // NTRJ[hAvDHTPhase1̂߂̌vZKv + // DHT`FbNphase1p̃nbVvZiDHT_CheckHashPhase1Update ֐jAʂ܂ŏoĂ + dht_arg.hash_length = (u32)length[i]; + result = HOTSW_ReadCardViaWram((void *)source[i], (void *)destaddr[i], (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_DHTPhase1Callback, &dht_arg ); + }else + { + // ȊO + CalcHMACSHA1CallbackArg arg; + SVC_HMACSHA1Init( &arg.ctx, (void *)s_digestDefaultKey, DIGEST_HASH_BLOCK_SIZE_SHA1 ); + arg.hash_length = length[i]; + if(!isCardApp) + { + result = FS_ReadFileViaWram(file, (void *)destaddr[i], (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcHMACSHA1Callback, &arg ); + }else + { + result = HOTSW_ReadCardViaWram((void *)source[i], (void *)destaddr[i], (s32)len, MI_WRAM_C, + WRAM_SLOT_FOR_FS, WRAM_SIZE_FOR_FS, SYSMi_CalcHMACSHA1Callback, &arg ); + //speed test code + /* + HOTSW_ReadCardData((void *)source[i], (void *)destaddr[i], (u32)len); + SVC_HMACSHA1Update( &arg.ctx, (void *)destaddr[i], length[i] ); + */ + } + SVC_HMACSHA1GetHash( &arg.ctx, &s_calc_hash[i * SVC_SHA1_DIGEST_SIZE] ); + } + if ( !result ) + { OS_TPrintf("RebootSystem failed: cant read file(%d, %d)\n", source[i], len); - UTL_SetFatalError(FATAL_ERROR_LOAD_READMODULE_FAILED); - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "LOAD_READMODULE_FAILED (sub info): region %d read failed.\n", i ); - goto ERROR; - } + UTL_SetFatalError(FATAL_ERROR_LOAD_READMODULE_FAILED); + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "LOAD_READMODULE_FAILED (sub info): region %d read failed.\n", i ); + goto ERROR; + } } - + // NTRJ[hAvDHTPhase1ŏIvZs if( !isTwlApp && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) { - SVC_HMACSHA1GetHash(&dht_arg.ctx, &s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE]); - } + SVC_HMACSHA1GetHash(&dht_arg.ctx, &s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE]); + } - if(!isCardApp) - { - (void)FS_CloseFile(file); + if(!isCardApp) + { + (void)FS_CloseFile(file); } } - + // W[ŏI[ḧ̂A݋󂢂ĂꏊNA // [TODO:]Ƃ肠x^B]T΃XbhB SYSMi_ClearRomLoadSegment( (ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF ); - - SYSM_SetLoadSucceeded(TRUE); - - // ŃX^bNĂȂ`FbN - if( OS_STACK_NO_ERROR != OS_GetStackStatus( &s_thread ) ) - { - OS_TPrintf("RebootSystem warning: stack was broken!\n"); - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "SYSMi_LoadTitleThreadFunc: stack was broken! %d\n", OS_GetStackStatus( &s_thread ) ); - } - - return; - + + SYSM_SetLoadSucceeded(TRUE); + + // ŃX^bNĂȂ`FbN + if( OS_STACK_NO_ERROR != OS_GetStackStatus( &s_thread ) ) + { + OS_TPrintf("RebootSystem warning: stack was broken!\n"); + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "SYSMi_LoadTitleThreadFunc: stack was broken! %d\n", OS_GetStackStatus( &s_thread ) ); + } + + return; + ERROR: - if(!isCardApp) - { + if(!isCardApp) + { (void)FS_CloseFile(file); } - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "SYSMi_LoadTitleThreadFunc: some error has occurred.\n"); + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "SYSMi_LoadTitleThreadFunc: some error has occurred.\n"); } // W[ŏI[ḧ̂A݋󂢂ĂꏊNA #define CLEAR_LIST_LENGTH (8 + 1 + RELOCATE_INFO_NUM * 2) static void SYSMi_ClearRomLoadSegment( ROM_Header_Short *rhs ) { - int l; - u32 twl_clear_list[CLEAR_LIST_LENGTH] = { - SYSM_TWL_ARM9_LOAD_MMEM, SYSM_TWL_ARM9_LOAD_MMEM_END, - SYSM_TWL_ARM7_LOAD_MMEM, SYSM_TWL_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, - NULL, - }; - u32 nitro_clear_list[CLEAR_LIST_LENGTH] = { - 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, - NULL, - }; - u32 *clear_list; - u32 length[RELOCATE_INFO_NUM]; - u32 dataExistAddr[RELOCATE_INFO_NUM]; - + int l; + u32 twl_clear_list[CLEAR_LIST_LENGTH] = { + SYSM_TWL_ARM9_LOAD_MMEM, SYSM_TWL_ARM9_LOAD_MMEM_END, + SYSM_TWL_ARM7_LOAD_MMEM, SYSM_TWL_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, + NULL, + }; + u32 nitro_clear_list[CLEAR_LIST_LENGTH] = { + 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, + NULL, + }; + u32 *clear_list; + u32 length[RELOCATE_INFO_NUM]; + u32 dataExistAddr[RELOCATE_INFO_NUM]; + length [0] = rhs->main_size; dataExistAddr[0] = (u32)rhs->main_ram_address; - + length [1] = rhs->sub_size; dataExistAddr[1] = (u32)rhs->sub_ram_address; - - if( !(rhs->platform_code & PLATFORM_CODE_FLAG_TWL) ) - { - clear_list = nitro_clear_list; - } - else - { - clear_list = twl_clear_list; + + if( !(rhs->platform_code & PLATFORM_CODE_FLAG_TWL) ) + { + clear_list = nitro_clear_list; + } + else + { + clear_list = twl_clear_list; length [2] = rhs->main_ltd_size; dataExistAddr[2] = (u32)rhs->main_ltd_ram_address; length [3] = rhs->sub_ltd_size; dataExistAddr[3] = (u32)rhs->sub_ltd_ram_address; - } + } - for( l=0; lplatform_code & PLATFORM_CODE_FLAG_TWL) && l==2 ) - { - break; - } - // Ĕzu񂪂΂̏擾 - if( SYSMi_GetWork()->romRelocateInfo[l].src != NULL ) - { - length[l] = SYSMi_GetWork()->romRelocateInfo[l].length; - dataExistAddr[l] = SYSMi_GetWork()->romRelocateInfo[l].src; - } - - // ̈̐؂ - SYSMi_CutAwayRegionList( clear_list, dataExistAddr[l], dataExistAddr[l] + length[l] ); - } - - // Xgɏ]ď - for( l=0; lplatform_code & PLATFORM_CODE_FLAG_TWL) && l==2 ) + { + break; + } + // Ĕzu񂪂΂̏擾 + if( SYSMi_GetWork()->romRelocateInfo[l].src != NULL ) + { + length[l] = SYSMi_GetWork()->romRelocateInfo[l].length; + dataExistAddr[l] = SYSMi_GetWork()->romRelocateInfo[l].src; + } + + // ̈̐؂ + SYSMi_CutAwayRegionList( clear_list, dataExistAddr[l], dataExistAddr[l] + length[l] ); + } + + // Xgɏ]ď + for( l=0; ltitleID & TITLE_ID_DATA_ONLY_FLAG_MASK ) - { - OS_TPrintf("SYSM_StartLoadTitle failed: This App has Data_Only flag.\n"); - return; - } - - // ŌAJ[h}ĂSYSM_GetCardTitleListĂ΂ĂȂ - // iʕ\⃊XgɕύXʒmĂȂjFATAL - // AJ[hN̂Ƃ̂ - if( SYSMi_GetWork()->flags.hotsw.isCardStateChanged && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) - { - UTL_SetFatalError(FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START); - } - - s_loadstart = TRUE; - s_loadTimes++; // [h񐔂̃`FbNpAڈȍ~͔Ή̎Ȃ̂ - - // ̂CardRomwb_obt@ROMwb_㏑œǂݍނ̂ - // ̎_HotSW~܂ĂȂƁAɃJ[hROMwb_ - // ㏑Ă܂”\ + static u64 stack[ STACK_SIZE / sizeof(u64) ]; - // Av[hԂȂA[hJn - if( !pBootTitle->flags.isAppLoadCompleted ) { - SYSM_SetLoadFinished(FALSE); - SYSM_SetLoadSucceeded(FALSE); - OS_InitThread(); - OS_CreateThread( &s_thread, (void (*)(void *))SYSMi_LoadTitleThreadFunc, (void*)pBootTitle, stack+STACK_SIZE/sizeof(u64), STACK_SIZE,THREAD_PRIO ); - OS_WakeupThreadDirect( &s_thread ); + HOTSW_InvalidHotSWAsync(); + // lω܂ŃX[vđ҂B + while( HOTSW_isEnableHotSW() != FALSE ) { + OS_Sleep( 2 ); + } - }else { - // Av[hς - SYSM_SetLoadSucceeded(TRUE); - SYSM_SetLoadFinished(TRUE); - } - - if( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) { - SYSM_SetCardBoot(TRUE); - }else if(pBootTitle->flags.isAppLoadCompleted) - { - // J[hu[głȂA[hς݂̏ꍇ͍̂Ƃ뉽Ȃ - } + // DataOnlyȃAv̓[hNȂ + if( pBootTitle->titleID & TITLE_ID_DATA_ONLY_FLAG_MASK ) + { + OS_TPrintf("SYSM_StartLoadTitle failed: This App has Data_Only flag.\n"); + return; + } + + // ŌAJ[h}ĂSYSM_GetCardTitleListĂ΂ĂȂ + // iʕ\⃊XgɕύXʒmĂȂjFATAL + // AJ[hN̂Ƃ̂ + if( SYSMi_GetWork()->flags.hotsw.isCardStateChanged && pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) + { + UTL_SetFatalError(FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START); + } + + s_loadstart = TRUE; + s_loadTimes++; // [h񐔂̃`FbNpAڈȍ~͔Ή̎Ȃ̂ + + // ̂CardRomwb_obt@ROMwb_㏑œǂݍނ̂ + // ̎_HotSW~܂ĂȂƁAɃJ[hROMwb_ + // ㏑Ă܂”\ + + // Av[hԂȂA[hJn + if( !pBootTitle->flags.isAppLoadCompleted ) { + SYSM_SetLoadFinished(FALSE); + SYSM_SetLoadSucceeded(FALSE); + OS_InitThread(); + OS_CreateThread( &s_thread, (void (*)(void *))SYSMi_LoadTitleThreadFunc, (void*)pBootTitle, stack+STACK_SIZE/sizeof(u64), STACK_SIZE,THREAD_PRIO ); + OS_WakeupThreadDirect( &s_thread ); + + }else { + // Av[hς + SYSM_SetLoadSucceeded(TRUE); + SYSM_SetLoadFinished(TRUE); + } + + if( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM ) { + SYSM_SetCardBoot(TRUE); + }else if(pBootTitle->flags.isAppLoadCompleted) + { + // J[hu[głȂA[hς݂̏ꍇ͍̂Ƃ뉽Ȃ + } } // Av[hς݂ǂ`FbN BOOL SYSM_IsLoadTitleFinished( void ) { - // [hς݂̎́ATRUE - if( !SYSMi_GetWork()->flags.arm9.isLoadFinished ) { - // [hXbh̊`FbNB - SYSM_SetLoadFinished(OS_IsThreadTerminated( &s_thread )); - } - return SYSMi_GetWork()->flags.arm9.isLoadFinished ? TRUE : FALSE; + // [hς݂̎́ATRUE + if( !SYSMi_GetWork()->flags.arm9.isLoadFinished ) { + // [hXbh̊`FbNB + SYSM_SetLoadFinished(OS_IsThreadTerminated( &s_thread )); + } + return SYSMi_GetWork()->flags.arm9.isLoadFinished ? TRUE : FALSE; } @@ -1047,67 +1179,67 @@ BOOL SYSM_IsLoadTitleFinished( void ) // ‚AviDS_E[hAvjʂ̃wb_F؏ static BOOL SYSMi_AuthenticateHeaderWithSign( TitleProperty *pBootTitle, ROM_Header *head ) { - // - const u8 *key; - u32 hi; - u8 keynum; - SignatureData sigbuf; - SVCSignHeapContext con; - char *gamecode = (char *)&(pBootTitle->titleID); - OSTick start,prev; - start = OS_GetTick(); - - prev = OS_GetTick(); - hi = head->s.titleID_Hi; - // Launcher͐p̌g - if( ( 0 == STD_CompareNString( &gamecode[1], "ANH", 3 ) ) + // + const u8 *key; + u32 hi; + u8 keynum; + SignatureData sigbuf; + SVCSignHeapContext con; + char *gamecode = (char *)&(pBootTitle->titleID); + OSTick start,prev; + start = OS_GetTick(); + + prev = OS_GetTick(); + hi = head->s.titleID_Hi; + // Launcher͐p̌g + if( ( 0 == STD_CompareNString( &gamecode[1], "ANH", 3 ) ) #ifdef DEV_UIG_LAUNCHER - || ( ( 0 == STD_CompareNString( &gamecode[1], "AN4", 3 ) ) && ( SCFG_GetBondingOption() != 0 ) ) + || ( ( 0 == STD_CompareNString( &gamecode[1], "AN4", 3 ) ) && ( SCFG_GetBondingOption() != 0 ) ) #endif - ) - { - keynum = LAUNCHER_KEY_INDEX; - }else - { - // keynum = 1:SystemApp 2:SecureApp 3:UserApp - keynum = (u8)( (hi & TITLE_ID_HI_SECURE_FLAG_MASK) ? SECURE_APP_KEY_INDEX - : ( (hi & TITLE_ID_HI_APP_TYPE_MASK) ? SYSTEM_APP_KEY_INDEX : USER_APP_KEY_INDEX ) - ); - } - - // Avʂƃ{fBOIvVɂĎg𕪂 + ) + { + keynum = LAUNCHER_KEY_INDEX; + }else + { + // keynum = 1:SystemApp 2:SecureApp 3:UserApp + keynum = (u8)( (hi & TITLE_ID_HI_SECURE_FLAG_MASK) ? SECURE_APP_KEY_INDEX + : ( (hi & TITLE_ID_HI_APP_TYPE_MASK) ? SYSTEM_APP_KEY_INDEX : USER_APP_KEY_INDEX ) + ); + } + + // Avʂƃ{fBOIvVɂĎg𕪂 //#define LNC_PDTKEY_DBG #ifdef LNC_PDTKEY_DBG - { - // FfoOpR[hB - // JpTS{[hŊJROMѐiROM̏`FbNAESfNvgfoO邽߂̃R[h - if( head->s.developer_encrypt_old || head->s.exFlags.developer_encrypt ) - { - // JŌ擾 - key = g_devPubKey[keynum]; - }else - { - // iŌ擾 - key = ((OSFromFirm9Buf *)HW_FIRM_FROM_FIRM_BUF)->rsa_pubkey[keynum]; - } - // fobKLTLFǂݍ݂Ȃ΁AnbV`FbNX[tO𗧂Ă - if( SYSM_IsRunOnDebugger() && SYSMi_GetWork()->romEmuInfo.isTlfRom ) - { - s_b_dev = TRUE; - } - } + { + // FfoOpR[hB + // JpTS{[hŊJROMѐiROM̏`FbNAESfNvgfoO邽߂̃R[h + if( head->s.developer_encrypt_old || head->s.exFlags.developer_encrypt ) + { + // JŌ擾 + key = g_devPubKey[keynum]; + }else + { + // iŌ擾 + key = ((OSFromFirm9Buf *)HW_FIRM_FROM_FIRM_BUF)->rsa_pubkey[keynum]; + } + // fobKLTLFǂݍ݂Ȃ΁AnbV`FbNX[tO𗧂Ă + if( SYSM_IsRunOnDebugger() && SYSMi_GetWork()->romEmuInfo.isTlfRom ) + { + s_b_dev = TRUE; + } + } #else if( SCFG_GetBondingOption() == 0 ) { - // iŌ擾 - key = ((OSFromFirm9Buf *)HW_FIRM_FROM_FIRM_BUF)->rsa_pubkey[keynum]; + // iŌ擾 + key = ((OSFromFirm9Buf *)HW_FIRM_FROM_FIRM_BUF)->rsa_pubkey[keynum]; }else { - // J - key = g_devPubKey[keynum]; - // fobKLTLFǂݍ݂Ȃ΁AnbV`FbNX[tO𗧂Ă - if( SYSM_IsRunOnDebugger() && SYSMi_GetWork()->romEmuInfo.isTlfRom ) - { - s_b_dev = TRUE; - } + // J + key = g_devPubKey[keynum]; + // fobKLTLFǂݍ݂Ȃ΁AnbV`FbNX[tO𗧂Ă + if( SYSM_IsRunOnDebugger() && SYSMi_GetWork()->romEmuInfo.isTlfRom ) + { + s_b_dev = TRUE; + } } #endif // ŕ @@ -1115,605 +1247,716 @@ static BOOL SYSMi_AuthenticateHeaderWithSign( TitleProperty *pBootTitle, ROM_Hea SVC_InitSignHeap( &con, (void *)SIGN_HEAP_ADDR, SIGN_HEAP_SIZE );// q[v̏ if( !SVC_DecryptSign( &con, sigbuf.digest, head->signature, key )) { - OS_TPrintf("Authenticate_Header failed: Sign decryption failed.\n"); - if(!s_b_dev) { - UTL_SetFatalError(FATAL_ERROR_SIGN_DECRYPTION_FAILED); - return FALSE; - } - } - if(s_calc_hash) - { - // ̃nbVlƃwb_̃nbVlr - if(!SVC_CompareSHA1(sigbuf.digest, (const void *)&s_calc_hash[0])) - { - OS_TPrintf("Authenticate_Header failed: Sign compare failed.\n"); - if(!s_b_dev) { - UTL_SetFatalError(FATAL_ERROR_SIGN_COMPARE_FAILED); - return FALSE; - } - }else - { - OS_TPrintf("Authenticate_Header : Sign check succeed. %dms.\n", OS_TicksToMilliSeconds(OS_GetTick() - prev)); - } - }else - { - OS_TPrintf("Authenticate_Header failed: Header Hash calc failed.\n"); - if(!s_b_dev) { - UTL_SetFatalError(FATAL_ERROR_HEADER_HASH_CALC_FAILED); - return FALSE; - } - } - OS_TPrintf("Authenticate_Header : total %d ms.\n", OS_TicksToMilliSeconds(OS_GetTick() - start) ); - - return TRUE; + OS_TPrintf("Authenticate_Header failed: Sign decryption failed.\n"); + if(!s_b_dev) { + UTL_SetFatalError(FATAL_ERROR_SIGN_DECRYPTION_FAILED); + return FALSE; + } + } + if(s_calc_hash) + { + // ̃nbVlƃwb_̃nbVlr + if(!SVC_CompareSHA1(sigbuf.digest, (const void *)&s_calc_hash[0])) + { + OS_TPrintf("Authenticate_Header failed: Sign compare failed.\n"); + if(!s_b_dev) { + UTL_SetFatalError(FATAL_ERROR_SIGN_COMPARE_FAILED); + return FALSE; + } + }else + { + OS_TPrintf("Authenticate_Header : Sign check succeed. %dms.\n", OS_TicksToMilliSeconds(OS_GetTick() - prev)); + } + }else + { + OS_TPrintf("Authenticate_Header failed: Header Hash calc failed.\n"); + if(!s_b_dev) { + UTL_SetFatalError(FATAL_ERROR_HEADER_HASH_CALC_FAILED); + return FALSE; + } + } + OS_TPrintf("Authenticate_Header : total %d ms.\n", OS_TicksToMilliSeconds(OS_GetTick() - start) ); + + return TRUE; } // TWLAvANTRgNANDAv ʂ̃wb_F؏ static BOOL SYSMi_AuthenticateTWLHeader( TitleProperty *pBootTitle, ROM_Header *head ) { - // pBootTitle->titleIDROMwb_titleID̈vmFB - // zCgXg}X^OꂽNTRAvłsꍇSYSMi_AuthenticateTWLHeaderֈړ - if( pBootTitle->titleID != head->s.titleID ) - { - //TWLΉROMŁAwb_titleIDNw肳ꂽIDƈႤ - OS_TPrintf( "Authenticate_Header failed: header TitleID error\n" ); - OS_TPrintf( "Authenticate_Header failed: selectedTitleID=%.16llx\n", pBootTitle->titleID ); - OS_TPrintf( "Authenticate_Header failed: headerTitleID=%.16llx\n", head->s.titleID ); - UTL_SetFatalError(FATAL_ERROR_TITLEID_COMPARE_FAILED); - return FALSE; - }else - { - OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" ); - } - - if( head->s.enable_signature || ( SYSM_IsRunOnDebugger() && SYSMi_GetWork()->romEmuInfo.isTlfRom)) - { - return SYSMi_AuthenticateHeaderWithSign( pBootTitle, head ); - }else - { - // LtOĂȂ@@fobKLTLFǂݍł̂łȂFAILED - OS_TPrintf("Authenticate_Header failed: Sign check flag is OFF!\n"); - UTL_SetFatalError(FATAL_ERROR_VALID_SIGN_FLAG_OFF); - return FALSE; - } + // pBootTitle->titleIDROMwb_titleID̈vmFB + // zCgXg}X^OꂽNTRAvłsꍇSYSMi_AuthenticateTWLHeaderֈړ + if( pBootTitle->titleID != head->s.titleID ) + { + //TWLΉROMŁAwb_titleIDNw肳ꂽIDƈႤ + OS_TPrintf( "Authenticate_Header failed: header TitleID error\n" ); + OS_TPrintf( "Authenticate_Header failed: selectedTitleID=%.16llx\n", pBootTitle->titleID ); + OS_TPrintf( "Authenticate_Header failed: headerTitleID=%.16llx\n", head->s.titleID ); + UTL_SetFatalError(FATAL_ERROR_TITLEID_COMPARE_FAILED); + return FALSE; + }else + { + OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" ); + } + + if( head->s.enable_signature || ( SYSM_IsRunOnDebugger() && SYSMi_GetWork()->romEmuInfo.isTlfRom)) + { + return SYSMi_AuthenticateHeaderWithSign( pBootTitle, head ); + }else + { + // LtOĂȂ@@fobKLTLFǂݍł̂łȂFAILED + OS_TPrintf("Authenticate_Header failed: Sign check flag is OFF!\n"); + UTL_SetFatalError(FATAL_ERROR_VALID_SIGN_FLAG_OFF); + return FALSE; + } } static s32 s_nam_error = NAM_OK; s32 SYSMi_getCheckTitleLaunchRightsResult( void ) { - return s_nam_error; + return s_nam_error; } // TWLAvANTRgNANDAv ʂ̔F static BOOL SYSMi_AuthenticateTWLTitle( TitleProperty *pBootTitle ) { - ROM_Header *head; - OSTick start,prev; - start = OS_GetTick(); - - head = ( ROM_Header *)SYSM_APP_ROM_HEADER_BUF; - - // NANDAv̏ꍇANAM_CheckTitleLaunchRights()ĂŃ`FbN - if( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND ) - { - s32 result = NAM_CheckTitleLaunchRights( pBootTitle->titleID ); - if( NAM_OK != result) - { - s_nam_error = result; - OS_TPrintf("Authenticate failed: NAM_CheckTitleLaunchRights failed. %d \n",result); - UTL_SetFatalError(FATAL_ERROR_CHECK_TITLE_LAUNCH_RIGHTS_FAILED); - return FALSE; - }else - { - OS_TPrintf("Authenticate : NAM_CheckTitleLaunchRights succeed. %d ms.\n", OS_TicksToMilliSeconds(OS_GetTick() - start) ); - } - } + ROM_Header *head; + OSTick start,prev; + start = OS_GetTick(); - // fobKȊO̎NANDAvNANDAJ[hAv̓J[ĥ݃u[g - if ( ! SYSM_IsRunOnDebugger() ) - { - if ( ( (pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND || - pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_TEMP) && !(head->s.titleID_Hi & TITLE_ID_HI_MEDIA_MASK) ) || - (pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM && (head->s.titleID_Hi & TITLE_ID_HI_MEDIA_MASK) ) ) - { - UTL_SetFatalError(FATAL_ERROR_MEDIA_CHECK_FAILED); - return FALSE; - } - } + head = ( ROM_Header *)SYSM_APP_ROM_HEADER_BUF; - // nbVr + // NANDAv̏ꍇANAM_CheckTitleLaunchRights()ĂŃ`FbN + if( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND ) { - int l; - u32 *module_addr[RELOCATE_INFO_NUM]; - u32 module_size[RELOCATE_INFO_NUM]; - u8 *hash_addr[RELOCATE_INFO_NUM]; - int module_num; - char *gamecode = (char *)&(pBootTitle->titleID); - - // ꂼARM9,7FLXLTDɂ‚ănbVvZăwb_Ɋi[ĂnbVƔr - module_addr[ARM9_STATIC] = head->s.main_ram_address; - module_addr[ARM7_STATIC] = head->s.sub_ram_address; - module_size[ARM9_STATIC] = head->s.main_size; - module_size[ARM7_STATIC] = head->s.sub_size; - hash_addr[ARM9_STATIC] = &(head->s.main_static_digest[0]); - hash_addr[ARM7_STATIC] = &(head->s.sub_static_digest[0]); - module_num = 2; - - // NITROAv̊gł͎gȂ̈ - if( head->s.platform_code != 0 ) - { - module_addr[ARM9_LTD_STATIC] = head->s.main_ltd_ram_address; - module_addr[ARM7_LTD_STATIC] = head->s.sub_ltd_ram_address; - module_size[ARM9_LTD_STATIC] = head->s.main_ltd_size; - module_size[ARM7_LTD_STATIC] = head->s.sub_ltd_size; - hash_addr[ARM9_LTD_STATIC] = &(head->s.main_ltd_static_digest[0]); - hash_addr[ARM7_LTD_STATIC] = &(head->s.sub_ltd_static_digest[0]); - module_num = RELOCATE_INFO_NUM; - } - - for( l=0; ltitleID ); + if( NAM_OK != result) + { + s_nam_error = result; + OS_TPrintf("Authenticate failed: NAM_CheckTitleLaunchRights failed. %d \n",result); + UTL_SetFatalError(FATAL_ERROR_CHECK_TITLE_LAUNCH_RIGHTS_FAILED); + return FALSE; + }else + { + OS_TPrintf("Authenticate : NAM_CheckTitleLaunchRights succeed. %d ms.\n", OS_TicksToMilliSeconds(OS_GetTick() - start) ); + } + } - return TRUE; + // fobKȊO̎NANDAvNANDAJ[hAv̓J[ĥ݃u[g + if ( ! SYSM_IsRunOnDebugger() ) + { + if ( ( (pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND || + pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_TEMP) && !(head->s.titleID_Hi & TITLE_ID_HI_MEDIA_MASK) ) || + (pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_ROM && (head->s.titleID_Hi & TITLE_ID_HI_MEDIA_MASK) ) ) + { + UTL_SetFatalError(FATAL_ERROR_MEDIA_CHECK_FAILED); + return FALSE; + } + } + + // nbVr + { + int l; + u32 *module_addr[RELOCATE_INFO_NUM]; + u32 module_size[RELOCATE_INFO_NUM]; + u8 *hash_addr[RELOCATE_INFO_NUM]; + int module_num; + char *gamecode = (char *)&(pBootTitle->titleID); + + // ꂼARM9,7FLXLTDɂ‚ănbVvZăwb_Ɋi[ĂnbVƔr + module_addr[ARM9_STATIC] = head->s.main_ram_address; + module_addr[ARM7_STATIC] = head->s.sub_ram_address; + module_size[ARM9_STATIC] = head->s.main_size; + module_size[ARM7_STATIC] = head->s.sub_size; + hash_addr[ARM9_STATIC] = &(head->s.main_static_digest[0]); + hash_addr[ARM7_STATIC] = &(head->s.sub_static_digest[0]); + module_num = 2; + + // NITROAv̊gł͎gȂ̈ + if( head->s.platform_code != 0 ) + { + module_addr[ARM9_LTD_STATIC] = head->s.main_ltd_ram_address; + module_addr[ARM7_LTD_STATIC] = head->s.sub_ltd_ram_address; + module_size[ARM9_LTD_STATIC] = head->s.main_ltd_size; + module_size[ARM7_LTD_STATIC] = head->s.sub_ltd_size; + hash_addr[ARM9_LTD_STATIC] = &(head->s.main_ltd_static_digest[0]); + hash_addr[ARM7_LTD_STATIC] = &(head->s.sub_ltd_static_digest[0]); + module_num = RELOCATE_INFO_NUM; + } + + for( l=0; ltitleIDROMwb_̃Q[R[ḧvmFB - ntr_fake_titleID = (u64)( ( head->s.game_code[ 3 ] << 0 ) | - ( head->s.game_code[ 2 ] << 8 ) | - ( head->s.game_code[ 1 ] << 16 ) | - ( head->s.game_code[ 0 ] << 24 ) ); - if( pBootTitle->titleID != ntr_fake_titleID ) - { - // wb_쐬[titleIDNw肳ꂽ^CgɊi[Ă[IDƈႤ - OS_TPrintf( "SYSMi_AuthenticateNTRCardAppHeader failed: header TitleID error\n" ); - OS_TPrintf( "SYSMi_AuthenticateNTRCardAppHeader failed: selectedTitleID=%.16llx\n", pBootTitle->titleID ); - OS_TPrintf( "SYSMi_AuthenticateNTRCardAppHeader failed: headerTitleID=%.16llx\n", ntr_fake_titleID ); - UTL_SetFatalError(FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR); - return FALSE; - }else - { - OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" ); - } - - if( head->s.exFlags.enable_nitro_whitelist_signature ) - { - // }X^OςNTRJ[hAv̏`FbNiTWLAvƓj - ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head ); - if( ret == TRUE ) - { - hash0 = head->s.nitro_whitelist_phase1_digest; - hash1 = head->s.nitro_whitelist_phase2_diegst; - } - }else - { - // zCgXg - const DHTDatabase* db; - PrepareDHTDatabase();// 60ms炢Ȃ̂ŁAłĂ܂OKƂB - if(!dht) - { - OS_TPrintf(" Search DHT : database init Failed.\n"); - if(!s_b_dev) - { - UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED); - ret = FALSE; - } - }else - { - OS_TPrintf("Searching DHT for %.4s(%02X)...", head->s.game_code, head->s.rom_version); - db = DHT_GetDatabase(dht, &head->s); - if ( !db ) - { - OS_TPrintf(" Search DHT : Failed.\n"); - if(!s_b_dev) - { - UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND); - ret = FALSE; - } - }else - { - hash0 = db->hash[0]; - hash1 = db->hash[1]; - ret = TRUE; - } - } - } - - return ret; + // pBootTitle->titleIDROMwb_̃Q[R[ḧvmFB + ntr_fake_titleID = (u64)( ( head->s.game_code[ 3 ] << 0 ) | + ( head->s.game_code[ 2 ] << 8 ) | + ( head->s.game_code[ 1 ] << 16 ) | + ( head->s.game_code[ 0 ] << 24 ) ); + if( pBootTitle->titleID != ntr_fake_titleID ) + { + // wb_쐬[titleIDNw肳ꂽ^CgɊi[Ă[IDƈႤ + OS_TPrintf( "SYSMi_AuthenticateNTRCardAppHeader failed: header TitleID error\n" ); + OS_TPrintf( "SYSMi_AuthenticateNTRCardAppHeader failed: selectedTitleID=%.16llx\n", pBootTitle->titleID ); + OS_TPrintf( "SYSMi_AuthenticateNTRCardAppHeader failed: headerTitleID=%.16llx\n", ntr_fake_titleID ); + UTL_SetFatalError(FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR); + return FALSE; + }else + { + OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" ); + } + + // phase 4̂ŏɓǂݍ + if ( !PrepareDHTDatabase() ) + { + OS_TPrintf(" SYSMi_AuthenticateNTRCardAppHeader failed : database init error.\n"); + if(!s_b_dev) + { + UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED); + return FALSE; + } + } + // }X^O̗L + if( head->s.exFlags.enable_nitro_whitelist_signature ) + { + // }X^OςNTRJ[hAv̏`FbNiTWLAvƓj + ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head ); + if( ret == TRUE ) + { + s_dht.hash1 = head->s.nitro_whitelist_phase1_digest; + s_dht.hash2 = head->s.nitro_whitelist_phase2_diegst; + // V}X^O̗L + if( head->s.exFlags.enable_nitro_extra_whitelist ) + { + s_dht.hash3 = head->s.banner_digest; + } + } + }else + { + // zCgXg + const DHTDatabase* db; + if(!s_dht.dht) + { + OS_TPrintf(" Search DHT : database init Failed.\n"); + if(!s_b_dev) + { + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): whitelist for phase 1/2 was not loaded.\n" ); + UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED); + ret = FALSE; + } + }else + { + OS_TPrintf("Searching DHT for %.4s(%02X)...", head->s.game_code, head->s.rom_version); + db = DHT_GetDatabase(s_dht.dht, &head->s); + if ( !db ) + { + OS_TPrintf(" Search DHT : Failed.\n"); + if(!s_b_dev) + { + ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 1/2.\n" ); + UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND); + ret = FALSE; + } + }else + { + s_dht.hash1 = db->hash[0]; + s_dht.hash2 = db->hash[1]; + ret = TRUE; + } + } + } + // ROMwb_Ƀoi[nbVȂ (}X^ÔƂ͕ʘg) + if( !s_dht.hash3 ) + { + // gzCgXg + const DHTDatabaseEx* db; + if(!s_dht.dhtex) + { + OS_TPrintf(" Search DHT Ex: database init Failed.\n"); + if(!s_b_dev) + { +#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND + ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): whitelist for phase 3 was not loaded.\n" ); + UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED); + ret = FALSE; +#endif + } + }else + { + OS_TPrintf("Searching DHT Ex for %.4s(%02X)...", head->s.game_code, head->s.rom_version); + db = DHT_GetDatabaseEx(s_dht.dhtex, &head->s); + if ( !db ) + { + OS_TPrintf(" Search DHT Ex: Failed.\n"); + if(!s_b_dev) + { + ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 3.\n" ); + UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND); + ret = FALSE; + } + }else + { + s_dht.hash3 = db->banner_hash; + ret = TRUE; + } + } + } + return ret; } // NTRŃJ[hAv̔F static BOOL SYSMi_AuthenticateNTRCardTitle( TitleProperty *pBootTitle) { #pragma unused(pBootTitle) - DHTPhase2Work* p2work = NULL; - ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; + DHTPhase2Work* p2work = NULL; + ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; - // phase1ŏI - if(s_calc_hash) - { - // Av[h鎞ɌvZnbV - if( !hash0 || !SVC_CompareSHA1( (const void *)hash0, (const void *)&s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE] ) ) - { - OS_TPrintf("DHT Phase1 failed: hash check failed.\n"); - if(!s_b_dev) { - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0Addr-%08x\n", hash0 ); - if(hash0) - { - ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0 - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", - hash0[0], hash0[1], hash0[2], hash0[3], hash0[4], hash0[5], hash0[6], hash0[7], hash0[8], hash0[9], - hash0[10], hash0[11], hash0[12], hash0[13], hash0[14], hash0[15], hash0[16], hash0[17], hash0[18], hash0[19]); - ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): calc_hash - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", - s_calc_hash[0], s_calc_hash[1], s_calc_hash[2], s_calc_hash[3], s_calc_hash[4], - s_calc_hash[5], s_calc_hash[6], s_calc_hash[7], s_calc_hash[8], s_calc_hash[9], - s_calc_hash[10], s_calc_hash[11], s_calc_hash[12], s_calc_hash[13], s_calc_hash[14], - s_calc_hash[15], s_calc_hash[16], s_calc_hash[17], s_calc_hash[18], s_calc_hash[19]); - } - UTL_SetFatalError(FATAL_ERROR_DHT_PHASE1_FAILED); - return FALSE; - } - }else - { - OS_TPrintf("DHT Phase1 : hash check succeed..\n"); - } - }else - { - OS_TPrintf("DHT Phase1 failed: hash calc failed.\n"); - if(!s_b_dev) { - UTL_SetFatalError(FATAL_ERROR_DHT_PHASE1_CALC_FAILED); - return FALSE; - } - } - - // DHT`FbNphase2 - OS_TPrintf("DHT Phase2..."); - p2work = SYSM_Alloc( sizeof(DHTPhase2Work) ); - if ( !p2work || !hash1 || !DHT_CheckHashPhase2(hash1, hs, p2work, WrapperFunc_ReadCardData, NULL) ) - { - OS_TPrintf(" DHT Phase2 : Failed.\n"); - if(!s_b_dev){ - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash1Addr-%08x\n", p2work, hash1 ); - if( p2work ) SYSM_Free(p2work); - UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED); - return FALSE; - } - } - if( p2work ) SYSM_Free(p2work); + // DHT`FbNphase1 + if(s_calc_hash) + { + // Av[h鎞ɌvZnbV + if( !s_dht.hash1 || !SVC_CompareSHA1( (const void *)s_dht.hash1, (const void *)&s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE] ) ) + { + OS_TPrintf("DHT Phase1 failed: hash check failed.\n"); + if(!s_b_dev) { + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1Addr-%08x\n", s_dht.hash1 ); + if(s_dht.hash1) + { + ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1 - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + s_dht.hash1[0], s_dht.hash1[1], s_dht.hash1[2], s_dht.hash1[3], s_dht.hash1[4], + s_dht.hash1[5], s_dht.hash1[6], s_dht.hash1[7], s_dht.hash1[8], s_dht.hash1[9], + s_dht.hash1[10], s_dht.hash1[11], s_dht.hash1[12], s_dht.hash1[13], s_dht.hash1[14], + s_dht.hash1[15], s_dht.hash1[16], s_dht.hash1[17], s_dht.hash1[18], s_dht.hash1[19]); + ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): calc_hash - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + s_calc_hash[0], s_calc_hash[1], s_calc_hash[2], s_calc_hash[3], s_calc_hash[4], + s_calc_hash[5], s_calc_hash[6], s_calc_hash[7], s_calc_hash[8], s_calc_hash[9], + s_calc_hash[10], s_calc_hash[11], s_calc_hash[12], s_calc_hash[13], s_calc_hash[14], + s_calc_hash[15], s_calc_hash[16], s_calc_hash[17], s_calc_hash[18], s_calc_hash[19]); + } + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE1_FAILED); + return FALSE; + } + }else + { + OS_TPrintf("DHT Phase1 : hash check succeed..\n"); + } + }else + { + OS_TPrintf("DHT Phase1 failed: hash calc failed.\n"); + if(!s_b_dev) { + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE1_CALC_FAILED); + return FALSE; + } + } - return TRUE; + // DHT`FbNphase2 + OS_TPrintf("DHT Phase2..."); + p2work = SYSM_Alloc( sizeof(DHTPhase2Work) ); + if ( !p2work ) + { + OS_TPrintf(" Cannot allocate DHT work area.\n"); + if (!s_b_dev){ + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 ); + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED); + return FALSE; + } + return TRUE; + } + if ( !s_dht.hash2 || !DHT_CheckHashPhase2(s_dht.hash2, hs, p2work, WrapperFunc_ReadCardData, NULL) ) + { + OS_TPrintf(" DHT Phase2 : Failed.\n"); + if(!s_b_dev){ + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 ); + SYSM_Free(p2work); + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED); + return FALSE; + } + } + + // DHT`FbNphase3 (oi[`FbN) + OS_TPrintf("DHT Phase3..."); + if ( !s_dht.hash3 || !DHT_CheckHashPhase3(s_dht.hash3, (NTRBannerFile*)&s_card_bannerBuf) ) + { + OS_TPrintf(" DHT Phase3 : Failed.\n"); + if(!s_b_dev){ + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "DHT_PAHSE3_FAILED (sub info): hash3Addr-%08x\n", s_dht.hash3 ); +#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND +#ifndef SYSM_IGNORE_DHT_PHASE_3 + SYSM_Free(p2work); + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE3_FAILED); + return FALSE; +#endif +#endif + } + } + + // DHT`FbNphase4 (•ʃ`FbN) + OS_TPrintf("DHT Phase4..."); + if ( !s_dht.dhtah ) + { + OS_TPrintf(" DHT Phase4 : No database.\n"); + if(!s_b_dev){ + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "DHT_PAHSE4_FAILED (sub info): no database\n" ); +#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND + SYSM_Free(p2work); + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE4_FAILED); + return FALSE; +#endif + } + } + else if ( !DHT_CheckHashPhase4(s_dht.dhtah, hs, (DHTPhase4Work*)p2work, WrapperFunc_ReadCardData, NULL) ) + { + OS_TPrintf(" DHT Phase4 : Failed.\n"); + if(!s_b_dev){ + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "DHT_PAHSE4_FAILED (sub info): p2workAddr-%08x\n", p2work ); + SYSM_Free(p2work); + UTL_SetFatalError(FATAL_ERROR_DHT_PHASE4_FAILED); + return FALSE; + } + } + + SYSM_Free(p2work); + + return TRUE; } // wb_F static BOOL SYSMi_AuthenticateHeader( TitleProperty *pBootTitle, ROM_Header *head ) { - ROM_Header_Short *hs = ( ROM_Header_Short *)head; - if( hs->platform_code & PLATFORM_CODE_FLAG_TWL ) - { - // TWLAv - // F؏ - switch( pBootTitle->flags.bootType ) - { - case LAUNCHER_BOOTTYPE_NAND: - OS_TPrintf( "Authenticate_Header :TWL_NAND start.\n" ); - return SYSMi_AuthenticateTWLHeader( pBootTitle, head ); - case LAUNCHER_BOOTTYPE_ROM: - OS_TPrintf( "Authenticate_Header :TWL_ROM start.\n" ); - return SYSMi_AuthenticateTWLHeader( pBootTitle, head ); - case LAUNCHER_BOOTTYPE_TEMP: - OS_TPrintf( "Authenticate_Header :TWL_TEMP start.\n" ); - if (!hs->permit_landing_tmp_jump) - { - OS_TPrintf("Authenticate failed: TMP flag error.\n"); - UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); - return FALSE; - } - return SYSMi_AuthenticateTWLHeader( pBootTitle, head ); - default: - UTL_SetFatalError(FATAL_ERROR_TWL_BOOTTYPE_UNKNOWN); - return FALSE; - } - } - else - { - if( hs->platform_code & PLATFORM_CODE_FLAG_NOT_NTR ) - { - // TWLłNTRłȂsȃAv - OS_TPrintf( "Authenticate_Header failed :NOT NTR NOT TWL.\n" ); - UTL_SetFatalError(FATAL_ERROR_PLATFORM_UNKNOWN); - return FALSE; - } - // NTRAv - switch( pBootTitle->flags.bootType ) - { - case LAUNCHER_BOOTTYPE_NAND: - OS_TPrintf( "Authenticate_Header :NTR_NAND start.\n" ); - return SYSMi_AuthenticateNTRNandAppHeader( pBootTitle, head ); - case LAUNCHER_BOOTTYPE_TEMP: - OS_TPrintf( "Authenticate_Header :NTR_TEMP start.\n" ); - if (!hs->permit_landing_tmp_jump) - { - OS_TPrintf("Authenticate_Header failed : TMP flag error.\n"); - UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); - return FALSE; - } - return SYSMi_AuthenticateNTRDownloadAppHeader( pBootTitle, head ); - case LAUNCHER_BOOTTYPE_ROM: - OS_TPrintf( "Authenticate_Header :NTR_ROM start.\n" ); - return SYSMi_AuthenticateNTRCardAppHeader( pBootTitle, head ); - default: - UTL_SetFatalError(FATAL_ERROR_NTR_BOOTTYPE_UNKNOWN); - return FALSE; - } - } + ROM_Header_Short *hs = ( ROM_Header_Short *)head; + if( hs->platform_code & PLATFORM_CODE_FLAG_TWL ) + { + // TWLAv + // F؏ + switch( pBootTitle->flags.bootType ) + { + case LAUNCHER_BOOTTYPE_NAND: + OS_TPrintf( "Authenticate_Header :TWL_NAND start.\n" ); + return SYSMi_AuthenticateTWLHeader( pBootTitle, head ); + case LAUNCHER_BOOTTYPE_ROM: + OS_TPrintf( "Authenticate_Header :TWL_ROM start.\n" ); + return SYSMi_AuthenticateTWLHeader( pBootTitle, head ); + case LAUNCHER_BOOTTYPE_TEMP: + OS_TPrintf( "Authenticate_Header :TWL_TEMP start.\n" ); + if (!hs->permit_landing_tmp_jump) + { + OS_TPrintf("Authenticate failed: TMP flag error.\n"); + UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); + return FALSE; + } + return SYSMi_AuthenticateTWLHeader( pBootTitle, head ); + default: + UTL_SetFatalError(FATAL_ERROR_TWL_BOOTTYPE_UNKNOWN); + return FALSE; + } + } + else + { + if( hs->platform_code & PLATFORM_CODE_FLAG_NOT_NTR ) + { + // TWLłNTRłȂsȃAv + OS_TPrintf( "Authenticate_Header failed :NOT NTR NOT TWL.\n" ); + UTL_SetFatalError(FATAL_ERROR_PLATFORM_UNKNOWN); + return FALSE; + } + // NTRAv + switch( pBootTitle->flags.bootType ) + { + case LAUNCHER_BOOTTYPE_NAND: + OS_TPrintf( "Authenticate_Header :NTR_NAND start.\n" ); + return SYSMi_AuthenticateNTRNandAppHeader( pBootTitle, head ); + case LAUNCHER_BOOTTYPE_TEMP: + OS_TPrintf( "Authenticate_Header :NTR_TEMP start.\n" ); + if (!hs->permit_landing_tmp_jump) + { + OS_TPrintf("Authenticate_Header failed : TMP flag error.\n"); + UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); + return FALSE; + } + return SYSMi_AuthenticateNTRDownloadAppHeader( pBootTitle, head ); + case LAUNCHER_BOOTTYPE_ROM: + OS_TPrintf( "Authenticate_Header :NTR_ROM start.\n" ); + return SYSMi_AuthenticateNTRCardAppHeader( pBootTitle, head ); + default: + UTL_SetFatalError(FATAL_ERROR_NTR_BOOTTYPE_UNKNOWN); + return FALSE; + } + } } // F static BOOL SYSMi_AuthenticateTitleCore( TitleProperty *pBootTitle) { - ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; - if( hs->platform_code & PLATFORM_CODE_FLAG_TWL ) - { - // TWLAv - // F؏ - switch( pBootTitle->flags.bootType ) - { - case LAUNCHER_BOOTTYPE_NAND: - OS_TPrintf( "Authenticate :TWL_NAND start.\n" ); - return SYSMi_AuthenticateTWLTitle( pBootTitle ); - case LAUNCHER_BOOTTYPE_ROM: - OS_TPrintf( "Authenticate :TWL_ROM start.\n" ); - return SYSMi_AuthenticateTWLTitle( pBootTitle ); - case LAUNCHER_BOOTTYPE_TEMP: - OS_TPrintf( "Authenticate :TWL_TEMP start.\n" ); - if (!hs->permit_landing_tmp_jump) - { - OS_TPrintf("Authenticate failed: TMP flag error.\n"); - UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); - return FALSE; - } - return SYSMi_AuthenticateTWLTitle( pBootTitle ); - default: - UTL_SetFatalError(FATAL_ERROR_TWL_BOOTTYPE_UNKNOWN); - return FALSE; - } - } - else - { - if( hs->platform_code & PLATFORM_CODE_FLAG_NOT_NTR ) - { - // TWLłNTRłȂsȃAv - OS_TPrintf( "Authenticate :NOT NTR NOT TWL.\n" ); - UTL_SetFatalError(FATAL_ERROR_PLATFORM_UNKNOWN); - return FALSE; - } - // NTRAv - switch( pBootTitle->flags.bootType ) - { - case LAUNCHER_BOOTTYPE_NAND: - OS_TPrintf( "Authenticate :NTR_NAND start.\n" ); - return SYSMi_AuthenticateNTRNandTitle( pBootTitle ); - case LAUNCHER_BOOTTYPE_TEMP: - OS_TPrintf( "Authenticate :NTR_TEMP start.\n" ); - if (!hs->permit_landing_tmp_jump) - { - OS_TPrintf("Authenticate failed: TMP flag error.\n"); - UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); - return FALSE; - } - return SYSMi_AuthenticateNTRDownloadTitle( pBootTitle ); - case LAUNCHER_BOOTTYPE_ROM: - OS_TPrintf( "Authenticate :NTR_ROM start.\n" ); - return SYSMi_AuthenticateNTRCardTitle( pBootTitle ); - default: - UTL_SetFatalError(FATAL_ERROR_NTR_BOOTTYPE_UNKNOWN); - return FALSE; - } - } + ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; + if( hs->platform_code & PLATFORM_CODE_FLAG_TWL ) + { + // TWLAv + // F؏ + switch( pBootTitle->flags.bootType ) + { + case LAUNCHER_BOOTTYPE_NAND: + OS_TPrintf( "Authenticate :TWL_NAND start.\n" ); + return SYSMi_AuthenticateTWLTitle( pBootTitle ); + case LAUNCHER_BOOTTYPE_ROM: + OS_TPrintf( "Authenticate :TWL_ROM start.\n" ); + return SYSMi_AuthenticateTWLTitle( pBootTitle ); + case LAUNCHER_BOOTTYPE_TEMP: + OS_TPrintf( "Authenticate :TWL_TEMP start.\n" ); + if (!hs->permit_landing_tmp_jump) + { + OS_TPrintf("Authenticate failed: TMP flag error.\n"); + UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); + return FALSE; + } + return SYSMi_AuthenticateTWLTitle( pBootTitle ); + default: + UTL_SetFatalError(FATAL_ERROR_TWL_BOOTTYPE_UNKNOWN); + return FALSE; + } + } + else + { + if( hs->platform_code & PLATFORM_CODE_FLAG_NOT_NTR ) + { + // TWLłNTRłȂsȃAv + OS_TPrintf( "Authenticate :NOT NTR NOT TWL.\n" ); + UTL_SetFatalError(FATAL_ERROR_PLATFORM_UNKNOWN); + return FALSE; + } + // NTRAv + switch( pBootTitle->flags.bootType ) + { + case LAUNCHER_BOOTTYPE_NAND: + OS_TPrintf( "Authenticate :NTR_NAND start.\n" ); + return SYSMi_AuthenticateNTRNandTitle( pBootTitle ); + case LAUNCHER_BOOTTYPE_TEMP: + OS_TPrintf( "Authenticate :NTR_TEMP start.\n" ); + if (!hs->permit_landing_tmp_jump) + { + OS_TPrintf("Authenticate failed: TMP flag error.\n"); + UTL_SetFatalError(FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF); + return FALSE; + } + return SYSMi_AuthenticateNTRDownloadTitle( pBootTitle ); + case LAUNCHER_BOOTTYPE_ROM: + OS_TPrintf( "Authenticate :NTR_ROM start.\n" ); + return SYSMi_AuthenticateNTRCardTitle( pBootTitle ); + default: + UTL_SetFatalError(FATAL_ERROR_NTR_BOOTTYPE_UNKNOWN); + return FALSE; + } + } } // F؏̃Xbh static void SYSMi_AuthenticateTitleThreadFunc( TitleProperty *pBootTitle ) { - - // [hJnĂ܂ - if( !s_loadstart ) - { - UTL_SetFatalError(FATAL_ERROR_LOAD_NEVER_STARTED); - return; - } - - // [h - if( !SYSM_IsLoadTitleFinished() ) { - UTL_SetFatalError(FATAL_ERROR_LOAD_UNFINISHED); - return; - } - // [hH - if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE ) - { - UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED); - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes ); - return; - } - // p[^`FbN - if( !SYSMi_CheckTitlePointer( pBootTitle ) ) { - UTL_SetFatalError(FATAL_ERROR_TITLE_POINTER_ERROR); - return; - } - // GgAhX̐`FbN - if( !SYSMi_CheckEntryAddress() ) { - UTL_SetFatalError(FATAL_ERROR_ENTRY_ADDRESS_ERROR); - return; - } - - // BOOTTYPE_MEMORYNTR[hFSŃu[gƁANitroSDKŃrhꂽAv̏ꍇA - // ROMA[JCuɃJ[h蓖ĂāAFSŊ֌WȂJ[hɃANZXɂĂ܂̂ŁAh~B - if( ( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_MEMORY ) && - ( ( (( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF)->platform_code ) == 0 ) && - ( ( (( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF)->fat_size ) > 0 ) - ) { - UTL_SetFatalError(FATAL_ERROR_TITLE_BOOTTYPE_ERROR); - return; - } - - // F - (void)SYSMi_AuthenticateTitleCore( pBootTitle ); - - // ŃX^bNĂȂ`FbN - if( OS_STACK_NO_ERROR != OS_GetStackStatus( &s_auth_thread ) ) - { - OS_TPrintf("RebootSystem warning: stack was broken!\n"); - // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O - ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: stack was broken! %d\n", OS_GetStackStatus( &s_auth_thread ) ); - } + + // [hJnĂ܂ + if( !s_loadstart ) + { + UTL_SetFatalError(FATAL_ERROR_LOAD_NEVER_STARTED); + return; + } + + // [h + if( !SYSM_IsLoadTitleFinished() ) { + UTL_SetFatalError(FATAL_ERROR_LOAD_UNFINISHED); + return; + } + // [hH + if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE ) + { + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes ); + UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED); + return; + } + // p[^`FbN + if( !SYSMi_CheckTitlePointer( pBootTitle ) ) { + UTL_SetFatalError(FATAL_ERROR_TITLE_POINTER_ERROR); + return; + } + // GgAhX̐`FbN + if( !SYSMi_CheckEntryAddress() ) { + UTL_SetFatalError(FATAL_ERROR_ENTRY_ADDRESS_ERROR); + return; + } + + // BOOTTYPE_MEMORYNTR[hFSŃu[gƁANitroSDKŃrhꂽAv̏ꍇA + // ROMA[JCuɃJ[h蓖ĂāAFSŊ֌WȂJ[hɃANZXɂĂ܂̂ŁAh~B + if( ( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_MEMORY ) && + ( ( (( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF)->platform_code ) == 0 ) && + ( ( (( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF)->fat_size ) > 0 ) + ) { + UTL_SetFatalError(FATAL_ERROR_TITLE_BOOTTYPE_ERROR); + return; + } + + // F + (void)SYSMi_AuthenticateTitleCore( pBootTitle ); + + // ŃX^bNĂȂ`FbN + if( OS_STACK_NO_ERROR != OS_GetStackStatus( &s_auth_thread ) ) + { + OS_TPrintf("RebootSystem warning: stack was broken!\n"); + // foOpBERRORLOG_Init()łɌĂ΂Ă鎖O + ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: stack was broken! %d\n", OS_GetStackStatus( &s_auth_thread ) ); + } } @@ -1721,372 +1964,372 @@ static void SYSMi_AuthenticateTitleThreadFunc( TitleProperty *pBootTitle ) #define AUTH_STACK_SIZE 0x1400 void SYSM_StartAuthenticateTitle( TitleProperty *pBootTitle ) { - static u64 stack[ AUTH_STACK_SIZE / sizeof(u64) ]; - OS_InitThread(); - OS_CreateThread( &s_auth_thread, (void (*)(void *))SYSMi_AuthenticateTitleThreadFunc, (void*)pBootTitle, stack+AUTH_STACK_SIZE/sizeof(u64), AUTH_STACK_SIZE,THREAD_PRIO ); - OS_WakeupThreadDirect( &s_auth_thread ); - + static u64 stack[ AUTH_STACK_SIZE / sizeof(u64) ]; + OS_InitThread(); + OS_CreateThread( &s_auth_thread, (void (*)(void *))SYSMi_AuthenticateTitleThreadFunc, (void*)pBootTitle, stack+AUTH_STACK_SIZE/sizeof(u64), AUTH_STACK_SIZE,THREAD_PRIO ); + OS_WakeupThreadDirect( &s_auth_thread ); + // ROMwb_NintendoS `FbN if( !UTL_CheckNintendoLogoData((ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF) ){ - UTL_SetFatalError( FATAL_ERROR_NINTENDO_LOGO_CHECK_FAILED ); + UTL_SetFatalError( FATAL_ERROR_NINTENDO_LOGO_CHECK_FAILED ); } } // ؍ς݁H BOOL SYSM_IsAuthenticateTitleFinished( void ) { - return OS_IsThreadTerminated( &s_auth_thread ); + return OS_IsThreadTerminated( &s_auth_thread ); } // AvNɕKvȃZ[ut@CSharedt@C̃Jo static char *s_strResult[] = { - "Target file exists and file size matched.", - "File size didn't match. Changing size succeeded.", - "Target file didn't exist. Creating file and setting size succeeded.", - "ERROR: File Recovery Failed." + "Target file exists and file size matched.", + "File size didn't match. Changing size succeeded.", + "Target file didn't exist. Creating file and setting size succeeded.", + "ERROR: File Recovery Failed." }; static void SYSMi_FileRecovery( TitleProperty *pBootTitle ) { - ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; - char path[2][ FS_ENTRY_LONGNAME_MAX ]; - UTL_RecoveryStatus stat; - - // TWLΉ̂Ƃ͕svȂ̂return - if ( !(hs->platform_code & PLATFORM_CODE_FLAG_TWL) ) - { - return; - } - - // NANDAv̂Ƃ - if ( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND ) - { - // get savedata_path - s32 result = NAM_GetTitleSaveFilePath( path[ 0 ], path[ 1 ], hs->titleID ); - - // pub_save - if( result == NAM_OK && hs->public_save_data_size != 0 ) - { - stat = UTL_RecoveryFile( path[0], hs->public_save_data_size ); - OS_TPrintf("pub_save recovery result : %s \n", s_strResult[stat]); - } - - // prv_save - if( result == NAM_OK && hs->private_save_data_size != 0 ) - { - stat = UTL_RecoveryFile( path[1], hs->private_save_data_size ); - OS_TPrintf("prv_save recovery result : %s \n", s_strResult[stat]); - } - - // sub_banner - if( hs->exFlags.availableSubBannerFile && NAM_GetTitleBannerFilePath( path[0], hs->titleID ) == NAM_OK ) - { - stat = UTL_RecoveryFile( path[0], SIZE_16KB ); - OS_TPrintf("sub_banner recovery result : %s \n", s_strResult[stat]); - } - } - - // shared2 (size+1) * 16kb - if( hs->shared2_file0_size != 0 ) - { - stat = UTL_RecoveryFile( "nand:/shared2/0000", (u32)( hs->shared2_file0_size + 1 ) * SIZE_16KB ); - OS_TPrintf("shared2_0 recovery result : %s \n", s_strResult[stat]); - } - if( hs->shared2_file1_size != 0 ) - { - stat = UTL_RecoveryFile( "nand:/shared2/0001", (u32)( hs->shared2_file1_size + 1 ) * SIZE_16KB ); - OS_TPrintf("shared2_1 recovery result : %s \n", s_strResult[stat]); - } - if( hs->shared2_file2_size != 0 ) - { - stat = UTL_RecoveryFile( "nand:/shared2/0002", (u32)( hs->shared2_file2_size + 1 ) * SIZE_16KB ); - OS_TPrintf("shared2_2 recovery result : %s \n", s_strResult[stat]); - } - if( hs->shared2_file3_size != 0 ) - { - stat = UTL_RecoveryFile( "nand:/shared2/0003", (u32)( hs->shared2_file3_size + 1 ) * SIZE_16KB ); - OS_TPrintf("shared2_3 recovery result : %s \n", s_strResult[stat]); - } - if( hs->shared2_file4_size != 0 ) - { - stat = UTL_RecoveryFile( "nand:/shared2/0004", (u32)( hs->shared2_file4_size + 1 ) * SIZE_16KB ); - OS_TPrintf("shared2_4 recovery result : %s \n", s_strResult[stat]); - } - if( hs->shared2_file5_size != 0 ) - { - stat = UTL_RecoveryFile( "nand:/shared2/0005", (u32)( hs->shared2_file5_size + 1 ) * SIZE_16KB ); - OS_TPrintf("shared2_5 recovery result : %s \n", s_strResult[stat]); - } + ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; + char path[2][ FS_ENTRY_LONGNAME_MAX ]; + UTL_RecoveryStatus stat; + + // TWLΉ̂Ƃ͕svȂ̂return + if ( !(hs->platform_code & PLATFORM_CODE_FLAG_TWL) ) + { + return; + } + + // NANDAv̂Ƃ + if ( pBootTitle->flags.bootType == LAUNCHER_BOOTTYPE_NAND ) + { + // get savedata_path + s32 result = NAM_GetTitleSaveFilePath( path[ 0 ], path[ 1 ], hs->titleID ); + + // pub_save + if( result == NAM_OK && hs->public_save_data_size != 0 ) + { + stat = UTL_RecoveryFile( path[0], hs->public_save_data_size ); + OS_TPrintf("pub_save recovery result : %s \n", s_strResult[stat]); + } + + // prv_save + if( result == NAM_OK && hs->private_save_data_size != 0 ) + { + stat = UTL_RecoveryFile( path[1], hs->private_save_data_size ); + OS_TPrintf("prv_save recovery result : %s \n", s_strResult[stat]); + } + + // sub_banner + if( hs->exFlags.availableSubBannerFile && NAM_GetTitleBannerFilePath( path[0], hs->titleID ) == NAM_OK ) + { + stat = UTL_RecoveryFile( path[0], SIZE_16KB ); + OS_TPrintf("sub_banner recovery result : %s \n", s_strResult[stat]); + } + } + + // shared2 (size+1) * 16kb + if( hs->shared2_file0_size != 0 ) + { + stat = UTL_RecoveryFile( "nand:/shared2/0000", (u32)( hs->shared2_file0_size + 1 ) * SIZE_16KB ); + OS_TPrintf("shared2_0 recovery result : %s \n", s_strResult[stat]); + } + if( hs->shared2_file1_size != 0 ) + { + stat = UTL_RecoveryFile( "nand:/shared2/0001", (u32)( hs->shared2_file1_size + 1 ) * SIZE_16KB ); + OS_TPrintf("shared2_1 recovery result : %s \n", s_strResult[stat]); + } + if( hs->shared2_file2_size != 0 ) + { + stat = UTL_RecoveryFile( "nand:/shared2/0002", (u32)( hs->shared2_file2_size + 1 ) * SIZE_16KB ); + OS_TPrintf("shared2_2 recovery result : %s \n", s_strResult[stat]); + } + if( hs->shared2_file3_size != 0 ) + { + stat = UTL_RecoveryFile( "nand:/shared2/0003", (u32)( hs->shared2_file3_size + 1 ) * SIZE_16KB ); + OS_TPrintf("shared2_3 recovery result : %s \n", s_strResult[stat]); + } + if( hs->shared2_file4_size != 0 ) + { + stat = UTL_RecoveryFile( "nand:/shared2/0004", (u32)( hs->shared2_file4_size + 1 ) * SIZE_16KB ); + OS_TPrintf("shared2_4 recovery result : %s \n", s_strResult[stat]); + } + if( hs->shared2_file5_size != 0 ) + { + stat = UTL_RecoveryFile( "nand:/shared2/0005", (u32)( hs->shared2_file5_size + 1 ) * SIZE_16KB ); + OS_TPrintf("shared2_5 recovery result : %s \n", s_strResult[stat]); + } } // [hς݂̎w^Cg̔F؂ƃu[gs // SYSM_GetNandTitleList܂SYSM_GetNandTitleListMakerInfôǂ炩SYSM_TryToBootTitleOɌĂԕKv void SYSM_TryToBootTitle( TitleProperty *pBootTitle ) { - // [TODO:] ̓̏Ŏsꍇɂ̂܂܃u[gĂ܂đvH - - if(s_calc_hash) - { - // nbVlۑ̈ - SYSM_Free( s_calc_hash ); - s_calc_hash = NULL; - } - - if(dht) - { - // dhtpobt@mۂĂ - SYSM_Free( dht ); - dht = NULL; - } - - // _CNgu[gȂǁA܂SystemMenuVersioñf[^ZbgĂȂꍇ́AŃZbgB - if( *(u8 *)HW_SYSM_VER_INFO_CONTENT_LAST_INITIAL_CODE == 0 ) { - SYSM_SetSystemMenuVersionControlData(); - } - - // fobKڑȊO̎̂TWLݒf[^Ƀu[g^CgTitleIDplatformCodeۑB + // [TODO:] ̓̏Ŏsꍇɂ̂܂܃u[gĂ܂đvH + + if(s_calc_hash) + { + // nbVlۑ̈ + SYSM_Free( s_calc_hash ); + s_calc_hash = NULL; + } + + if(s_dht.buffer) + { + // DHTpobt@mۂĂ + SYSM_Free( s_dht.buffer ); + s_dht.buffer = NULL; + } + + // _CNgu[gȂǁA܂SystemMenuVersioñf[^ZbgĂȂꍇ́AŃZbgB + if( *(u8 *)HW_SYSM_VER_INFO_CONTENT_LAST_INITIAL_CODE == 0 ) { + SYSM_SetSystemMenuVersionControlData(); + } + + // fobKڑȊO̎̂TWLݒf[^Ƀu[g^CgTitleIDplatformCodeۑB if( !SYSM_IsRunOnDebugger() || // X^hA (OSi_DetectDebugger() & OS_CONSOLE_TWLDEBUGGER) ) // fobO { - u8 *pBuffer = SYSM_Alloc( LCFG_WRITE_TEMP ); - if( pBuffer != NULL ) { - LCFG_TSD_SetLastTimeBootSoftPlatform( (u8)SYSM_GetAppRomHeader()->platform_code ); - (void)LCFG_WriteTWLSettings( (u8 (*)[ LCFG_WRITE_TEMP ] )pBuffer ); - SYSM_Free( pBuffer ); - } - } - - // }Eg̓o^ - SYSMi_GetWork2()->bootTitleProperty = *pBootTitle; - SYSMi_SetBootSRLPathToWork2( pBootTitle ); - - // u[gʉZbg - SYSMi_GetWork()->appBootType = s_launcherToOSBootType[ pBootTitle->flags.bootType ]; - + u8 *pBuffer = SYSM_Alloc( LCFG_WRITE_TEMP ); + if( pBuffer != NULL ) { + LCFG_TSD_SetLastTimeBootSoftPlatform( (u8)SYSM_GetAppRomHeader()->platform_code ); + (void)LCFG_WriteTWLSettings( (u8 (*)[ LCFG_WRITE_TEMP ] )pBuffer ); + SYSM_Free( pBuffer ); + } + } + + // }Eg̓o^ + SYSMi_GetWork2()->bootTitleProperty = *pBootTitle; + SYSMi_SetBootSRLPathToWork2( pBootTitle ); + + // u[gʉZbg + SYSMi_GetWork()->appBootType = s_launcherToOSBootType[ pBootTitle->flags.bootType ]; + #if 0 - // u[gt@CJo - SYSMi_FileRecovery( pBootTitle ); + // u[gt@CJo + SYSMi_FileRecovery( pBootTitle ); #endif - // ^CgIDXg̍쐬 - SYSMi_makeTitleIdList(); - - // oupb` - SYSMi_applyPatchToBandBrothers(); - - BOOT_Ready(); // never return. - + // ^CgIDXg̍쐬 + SYSMi_makeTitleIdList(); + + // oupb` + SYSMi_applyPatchToBandBrothers(); + + BOOT_Ready(); // never return. + } // oupb`𓖂Ă֐ static void SYSMi_applyPatchToBandBrothers( void ) { - ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; + ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; - if( ( 0 == STD_CompareNString( hs->game_code , "AXBJ", 4 ) ) && ( hs->rom_version == 0 ) ) - { - u32 len = 0; - u32 llen; - FSFile src; - void *dest; + if( ( 0 == STD_CompareNString( hs->game_code , "AXBJ", 4 ) ) && ( hs->rom_version == 0 ) ) + { + u32 len = 0; + u32 llen; + FSFile src; + void *dest; - // f[^ǂݍ + pb` - FS_InitFile( &src ); - if ( !FS_OpenFileEx( &src, "rom:/data/bandbrothers_arm7flx_patch.sbin", FS_FILEMODE_R ) ) return; - len = FS_GetFileLength( &src ); - - // wb_̂AARM7FLX̃TCYς - hs->sub_size = len; - - if( SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC].src != NULL ) - { - // ARM7FLXĔzȕꍇ - dest = (void *)SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC].src; - SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC].length = len; - OS_TPrintf("bandbrothers patch : relocate info changed! \n"); - }else - { - // ĔzuȂ - dest = hs->sub_ram_address; - } + // f[^ǂݍ + pb` + FS_InitFile( &src ); + if ( !FS_OpenFileEx( &src, "rom:/data/bandbrothers_arm7flx_patch.sbin", FS_FILEMODE_R ) ) return; + len = FS_GetFileLength( &src ); - for(llen = 0; llen < len; ) - { - int rd; - rd = FS_ReadFile( &src, dest, (s32)len ); - if(rd == -1) - { - FS_CloseFile( &src ); - return; - } - dest = (void *)((u32)dest + rd); - llen += rd; - } - if ( !FS_CloseFile( &src ) ) return; - if (len != llen) return; - - OS_TPrintf("bandbrothers patch : apply succeeded! \n"); - } - - return; + // wb_̂AARM7FLX̃TCYς + hs->sub_size = len; + + if( SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC].src != NULL ) + { + // ARM7FLXĔzȕꍇ + dest = (void *)SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC].src; + SYSMi_GetWork()->romRelocateInfo[ARM7_STATIC].length = len; + OS_TPrintf("bandbrothers patch : relocate info changed! \n"); + }else + { + // ĔzuȂ + dest = hs->sub_ram_address; + } + + for(llen = 0; llen < len; ) + { + int rd; + rd = FS_ReadFile( &src, dest, (s32)len ); + if(rd == -1) + { + FS_CloseFile( &src ); + return; + } + dest = (void *)((u32)dest + rd); + llen += rd; + } + if ( !FS_CloseFile( &src ) ) return; + if (len != llen) return; + + OS_TPrintf("bandbrothers patch : apply succeeded! \n"); + } + + return; } // ^CgIDXg̍쐬 static void SYSMi_makeTitleIdList( void ) { - OSTitleIDList *list = ( OSTitleIDList * )HW_OS_TITLE_ID_LIST; - ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; - int l; - u8 count = 0; - int max = AMN_getRomHeaderListLength(); - OSTick start; - - // Ԍv - start = OS_GetTick(); - - // Ƃ肠[NA - MI_CpuClear8( (void *)HW_OS_TITLE_ID_LIST, HW_OS_TITLE_ID_LIST_SIZE ); + OSTitleIDList *list = ( OSTitleIDList * )HW_OS_TITLE_ID_LIST; + ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; + int l; + u8 count = 0; + int max = AMN_getRomHeaderListLength(); + OSTick start; - // ꂩNAvTWLAvłȂ - if( !hs->platform_code ) - { - return; - } + // Ԍv + start = OS_GetTick(); - for(l=0;ltitleID; - - for(m=0;mmaker_code[m] != pe_hs->maker_code[m]) - { - same_maker_code = FALSE; - } - } - - // TitleID̓XLbv - if( id == NULL ) - { - continue; - } - - gamecode = (char *)&(id); - - // `[̓XgɓȂ - if( ( 0 == STD_CompareNString( &gamecode[1], "ANH", 3 ) ) + // ꂩNAvTWLAvłȂ + if( !hs->platform_code ) + { + return; + } + + for(l=0;ltitleID; + + for(m=0;mmaker_code[m] != pe_hs->maker_code[m]) + { + same_maker_code = FALSE; + } + } + + // TitleID̓XLbv + if( id == NULL ) + { + continue; + } + + gamecode = (char *)&(id); + + // `[̓XgɓȂ + if( ( 0 == STD_CompareNString( &gamecode[1], "ANH", 3 ) ) #ifdef DEV_UIG_LAUNCHER - || ( ( 0 == STD_CompareNString( &gamecode[1], "AN4", 3 ) ) && ( SCFG_GetBondingOption() != 0 ) ) + || ( ( 0 == STD_CompareNString( &gamecode[1], "AN4", 3 ) ) && ( SCFG_GetBondingOption() != 0 ) ) #endif - ) - { - continue; - } - - if( same_maker_code ) - { - // Xgɒlj - list->TitleID[count] = id; - // sameMakerFlagON - list->sameMakerFlag[count/8] |= (u8)(0x1 << (count%8)); - } - - // Wv”\tOON or u[gAvg or WvAv Ȃ΃Wv”\ - if( pe_hs->permit_landing_normal_jump || hs->titleID == id || - ( SYSMi_GetWork()->flags.arm7.isValidLauncherParam && SYSM_GetLauncherParamBody()->v1.bootTitleID && ( SYSM_GetLauncherParamBody()->v1.prevTitleID == id ) ) - ) - { - // XgɒljăWv”\tOON - list->TitleID[count] = id; - list->appJumpFlag[count/8] |= (u8)(0x1 << (count%8)); - } - - // u[gAvZLAAv̏ꍇ - if( hs->titleID & TITLE_ID_SECURE_FLAG_MASK ) - { - // Prv,PubꂼZ[uf[^邩āA݂΃tOON - if(pe_hs->public_save_data_size != 0) - { - list->publicFlag[count/8] |= (u8)(0x1 << (count%8)); - } - if(pe_hs->private_save_data_size != 0) - { - list->privateFlag[count/8] |= (u8)(0x1 << (count%8)); - } - // Xgɋlj - list->TitleID[count] = id; - }else - { - // ZLAAvłȂ && [J[R[h - if( !(id & TITLE_ID_SECURE_FLAG_MASK) && same_maker_code ) - { - // Prv,PubꂼZ[uf[^邩āA݂΃tOON - if(pe_hs->public_save_data_size != 0) - { - list->publicFlag[count/8] |= (u8)(0x1 << (count%8)); - // Xgɒlj - list->TitleID[count] = id; - } - if(pe_hs->private_save_data_size != 0) - { - list->privateFlag[count/8] |= (u8)(0x1 << (count%8)); - // Xgɒlj - list->TitleID[count] = id; - } - } - } - - // ܂ł̂ɁAlist->TitleID[count]ҏWĂcountCNg - if( list->TitleID[count] != NULL ) - { - count++; - } - } - list->num = count; - // endԌv - OS_TPrintf("SYSMi_makeTitleIdList : total %dms\n",OS_TicksToMilliSeconds(OS_GetTick() - start)); + ) + { + continue; + } + + if( same_maker_code ) + { + // Xgɒlj + list->TitleID[count] = id; + // sameMakerFlagON + list->sameMakerFlag[count/8] |= (u8)(0x1 << (count%8)); + } + + // Wv”\tOON or u[gAvg or WvAv Ȃ΃Wv”\ + if( pe_hs->permit_landing_normal_jump || hs->titleID == id || + ( SYSMi_GetWork()->flags.arm7.isValidLauncherParam && SYSM_GetLauncherParamBody()->v1.bootTitleID && ( SYSM_GetLauncherParamBody()->v1.prevTitleID == id ) ) + ) + { + // XgɒljăWv”\tOON + list->TitleID[count] = id; + list->appJumpFlag[count/8] |= (u8)(0x1 << (count%8)); + } + + // u[gAvZLAAv̏ꍇ + if( hs->titleID & TITLE_ID_SECURE_FLAG_MASK ) + { + // Prv,PubꂼZ[uf[^邩āA݂΃tOON + if(pe_hs->public_save_data_size != 0) + { + list->publicFlag[count/8] |= (u8)(0x1 << (count%8)); + } + if(pe_hs->private_save_data_size != 0) + { + list->privateFlag[count/8] |= (u8)(0x1 << (count%8)); + } + // Xgɋlj + list->TitleID[count] = id; + }else + { + // ZLAAvłȂ && [J[R[h + if( !(id & TITLE_ID_SECURE_FLAG_MASK) && same_maker_code ) + { + // Prv,PubꂼZ[uf[^邩āA݂΃tOON + if(pe_hs->public_save_data_size != 0) + { + list->publicFlag[count/8] |= (u8)(0x1 << (count%8)); + // Xgɒlj + list->TitleID[count] = id; + } + if(pe_hs->private_save_data_size != 0) + { + list->privateFlag[count/8] |= (u8)(0x1 << (count%8)); + // Xgɒlj + list->TitleID[count] = id; + } + } + } + + // ܂ł̂ɁAlist->TitleID[count]ҏWĂcountCNg + if( list->TitleID[count] != NULL ) + { + count++; + } + } + list->num = count; + // endԌv + OS_TPrintf("SYSMi_makeTitleIdList : total %dms\n",OS_TicksToMilliSeconds(OS_GetTick() - start)); } // VXej[o[W񐧌f[^̃Zbg void SYSM_SetSystemMenuVersionControlData( void ) { - int l; - int max = AMN_getRomHeaderListLength(); - - for(l=0;ltitleID; - - gamecode = (char *)&(id); - // o[W̓ꏈ - if( ( 0 == STD_CompareNString( &gamecode[1], "LNH", 3 ) ) ) - { - char path[ FS_ENTRY_LONGNAME_MAX ]; - char *p; - NAM_GetTitleBootContentPathFast(path, id); - p = STD_SearchString( path, ".app" ); - if( p == NULL) - { - // s - continue; - } - MI_CpuCopy8( p-8, (void *)HW_SYSM_VER_INFO_CONTENT_ID, 8 ); - ((char *)HW_SYSM_VER_INFO_CONTENT_ID )[8] = '\0'; - ((char *)HW_SYSM_VER_INFO_CONTENT_ID )[9] = gamecode[0]; - } - } + for(l=0;ltitleID; + + gamecode = (char *)&(id); + // o[W̓ꏈ + if( ( 0 == STD_CompareNString( &gamecode[1], "LNH", 3 ) ) ) + { + char path[ FS_ENTRY_LONGNAME_MAX ]; + char *p; + NAM_GetTitleBootContentPathFast(path, id); + p = STD_SearchString( path, ".app" ); + if( p == NULL) + { + // s + continue; + } + MI_CpuCopy8( p-8, (void *)HW_SYSM_VER_INFO_CONTENT_ID, 8 ); + ((char *)HW_SYSM_VER_INFO_CONTENT_ID )[8] = '\0'; + ((char *)HW_SYSM_VER_INFO_CONTENT_ID )[9] = gamecode[0]; + } + } } @@ -2094,46 +2337,46 @@ void SYSM_SetSystemMenuVersionControlData( void ) static BOOL SYSMi_CheckTitlePointer( TitleProperty *pBootTitle ) { #pragma unused( pBootTitle ) - - return TRUE; + + return TRUE; } #if 0 void CheckDigest( void ) { - int i; - for( i = 0; i < 4; i++ ) { - if( SYSMi_GetWork()->reloc_info[ i ].src ) { - - }else { - } - } + int i; + for( i = 0; i < 4; i++ ) { + if( SYSMi_GetWork()->reloc_info[ i ].src ) { + + }else { + } + } } #endif // PXgvf폜 static void SYSMi_DeleteElementFromList( u32 *list, u32 index ) { - int l; - for( l=(int)index; list[l]!=NULL; l++ ) - { - list[l] = list[l+1]; - } + int l; + for( l=(int)index; list[l]!=NULL; l++ ) + { + list[l] = list[l+1]; + } } // PXgvflj static void SYSMi_InsertElementToList( u32 *list, u32 index, u32 value ) { - int l = (int)index; - while(list[l]!=NULL) - { - l++; - } - list[l+1] = NULL; - for( ; index= start ) - { - break; - } - } - for( m=l; regionlist[m]!=NULL; m++ ) - { - if( regionlist[m] > end ) - { - break; - } - } - // ̎_regionlist[l]regionlist[m]́Astart <= regionlist[l], end < regionlist[m]ŁAłȒl - - if( m % 2 == 1 ) - { - SYSMi_InsertElementToList( regionlist, (u32)m, end ); - // endXgɒljꍇAm͒ljvfw悤 - } - if( l % 2 == 1 ) - { - SYSMi_InsertElementToList( regionlist, (u32)l, start ); - m++; - // startXgɒljꍇAm1 - l++; - // startXgɒljꍇAl͒ljvf̗̎vfw悤 - } - - // regionlist[l]regionlist[m-1]܂ł̗vf - for( n=l; l= start ) + { + break; + } + } + for( m=l; regionlist[m]!=NULL; m++ ) + { + if( regionlist[m] > end ) + { + break; + } + } + // ̎_regionlist[l]regionlist[m]́Astart <= regionlist[l], end < regionlist[m]ŁAłȒl + + if( m % 2 == 1 ) + { + SYSMi_InsertElementToList( regionlist, (u32)m, end ); + // endXgɒljꍇAm͒ljvfw悤 + } + if( l % 2 == 1 ) + { + SYSMi_InsertElementToList( regionlist, (u32)l, start ); + m++; + // startXgɒljꍇAm1 + l++; + // startXgɒljꍇAl͒ljvf̗̎vfw悤 + } + + // regionlist[l]regionlist[m-1]܂ł̗vf + for( n=l; l=)jzfB8OrZ3TAT5|O5?l$giD-_OM)VKMow)oD`>FcF82yQq$b?OhZ1xYQd zdhhL1j(8ulM`3r}_l)In*K<~G@n;AUTm4&Rzr^Rdz(V b7iLYnl&l^9grFs9(zy=XWC|miltZHdS~Y1V literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/DSHashTable/DSHashTableEx.bin b/build/systemMenu_RED/DSHashTable/DSHashTableEx.bin new file mode 100644 index 0000000000000000000000000000000000000000..5c8bde0235135e3d0cc3a2e550b0841381ad10d6 GIT binary patch literal 160156 zcmd44cRbe7|M-pU85*K8%9g#e-o|BRZ<3I`LMS8IAzPF^GEyi)vMaMFDj7uy*(<9- z_xn2Md;fP`eICEhegE$J*T2ul>vdkQbI$v`#yOXCRW;1dx*lfA@c1miQ2xE;KzTDo zRKKG3l8s~w2X*J)qbokLhn}2x%$(Rpzm@tZA*}Y$nk#pOxRFq(o8ax)fH~Q#`Qb-0 z4?8eGySfpmX-zG}&F%SGVP|zmhWQsWlQWa6ZH`tj<@5XWl7%kz14f zST3tds1ni~_IVg(z|IzL5n48GCs8T0yuHN3SG1*Ao})UYfX;&PyN1R$zx=)7FZw|( zt-pkFE58`ausZQDpp)()rN!2fz=XNq`Iq&-a$fxXrXw5?l?FP~`92lB$&S3^b$qI- z^u}Jn*jk_)A}Ry?d;a0tdkbQhz_YnLgde$d(gQOyunfpWMN>=-a@W^w_4IoOTOHL@ zu>2Z~GB6%)IRwaE9r$50c#0DwH7zD){kZ$*i?RB z_}x0_IwGnHY%$`keaNwY;o;zver1bR{fkc>>$xZca=~eVhlkrE)rHvTNT_RcEXiJ0 z-$WVMXVRP3SmxRfxEzgnLVB{`)A|&_dhdT=zz5vpsR3J_C7-OFeAIY`-Tpvx3OD9v zT)yLNMD$+_1MD3Cw3ZmAYs@a>yl<<=L!ZE5>M4SVV!-<0X6j(Py3abLD!sF3PU$uHY9TJa(D5{ZPL-mxL&KMS_0mkT37e@s?xao#p=Xa4kgK#4(k@NfQ>t5@Y&N8n zBmX91e*h8H2JCiy>M4pOuDfmR*;!IYuV;0!`w$|c=YTD;XR0ptZO^Z2=ljghFjuIM zzqrPVGBDmxwVCtnWf#tuze`u;Zl;*Y{@FM7bv z=y!#8Hb2botI}NTxBEPLSV3R@JIa90rau49Uy`wr8h1awSUu8aL4Rse|G#I3V7$r4 z%zW{28Fj}`83tVaW!6jebmbT#Y6R?*_WKd65WYBh@KD{F=I#Y!E(*J=h^R4Of(k#z zHn*OCBetfmoot&pYr|40jxu0p(8Z)sl!E#Z zg9B5B>ySXo|EFx+S z&ZX_d`ma?c7Sq&;gd;BZN=1vEt57@t#Vml%x#W9Jeyws655N4bRC=7WM%5vW>a+l7 z2ySKx}=Ve0W$_>G9c*f=KFP{w`st0K$$nCAui zY}4Ev{x=pL134%Ib{=bycomv*|ABo`pyAKa$$87m zrza6H7#l-wEGrBipZ}a=Ngv(4I{c*Wk@jaq493Q;;iQW-aVN*)MtQw2KGJ7?xI#RH zh{5=0+?=ECns07*^Zu>x9ivA!+-ZEO5iuB#Fm}JK?4#XJ3eZ-11`tkp`bRs|V;S}v z!^6Ow)d~8Anz{=+Pm~|K_nqeZJ(V+Em53OOV`+z@Zq2>hqq{~G67-8u>Q$=%>02zr z>cqo%Xj*8 z=7L0U(*8FiL=471+ziIQKWBN}8Fh3qz4~K>RFdU}7Trc-h!~82$MVyotc4$n`xSNH zOmi>u(?SFUQ3lpQQoTca_+g{H42D!#_h-AJ%7*X;A_ikz)8UwkFRpjkoyFV4`$`qN z&h98AVHtKE@Gh<<`wNlO zTkDZw-=fj)7RFTEat6SM+v?3LbFJxR74F-FzZMA&e3$8-K*S6|TuD+Hp!r;;lW{%v zcu*v`%ZVi+HJ7skhf41D&dag+g_TxWBxN2&#I6W^ueDvBZ+sH1)I5@i^y9C_kz#Erg#(TV@@^-58V z`rSSiS(IsDnXQY%obI66v&QdXAq>-h8kZW2IZ>vGWt$%y!wsrQiVW(MQlANnHq^yg zlA;XQiDx_`tX%rNKfh((q<^#foH3-k!9#tn+o2EC8^Y|XQr|<{%$xT2J-@e6)V|;YppFExf@%r zlV0q51?U%}46M;}vfkJU(|yHLV~1}Vyj@`Q5`3hNW!OEBo58%`#LA%Qoyn^Q56=j( z*8Fw(()W(@F(PILeE2Vz33kq22<=X?Jl(XqbyFZVv~kP2kMe38s`FnA%!{DU0fOZL zi8pDJ(Up@i6lD{WG3eO?^AOz39PF3%k2~Mi;_me<+*6CK^LIS)ZQMlw5irJPGtgQDuo@oLhi@jdibbsZuO^Pcd*=f^~g4DZz?=yBVfTg^=` z$}K^}Vcs)to>k^l`}E_VNQ+t7u9wH?;)dR$4CrJ{IPhL@CP18j$cIkdOq|28DmDZW zhk4Hu*VJZMn8(tH%-HEC_eR85b*5_&@&D-ww4UwE6jOUipzFrC7==V7C?(!O#9{st z!*TBW+_sy5BgLNHZWEKhMHd&;KbWJ)xfqY6e(dvccw6APLw6~4Ko)t4h{HTY>YU4R zM))0R?hkKik11PyW{YqtLd0PnQhs>QB0F{W^BO0H<)TZ^haZuL9wOo@U@tlM3nXnO zDqoEyYxexYSYz~1FKh{AV6L|olv78e!#|!sK5O1%{q0`dj2RKifbW?Cvyz(@d9;@$ zdTmG#P>@RamT;mBd@C`Rxb6RB)*GLZpsm*!_Z=!JKF!wZ_}ChDJGX z>0m@;YGvnsb77JKjPkWTm$G>AJ#1X>GZX#EEUbmEZ%j6_nA#o?8|W?*>F ztp2|JhteDO<58XeU@!;!IuqsV{IOF(wrO;dLaZmf!)YAdFR&*-zxm)yhHOA>iOz{w zYNzIp$G)kDA>uIaF^Su~@>|4PQ?#E@Cvy30^aayD#V7;g;byS5kDw#ApS+agMD1O- zl(X|~+4g(|A0n;=&UxGn=0pw~Cwl!qHf2!7WlrdQGp0I1#h!qO!<+~=gL#i^=qKyT z?BsM~kDWajs4f3y`EG9`;<{kJ5H;WW^1O?Z#LpmqIUpv<;EqQ|50+u~AZ`Y8ls>If zY8P*0q*nzj{3fQ^b`U#j&VY!+9OV(;Qu~#P_qPWJ88i3JKaG?)IM{(QFfX{}^uagA zk-2_YKCa=a=JCfKh3mF250z`7{^yzn zps7n9cvInd(8@|O+s1`{fjR4inSV1F!;cBY(5pJ-lYU@;>aAWE%3-qHA)d`84Az?obT z^y072g4WwR9-CK#)<_*sxO}+vZ)OSROgjAAnjCwp!-t3D5=nUv4AXf@1rTvdFlRRI zj@*%M=ZzHah0anx=I>DXP)&kJz_^02wG*2EemZ~WE+H+^sl1B(Xp9FU0b>V+Z)zFC zHDzj5hj@JkE!$fuuUu{*5-dM12!p;EP6jORtgd62K-@LiU%laF}r-{Z2nQhN(!V7!w(ArHpiL^&m%C=ZXKDPL)L zP5v2WV9vh0|Cm&jMmIH8Jft%n zWnetA2?|B^-XAoP+cP`GG0~&Q1i=u>fX>>ljz#OHB3l&uw;R;B0~0Pz+1Mcxu-0}J zY*JFX9G~6v@GQOd&Rj$Z(a{)00s-Surg^eFcX-H?$v{%nVVGF3m#*^@WnjFhWi42*|I4#XVX48}jI-R2c}0iv&-(o&yuS9Deb9+K%H5-`Te z(@kbQh#%64(9vhzA@#L=a8Q37k$~|?AyHQ7g{;7{c^b#=1lliGtmN+(Ardei;p{<3 zV1R!@;Z|8jG`Sdt$-J(`>3hWj!W~e$!n!9!f%dqDX zK8CIT@G!9MzGc;^QYWvht4>^ADchtL<~nh?0@bOF)%jmAFxN`D8iVn|*_ox8w)R#2 zpM98juLL6!u(!>z^Y&{&{d-@wW}95k@0T4ic8=diBw($rTYupCHZN!D4YxP1SkAO; zRo3oKA`&pJd=D3LsWowcUAaK3*t7z5P0ubT|qxKv6?I&UH))@*4X+KPUg@SMlZ z;5pAmxw@P<>q~RuNFQS>p>6r^TK`%^LLcnwOLxv*|6Eq*RqpMwBRrse>dC2qA1DJp z;E@CS8aIRS!AZ99_DtJ&`*EI{%vmpLwLH!>Lqr0`hkdQ}>XSW$^F^LMS?8vVO&nt= z9wQR4HWcM$5w)Y(8V|UXvU4%hDUa^*=pM>|otDSVM(^ITwjd9Qpgj8f1GPqRPYud| zot(dEed0#~tzz}Oxmtb)wo0Zoqs#>C`BwyoOj17cQh(48GNQrUOnRUAXcJ{X4mX46 zJiYOkJ#(c77kg8k3PE;R=_~UJ8;B(AajG%x-AN!^S$%$(BiJNDH!YjdV-{t=&MV(% z-<7x@tmbaE(hqx0DZ+CkunlG4dzc$++-*`6p3Pu;bts`e(uw5h1~bZlEw@y%?x<=v z2z!O))#nsTnkYFti6N4(?s#@o>X^`z1&(P#^VhMz&uPlsH9LbcFkZra=avtvqWl+V z{8#Qz=coN&e_4!5?`<62=GNSF0oKs{E3V-qC(6 zPZx-sb>-neBw-AwLVAxZsp|z!iay*}JuH^WIr8W*A_>p=B7X865gCijs+8w}B72!* zgsOB05J^}EJR!UEx8Z|-a`#=%U+G@Ks-0Gf4TvN>Tj>mMIfYYf@p!tqH%4-<>UK`3 z8lVjLAXv0D`|ZA@kacL5a+9pBcT73+$N$3^SR>p%D1&`=_JWVzpZv7U9Zr(U{-u=V z%b}K#C*8t5*y+6HfnhN$HcL z|M60bl34|jgfXW)E95lAO?9R7r0$-QYxe~feMO)CZ(_hs+_u0N=jE5@+L4M-y!W8* zYT>>8tg>9-5+Vs>++BTb;qraHGnTp+8|UaQ>(qw_Gu+ zNmLXf346F)iw9nk|BBp_h}bF$3G8RBr|l#|Bw;NxmD+Zeg}p^D$IkmFIbDpa@a?K2 zh@>{ygQS|lNVr0*Zc@v0{b90CJNtb;NB;u@^HRC&mhO_Ca7kT2A^hH~XO76&T@O_5 zUkuC{p7H*{V10B{IyWo*frrv&#JH&Ae8hSrZK)R`sSA8~Gy2($H1>>VRoC*8qLjK^ z$tA;4lmS~VRhj61^Kv(t&teNMWSvvHVSJdp8Q%_E;Is~5SI~B-j&5|M~An0AlqmMGMMuC|O7>2SIPC>@Yh}$-Et;qV6G$IM> zF=EfNB+-BRiEj3Gr%dh_<-Od|RYoLX|1*To<(jxek=&aI%<{MNtL9v(U;J<{wA}ju&4WRcLdr3e0i9>% zY%#(=a$?oi1xg0eJUgj%dXFQLu$RX<;wH%7amdj@NjTO}p--0i-Owx|1>^MO#dwBO z6hoJe=?-|$mgr=%3%*N68CZv=ZXOrnqaI!y1P(#ApXYh#pI0`a48&>u($JRs50V%U z&3O2mQx}cC8$Ngyk%I9yklH7mtb% zZ>=!2cEp+6ZX!}J-rg%oFecrNf5n_2SJ4^dQ1JZKNE{*s?SAtnwuKw*UI~yx**1OD)Wp0%D}!B^*Cl3qi6BzsUV$O7iK7= z|Bhi8QPa#<7p||Shx@Gy@ZY#&q(LKHj!46N_eLtWak2DsnP+jEH(cZc3QennZz0mk zK&Pw7%P%sRzs2(JO%$1T?j{|aDnfmS`#L{;ZN=(WHSKIRVViGjgYjXGBOE9LJ{a>T zq#KeGWrq$wsMY9M{pG#iwT3d_!zJ_EPwh*$ldm!r4eA?x((M?j-u@2^*g{64Z?iPY zJlJC>6HIt+M}Sw;%Ndb|-^#*?^+40A+N3&X7EWb}WZS)!^9N7{Y-#&#*>1cw`~8OM zr=x`H3O|ZDdPz|RbP}IiDM?jGwKCEk`OaUpOI;vGq+yPdk&&!)v0n6PUK>YmAAOTt^{4fm|HQEI z9iQAk7?{sNcltV3M&4uZU1EJo%T^3o$BrqYfrz2Lo%g@?unaA<*Mc;8RUn zkqYMPhSHYq=y-tP@j)M}6So}9vv7Y82H<>Qku-@RNNyg>C%P*}k^4&;GZgNLNW(k} z4+FN~W-!n4O>uf{QgHgxxBc@zt%ncZ`L+KN{Z?SU^g_n^yi*-xMch@bKS{Tvq_{Q& zZ=($KHB3TM-%sZ&xqkC3`K5SH$?j_B*-eyz_gOt$iw|{ogmizEKatk?O64woLM#`N zhIy9nB8Oz41(V=faO1D1NB{C>JU{pe%dqo;k74^~coNSsnQ*Fd8D5s`UJQ3 z>$fMmP@N!G#K*8Y@i1@}q*YfEhdldo>)R=5&qXo1iE*!l$EePKF)-J7>;&un|1N|1 zCy|&*r1v)uv-0dt@h!^vg!6r5HxX%gAHXyCPUq~!*i08?;Vn6{B>R|w4i7}y49wZH zi_2|qTi!-qE$tTm%uC_x7UuzyIWCY4#W#P&U7UGO%B8%fa)SYC#Zq_I!}3U@ljE_?=lGKUy%@ul3d)`qu~o&z@*n zTBT>j0eOqxT!dxQE{NKzwNIc7yt}~7V2xL9@?)g&ahpEUBv;WYy^~8K-%f!j!@48z z#!-gj@#d`VbH;~fzjTS+D*4!oGB7W=8SL}<2hDWdI`v^rysJ+o(&oYpU#R09L>cb0 z#0Q?;6=IX8pPfCjxM$H2nN21th%%tFPEhsvv`nu2a+mo^jF{ZXE8g+~h_X01TQi90 z-!<6Myg9Z$W+mv(7%?s?0a6Y08>y;@3mrL&Bcgln+NC{>MT|ea>@nOL->{*A0f${p9KDHjW zdXQ>FdYsT#YdH3{4re+l2Yi^O`YEg|-Z0h{*ihg2S}#NVBxxj~4DX!|5HcE9zaZ42 z^B(x}l%0$~%ef>6Wk8N9oRQY4=8el00Fn=9nv; zhiAKV9U>m149MYTum+kl;(Ytf3@OIxEgPy3W%wP1Z8bPB{BX(TyJ)FO z@w$arQ8rKvWk6@rw91{G00lwz81kTOyDQzsWPR$0GOU4&c}OWsY@`>zP`#2c)3)IY zXz+iCG9ZVW!QP=QDikC>ZPs~G@?znAR1U-yd<+{`@G#&*EQ3W{R4C8r zP5*6@mX4b=LcAw!P@Nz?;ASw7Oj2-}iK9F1MzT8}PA7L~je^cqoyXAgP5c1UhK7dQV2hRZkD79NzpRYSiASRb`52#<76PLI6V z$!ni+;nU>3b@>X)fbWsJ+wtL)aSP1y7tZNTRjuri+%!QM@Bz0RJbM~;Lj`Jzl&y;6 z&eH}JyLVHEeL(j-tdCsI2nJB!A|l=lEnXFPouBi#%e4_@aIQHF6PD zqh$BNqYGtVJc4mqr;evp77ZpP#?-aEt!@)MPKYwBtE@$y8=X&*!5EcfF)>eX>*uD_ zFrW6Hx|qrv0=#a!+`moYgq?N6U?jE77dkY$yXdam&Fv z?tYw$_NkM#5_AV7LXtpZ^Y=?<7z7p^UJjVI zReq{V;WvNLHi;`-zOxpLjM_Sy9TIdm0HtnK%A}9I$0GmeJ19XPO|T=y>2C z*Tan#WK@cXGQ5v-@R-PX!cD&_Qya##8!B6D&7Nz9G9ZVW!Pp@;o$;Exesc8TDCMo1 zdu!u^PcXBHGJOAun;C&MVs-2MJ4AERef&7p1l1FdEuYNVQ;0ImKPx5OCEts-kSEK1 zr8Y}^eeHes-er^lTYM)cNz=k+uH=+`eWQ}FeA6KL)=fki-j9`*ugprkj%Bt9UfneM zcrs~j?fKIzpr`GvT*HZNC4w71l(HQEu z%oQTaFh5gcea6L_LQj{rdHIntVerE}`?&XrGJJQa&6%GavEp^ z{{sf>jIBRSm*D=CZ!&)5#&3iAvqFCo*HNASEd#l5jtzmf#O$U|+1J=N$<>}cZ&Om` zP@Vr`U|wouyXX#a1SAPn+#D_#<=$KkPYXrm{!0e$BE8gA1zxz4j;Z+5???XZ(GN)C zN6%}Ro4(P%A9>`F$7$!a#U885N4BCNWfLd^Zv?Q;i zz)^iG7g2%v%YYr(bEbPjdgAX>H4pUZ40Y(7zl&wqvj7hRbA3=&pDFZx-K`U412)n- z5iFMjRv(~p|6;&S+_u1+=-T6FVqyv&R%^e~O*R`YjfR~lL~VgN(TJ5=f`xkEc)Q4z zs0doV!I=6HC6oc3xaDBJRNr&KSzSu8cscuG5RA8QUUo+O;{1D?oj+2YFfA2o%8K=B}&L_;5@Gwxra)_@9 z2}Ko$8!jcCU^h_Pa#Y-RL*+mX>t8^t*D=&j@b|vqN1NtTzGp9#cOoh<&+6b%Hguw` zB(uvi-3h2Ni3*j9i9s3oj^d)&BF2SY*QMKh#S~i=^pi_cc(aa&fp_V67_bEo1MkvtGnk*P$r;tKm@b|QnldmU^q5|_X+zj@p2|13425~*f>MtLA9Ts!SFaOEGXNU^S-5TS@(qojee!ft* zq0h7RX4|1x48k((p2x$054d&0oKMGV?!!f5Vp)xsp+1OiN^bHE(ldw(>;byW{LG)1 zms9#x?au5UnZC9fzTb#4@U2{4mpR-1Em>d4p-0h9qUDg4oo~i}V8E74d%@ud(G^DJ z+t!n{bqLo~)vJ9}4(v1B4AzueOd{v`11tH9%Zcn2ZGv_Q#%9zI6?jK`k?#4<>)_?3RT!DQ4RV)3Si zk*f6SQHj(cLPhK3Cjp4`$MH!G|&TlGE+32Z>&L7R86>#w= zb(>5;8Q5pI8O#+et8{|yS2aB8Rh(`7IX~}X>kvqUsK9&>H-kA}LnTc`aLwC%Ketqq zjf8l&=$>?LMCHF{U(or)trO;ogNGYbYomXTd<-bC_#~%b8zBF-MFApMw?YWbK;{whAkh0iC$zU|x5pL&hQLrQL65 zyR6a)6W7z(gj=PE3cO2Z%545vXZl7xP zh}k15Fvo1aI1(-CL}eB<{n7GA!?5k{nL-7W0Xsc0+l+I;{>gP~>_LdCHz7^=+jc|+ z=8>J00)Fr5?`KMAE2mJguzqXTazy9M7}$9_{EETLuvP*v6ay_cew(W51WGH|}&kppoIH-o?Var5&f+zyJYY?r#1Q}~lO`nudWdM3l% z^hYe&!y=5BMN(AhAyVG{+g9U;$gm81zTjcNKioQD&(U7_(|*eXryn9}2@Nqvb5yR| zyU-viWv)tg6XFgi12Oe&+R9(<**l*J8ydN{g9Pr_d55F6 zz#MbZ(>^69|H)(1m9D}5baH+D%^hWwfqB8B6Re+qyLejBt1NO%!mzGs9g&S&dB=HF z4y+#@J1x;=Ai&8~VcuHnFfB88GnD4F-A5zVck4NCrDyvQRhYN>h!P+Z_A2pK{`tBy z9A_ysc)v_z8Fp>)Fc2F{4}IDxx4yrbM|AP5(w$PeAnRC0RPJ94_>S9_|H*|RGj1o@7VmT|KyTgQ*!1ncG>9t9Tch}6JC|K-)zwaiX^Bbya!yJ! zZ$cRu4>yDTa_yR#Jc|8b!Zr@V^g#Nr2~Up%okLV%ZhCXa{r+*8AFKr8+<(}1JgP&+ z>cUV4&aAkWjX8{T8v}z2@g+8K@`?u53{4K7`UvV_k?*Ep<$FR2G8}DC?@*i?E_!-Fc@%WCxj)#YV zGpk0x*83e**tM%O!QG_m`jXF1OiiKwX=3H@FtC1jdL9W6O6T6rhr+~{7O`j+A!&EYTcm=aNi z?+dz_ZWu(;%FwCU^>iqNbY>$FyXf~0YYX|{;XtA3Ujj6wnT!&wq4J9TdF&_ybCzwQ zp}n@4pYi@^xazqiUX?s;hgpX@x`&Eo~YU#Jo$K+TV@$ih3^D# z{-#hBz7x2>^PuhvcRkWT<*{u;?!eZ_{DT2eg|$Uq3WkoQ?~&{H=d&sw_+^7xHQ1}M z>+a5<^EBaFuj4+}K z>jz?{KbqTV^-iyIn1Xx`nk&8H9t%bpn6v7w<-5L%d^%i~)m1xMLwgUyf4)K)@Q>zo zx9^i*#L_{i{>dzLGZPgG}SU-#pN54>a=<@446H-8{6NRWgI5|; z18!Sjz2ca(dqHZ6xjJX=-S@gBAsyS^zDPtB)+<~koGrBB`kX0A6>4I=gHL#^5(2Rd z>mP0g>xYzps{QbjbBwLsV^ng@Ovs&Y#TAIEKCm;&Z_mfgTs_WOOJHj%RCm6~-+kgg zFyKST<45nZ$5<%k?%ZeOV6YVDYSZ3BRNbVrgT((U5eraI} zuj#3x@$}n75dyxMm3oH?I%=OC4Wbo8RL#MD!OdVDkn}xII>ddi%!G?G{M2!l z-6lQ_6GRo}`r}MS!IRbpN?3AttNDi-sEE24 zhZs~R>{Z$b$h1yqKjJ)gUrpD&x5>4_s@DrqgE^nE1zA9!fP`VrCVLG@qWd|WofLj7 z!>$o-26MiPnF_DB`Jav%b8<*tkK$48@^xK6)MS7hZU*zS_r-PQ6rL6)k5%4me41MQ zv|#fn2vLK5McfSb6>nd2Z)4Grn5g7){7mtwW7hl7&Jjcn#%VelCyv&r&2r;=BTq;K z4seybr1D}J)(1Qc>}v|W#5JncMMnc|<}m(iE(eHO^oUV8u(rAuzDh zwV+jwsKI!v`RGgOAa!@x?83$vM{P;1pwD@9t}&oC%;GkQd(vKcRUHN6 zgoql9jj7zz!Mh2R*-Ixheq}d54wtWJc!DyZ6So|UjkmOdA7-!ZT=1r3iVN%=IVcmS zp@gWxJK9XYp0MnwHU1$cGP)JEM#>#=1{;(Cop>1Ro8pv%u~B?ebH8M3g|2+SWOCl;uZT(8y?ZP&RAfg}T6?=#91%5m&U0!hDNP@E;!MEQW57OrK9f3! zD->m54^F*!aA53)^X8)~FCSzd-V8j@9m0w-FlVoS3(vowbG2bVKUOA_p*dh&PN;&Y z!QKN`MTTCh%x>Zfq6W|TE9S?m#wd>66C$9`IM%QjPXFcgc`U=u z3qFQDcX2Zq13oFOFJEhZ|9Y{T>l^lJf6vzVBHjm3^(rpOjg< z@H8N5@JwDUiS&)Ni~2;z)wUoSEvrFFKJJI8!M;sVa`LIKoyG;QfS;?eWe=zzR#WLxq2f%67T7A6J$o!<~Oc+SreJ|X$Oc1S|^#JhOm z$i!}yL6({ZnuBVk@JL z1eTG_(Z@P3tNv=d%7S2E-H)5W7+|D_iG4Zb)plZx*mxii>C>2ZevM#Y-CrSfWL1e+ z!IAJjOFM6^53T02u<{voEkbU1TAuwKgf>% z`0JH$%ClsEZHypy?F7oeo+r%LxL_{w+cuokqry;rD3fTgF$ZN}jd*zWKJ>ViI$CSI zdJ=xj{>ovJhdTdeFg^rFp6|IGbkiYDf|kR1Cw1Xt&SE5jfi>O_$xn}s7|rN!$Q!ZJ z#s(+x4$*u>Fz}oopli7GkmyqQ8E$P+-||b>X7}E1BN$k#wd_3P^!jjoGn;=n;zj5u z(w%QgPf-SZ$Iak79rmfW`3|QS9FMRB_Yf)!JZ8Hl_5s2CZ((3QO?PA5P8`4R?uG6i znd|LGg)V@P2Zjao|#yD<2btgeE@Luh|V8B1zaxhMR6jnV>`#64zQ1#6upVT>;9X@?@ zJQ$~OGZ>5Q3+J3on4dCz^=)Xd4vJ=>y*oCIVBo!4Yp6x^2g9K}c^M^D6Tc(hob6f? zQ3m2Bk8k&w%9oi-6lFZ!x+H)3A~>ly5e$sC=blBRuev3RzNfepv-87~FhT%wZtc*@||`+bywJ)s-B zBlqEZ{Ow8ML(EH>8wQ#MUyJ|EbU~lb)3i+8?a?8DlNAbYwkBM!RE?tVBQdc4>(U8Y zc(DA~#%Zp-^jW_^`I{1(ew2ZIoprW{?!pJxOD@@@OsU922~$MM3}s*)@W_FAp?;$+ z_q6fquj$fi-GL()tgS9fpx>=7=(Bq#6~3sN%{jCho3W85s7tSenKwr;@Se-#qK|D` ziJyKU70I$3ad21Wbl^*r0b8cO1}rJQu5^Cic&9+I^5*<6E~gGG!^QyI4CV|Gr=_`f ze%tlfwAJ~=24KDmWKh{47+5#TekheR4!r-~Rj5yCOlQCEB|+gel!5Ucq+NCD*I7E) zy0II@E=_j!^wr>#C9R<0 zi-L|At|0!6OIe8XxCPAy+8-CT%&xks_i##$r z``(sKR#ddf)S~Pz1)8q%S?Ik%88|20BzH?44L63#zDUIJ zh7%2rKRPUdGN5yojF6(}Z!cBsfKl0+E%|2!{){a|9o7%TZ(bj9VaTG(zPB=3v8I_| zf9%r$%79Lsf3FK=*fqk#z<7_?F77WiUt;QPYG-I^x?~Yy;i7=3!`~wy?y)kBAquZ! zbDtL3ubdJx(fM;9WzYwG$}$Ioi3zI$oxJp?Z|S4Ch38NPbnd8}n%?(L=rdgHXA5C; ztqnXA6NRY5zLb!xN&TvPMVs4=_fMoRjS8HfiZ=Q;gFU1U-dMp)dkM~7`F};Dnsvn& z=9C2xb$HiPThr^Vq4C}K_g3fYmF5Std*wR9Scdf-4+D1M(Ft-CJPhP0xEZ`7G7`S@ z@?50amuB(h;BA$qoYCRDdPE)876GU0x#^j-1-wG@*AMzF`@p`YqnVK;&l>6-2FM2oJ$~q<{>bK34fo0gei-&>nn(V9m zI>{+#rWF_yJ-Ad}radw~j;O=l6UTeq`cJ2Jjl{^_^(eImF-tq~k0RF(oR%4T7k*>*%7=2F3dM{at*;bkKAkSc$z)>Zbtr#=&9V7%boFU$%QcQu$p z^6OjoIbwDq-!~%aFqaxSm0tVTsPIK4?RPmE&BwM68GF$6gT1FQ3LUycM!k^z8})AI zQiuQ0uG%P}4Cury2lK3@a=FFr=|`+J5dj9xruIJ?GlEuLA>*4Nn$k&k*z0YWsq`0y zWDyP6m%3v-lpG}VM@8q0Zq1|8dvTRKO9_YujB&f97u@6fzU3#WQRYANe=6bVqBo9Z z*mWQIX0+Cwz*FELF+h3iwYrhN0bdTv!2VqLZgz+8>X!tv#})K0o97&F{3TPsGOQdP z2K-BG#K5?@0ZI3rDV z+r(ZU6;XL(VeR|LSa-Mo!{O^F1AiCX+VN_Pbw2w4A|xO)e%uqT3HN@Ep$z0p6T`t* z6m9lH8$aBqieVkw;=B@>hcYlPc*X;HPrKljoTvQvwO0;bKL?VLt9oQ;pFuQWd~aU9 zM9oGncX-uE-jjJOP`vR)j19`b8tsXWhIwlyNpCqCbv}IE$31$ga1do+ymJq>HIdL0 zp_E%EiKGgwe0e`Q?;;v7h9@7FF5I4bFs`HU(Xi9^MEaY6Pr8T(jKzD5#s%G0lD*!N zts`5#;#)@|PidnJjF+{QA=`HFZP8;&wSJu=7d*_qMwz1wjE7qe_71mC*bbbQwxdj| zzPC4ZQgCf0^feoz0egqI8SLe$j|)pV^k|*4+W)d*{@nbsyqRejOj%qSsIc z#=|WK_3MDk z>lpOggm*+`y;MY(&zcEeNFfi+7V7C@P>c{p8L(xfXIfChHR8m@;;bk6X$N$?6o1Jf z8u0yurz+9?Wajj|@+_`JUB>N~r^{}|V;T0F#>cSVG;Rjpf*0(D{y0BVYO!)Y?i}@1 z<)q(7G|_d3Z^7Ty-M1>Dlol!P_HR49l=nL(?-l{d!1)qU)#KuM%35i+`&Z!|v%U)y zSC5_e4-Dj4ZY6{#u*9_D^+zDr|zoI&R@{5O%fSIuA=FL8Ta@3apmVteSXU_h?V9qD>k8nBOfo+GbL?&VuYLUtx;Y2&quvZ1qPhz890s(;;fT(`|2HNb^%`Ui8q*>94;pA+Su$8((bd2HvO zG^JCch-ko^FIiw9bd-;tl85fc#?i#AZ-xp?&L{(G^hDtt`;$;3+OG$=O||_C%R<)M z{ZIzR!z~B%Iy1k{%}1}k3WOz|Io+%hz~_0MtO?OD0CNB94EFilM$Epgi}*&_O@?`k z%PP$=8)#1>8ZcKpKTI;s(C{u_*MPF2l0{{uo;4YbW3UHUA>#K?$Ko@S_?fCYL-DQg z`_b-&hz9HdN_fO_We41_G<_x8<0(4W_LlExFv@`M6t!)8#Z~;3o^oAeJ}l=O*lo}I zqYU_vBu!F$_i4*XwF~^ z&RyIL=9t47!*dl|rcu{rXFM}2-N<$KmVYA}FvrBrU_O{?TM|*P_QpY8dnSpDGf~0t zEXe?(0rSDmcA55v4D2Rz@0!y@Rx0j}zoJ3UCHQva`k^`rpPn@SdpDV1@jTTbk33?F zo)eZJXYdUit$3S^(XC&j;A9G$KoX4vlTikI$H_EdUn7)_G~#RhHx&UXIxndVmV-C< zR>=`f*w^@9XYjsJB|}+_kGE^*a_Ov`4s(j$rR3iUh^CksdL$F9^h(j6kI6~8AUtEC ztK{qFcHDj&W#DWr*6P+*NTc!}TGTI`p1LIFdv4@3%E0+ad_sYs9{n#F^xs{YIN6-W zTz5}~6J_AdI%UAYg=fwazP9Q2`9v~$UYK$n+Cem7?)JMub0Mm$xZOzMe1Q+i*ntN> zJ>DUj@Qq8Q-h+Jtq0X|B9-Xstx#P5AU2H!PO_-y&3cjEpd1OBDijwQ&-_G}zzFn`F zQ3mHz!!Z6{w_9HJdhe=0)ytAM3i}p_ChQ697uDB3e#t&6%Q&SCt6~S7CQQYW=bQi@o;_=kopk|B;!M zWN#r`$)-51>^&;7iik+bPDCVS?@?xEW>IElR#JrQQC0~ld;Bif`TqU)e7;`C`|~@# z$M1W5kMG~N<8fY(b3X3p<2e(N`_f|GT+NL^SCed+w90-(AV?GZBXR zLX{9zvehf9lKq_QrUm$=Ne~3X!`+BhwQcbgZaD;mTsKaw0fsF$hrNa9>eMVeCvQ_Ma zkGNiF19iAw_v(!7q)GI9Qk89`)=+@6^A+G5P={+W)x|0os@8H70%e_GVKKbpDy|yV z2t%KT`ywRz^SQ)FH=hkFT$Akl{P4_gW1tStWx5q{lPvh^3Jv>6%+6hNW4dr_Ul?Ji z-N{qbw^U#Jy|BhOoN{8P_v++Z(<49~-Vf0z`Cb@JBd9H1Q^xti?h^Ye_rPMH4)^Ga zgXUZcH;6rn_Gik1h4|~eLT$(n*>Y$6P;A8qMa#@Kr;cLA2Ah$^v;=+Mfy+du=ZyVp%~IV`Fo zz^eyiZsyJ(rUrAo4S@z+3sgV-a`YvbhX2;C#0eFFeXa=9hjeqb?mS9dVg3oxr``LF!WnG~nJsY(=8NeL;_vwIK1*=QTd{ zu9_OHLw4BKm>HbYXEhS4Qgg$74xT1?((Jrh$!J6Vv!wy&w9@SprtY@yr(z=P-boVd zRDBh{q75|QytVQP{sD%jn*98QmH4mfYvzv=x&sY3H{TW!Zf+@0+L(3H=XYsPy$~cT z`U^B*E-!$DPWJ8tJ-Hi=JtdFow!PhWnPL!z_5)@H=dA_K=$!Bdhr04(wxI6iTGxGn z)Ym`*>bhT7sE?K}nvf($%lmQ5eOz5w-am~nw5{*ewwyXm@w$AHYj}oTo>s%ke={9n z=<~dXrM%>+Wt2EAvzI9pV!z|;f3*b~aNeHfw)#@gz}V}?&5p}1OkhL(wip=DxbP@mz*e2+Tin3G5p(0WXLh+ri0*DlgWa4l%-UpCaG z=>3?`?99eXUoLwvT7;I7?Z_NZji zI(3j7YbDu-#j&JcvOp7RFbX2_!bp!+g^piaziCP&cg7{3UO*Vy))>DBuPKVgTZ@5Y z4h#FyHSt)fMpoz18D2tGQlJTQav1+@tO@gO{ffjXzv*%YuC-a%*a|uj;I$i8Aa-c~ zP1E(=iEovR(xDhjx!$YneD+=j70`rQN^p0_16+{trTEg1ckal-Q!@dbwAS6R$powUz+?-CG>u<$Nih+Wc|M|^m(nI@M@b+hOHtK=({D@$n2{m76!(9ogrY8nYUlN}CsT}bz*OOd0WQWhg%;3GJ`Gk1) z+=g8Z<>&Tt)f^wQPVPRs1T_Dn6$xf6pRf;Yvh8rs2MZ7+O^yC2L>TI4sSq3Mo0Raj zdp90dDO&TrJ`s|61ZcvT6XNL2&$lF*=v4WkuWG@mYg~F&8fe0pGvWD`Kl3WvbH--F zq#g^oQURXafi_QcGf7IyN9YTUyk zt=4v?2pjoUC7piut`^YzCkA7x;hj1u!X>Bvi+D?vmO;FDFJ*QufF_Kom>GQZ&yqkG+Ab^HTEP^pYwU08P6x+1%Ny%GZNGWQ z4(9_FhSnW(nK1VEi5y6s_3tE^yz{VpjeR)E?qx&_(1Ni)`p$u>=PlA_*sOZc9cNNaMhF3XdC47nPRlp!v8O5E{7xhKLX3J8jz&7?ob?Lg#T!Fzl{L(_%IyO!s2NOk;;rS#VgoLGwOku>w6(nA^K}?#!Skvj z(d{h?e=U+329^`bnr`El#c7cF05yXjSl{M0{<7xRqE12jx}IwFl;twQP+u6@t}aka zw!~MRh|8>HBDNZJf8vWUbUt8V=zPG;;CWTptK`0|j|Sm{*_C#}F?NfB1@xLg3!YbD zW>6RSnNKsQbWM488ePgad%-q1?2A7Ew4g5V!0p&4)fbY|KA}-4^EF3$BsI_`zaxMDc2RU)BUz z-GCO1#r5r}%OzoV+!+p1MeT~`$i7I9-v(MR7LOPHSTHHxpO<6Fd*$B-nnkRZIRE!z zaIZc4^)HFuwMRz3{>alb-t1DGih8gEwBTMFGlP3=tuhavJHIA$uF~FkvYv5c{N?5M zGe8S!hOvV0T&?!JG=MAkw2_OAb3bo-BG7{8B=yBng`x&0zst-@pXlA=43`Ov{DUxb z?HRJ0ClYw$u&(t@{*&h8r;Q?$ZeJ0G_WRlAxi<--r|t7U^f?uG7cJQ;DvARwQ}o^i zCqItR{cjiPY5X5EY%srhYA^h;31MjLcx!V$+peIFI6d|r|BVcPwMC+)d4!?QV-x$X zt`PFRp+mOK`f^<}_vq?!J;KoEVX;HMkAj7va~g{;=$yvF&~ppS44x55sqNlz%e>U! zGSF5brr=1oN>|ANwBQ*L7KZwQnZdi+vdY#2`OE$cJ^oSFYTxR-kJ-eS0xhVCurTy2 z84E-2qhMiZdtzbeeH6?LYAGGAgvnB-gS&e+V^g2XM_X@J-i`p;|ItevZ|L?3nr5ci zVlQhNU2F5fO)5QPlgJvff|0?z#z=#ewEcRUHIs9GMS$u073sYTEkGM;4Q=7uZv9VW zuV?U{+kCieP)zhT#0+8Rc-eard~zf9(dNv;QGyCZ<7&^*ch?by*3Y^j_ub3ice+;( zDm4OV^n%Zf3!ebmFz4Zo8&PR1^mBr<=+`l}Vj&Yt0>dbv4fVto%d(C7K`Y7@nUf@B z4t9iEFEiZ`hL(w$L9MYX6=kpBaq+#hFNIn)oElhifYqhHAcV zyvW+9Zu7OZm&B&7>w~zHNn#mN=07l~L!P#25|gzGitDWjhw4$&j{Q0RD+g%9J3NEl zIUBDp8nrTCSRn~H>)0~sc|HzdX#KF*p<@>_gZc%pW{m&jIE$6o2?p0+{$Hym`6-%! zHq7Z@{P*EMGt?K%WdgL{1I|vnPJs9i0?okpSn7d(P(lUXhTiZ?f31e-pj70 zzb!kKq?_F!_&lXD(1v$^^ttwz`{g(lyXmNp-rn4n)ehuG#ss|kgPC1G*W`2OcB>lW zMV+Y%bbdOto9u_LQ zt4<@td9HQ$24YsvS!pA7=-kA@(0<4Gk1=hve`09;u=s-J889<=W;(bA?t3<-iLM=x zSqP8SuxM#%B5NzmgPl+Flx}b}?eO~fFWjJs{9K9N zNG?Sy9$ugg&t57rJ~c`3(3Awep8PPG!r86VTWXFl)KAO|=8#H4LpDW^bWiJ1cB|9H z_Tnz?I`aT+_`W@62J=hCo+s2kOC%@%xWYmgTCA_g8ZLGcXv6#xW(MEKJEd4@?z-gj zV&;6Sx9Zi-Ke=tDpMW;ZFOlBC?MpjY6LGuV7#*Py(4f;GRe&(G4w&tr#>{a3rpvu* zrqFTKZ_fN}@vUAhs}!IO^GmW`><_*LJ~_R_dux?l?@Ve%_U%K4ju)1g<)#l6dQTQj z`Mn}kwm!CLXd};q+SHqj!netJJnSbAXJonA?}v4JqE)$pB4Qq)9%(2 zsb@kM>Pyn|J|n*{l^v#=(vjk4=G^91-jg8=tvhBrm|xn{dnr5VCu|`(DpT`mnuzUq zUIYoyhFTFbgIaNYm%#tI36tFl#S*KcyT}rQ<2D7*hI+89_k+RRzE7d&UcUBW)>mS@ zj{l7dXhY3cb^}!In9a_x@m(_59zM&?KzV)vVW^*&8Pr)JTNV0AU+mbU|Gsy)P2#k* zEisMEX{fU>GngmZ#hVfCO%bD%GUt_0BCRy{JVlrWw4r`+5q;I~T}rWPE~ppE%RAR8 zoRpdhbfA98UQJZF$oxY1X~wohoR;U%r5KB+hwLy;V`fmJP~Q9L6hHBP+}Uoo?m$Xt4)n5(1H5Jv$^x;`W3U^ zSKA)mv%Ks%5%zX31?WKi@+X>e_h!?@-c$8*M7B7jNmzV}RP)~GJ^0%7F`d#1EzHd#2bM)m(hEOQN&@o?Ik@x&-jP;qY zB)RtX8a4Omh+JKSq4mRT2Q@=8z2hZ2TKw-O-9Nul4d6~@j3^+_gPLI?bR?45a_!s` z`&K?__t$hA`?68k8GpHGOf3IE>r`&oXQ-4}2PO5zS?L{qBpab6r!pvao7tkC2 zQ|5B(%#*m|+@~8YjeftTXaPF#eliw@)_vq+a_;qtH-o!Dmu6+!S{NuFf9^%>(3q1p z*p2^}Vo~sF@;Iw{aCMA>QZMoy?0;lvn?)2?Hs*9DOivxR?&kmVdoA;{k^^Fg?yIuq zJQEUG&C8~T)H~|xIZi%Kce?>}phlsKQ2aIPEm0cvN@UBfl((~=Y3DW2ff_|N@Kw~U z(@h}w@}yK5jy9z`(c(D5(C1-hFyGS_BCbtHBh>II{t64uQx##2n_WFX2YxdS3q$KJ z*z;|ASFKVJH`hxthD54Trco>(vHK^6`jY+CwL0`wVNO}w!|q|eExG39z-6EVb4Y5N z8Y>@OMV9v+D7Gu6lQn!)s4hhqTIN^(4^{SM(E$zBYqD=9%}a@g_4EFPq0h@B$rv$c z7?7nI^whnSC!j4#7rPB~;6EtO2T@)L|Ll&FvHNJ+BzV>`S*0B5TNwL2TKOid<+$~@ zba)i+P!cr@>^XZQ3@!6~<#Ala!i7$jtL4A@uR6Y;w7#Q-{Q3#qYg<^CTB^ww`{*?H z#*ciZCUSENN9GaCOJQa(FQq#7#_b#K-E@CD;%^Ff%0^9ZH0=N#s3#IbI=X%eFzEGn z8r2?O|9tS6rwk8as4uxwTf5}uhWgo#igJaHEH^8&GH(JMs5KZCoKge#*mWxt|2+9| zex>ETrR-;fp?0RX|LDhs&z&q4emeX7*sHvTgTPNf2Y%ZwX!Sjpx$2StUekjh=6gcJ z9wnwj2t((?*n)#P4&`EB*$%+n>9Jb*9+3LtkR8rjEDY_x-0x=RQo{YFu0Fp1T6A#A zr_LAoAEplcwgDD~`ngF$=ruGQcKtmtaAz?&r@xoSZ9v z^1eDF3_kCdoRY-N)bej}UZ*rOE`uC8oEJ`tHZ`W`xSb!ldd+Ce^UZFP`|jU7ii~lSw)_5WS7jrS?^K%NlJUj4%-Y1 zL(2?Z8~i5y**Wio`moGersdP?B@g(34%9XVFGfO)637qquPoFz^*cP}=WZ1`WQS#9 zVQ4>$FYS-sIQApw-n2k+-}*%$Q{gU2kGw2dm{qBn}v`ox) zP=o#PP|Qque)5Uud-9k@6|NMT=KE)X4%A?I9e2)?lo?e?m)x^SGIEKOh%M7RWQTRf z%%BE4pI20(*Lr?3ZMpQ;#(Ldo2zfT58K4H!HM&wwE7+yU?n+JaIh=fIwV?Me(1BVC z|FUQvrGJ-B8Sm}m2KqW;0Wbizb0EZpaZqk zf6riEDl=utf3SS&^NxE4?Rca6`rQpTDWC&2*lhKdN!SI7F-g%|7b9LX>U_HV6dBj> zUS8?Mt>+?LuWqVl3}?9JoRgj6-m^s*+DA#&tdB(XEWB0>Z7VhB%+@+>{vdq|@8un_ z+4xyeH7|X(KB9S*?qQ+3+Vf4I3$N3 zc-x%{-yJWvNzE}^4LRgnLb@>bgqcC@=JW2+6IYe+y5V!5kN9=09=Q1jDFR)n!AKqX zt<$p2$P-tI8{*CxduFNbi6ac{hw^d$J`P2eSG**jVh}8rRJ!xV zp|!K3&ZDt?BQ@+wAOjldsEEd751QEDv;{UJ9!b9lLz} z+}X%I1633It2~b>$dTv4`!>fjWeHB*>V020-Lyo0UVd1h>OclzX#EVW=EnP#1~&%0 zarnYY+=y9*+c|+Q%$4-GOI^juRxp;oni0ZIy(m1uFIft7p?-1NzU5I%ZYI>rdLaNe zURL~T&xFz;J6xAAGpIG1`W~&E!Kvmdo{JDqH`(i9nrw;yy6}B2%nWLcN3;(W%e5N{ zh5u?b5q3nc;k0rD0$mL>hZKAFriqvferJ7dsbf3&uub3S)BXO$q0S^~D{8q3sfXO^Z~*af?jj;n~IK z&j*=HJ{c_mT`lx^J(GfFW*_=@J3{%63iovXZq$6Ni7?a-GlP1ftaK8G^+XqcrN4lv zI?t~uy6Ti}pbO)>Xs967K+L3#@`B(|ox8wi;GIUJIG_u4fsx!x@!e73VGBxj1>yvQBi_GQ$`9G$^Dr~03smAuc*|OsK&&?(0;(e(0<3l&~`@L+Ccx4%J~M!^H5#D{`LtaTW*%Xz5FiuvDnDoGj&>)|H9DvVR;^! zSH#Rc$)lYHc*oCS2@nOlC#m}ah^jJxd%^@)d zo}Gy^y4!9ATjwV!80(8#ZojL4S&xht7{l35J&LodVG6?;VqQw&A1F`{cU40e>L+{b zk@>YB?`}3x(2})ubNy6l==%$FVVt)7^p&ljy>g?TkL@@9qdm&s)U63X7sg^`O|9@~ zoq2x)rMjBv2?dgSMop6lL(9a>U@WGf`1X9Ih{2*Q>&m;w}6y#z6q%T`xPPlzU_(Je!x(76qo{k>|k}?pR3PpeXnR z=bbt2CNM#EV#93f2t$3rXr~A7;+%6>6RQ{&lqlkyYYy+BbY_dckqh)-e3xh1#ig-D z)(+|3^gBCArm_8UMhHX8#B2x8JASw?8hlr@(VwHLmV9D2QX+i%i7n8B@u4zydao*o z&Q`!9%VTxcPj0OM*$3#se-aeBf0Nz&Y~lR;Q<+5)H3`?;LaOs2BS7XK7KY9T_a%P= zvC`4xXxENbIX;iz2fd96h}}Q3!!ohi{S!O-4|a$D7Qj*_+PCt7lY{w-`jKV7g={eyxaoJlAJgSbit9XT0QBIwlPiC~Vu_642;;GGLf%gq zwx%CS=@Evui-(gx&6I$=lLaHS4R6i$o?33A;|N3jR9aG#Yn$QFdyvKNbas|BQCIYu z{l74DK45+x%ssV^nW|oqq5LxQT500FT}s&GMhfz`U8rBwNnM{`j;EQIU~)Klq-VwI zeMkBb!cbqN{CiI`=W^iPny3#6d+X->vLB!CUl{5O=I238L^5+k*ps(})~$XHC+az8 zTCYqG4bc0~duKx5Cu4Gm9z+nB$S5>te|<aTF zAm50XBG6I^xeG$^FJ2)GZR_lur$&UEVO@+*%h8`mfZI>J^ zin;TgQx7ZmE*i47zI7cqiCX~lpmr-#Ck)>inkqFKcYYwRluVsr&0KoO4)qc?cBs!V zGk8bo$h`VZ`Y4ydJ4+uM#aB76NxwX`0ra3AeDDc*;Wg7B`}I@ZQ#M-5X|b7UIS51B z^JC{(5K}n8cQ*2j3>{to>*z}(mw#bs{V+cd>cRY^aj9o}&wS))20FbN-efW~^l}3| zs0T4KJyg2|b?^8MauFw+39}ouPlvzT;K)PPYp4~mFf=}3VW^*&8GJWsR_hy4l5$s^ zT*?$7wXVur{6%hLOu#%57KWBtkrT5qe0};vQP|2zLMli%`t3*z^kCkmt8Rc~$a$AP zLH*>m(%tQqk1F}d8yqk{z|7!zochO> z`hhFi9A(k-A(F~G6Hx~IuYn%apEdPWCtBrdIRDZxyQWDv@n77D9szn#f3`YyX_bFB z0-|4cYXt4L`@)0ow;~L!A7%#cZP(vC;@ZYK8(Wn>e4VyZ?en(y%q5@)|EqwRL2YU` z_YF6Pn?&pZgV!aNc6qGfp*{rgZiO`J&C{I?OYw#8QwhWf&`+c>$* zaALAse3xt*r#HRkh>#%AgBtVHTtc$__FAD;(|Xqdj}uLxjR_^thdMI-qpi+H#$NpF zJC1u~uBXnQ={tQ9VQ85x$FAS^e|?bfs<QAT<74u*DaV6T5 z!-jJMVJb+s<6vRv+{D6AeTIdh^8pJ(+XV|lH4$b8&pwG_GYg-3&)mLhm+{hfw)VEx zvaBW0hj*|rGkD*dga0}1$yQ$8^NAeq?>qaANJf*+0ezT1>(kCj9M4nWKU;U5-l&sq zomsVF2a3t^0*Nn)Z$lb2nYb9}^QEbCVswvv5ZkTKDgl+<#H-Hsyrhn>aY5?T~p~bowXI zhj}SQIlmZp`^g~Df|dN@o9rXFbTu{zL(8lP`%Wm>$|LmkWs^g!V$aR}q(4X<;Q40G zD9t(BI;G;VQzIQyk(cYkU+BphK^6n4DLH}E*t$E z?7Xi{cTG2mTAcDjM%zPV48nKdurRdDUgha7(?QjRQ(ZMn)b1Rg&sJ)90e$#>ocY%= zSs9bGA1^|zIK0+qx$YR>q(>N9huvV`q^~`|m`>Z_<3aiD*p}1Zq!5PIfx7upGFM;K zh%JtOgthU@n?ZAu<3L{t9lOI$s#7hI99eXuH19|Dc8*L)zwSpES|)we7kh8Xv)mC| zDzW7rd7EoF`(+42*Yag1%1W{*^ET;-GrqxJ`mef({@VK&hK}oJ3rY^*iYH@h!XC8? z45ruLBsjJP^r04xzO-vx9IxlDoF7+dO6G6ITkLli=)-S1@x*1#8(%#oo%ziEQ*0rd zhttT+3522byRtS^+j&}H@Zv?QqwA$oNy_PaIS51B6ElN)*Isr5FUz^!KXDr4RChC;7Fyoc@KO?TPt$Fz0xxq2|3E zbJc0Ts@%uPdDFzK!6o@XALa)!GpJ1$j@0^XO^;1YHi(i7ooq8zh?YX;7}Tbl(oqWL zQ%)b~uFezPm1#V-apVr-C)A&67n;)9vMk6xTq%9lo-|?H9Zn()^x-+>=M3+rETcDp zjZA(Sk;2@RwHMOJ5r(eUpT4UN3O7em-^Qhn)4NOBS2SIE5@BflFf*tzmvmd7jXa|K zocznO_u+J%(2G9NT%Zs2U>0SgV`6}^8| ztc&^r8je)x1AUlRO!M0z>P=bPI~D#ZJA&G|+pKb|5Mk)^WQWO!*{X2bl#ftSzE!4D z>g=&W)@uW_T?T|t*wCdkwvwh(b-xIgrk`{g%|IAxH>yr?OG?eyAv9a@$9LgC|4bge zD1@Q&XnQ(9YWah2=dfrBO;8d2tfyiWvc5pA=%z5w9yR@G=;x>7Vwx7|KCAatk#>Pv zajP}_Vqj^qaDth~a^7^_;%RUDX`m0a+v~e~^rClbm1d`EJk1K6SA1#}7lA(1S#|V+ zZ(i-K9$CZt$wAj(n{_W>B>-WlpL-=o%a6BK<`~q2H-7c=o)e<~9rXA!QJdUi#J$Kd&RlirQk;;n18#KV+EE-p| zmUkNQ>82`ltG4YDh==zbdF<qJeVI7k-z%S7S=~hwRW7%nWLq zo3l*ZYrB>`6K^E`blsxHe<4Hr2N*zYgPB2Xb2=PPfTVU`e7q!r;n(#iUy|_Ji-3Uy z`aCQQ?T6nN8YQ#wIM&Z<_?7lZs8Y~$>t_H1sC!~OD-5l~)HyklyZ>lga+>-mjUx4f zcgU-*#5}4kWcX2%pv-S~M(j~#1Gtll4J?=p>QP-`{-1E`6N z3DpQlR`8^A9-TVFP&}pU7nzNe3AIg7#*N^q;#X(>9I?0?y;6~O{)J35Fn}6`HZ6+f zc;}SkH8)9)wMfhF)km3o5QaYQe228CG%t4O!nZ=^*)T`mk%;5E(BpM>fN| zD07KNj?X(TpN1(=hr=UHJ|1D{^GtndhANB;{P&zEvX2yH;4xgoMfw5W!Rl=rVohXl zZ#poEvnh&^u*k}5u0t5wF0!__dOpsJ=hqLP;=Ua4QKmm;pyQAoj%zFoecmm`Y9rgP z$prRFo1AkRE7x^B%0lb$N@}B0}kYbg;j@j9}{hpC` zlcqcafC0>#z7u-Vk5^;;&Uy9<3C-CN9BIOZOke=DsewsYxTKw3Oi|8J99;6h9K64_ z{SMh--(qGkZ|blrF2cM}M=Kq4L}&Gh@V3ugpO?Tu3$??{pl;PsU=vuqtXD~^s;?ly zSmN?^;L>Ga0RJ6}g`wkxT&Vuy~U=eAT&rX%=~ZxpF$ z1im}f|MtkdCoq6H)uK~RNk?v}>-;urB9)jsC_gAszK<}p%oWlP=3g%POEtBqE`8bC zxy}&X7KJdh%r0fAMZM?`zPMqvrYyDX?Q~l5pMU|>!pwf!go>U5e~->Kr=^a$eBl|1 z6FOvvZHAdaom_0SQchwUxmP3iN_cuCqb%=3JOeO*S{O5fdROH8FTu|&f|py$XuPHojs5DQnS`1{1*GyVv=!S0JZ5euT1bf#mZsmRV=d^Wh}QF9X(P% zs7=H9QX@CF?$Jh2J{$kaD*kYSH#hQF34`FEkVP^0QdX?>{v!zSBWY9tRwxJTIrsXak5io$duF3z0 z!rz@|&2_Fg_g)>RD`mKg--|G`Oj*N=ToxA|DRh53pk#d%7r$H8N&r4)5}+ZA-rRTnZf+op4_ono=9CWUwWL(-1}dz?I!+}0ERGs zhM7T)8DtT|kAWe~pOrYb+s$##xqhnt<7tDGnGy&4-^SEfOI>jQ`lr<@1d5oklI2^Mb$-=DL30T>MhI z+2Nco5K0z^45`Ws{_shL#X*&uk_9D zKizmr)wXu&5#18UG5q#YgrR<>L@=54SpLk5lf!MBpXuWW4MDzxZU}Qv{@UGpvI$g2 znf=l~m)%V${+fQ>2N*)lmnlHJaYp)5LUB}+_nEzfVO(X(BM3vw#KO=zU}jJ&Hh3kx z$_Qb>JsXg`lR)M!#g31Y3=E-GbnZ3u?oJH8bVW8lJoPw5wy#igC@_S2aHj3TPR&nC zg1^>R@9~VxZ}}S2Tt*n`OQ74ML_Ni`ODCvPFS^lk5ApY1M*1DIgj)kcc%J&bSeWv!Ih9rK{m{1qN!OMoY$J0JhSp(B@C%vLL*i#9 zi#SSK2Km&o!y=OiL!XD)4#whT+m`C7nCPUWPj>m-d8r}(@{&%#5XNHKLVuc*0)176 zC&W(nEfa->84BVc3@x+&bnesZr9F4ANa2V0wKUR&9qZl)hA@Yul93U|zDTy9lFRb4 zB0TkWbWw&C!caeVb1Vf6#RPBk1Qc8|dABsyy7lCcp=DyWgZJlM?3SM8(Hy_qoO(k1 zG^NYpZ8O;+UWI{ys5QdhC*$(EVBC0*xa<3Inq}dFe z{GcTJl&br}9bl-fgoHSp^5su^i4s+kEHjE`r<&+^UT~3c{|iIU7)p=yWR+hh_FZoC z*YS*)YWeB5t%=y7cP_Cov|X}Z-JxU+?vJ&(bnB)@CVkDl{jN>K4vn|i*x@-B7KX;7 zP#!la3#U|K5yBDuezRgmC#^r8NSXh{&^E*Drw-aK-Wu+}R42MVu-c(=fwuC`P+{XA zVEB&=Z5MkJ(X3wFuro(-3s}UDh9;g3dXs_Jp>_8g))i}8X=qi646LnrXse-&Pl>EA zP@`bBgIa^dLMzN#@jmUyN54gTzndpFi^Xt(A^a{lUy1QtwOCnBA=}$b1I9|5To(c4 zc~FO7wu3o2Q|D2&nG@fX$aDFN)RQM&#y=Y)Yb(?!PXnw1n9b(XO=fXBonjY1&d$u! zAPj9YhnJe?x29-5->Ot<(b)=)=#%e8#tS^7t+_0(+BQc{Y;5{9NU4gL{2*x50~o@) zehSxJ2QwO*2=pYLRI4!Fm}wMXEJGMtCT0fnZge$_XCfIyPRvXFA|rj69ahFfyax=S z?(zTlx4t5WmF`^IE#AkSj}#3h&mij=e1{RU9lSpusm%mr-Ur71I_q{Vh=lv-q)KNm zF#KP_(0;e?*?&Rq?KPkGe7&xYt>dyyQnM)XJhbjueEDC(CXsoB?RnT4)QYxV1+K)+ z%}%|Qdjs|=-ua42qR2WA^O%3}HPl^b)!QX5goWLAa|yYmOg1KAaHpCLy%~7{Xj$VB_Nlwi+AqM$+6? zmNo8C*_50&fFaa;7{A?a1oc@Sv8S|p42RphqbxMPqZV>w1PnCsu(ry=4{*Im)HM<@Tj3m%?;@*WnY4^_yR+oLB`eL#!^Mjklj}>94-IERG zO|>V5_li|-bbP?Gddc^8trKDBnDC*ypnj3Q{?tlpi`4=S*Zf(pmQY{>HJH%-?Cfj; z>WpO3>mvK@*BeBMbkY%qmWhR-WnyM9?=~tPet*{EY3!dfDdw5ttb@s%8UDZs=G{Jb zTn?#?Dyhl;YB3eN{3+{$&{`_O(B~C0Y88G^*fxDP%S(4j`&0zc%Bvn=1a+2gn9t~= zQT∈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 literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/DSHashTable/Makefile b/build/systemMenu_RED/DSHashTable/Makefile index 8d774c5b..b527f460 100644 --- a/build/systemMenu_RED/DSHashTable/Makefile +++ b/build/systemMenu_RED/DSHashTable/Makefile @@ -27,6 +27,8 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs include ./commondefs.DSHashTable MY_DATA = $(DS_HASH_TABLE_DATA) +MY_DATA_EX = $(DS_HASH_TABLE_EX_DATA) +MY_DATA_ADHOC = $(DS_HASH_TABLE_ADHOC_DATA) MY_APPEND = revision.bin MY_DATA2 = data.bin @@ -49,8 +51,8 @@ do-build : $(MY_TAD) $(MY_TAD): $(MY_DATA2) $(MAKETAD) $(call empath,$<) $(DS_HASH_TABLE_MAKETAD_OPTION) -o $@ -$(MY_DATA2): $(MY_DATA) $(MY_APPEND) - cat $(MY_DATA) $(MY_APPEND) > $@ +$(MY_DATA2): $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND) + cat $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND) > $@ $(MY_APPEND):: @if test -e $(SYSMENU_ROOT)/.svn; then \ diff --git a/build/systemMenu_RED/DSHashTable/commondefs.DSHashTable b/build/systemMenu_RED/DSHashTable/commondefs.DSHashTable index 8bab299b..4685b71e 100644 --- a/build/systemMenu_RED/DSHashTable/commondefs.DSHashTable +++ b/build/systemMenu_RED/DSHashTable/commondefs.DSHashTable @@ -17,8 +17,12 @@ #---------------------------------------------------------------------------- DS_HASH_TABLE_TITLE_NAME := DSHashTable +DS_HASH_TABLE_EX_TITLE_NAME := DSHashTableEx +DS_HASH_TABLE_ADHOC_TITLE_NAME:= DSHashTableAdHoc DS_HASH_TABLE_DATA_DIR := $(SYSMENU_ROOT)/build/systemMenu_RED/DSHashTable DS_HASH_TABLE_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_TITLE_NAME).bin +DS_HASH_TABLE_EX_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_EX_TITLE_NAME).bin +DS_HASH_TABLE_ADHOC_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_ADHOC_TITLE_NAME).bin DS_HASH_TABLE_TITLE := HNHA DS_HASH_TABLE_TITLE_ID_HI := 0003000F DS_HASH_TABLE_TITLE_ID_LO := $(shell perl -e 'printf "%02X%02X%02X%02X", unpack("C4", "'$(DS_HASH_TABLE_TITLE)'")') @@ -32,7 +36,7 @@ DS_HASH_TABLE_VERSION := $(shell perl -e 'open IN, "$(DS_HASH_TABLE_D #DS_HASH_TABLE_MINOR_VERSION := $(shell expr $(DS_HASH_TABLE_VERSION) % 256) DS_HASH_TABLE_MAJOR_VERSION := 0 -DS_HASH_TABLE_MINOR_VERSION := 0 +DS_HASH_TABLE_MINOR_VERSION := 1 DS_HASH_TABLE_MAKETAD_OPTION := -s -d $(DS_HASH_TABLE_TITLE_ID) $(DS_HASH_TABLE_GROUP_ID) $(DS_HASH_TABLE_MAJOR_VERSION) $(DS_HASH_TABLE_TITLE_NAME) \ -v $(DS_HASH_TABLE_MINOR_VERSION) -p diff --git a/build/systemMenu_RED/Launcher/ARM9/src/main.c b/build/systemMenu_RED/Launcher/ARM9/src/main.c index e1124701..76a0e06a 100644 --- a/build/systemMenu_RED/Launcher/ARM9/src/main.c +++ b/build/systemMenu_RED/Launcher/ARM9/src/main.c @@ -39,13 +39,13 @@ #define INIT_DEVICES_LIKE_UIG_LAUNCHER // fobOpԌvXCb` -#define MEASURE_TIME 1 +#define MEASURE_TIME 1 #if ( MEASURE_TIME == 1 ) -#define MEASURE_START(tgt) ( tgt = OS_GetTick() ) -#define MEASURE_RESULT(tgt,str) OS_TPrintf( str, OS_TicksToMilliSeconds( OS_GetTick() - tgt ) ) +#define MEASURE_START(tgt) ( tgt = OS_GetTick() ) +#define MEASURE_RESULT(tgt,str) OS_TPrintf( str, OS_TicksToMilliSeconds( OS_GetTick() - tgt ) ) #else -#define MEASURE_START(tgt) ((void) 0) -#define MEASURE_RESULT(tgt,str) ((void) 0) +#define MEASURE_START(tgt) ((void) 0) +#define MEASURE_RESULT(tgt,str) ((void) 0) #endif // function's prototype------------------------------------------------------- @@ -71,51 +71,51 @@ static StreamInfo s_strm; // stream info const char filename[] = "data/fanfare.32.wav"; -static const char *fatal_error_msg[FATAL_ERROR_MAX] = +static const char *fatal_error_msg[FATAL_ERROR_MAX] = { - "UNDEFINED", - "NAND", - "HWINFO_NORMAL", - "HWINFO_SECURE", - "TWLSETTINGS", - "SHARED_FONT", - "WLANFIRM_AUTH", - "WLANFIRM_LOAD", - "TITLE_LOAD_FAILED", - "TITLE_POINTER_ERROR", - "AUTHENTICATE_FAILED", - "ENTRY_ADDRESS_ERROR", - "TITLE_BOOTTYPE_ERROR", - "SIGN_DECRYPTION_FAILED", - "SIGN_COMPARE_FAILED", - "HEADER_HASH_CALC_FAILED", - "TITLEID_COMPARE_FAILED", - "VALID_SIGN_FLAG_OFF", - "CHECK_TITLE_LAUNCH_RIGHTS_FAILED", - "MODULE_HASH_CHECK_FAILED", - "MODULE_HASH_CALC_FAILED", - "MEDIA_CHECK_FAILED", - "DL_MAGICCODE_CHECK_FAILED", - "DL_SIGN_DECRYPTION_FAILED", - "DL_HASH_CALC_FAILED", - "DL_SIGN_COMPARE_FAILED", - "WHITELIST_INITDB_FAILED", - "WHITELIST_NOTFOUND", - "DHT_PHASE1_FAILED", - "DHT_PHASE2_FAILED", - "LANDING_TMP_JUMP_FLAG_OFF", - "TWL_BOOTTYPE_UNKNOWN", - "NTR_BOOTTYPE_UNKNOWN", - "PLATFORM_UNKNOWN", - "LOAD_UNFINISHED", - "LOAD_OPENFILE_FAILED", - "LOAD_MEMALLOC_FAILED", - "LOAD_SEEKFILE_FAILED", - "LOAD_READHEADER_FAILED", - "LOAD_LOGOCRC_ERROR", - "LOAD_READDLSIGN_FAILED", - "LOAD_RELOCATEINFO_FAILED", - "LOAD_READMODULE_FAILED", + "UNDEFINED", + "NAND", + "HWINFO_NORMAL", + "HWINFO_SECURE", + "TWLSETTINGS", + "SHARED_FONT", + "WLANFIRM_AUTH", + "WLANFIRM_LOAD", + "TITLE_LOAD_FAILED", + "TITLE_POINTER_ERROR", + "AUTHENTICATE_FAILED", + "ENTRY_ADDRESS_ERROR", + "TITLE_BOOTTYPE_ERROR", + "SIGN_DECRYPTION_FAILED", + "SIGN_COMPARE_FAILED", + "HEADER_HASH_CALC_FAILED", + "TITLEID_COMPARE_FAILED", + "VALID_SIGN_FLAG_OFF", + "CHECK_TITLE_LAUNCH_RIGHTS_FAILED", + "MODULE_HASH_CHECK_FAILED", + "MODULE_HASH_CALC_FAILED", + "MEDIA_CHECK_FAILED", + "DL_MAGICCODE_CHECK_FAILED", + "DL_SIGN_DECRYPTION_FAILED", + "DL_HASH_CALC_FAILED", + "DL_SIGN_COMPARE_FAILED", + "WHITELIST_INITDB_FAILED", + "WHITELIST_NOTFOUND", + "DHT_PHASE1_FAILED", + "DHT_PHASE2_FAILED", + "LANDING_TMP_JUMP_FLAG_OFF", + "TWL_BOOTTYPE_UNKNOWN", + "NTR_BOOTTYPE_UNKNOWN", + "PLATFORM_UNKNOWN", + "LOAD_UNFINISHED", + "LOAD_OPENFILE_FAILED", + "LOAD_MEMALLOC_FAILED", + "LOAD_SEEKFILE_FAILED", + "LOAD_READHEADER_FAILED", + "LOAD_LOGOCRC_ERROR", + "LOAD_READDLSIGN_FAILED", + "LOAD_RELOCATEINFO_FAILED", + "LOAD_READMODULE_FAILED", "NINTENDO_LOGO_CHECK_FAILED", "SYSMENU_VERSION", "DHT_PHASE1_CALC_FAILED", @@ -123,7 +123,9 @@ static const char *fatal_error_msg[FATAL_ERROR_MAX] = "LOAD_AUTH_HEADER_FAILED", "LOAD_NEVER_STARTED", "EJECT_CARD_AFTER_LOAD_START", - "TITLEID_COMPARE_FAILED_NTR" + "TITLEID_COMPARE_FAILED_NTR", + "DHT_PHASE3_FAILED", + "DHT_PHASE4_FAILED" }; //#define DEBUG_LAUNCHER_DUMP @@ -147,12 +149,12 @@ static int CreateDspSlotBitmap(int slot_num) { int i, bitmap; bitmap = 0; - + for (i=0; iflags.isLogoSkip ) - { - SYSM_MakeNandTitleListMakerInfoAsync(); // AvɈn^CgXg쐬p̍쐬 - }else - { - SYSM_MakeNandTitleListMakerInfo(); - } - } + if( !pBootTitle->flags.isLogoSkip ) + { + SYSM_MakeNandTitleListMakerInfoAsync(); // AvɈn^CgXg쐬p̍쐬 + }else + { + SYSM_MakeNandTitleListMakerInfo(); + } + } // endԌv5 - MEASURE_RESULT( start, "GetNandTitleList : %dms\n" ); + MEASURE_RESULT( start, "GetNandTitleList : %dms\n" ); // startԌv6 MEASURE_START(start); - + // u_CNgu[głȂv // u_CNgu[gASf\v̎Ae탊\[X̃[h------------ #ifndef SYSM_BUILD_FOR_PRODUCTION_TEST if( !pBootTitle || ( pBootTitle && !SYSM_IsLogoDemoSkip() ) ) { - u32 timestamp; - if( !LoadSharedFontInit() ) { // LtHg̃[h - UTL_SetFatalError( FATAL_ERROR_SHARED_FONT ); - } - timestamp = OS_GetSharedFontTimestamp(); - if( timestamp > 0 ) OS_TPrintf( "SharedFont timestamp : %08x\n", timestamp ); - } + u32 timestamp; + if( !LoadSharedFontInit() ) { // LtHg̃[h + UTL_SetFatalError( FATAL_ERROR_SHARED_FONT ); + } + timestamp = OS_GetSharedFontTimestamp(); + if( timestamp > 0 ) OS_TPrintf( "SharedFont timestamp : %08x\n", timestamp ); + } #endif // SYSM_BUILD_FOR_PRODUCTION_TEST - + // endԌv6 - MEASURE_RESULT( start, "GetSharedFont : %dms\n" ); + MEASURE_RESULT( start, "GetSharedFont : %dms\n" ); // JnXe[g̔-------------- // startԌv7 MEASURE_START(start); - + if( pBootTitle ) { // _CNgu[gȂASA`[΂ă[hJn if( pBootTitle->flags.isLogoSkip ) { @@ -422,9 +424,9 @@ void TwlMain( void ) #ifdef SYSM_BUILD_FOR_PRODUCTION_TEST if( !pBootTitle || ( pBootTitle && ( pBootTitle->flags.bootType != LAUNCHER_BOOTTYPE_ROM ) ) - ) { - state = STOP; - } + ) { + state = STOP; + } #endif // SYSM_BUILD_FOR_PRODUCTION_TEST // `lbN @@ -437,20 +439,20 @@ void TwlMain( void ) s_strmThreadStack + THREAD_STACK_SIZE / sizeof(u64), THREAD_STACK_SIZE, STREAM_THREAD_PRIO); OS_WakeupThreadDirect(&s_strmThread); - + // endԌv7 - MEASURE_RESULT( start, "time 7 (etc...) : %dms\n" ); + MEASURE_RESULT( start, "time 7 (etc...) : %dms\n" ); // startԌv8 MEASURE_START(start); - + // t@[EFA𖳐W[Ƀ_E[hB if( FALSE == InstallWlanFirmware( SYSM_IsHotStart() ) ) { OS_TPrintf( "ERROR: Wireless firmware download failed!\n" ); } - + // endԌv8 - MEASURE_RESULT( start, "Load WlanFirm Time : %dms\n" ); + MEASURE_RESULT( start, "Load WlanFirm Time : %dms\n" ); if( UTL_IsFatalError() ) { // FATALG[ @@ -459,11 +461,11 @@ void TwlMain( void ) goto MAIN_LOOP_START; // state STOP ɂċIɃC[vJn } - // end Ԍvtotal - MEASURE_RESULT( allstart, "Total Time : %dms\n" ); - + // end Ԍvtotal + MEASURE_RESULT( allstart, "Total Time : %dms\n" ); + MAIN_LOOP_START: - + // C[v-------------------- while( 1 ) { OS_WaitIrq(1, OS_IE_V_BLANK); // VuN荞ݑ҂ @@ -487,27 +489,27 @@ MAIN_LOOP_START: state = LOGODEMO; break; case LOGODEMO: - if( IsFinishedLoadSharedFont() && // ʏu[ǵAtHg[hIŃ`FbN - LogoMain() && - SYSM_isNandTitleListReady() // NAND^Cg擾ǂ`FbN - ) { - // :::::::::::::::::::::::::::::::::::::::::::::: - // SystemMenuo[Wetc.̓ǂݍ - // :::::::::::::::::::::::::::::::::::::::::::::: - - // NAND^CgXg擾_ŁȀƂSystemMenuVersionf[^ɃANZX邽߂̐ZbgB - SYSM_SetSystemMenuVersionControlData(); - PrintSystemMenuVersion(); - - if( !direct_boot ) { - sp_titleList = SYSM_GetTitlePropertyList();// TitlePropertyList̎擾 + if( IsFinishedLoadSharedFont() && // ʏu[ǵAtHg[hIŃ`FbN + LogoMain() && + SYSM_isNandTitleListReady() // NAND^Cg擾ǂ`FbN + ) { + // :::::::::::::::::::::::::::::::::::::::::::::: + // SystemMenuo[Wetc.̓ǂݍ + // :::::::::::::::::::::::::::::::::::::::::::::: + + // NAND^CgXg擾_ŁȀƂSystemMenuVersionf[^ɃANZX邽߂̐ZbgB + SYSM_SetSystemMenuVersionControlData(); + PrintSystemMenuVersion(); + + if( !direct_boot ) { + sp_titleList = SYSM_GetTitlePropertyList();// TitlePropertyList̎擾 state = LAUNCHER_INIT; }else { state = LOAD_START; } - // SfIꍇ́AHotBoottO}B - OSi_SetEnableHotBoot( TRUE ); - } + // SfIꍇ́AHotBoottO}B + OSi_SetEnableHotBoot( TRUE ); + } break; case LAUNCHER_INIT: LauncherInit( NULL ); @@ -520,26 +522,26 @@ MAIN_LOOP_START: } break; case LOAD_START: - if( IsFinishedLoadSharedFont() // _CNgu[g̎́AtHg[hIŃ`FbN + if( IsFinishedLoadSharedFont() // _CNgu[g̎́AtHg[hIŃ`FbN && PollingInstallWlanFirmware() -#ifndef SYSM_DISABLE_WDS_SCAN // Avu[gOWDSXL͏IĂKv - && ( WDS_WrapperStopScan() != WDSWRAPPER_ERRCODE_OPERATING ) +#ifndef SYSM_DISABLE_WDS_SCAN // Avu[gOWDSXL͏IĂKv + && ( WDS_WrapperStopScan() != WDSWRAPPER_ERRCODE_OPERATING ) #endif // SYSM_DISABLE_WDS_SCAN - ) { - SYSM_StartLoadTitle( pBootTitle ); - state = LOADING; - start = OS_GetTick(); - // ÔߕKʂpXłV[gJbgNAHotBoottO}ĂB - OSi_SetEnableHotBoot( TRUE ); - } + ) { + SYSM_StartLoadTitle( pBootTitle ); + state = LOADING; + start = OS_GetTick(); + // ÔߕKʂpXłV[gJbgNAHotBoottO}ĂB + OSi_SetEnableHotBoot( TRUE ); + } break; case LOADING: // Ń[hOzCgXg`FbNsbZ[W|[OA󂯎stateLOAD_PAUSE if( SYSM_IsLoadTitlePaused() ) { - state = LOAD_PAUSE; - PrintPause(); - } + state = LOAD_PAUSE; + PrintPause(); + } if( SYSM_IsLoadTitleFinished() ) { SYSM_StartAuthenticateTitle( pBootTitle ); state = AUTHENTICATE; @@ -559,14 +561,14 @@ MAIN_LOOP_START: // N邩~邩̑IꂽLOADINGɖ߂ if( IsCommandSelected() ) { - state = LOADING; - } + state = LOADING; + } break; case AUTHENTICATE: if( ( direct_boot || ( !direct_boot && LauncherFadeout( sp_titleList ) ) ) && SYSM_IsAuthenticateTitleFinished() - ) { - // C[vJn猟؏I܂ł̊ԂɋNFATAL̏ + ) { + // C[vJn猟؏I܂ł̊ԂɋNFATAL̏ if( UTL_IsFatalError() ) { // FATALG[ // [TODO:]NAقǂf[^iȂǁjΏ @@ -574,59 +576,59 @@ MAIN_LOOP_START: state = STOP; break; // state STOP ɂ break A Boot Ȃ } - + #ifndef SYSM_DISABLE_WDS_SCAN - // NintendoX|bgu[ǵAAvԃp[^Ƀr[RZbgB - if( STD_CompareNString( (char *)&pBootTitle->titleID + 1, "JNH", 3 ) == 0 ) - { - (void)WDS_WrapperSetArgumentParam(); - } + // NintendoX|bgu[ǵAAvԃp[^Ƀr[RZbgB + if( STD_CompareNString( (char *)&pBootTitle->titleID + 1, "JNH", 3 ) == 0 ) + { + (void)WDS_WrapperSetArgumentParam(); + } #endif // SYSM_DISABLE_WDS_SCAN - - state = BOOT; - } - break; - case BOOT: + + state = BOOT; + } + break; + case BOOT: #ifndef SYSM_DISABLE_WDS_SCAN - // Avu[gOWDSXL͏IĂKv - if( ( WDS_WrapperCleanup() != WDSWRAPPER_ERRCODE_OPERATING ) && - IsClearnupWDSWrapper() ) + // Avu[gOWDSXL͏IĂKv + if( ( WDS_WrapperCleanup() != WDSWRAPPER_ERRCODE_OPERATING ) && + IsClearnupWDSWrapper() ) #endif // SYSM_DISABLE_WDS_SCAN - { - SYSM_TryToBootTitle( pBootTitle ); // never return. + { + SYSM_TryToBootTitle( pBootTitle ); // never return. } break; case STOP: // ~ - OS_Terminate(); + OS_Terminate(); break; } // J[hAvXg̎擾iXbhŐJ[h}ʒm̂C[vŎ擾j { - BOOL changed; - sp_titleList = SYSM_GetCardTitleList( &changed ); - if( changed ) - { - OS_TPrintf( "Change CARD status.\n" ); - } - } + BOOL changed; + sp_titleList = SYSM_GetCardTitleList( &changed ); + if( changed ) + { + OS_TPrintf( "Change CARD status.\n" ); + } + } // t@[[h̃|[O - if( PollingInstallWlanFirmware() && - ( GetWlanFirmwareInstallFinalResult() == WLANFIRM_RESULT_SUCCESS ) // [h - ) { - // L𖞂ȂAWDSXLJn + if( PollingInstallWlanFirmware() && + ( GetWlanFirmwareInstallFinalResult() == WLANFIRM_RESULT_SUCCESS ) // [h + ) { + // L𖞂ȂAWDSXLJn #ifndef SYSM_DISABLE_WDS_SCAN - if( !isStartScanWDS && // WDSXLJnς݂łȂ - !direct_boot && // _CNgu[głȂ - !LCFG_THW_IsForceDisableWireless() && // OFFłȂ - LCFG_TSD_IsAvailableWireless() // ON - ) { - InitializeWDS(); // ƓJn˂ĂBisĂ~܂͂Ȃ̂ŁACɂȂj - isStartScanWDS = TRUE; - } + if( !isStartScanWDS && // WDSXLJnς݂łȂ + !direct_boot && // _CNgu[głȂ + !LCFG_THW_IsForceDisableWireless() && // OFFłȂ + LCFG_TSD_IsAvailableWireless() // ON + ) { + InitializeWDS(); // ƓJn˂ĂBisĂ~܂͂Ȃ̂ŁACɂȂj + isStartScanWDS = TRUE; + } #endif // SYSM_DISABLE_WDS_SCAN - } + } // R}htbV (void)SND_FlushCommand(SND_COMMAND_NOBLOCK); @@ -637,7 +639,7 @@ MAIN_LOOP_START: //iWJԂƃfobKڑ̃LZ̓ftHgōsj if ( PollingInstallWlanFirmware() ) { - UTL_GoSleepMode(); + UTL_GoSleepMode(); } #endif // DISABLE_SLEEP } @@ -645,123 +647,123 @@ MAIN_LOOP_START: static BOOL IsCommandSelected(void) { - static BOOL left = FALSE; - if( !( pad.cont & ( PAD_BUTTON_A | PAD_BUTTON_B ) ) ) - { - left = TRUE; - } - - if( left && ( pad.trg & PAD_BUTTON_A ) ) - { - NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); - PrintfSJIS( 1, 25, TXT_COLOR_RED,"Resume Loading....\n" ); - SYSM_ResumeLoadingThread( TRUE ); - left = FALSE; - return TRUE; - }else if( left && ( pad.trg & PAD_BUTTON_B ) ) - { - NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); - PrintfSJIS( 1, 25, TXT_COLOR_RED,"Please Wait....\n" ); - SYSM_ResumeLoadingThread( FALSE ); - left = FALSE; - return TRUE; - } - return FALSE; + static BOOL left = FALSE; + if( !( pad.cont & ( PAD_BUTTON_A | PAD_BUTTON_B ) ) ) + { + left = TRUE; + } + + if( left && ( pad.trg & PAD_BUTTON_A ) ) + { + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); + PrintfSJIS( 1, 25, TXT_COLOR_RED,"Resume Loading....\n" ); + SYSM_ResumeLoadingThread( TRUE ); + left = FALSE; + return TRUE; + }else if( left && ( pad.trg & PAD_BUTTON_B ) ) + { + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); + PrintfSJIS( 1, 25, TXT_COLOR_RED,"Please Wait....\n" ); + SYSM_ResumeLoadingThread( FALSE ); + left = FALSE; + return TRUE; + } + return FALSE; } static void PrintPause(void) { - LauncherInit( NULL ); - GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); - NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); - G2_ChangeBlendAlpha( 0, 31 ); - PrintfSJIS( 1, 25, TXT_COLOR_RED,"WhiteList Check Failed.\n" ); - PrintfSJIS( 1, 40, TXT_COLOR_RED,"Prease Select Command." ); - PrintfSJIS( 1, 55, TXT_COLOR_RED,"A : Force to Launch" ); - PrintfSJIS( 1, 70, TXT_COLOR_RED," or" ); - PrintfSJIS( 1, 85, TXT_COLOR_RED,"B : Stop And Show Error Message" ); - GX_DispOn(); - GXS_DispOn(); + LauncherInit( NULL ); + GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); + G2_ChangeBlendAlpha( 0, 31 ); + PrintfSJIS( 1, 25, TXT_COLOR_RED,"WhiteList Check Failed.\n" ); + PrintfSJIS( 1, 40, TXT_COLOR_RED,"Prease Select Command." ); + PrintfSJIS( 1, 55, TXT_COLOR_RED,"A : Force to Launch" ); + PrintfSJIS( 1, 70, TXT_COLOR_RED," or" ); + PrintfSJIS( 1, 85, TXT_COLOR_RED,"B : Stop And Show Error Message" ); + GX_DispOn(); + GXS_DispOn(); } static void PrintError( void ) { - u64 error_code; - int l; - int count = 0; - LauncherInit( NULL ); - GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); - NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); - G2_ChangeBlendAlpha( 0, 31 ); - PrintfSJIS( 128, 0, TXT_COLOR_BLUE, "IPL:%s", g_strIPLSvnRevision ); - PrintfSJIS( 128, 12, TXT_COLOR_BLUE, "SDK:%s", g_strSDKSvnRevision ); - error_code = UTL_GetFatalError(); - PrintfSJIS( 2, 25, TXT_COLOR_RED,"ERROR! - 0x%016llx\n", error_code ); - ERRORLOG_Write(error_code); - for(l=0;l<64;l++) - { - if( error_code & 0x1 ) - { - PrintfSJIS( 2, 50+count*13, TXT_COLOR_RED,"%s\n", fatal_error_msg[l] ); - count++; - } - error_code = error_code >> 1; - } - GX_DispOn(); - GXS_DispOn(); + u64 error_code; + int l; + int count = 0; + LauncherInit( NULL ); + GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_NULL ); + G2_ChangeBlendAlpha( 0, 31 ); + PrintfSJIS( 128, 0, TXT_COLOR_BLUE, "IPL:%s", g_strIPLSvnRevision ); + PrintfSJIS( 128, 12, TXT_COLOR_BLUE, "SDK:%s", g_strSDKSvnRevision ); + error_code = UTL_GetFatalError(); + PrintfSJIS( 2, 25, TXT_COLOR_RED,"ERROR! - 0x%016llx\n", error_code ); + ERRORLOG_Write(error_code); + for(l=0;l<64;l++) + { + if( error_code & 0x1 ) + { + PrintfSJIS( 2, 50+count*13, TXT_COLOR_RED,"%s\n", fatal_error_msg[l] ); + count++; + } + error_code = error_code >> 1; + } + GX_DispOn(); + GXS_DispOn(); } // VXej[o[W̃vg static void PrintSystemMenuVersion( void ) { - u8 *pBuffer = SYSM_Alloc( NA_VERSION_DATA_WORK_SIZE ); - - if( pBuffer && - ReadSystemMenuVersionData( pBuffer, NA_VERSION_DATA_WORK_SIZE ) ) { - // [h - }else { - // FATALG[ - UTL_SetFatalError( FATAL_ERROR_TWLSETTINGS ); - } - SYSM_Free( pBuffer ); - - // o[W̕\ - { - char str_ver[ TWL_SYSMENU_VER_STR_LEN / sizeof(u16) ]; - int len = sizeof(str_ver); - MI_CpuClear8( str_ver, sizeof(str_ver) ); - OS_TPrintf( "SystemMenuVersionData\n" ); - // - if( STD_ConvertStringUnicodeToSjis( str_ver, &len, GetSystemMenuVersionString(), NULL, NULL ) == STD_RESULT_SUCCESS ) { - OS_TPrintf( " Version(str) : %s\n", str_ver ); - } - // l - OS_TPrintf( " Version(num) : %d.%d\n", GetSystemMenuMajorVersion(), GetSystemMenuMinorVersion() ); - // [U[̈MAXTCY̕\ - OS_TPrintf( " TotalUserAreadSize : 0x%08x\n", FSi_GetTotalUserAreaSize() ); - // EULA URL̕\ - OS_TPrintf( " EULA URL : %s\n", GetEULA_URL() ); - // NUP HostName̕\ - OS_TPrintf( " NUP HostName : %s\n", GetNUP_HostName() ); - // SystemMenuVersioñ^CX^v̎擾 - OS_TPrintf( " Timestamp : %08x\n", GetSystemMenuVersionTimeStamp() ); - } + u8 *pBuffer = SYSM_Alloc( NA_VERSION_DATA_WORK_SIZE ); + + if( pBuffer && + ReadSystemMenuVersionData( pBuffer, NA_VERSION_DATA_WORK_SIZE ) ) { + // [h + }else { + // FATALG[ + UTL_SetFatalError( FATAL_ERROR_TWLSETTINGS ); + } + SYSM_Free( pBuffer ); + + // o[W̕\ + { + char str_ver[ TWL_SYSMENU_VER_STR_LEN / sizeof(u16) ]; + int len = sizeof(str_ver); + MI_CpuClear8( str_ver, sizeof(str_ver) ); + OS_TPrintf( "SystemMenuVersionData\n" ); + // + if( STD_ConvertStringUnicodeToSjis( str_ver, &len, GetSystemMenuVersionString(), NULL, NULL ) == STD_RESULT_SUCCESS ) { + OS_TPrintf( " Version(str) : %s\n", str_ver ); + } + // l + OS_TPrintf( " Version(num) : %d.%d\n", GetSystemMenuMajorVersion(), GetSystemMenuMinorVersion() ); + // [U[̈MAXTCY̕\ + OS_TPrintf( " TotalUserAreadSize : 0x%08x\n", FSi_GetTotalUserAreaSize() ); + // EULA URL̕\ + OS_TPrintf( " EULA URL : %s\n", GetEULA_URL() ); + // NUP HostName̕\ + OS_TPrintf( " NUP HostName : %s\n", GetNUP_HostName() ); + // SystemMenuVersioñ^CX^v̎擾 + OS_TPrintf( " Timestamp : %08x\n", GetSystemMenuVersionTimeStamp() ); + } } // _~[DSj[bsOpt@C쐬iUIG`[Ắj static void CreateDummyWrapFile( void ) { - const char *path = "nand:/shared2/launcher/wrap.bin"; - - if( FS_CreateFileAuto( path, FS_PERMIT_R | FS_PERMIT_W ) ) { - FSFile file; - if( FS_OpenFileEx( &file, path, FS_FILEMODE_RW ) ) { - (void)FS_SetFileLength( &file, 16 * 1024 ); - FS_CloseFile( &file ); - } - } + const char *path = "nand:/shared2/launcher/wrap.bin"; + + if( FS_CreateFileAuto( path, FS_PERMIT_R | FS_PERMIT_W ) ) { + FSFile file; + if( FS_OpenFileEx( &file, path, FS_FILEMODE_RW ) ) { + (void)FS_SetFileLength( &file, 16 * 1024 ); + FS_CloseFile( &file ); + } + } } diff --git a/docs/メモリマップ_NANDファーム.vsd b/docs/メモリマップ_NANDファーム.vsd index 3ac08045d774638db874b5854473adb8a050c728..16f17ef21bcb82bf322149c22273a107c6394c4c 100644 GIT binary patch delta 19587 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 delta 19753 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 diff --git a/include/sysmenu/dht/dht.h b/include/sysmenu/dht/dht.h index 492421dc..9f14f7b9 100644 --- a/include/sysmenu/dht/dht.h +++ b/include/sysmenu/dht/dht.h @@ -2,7 +2,7 @@ Project: TwlIPL - DHT File: dht.h - Copyright 2008 Nintendo. All rights reserved. + Copyright 2008,2009 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo @@ -17,13 +17,28 @@ #ifndef SYSMENU_DHT_H_ #define SYSMENU_DHT_H_ +/* + PhaseAzCgXgA}X^Oς݃wb_̑Ή֌W + + Phase1 DHTDatabase->hash[0] ROM_Header_Short->nitro_whitelist_phase1_digest + Phase2 DHTDatabase->hash[1] ROM_Header_Short->nitro_whitelist_phase2_digest + Phase3 DHTDatabaseEx->banner_hash ROM_Header_Short->banner_digest + Phase4 - - + + Phase4̃nbVldht_phase4_list.cɊ܂܂ +*/ + #include #include #include +#define nitro_whitelist_phase2_digest nitro_whitelist_phase2_diegst // for spell miss + #define DHT_FAT_PAGE_SIZE 512 #define DHT_FAT_CACHE_SIZE (DHT_FAT_PAGE_SIZE * 2) +#define DHT_PHASE3_MAX DHT_OVERLAY_MAX + /* DHT_CheckHashPhase2ŕKvȃ[N */ @@ -34,6 +49,17 @@ typedef struct DHTPhase2Work } DHTPhase2Work; +/* + DHT_CheckHashPhase4ŕKvȃ[N + (DHTPhase4Work <= DHTPhase2WorkK藧) +*/ + +typedef struct DHTPhase4Work +{ + u32 buffer[DHT_PHASE3_MAX/sizeof(u32)]; +} +DHTPhase4Work; + /* DHT_CheckHashPhase2ExŕKvȃ[N */ @@ -48,7 +74,7 @@ extern "C" { #endif /* - DHT_CheckHashPhase2/DHT_CheckHashPhase2ExŎgpRead֐ + DHT_CheckHashPhase2/DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4ŎgpRead֐ dest ]AhX offset ]ROMItZbg length ]TCY @@ -59,7 +85,7 @@ extern "C" { typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg); /* - DHT_CheckHashPhase2ExŎgpRead֐ + DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4ExŎgpRead֐ ]AhX݂͑AɓƎobt@ɓǂݍ񂾌 DHT_CheckHashPhase2ExUpdateĂяo(ו”\) ctx DHT_CheckHashPhase2ExUpdateɓn @@ -71,7 +97,7 @@ typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg); */ typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length, void* arg); /*---------------------------------------------------------------------------* - Name: DHT_PrepareDatabase + Name: DHT_GetDatabaseLength Description: ǂݍݍς݂̃f[^x[X̃wb_TCYԂ @@ -81,12 +107,34 @@ typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length *---------------------------------------------------------------------------*/ u32 DHT_GetDatabaseLength(const DHTFile* pDHT); +/*---------------------------------------------------------------------------* + Name: DHT_GetDatabaseExLength + + Description: ǂݍݍς݂̊gf[^x[X̃wb_TCYԂ + + Arguments: pDHT gf[^x[Xwb_̊i[ + + Returns: ȃwb_ȂTCYAłȂȂ0 + *---------------------------------------------------------------------------*/ +u32 DHT_GetDatabaseExLength(const DHTFileEx* pDHT); + +/*---------------------------------------------------------------------------* + Name: DHT_GetDatabaseAdHocLength + + Description: ǂݍݍς݂̌•ʑΉf[^x[X̃wb_TCYԂ + + Arguments: pDHT •ʑΉf[^x[Xwb_̊i[ + + Returns: ȃwb_ȂTCYAłȂȂ0 + *---------------------------------------------------------------------------*/ +u32 DHT_GetDatabaseAdHocLength(const DHTFileAdHoc* pDHT); + /*---------------------------------------------------------------------------* Name: DHT_PrepareDatabase - Description: FS֐𗘗pđSf[^x[Xǂݍ݂ƌ؂s + Description: FS֐𗘗păf[^x[Xǂݍ݂ƌ؂s - Arguments: pDHT Sf[^x[X̊i[ + Arguments: pDHT f[^x[X̊i[ fp t@C\̂ւ̃|C^ DHTHeader̐擪܂ŃV[Nς݂łKv @@ -94,18 +142,56 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT); *---------------------------------------------------------------------------*/ BOOL DHT_PrepareDatabase(DHTFile* pDHT, FSFile* fp); +/*---------------------------------------------------------------------------* + Name: DHT_PrepareDatabaseEx + + Description: FS֐𗘗pĊgf[^x[Xǂݍ݂ƌ؂s + + Arguments: pDHT gf[^x[X̊i[ + fp t@C\̂ւ̃|C^ + DHTHeader̐擪܂ŃV[Nς݂łKv + + Returns: TRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_PrepareDatabaseEx(DHTFileEx* pDHT, FSFile* fp); + +/*---------------------------------------------------------------------------* + Name: DHT_PrepareDatabaseAdHoc + + Description: FS֐𗘗pȕʑΉf[^x[Xǂݍ݂ƌ؂s + + Arguments: pDHT •ʑΉf[^x[X̊i[ + fp t@C\̂ւ̃|C^ + DHTHeader̐擪܂ŃV[Nς݂łKv + + Returns: TRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_PrepareDatabaseAdHoc(DHTFileAdHoc* pDHT, FSFile* fp); + /*---------------------------------------------------------------------------* Name: DHT_GetDatabase Description: ROMwb_ɑΉf[^x[X - Arguments: pDHT Sf[^x[X̊i[ + Arguments: pDHT f[^x[X̊i[ pROMHeader ΏۂƂȂROMwb_i[ - Returns: Ώۃf[^x[Xւ̃|C^ + Returns: ΏۃGgւ̃|C^A‚ȂNULL *---------------------------------------------------------------------------*/ const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader); +/*---------------------------------------------------------------------------* + Name: DHT_GetDatabaseEx + + Description: ROMwb_ɑΉgf[^x[X + + Arguments: pDHT gf[^x[X̊i[ + pROMHeader ΏۂƂȂROMwb_i[ + + Returns: ΏۃGgւ̃|C^A‚ȂNULL + *---------------------------------------------------------------------------*/ +const DHTDatabaseEx* DHT_GetDatabaseEx(const DHTFileEx* pDHT, const ROM_Header_Short* pROMHeader); + /*---------------------------------------------------------------------------* Name: DHT_CheckHashPhase1Init @@ -178,7 +264,6 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT Name: DHT_CheckHashPhase2Ex Description: I[o[C̈̌ - (foCXRead APIo^łׂ) Arguments: hash ΉnbV (db->hash[1]) pROMHeader ΏۂƂȂROMwb_i[ @@ -193,10 +278,11 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, DHTPhase2ExWork* work, DHTReadFunc func, DHTReadFuncEx funcEx, void* arg); /*---------------------------------------------------------------------------* - Name: DHT_CheckHashPhase2ExUpdate + Name: DHT_CheckHashPhase2ExUpdate / DHT_CheckHashPhase4ExUpdate - Description: I[o[Č + Description: I[o[Č؂ь•ʂ̌ DHTReadFuncExĂяo(Ȃו͎R) + : Phase4łpĂ Arguments: ctx ؗpSVCHMACSHA1ReLXg ptr ΏۂƂȂf[^̈ @@ -205,6 +291,51 @@ BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, D Returns: None *---------------------------------------------------------------------------*/ void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 length); +#define DHT_CheckHashPhase4ExUpdate DHT_CheckHashPhase2ExUpdate + +/*---------------------------------------------------------------------------* + Name: DHT_CheckHashPhase3 + + Description: oi[̈̌ + (j[\Ɏgpf[^nׂ) + + Arguments: hash ΉnbV (dbex->banner_hash) + pBanner ΏۂƂȂoi[i[ + + Returns: ȂTRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_CheckHashPhase3(const u8* hash, const NTRBannerFile* pBanner); + +/*---------------------------------------------------------------------------* + Name: DHT_CheckHashPhase4 + + Description: •ʂ̌ + + Arguments: pDHT •ʑΉf[^x[X̊i[ + pROMHeader ΏۂƂȂROMwb_i[ + work {APIŎgp郏[N (512KB) + phase2̎g񂵂OK + func ΏۃfoCXɉRead֐ + arg Read֐ɓn + + Returns: ȂTRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_CheckHashPhase4(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTPhase4Work* work, DHTReadFunc func, void* arg); + +/*---------------------------------------------------------------------------* + Name: DHT_CheckHashPhase4Ex + + Description: •ʂ̌ + + Arguments: pDHT •ʑΉf[^x[X̊i[ + pROMHeader ΏۂƂȂROMwb_i[ + funcEx ΏۃfoCXɉēƎobt@Ƀf[^ǂݍ + DHT_CheckHashPhase2ExUpdateĂяoKv + arg Read֐ɓn + + Returns: ȂTRUE + *---------------------------------------------------------------------------*/ +BOOL DHT_CheckHashPhase4Ex(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTReadFuncEx funcEx, void* arg); #ifdef __cplusplus } /* extern "C" */ diff --git a/include/sysmenu/dht/dht_format.h b/include/sysmenu/dht/dht_format.h index b41f957b..655c843b 100644 --- a/include/sysmenu/dht/dht_format.h +++ b/include/sysmenu/dht/dht_format.h @@ -21,7 +21,12 @@ #define DHT_DS_HEADER_SIZE 0x160 #define DHT_OVERLAY_MAX (512*1024) +#define DHT_MAGIC_CODE_EX (('N' << 0)|('D' << 8)|('H' << 16)|('X' << 24)) + +#define DHT_MAGIC_CODE_ADHOC (('N' << 0)|('D' << 8)|('H' << 16)|('I' << 24)) + #include +#include #ifdef __cplusplus extern "C" { @@ -35,6 +40,8 @@ typedef struct DHTHeader } DHTHeader; +#define DHTHeaderEx DHTHeader + typedef struct DHTDatabase { u8 game_code[4]; @@ -44,6 +51,33 @@ typedef struct DHTDatabase } DHTDatabase; +typedef struct DHTDatabaseEx +{ + u8 game_code[4]; + u8 rom_version; + u8 reserved[3]; // for 4B alignment DHTDatabase array + u8 banner_hash[20]; +} +DHTDatabaseEx; + +/* + ad-hocΏp +*/ +#define DHT_INDIVIDUAL_ENTRY_MAX 8 +typedef struct DHTDatabaseAdHoc +{ + u8 game_code[4]; + u8 rom_version; + u8 reserved[3]; // for 4B alignment DHTDatabase array + struct + { + u32 offset; + u32 length; + } entry[DHT_INDIVIDUAL_ENTRY_MAX]; + u8 hash[20]; +} +DHTDatabaseAdHoc; + typedef struct DHTFile { DHTHeader header; @@ -51,6 +85,20 @@ typedef struct DHTFile } DHTFile; +typedef struct DHTFileEx +{ + DHTHeader header; + DHTDatabaseEx database[]; +} +DHTFileEx; + +typedef struct DHTFileAdHoc +{ + DHTHeader header; + DHTDatabaseAdHoc database[]; +} +DHTFileAdHoc; + #define DHT_HMAC_KEY { \ 0x61, 0xbd, 0xdd, 0x72, 0x7e, 0x72, 0xbe, 0xde, 0xad, 0x3a, 0xdf, 0x7f, 0x3d, 0x2d, 0xf7, 0xa5, \ 0x16, 0x7e, 0xb4, 0xc9, 0x7c, 0x6c, 0x00, 0x7c, 0x57, 0xbb, 0x94, 0x8a, 0x64, 0xcd, 0x4e, 0x1c, \ @@ -58,16 +106,28 @@ DHTFile; 0x7f, 0xd9, 0x7c, 0xe9, 0x92, 0x44, 0x0f, 0xef, 0x6b, 0xb6, 0x12, 0x21, 0x68, 0x88, 0xd8, 0xee \ } +#define DHT_HMAC_KEY2 { \ + 0x85, 0x29, 0x48, 0xf3, 0xa1, 0xbb, 0x13, 0x30, 0x93, 0x5d, 0xb8, 0xc9, 0xa5, 0x9a, 0xe8, 0x30, \ + 0xc4, 0xd0, 0x4a, 0xdd, 0xa4, 0x92, 0x81, 0xfd, 0x4f, 0xa1, 0x32, 0xfa, 0x46, 0x05, 0xde, 0x68, \ + 0x7b, 0xa7, 0xd7, 0x5b, 0xc9, 0x3a, 0xc8, 0x8d, 0xcd, 0x25, 0x3a, 0x17, 0x3c, 0xc2, 0xd6, 0xe0, \ + 0xd2, 0xe5, 0xb9, 0xfb, 0x49, 0xf9, 0x4d, 0x05, 0x70, 0x10, 0x29, 0x51, 0x7a, 0xc5, 0x89, 0x49, \ +} /* [eBeB - hp: ̃t@C̐擪AhX + hp: ̃f[^x[X̐擪AhX */ #define DHT_GET_SIGN_TARGET_ADDR(hp) (&((DHTHeader*)hp)->nums) #define DHT_GET_SIGN_TARGET_SIZE(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabase) + sizeof(u32)) - #define DHT_GET_SIGN_TARGET_OFFSET (int)DHT_GET_SIGN_TARGET_ADDR(0) +#define DHT_GET_SIGN_TARGET_ADDR_EX(hp) DHT_GET_SIGN_TARGET_ADDR(hp) +#define DHT_GET_SIGN_TARGET_SIZE_EX(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabaseEx) + sizeof(u32)) +#define DHT_GET_SIGN_TARGET_OFFSET_EX DHT_GET_SIGN_TARGET_OFFSET + +#define DHT_GET_SIGN_TARGET_ADDR_ADHOC(hp) DHT_GET_SIGN_TARGET_ADDR(hp) +#define DHT_GET_SIGN_TARGET_SIZE_ADHOC(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabaseAdHoc) + sizeof(u32)) +#define DHT_GET_SIGN_TARGET_OFFSET_ADHOC DHT_GET_SIGN_TARGET_OFFSET #ifdef __cplusplus } /* extern "C" */ diff --git a/include/sysmenu/util.h b/include/sysmenu/util.h index 1db41990..97144994 100644 --- a/include/sysmenu/util.h +++ b/include/sysmenu/util.h @@ -15,8 +15,8 @@ $Author$ *---------------------------------------------------------------------------*/ -#ifndef __SYSM_UTIL_H__ -#define __SYSM_UTIL_H__ +#ifndef __SYSM_UTIL_H__ +#define __SYSM_UTIL_H__ #include #include @@ -26,62 +26,64 @@ extern "C" { #endif // define data---------------------------------------------------------- -#define BACKLIGHT_BRIGHTNESS_MAX 4 +#define BACKLIGHT_BRIGHTNESS_MAX 4 typedef enum FatalErrorCode { - FATAL_ERROR_UNDEFINED = 0, - FATAL_ERROR_NAND = 1, // NANDfoCX̃G[ - FATAL_ERROR_HWINFO_NORMAL = 2, // HWm[}̃[hG[ - FATAL_ERROR_HWINFO_SECURE = 3, // HWZLÃ[hG[ - FATAL_ERROR_TWLSETTINGS = 4, // {̐ݒf[^̃[hG[ - FATAL_ERROR_SHARED_FONT = 5, // LtHg̃[hG[ - FATAL_ERROR_WLANFIRM_AUTH = 6, // t@[̔F؃G[ - FATAL_ERROR_WLANFIRM_LOAD = 7, // t@[̃[hG[ - FATAL_ERROR_TITLE_LOAD_FAILED = 8, // AvP[Ṽ[hG[ - FATAL_ERROR_TITLE_POINTER_ERROR = 9, // u[gvꂽAAvw肳ĂȂ - FATAL_ERROR_AUTHENTICATE_FAILED = 10, // AvF؎s - FATAL_ERROR_ENTRY_ADDRESS_ERROR = 11, // Av̋NAhXs - FATAL_ERROR_TITLE_BOOTTYPE_ERROR = 12, // Avu[g^CvsiNANDu[gAJ[hu[gAMBu[gȊO̒lj - FATAL_ERROR_SIGN_DECRYPTION_FAILED = 13, // AvfNvgs - FATAL_ERROR_SIGN_COMPARE_FAILED = 14, // Av؎s - FATAL_ERROR_HEADER_HASH_CALC_FAILED = 15, // AvnbVvZpmێs - FATAL_ERROR_TITLEID_COMPARE_FAILED = 16, // u[gvꂽTWLAvƎۂɃ[hAvTitleIDsv - FATAL_ERROR_VALID_SIGN_FLAG_OFF = 17, // AvROMwb_̏LtOĂȂ - FATAL_ERROR_CHECK_TITLE_LAUNCH_RIGHTS_FAILED = 18, // AvNF؎s - FATAL_ERROR_MODULE_HASH_CHECK_FAILED = 19, // AvnbVsv - FATAL_ERROR_MODULE_HASH_CALC_FAILED = 20, // AvnbVvZpmێs - FATAL_ERROR_MEDIA_CHECK_FAILED = 21, // J[hAvNANDN or NANDAvJ[hN悤ƂifobKNj - FATAL_ERROR_DL_MAGICCODE_CHECK_FAILED = 22, // DS_E[hvCAṽ}WbNR[hsiTEMPu[gAvu[gj - FATAL_ERROR_DL_SIGN_DECRYPTION_FAILED = 23, // DS_E[hvCAṽfNvgsiTEMPu[gAvu[gj - FATAL_ERROR_DL_HASH_CALC_FAILED = 24, // DS_E[hvCAvnbVvZpmێsiTEMPu[gAvu[gj - FATAL_ERROR_DL_SIGN_COMPARE_FAILED = 25, // DS_E[hvCAvnbVsviTEMPu[gAvu[gj - FATAL_ERROR_WHITELIST_INITDB_FAILED = 26, // NTRzCgXgg̔F؎s - FATAL_ERROR_WHITELIST_NOTFOUND = 27, // NNTRAṽCjVR[hNTRzCgXgɌ‚Ȃ - FATAL_ERROR_DHT_PHASE1_FAILED = 28, // AvNTRzCgXgF؎sitF[YPj - FATAL_ERROR_DHT_PHASE2_FAILED = 29, // AvNTRzCgXgF؎sitF[YQj - FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF = 30, // TMPu[gAvROMwb_TMPWvƒrbgĂȂ - FATAL_ERROR_TWL_BOOTTYPE_UNKNOWN = 31, // TWLAvu[g^Cvs - FATAL_ERROR_NTR_BOOTTYPE_UNKNOWN = 32, // NTRAvu[g^Cvs - FATAL_ERROR_PLATFORM_UNKNOWN = 33, // ROMwb_̃vbgz[R[hs - FATAL_ERROR_LOAD_UNFINISHED = 34, // Av[hĂȂ̂ɁAF؃tF[Yɐi - FATAL_ERROR_LOAD_OPENFILE_FAILED = 35, // NANDAṽt@CI[vs - FATAL_ERROR_LOAD_MEMALLOC_FAILED = 36, // AvnbVvZpmێs - FATAL_ERROR_LOAD_SEEKFILE_FAILED = 37, // NANDAṽt@CV[Ns - FATAL_ERROR_LOAD_READHEADER_FAILED = 38, // AvROMwb_[hs - FATAL_ERROR_LOAD_LOGOCRC_ERROR = 39, // AvROMwb_NintendoSCRCs - FATAL_ERROR_LOAD_READDLSIGN_FAILED = 40, // TMPu[gAvDS_E[hvC[hs - FATAL_ERROR_LOAD_RELOCATEINFO_FAILED = 41, // AvĔzu񐶐s - FATAL_ERROR_LOAD_READMODULE_FAILED = 42, // Av[hs - FATAL_ERROR_NINTENDO_LOGO_CHECK_FAILED = 43, // AvROMwb_NintendoSf[^s - FATAL_ERROR_SYSMENU_VERSION = 44, // - FATAL_ERROR_DHT_PHASE1_CALC_FAILED = 45, // NTRAvzCgXgnbVvZpmێs - FATAL_ERROR_LOAD_UNKNOWN_BOOTTYPE = 46, // Avu[g^Cvs - FATAL_ERROR_LOAD_AUTH_HEADER_FAILED = 47, // AvROMwb_F؎s - FATAL_ERROR_LOAD_NEVER_STARTED = 48, // [hJnĂȂ̂ɁAF؂Jnꂽ - FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // J[hĂ̂ɁAJ[hAṽ[hJnꂽ - FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // u[gvꂽNTRAvƎۂɃ[hAvTitleIDsv + FATAL_ERROR_UNDEFINED = 0, + FATAL_ERROR_NAND = 1, // NANDfoCX̃G[ + FATAL_ERROR_HWINFO_NORMAL = 2, // HWm[}̃[hG[ + FATAL_ERROR_HWINFO_SECURE = 3, // HWZLÃ[hG[ + FATAL_ERROR_TWLSETTINGS = 4, // {̐ݒf[^̃[hG[ + FATAL_ERROR_SHARED_FONT = 5, // LtHg̃[hG[ + FATAL_ERROR_WLANFIRM_AUTH = 6, // t@[̔F؃G[ + FATAL_ERROR_WLANFIRM_LOAD = 7, // t@[̃[hG[ + FATAL_ERROR_TITLE_LOAD_FAILED = 8, // AvP[Ṽ[hG[ + FATAL_ERROR_TITLE_POINTER_ERROR = 9, // u[gvꂽAAvw肳ĂȂ + FATAL_ERROR_AUTHENTICATE_FAILED = 10, // AvF؎s + FATAL_ERROR_ENTRY_ADDRESS_ERROR = 11, // Av̋NAhXs + FATAL_ERROR_TITLE_BOOTTYPE_ERROR = 12, // Avu[g^CvsiNANDu[gAJ[hu[gAMBu[gȊO̒lj + FATAL_ERROR_SIGN_DECRYPTION_FAILED = 13, // AvfNvgs + FATAL_ERROR_SIGN_COMPARE_FAILED = 14, // Av؎s + FATAL_ERROR_HEADER_HASH_CALC_FAILED = 15, // AvnbVvZpmێs + FATAL_ERROR_TITLEID_COMPARE_FAILED = 16, // u[gvꂽTWLAvƎۂɃ[hAvTitleIDsv + FATAL_ERROR_VALID_SIGN_FLAG_OFF = 17, // AvROMwb_̏LtOĂȂ + FATAL_ERROR_CHECK_TITLE_LAUNCH_RIGHTS_FAILED = 18, // AvNF؎s + FATAL_ERROR_MODULE_HASH_CHECK_FAILED = 19, // AvnbVsv + FATAL_ERROR_MODULE_HASH_CALC_FAILED = 20, // AvnbVvZpmێs + FATAL_ERROR_MEDIA_CHECK_FAILED = 21, // J[hAvNANDN or NANDAvJ[hN悤ƂifobKNj + FATAL_ERROR_DL_MAGICCODE_CHECK_FAILED = 22, // DS_E[hvCAṽ}WbNR[hsiTEMPu[gAvu[gj + FATAL_ERROR_DL_SIGN_DECRYPTION_FAILED = 23, // DS_E[hvCAṽfNvgsiTEMPu[gAvu[gj + FATAL_ERROR_DL_HASH_CALC_FAILED = 24, // DS_E[hvCAvnbVvZpmێsiTEMPu[gAvu[gj + FATAL_ERROR_DL_SIGN_COMPARE_FAILED = 25, // DS_E[hvCAvnbVsviTEMPu[gAvu[gj + FATAL_ERROR_WHITELIST_INITDB_FAILED = 26, // NTRzCgXgg̔F؎s + FATAL_ERROR_WHITELIST_NOTFOUND = 27, // NNTRAṽCjVR[hNTRzCgXgɌ‚Ȃ + FATAL_ERROR_DHT_PHASE1_FAILED = 28, // AvNTRzCgXgF؎sitF[YPj + FATAL_ERROR_DHT_PHASE2_FAILED = 29, // AvNTRzCgXgF؎sitF[YQj + FATAL_ERROR_LANDING_TMP_JUMP_FLAG_OFF = 30, // TMPu[gAvROMwb_TMPWvƒrbgĂȂ + FATAL_ERROR_TWL_BOOTTYPE_UNKNOWN = 31, // TWLAvu[g^Cvs + FATAL_ERROR_NTR_BOOTTYPE_UNKNOWN = 32, // NTRAvu[g^Cvs + FATAL_ERROR_PLATFORM_UNKNOWN = 33, // ROMwb_̃vbgz[R[hs + FATAL_ERROR_LOAD_UNFINISHED = 34, // Av[hĂȂ̂ɁAF؃tF[Yɐi + FATAL_ERROR_LOAD_OPENFILE_FAILED = 35, // NANDAṽt@CI[vs + FATAL_ERROR_LOAD_MEMALLOC_FAILED = 36, // AvnbVvZpmێs + FATAL_ERROR_LOAD_SEEKFILE_FAILED = 37, // NANDAṽt@CV[Ns + FATAL_ERROR_LOAD_READHEADER_FAILED = 38, // AvROMwb_[hs + FATAL_ERROR_LOAD_LOGOCRC_ERROR = 39, // AvROMwb_NintendoSCRCs + FATAL_ERROR_LOAD_READDLSIGN_FAILED = 40, // TMPu[gAvDS_E[hvC[hs + FATAL_ERROR_LOAD_RELOCATEINFO_FAILED = 41, // AvĔzu񐶐s + FATAL_ERROR_LOAD_READMODULE_FAILED = 42, // Av[hs + FATAL_ERROR_NINTENDO_LOGO_CHECK_FAILED = 43, // AvROMwb_NintendoSf[^s + FATAL_ERROR_SYSMENU_VERSION = 44, // + FATAL_ERROR_DHT_PHASE1_CALC_FAILED = 45, // NTRAvzCgXgnbVvZpmێs + FATAL_ERROR_LOAD_UNKNOWN_BOOTTYPE = 46, // Avu[g^Cvs + FATAL_ERROR_LOAD_AUTH_HEADER_FAILED = 47, // AvROMwb_F؎s + FATAL_ERROR_LOAD_NEVER_STARTED = 48, // [hJnĂȂ̂ɁAF؂Jnꂽ + FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // J[hĂ̂ɁAJ[hAṽ[hJnꂽ + FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // u[gvꂽNTRAvƎۂɃ[hAvTitleIDsv + FATAL_ERROR_DHT_PHASE3_FAILED = 51, // AvNTRzCgXgF؎sitF[YRj + FATAL_ERROR_DHT_PHASE4_FAILED = 52, // AvNTRzCgXgF؎sitF[YSj - FATAL_ERROR_MAX = 51 + FATAL_ERROR_MAX = 53 }FatalErrorCode; @@ -91,26 +93,26 @@ typedef enum FatalErrorCode { #ifdef SDK_ARM9 // obNCg -extern u32 UTL_SetBacklightBrightness( u8 brightness ); // obNCgPxZbg -extern u32 UTL_GetBacklightBrightness( u8 *pBrightness ); // obNCgPxQbg +extern u32 UTL_SetBacklightBrightness( u8 brightness ); // obNCgPxZbg +extern u32 UTL_GetBacklightBrightness( u8 *pBrightness ); // obNCgPxQbg // ^b`pl -extern void UTL_CaribrateTP( const LCFGTWLTPCalibData *pCalib ); // TPLu[V -extern BOOL UTL_IsValidCalibration( u16 x, u16 y, u16 correct_x, u16 correct_y ); // TPLu[VɃ^b`|CgmH +extern void UTL_CaribrateTP( const LCFGTWLTPCalibData *pCalib ); // TPLu[V +extern BOOL UTL_IsValidCalibration( u16 x, u16 y, u16 correct_x, u16 correct_y ); // TPLu[VɃ^b`|CgmH // X[v extern void UTL_GoSleepMode( void ); // RTC֌W -extern BOOL UTL_CheckRTCDate( RTCDate *pDate ); // t킩`FbN -extern BOOL UTL_CheckRTCTime( RTCTime *pTime ); // 킩`FbN -extern s64 UTL_CalcRTCOffset( RTCDate *pNewDate, RTCTime *pNewTime ); // RTCItZbgvZRTCւ̓t`FbNs -extern u32 UTL_GetDayNum( u32 year, u32 month ); // w肳ꂽNE̓擾 -extern BOOL UTL_IsLeapYear100( u32 year ); // w肳ꂽN邤Nׂ +extern BOOL UTL_CheckRTCDate( RTCDate *pDate ); // t킩`FbN +extern BOOL UTL_CheckRTCTime( RTCTime *pTime ); // 킩`FbN +extern s64 UTL_CalcRTCOffset( RTCDate *pNewDate, RTCTime *pNewTime ); // RTCItZbgvZRTCւ̓t`FbNs +extern u32 UTL_GetDayNum( u32 year, u32 month ); // w肳ꂽNE̓擾 +extern BOOL UTL_IsLeapYear100( u32 year ); // w肳ꂽN邤Nׂ // yA^Rg[₢킹 -extern u32 UTL_CalcPCTLInquiryCode( void ); // ₢킹R[hiPOiWjZo -extern u32 UTL_CalcPCTLMasterKey( void ); // }X^[L[@@iPOiTjZoiRTC_GetDategp܂Bj +extern u32 UTL_CalcPCTLInquiryCode( void ); // ₢킹R[hiPOiWjZo +extern u32 UTL_CalcPCTLMasterKey( void ); // }X^[L[@@iPOiTjZoiRTC_GetDategp܂Bj // AvROMwb_̗vEULAtO擾 extern BOOL UTL_IsROMHeaderEULARequired( void ); @@ -121,9 +123,9 @@ extern BOOL UTL_CheckNintendoLogoData( ROM_Header_Short *rh ); #endif // FATALG[ -extern BOOL UTL_IsFatalError( void ); // FATALG[H -extern void UTL_SetFatalError( FatalErrorCode error ); // FATALG[̃Zbg -extern u64 UTL_GetFatalError( void ); // FATALG[Ԃ̎擾iFatalErrorCoderbgɊ蓖ĂĊi[Ă܂Bj +extern BOOL UTL_IsFatalError( void ); // FATALG[H +extern void UTL_SetFatalError( FatalErrorCode error ); // FATALG[̃Zbg +extern u64 UTL_GetFatalError( void ); // FATALG[Ԃ̎擾iFatalErrorCoderbgɊ蓖ĂĊi[Ă܂Bj // [W`FbN @@ -131,21 +133,21 @@ static inline BOOL UTL_CheckAppRegion( u32 card_region_bitmap ) { #ifdef SYSM_BUILD_FOR_DEBUGGER #pragma unused(card_region_bitmap) - return TRUE; + return TRUE; #else - return ( card_region_bitmap & ( 0x00000001 << OS_GetRegion() ) ) ? TRUE : FALSE; + return ( card_region_bitmap & ( 0x00000001 << OS_GetRegion() ) ) ? TRUE : FALSE; #endif } // CRC`FbN static inline BOOL UTL_CheckAppCRC16( ROM_Header_Short *pROMH ) { - u16 calc_crc = SVC_GetCRC16( 65535, pROMH, 0x015e ); - if( ( calc_crc != pROMH->header_crc16 ) || - ( 0xcf56 != pROMH->nintendo_logo_crc16 ) ){ - return FALSE; - } - return TRUE; + u16 calc_crc = SVC_GetCRC16( 65535, pROMH, 0x015e ); + if( ( calc_crc != pROMH->header_crc16 ) || + ( 0xcf56 != pROMH->nintendo_logo_crc16 ) ){ + return FALSE; + } + return TRUE; }