/*---------------------------------------------------------------------------* Project: Horizon File: Importer.cpp Copyright 2009 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev$ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include // cfg:norの初期化に必要 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FileName.h" #include "Importer.h" #include "SdMountManager.h" #include "HeapManager.h" #include "SdReaderWriter.h" #include "CommonLogger.h" #include "FileTransfer.h" #include "common_Types.h" #include "Aes_define.h" #include "configLoader.h" #include "FileChecker.h" #include "VersionDetect.h" #include "SaveDataMover.h" #include "RegionIdModifier.h" #include #include namespace ConsoleRestore { namespace { const size_t IMPORT_THREAD_STACK_SIZE = 0x4000; nn::os::Thread s_ImportThread; nn::os::StackBuffer s_ImportThreadStack; bool s_IsImportSucceeded; const size_t TIME_ZONE_LENGTH = 9; // "+23:45" char s_TimeZoneStr[TIME_ZONE_LENGTH]; TimeZone s_TimeZone; const size_t NTP_SERVER_NAME_LENGTH = 256; char s_NtpServerName[NTP_SERVER_NAME_LENGTH]; bool s_CheckedEqualsRegionDataandRegion = false; bool s_ReadSerialNumber = false; struct SdFileSize { s64 totalFileSize; s64 twlFileSize; s64 twlSoundFileSize; s64 twlPhotoFileSize; s64 ctrFileSize; }; SdFileSize s_SdFileSize; // シリアルナンバー u8 s_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN]; // 空のファイルを作成する bool CreateEmptyFile(const wchar_t* path); // SDからNANDにセーブデータをコピーする void ImportSaveData(); // SDからNORにNORデータをコピーする nn::Result ImportNorData(); // SDカードに保存してあるバージョン情報 common::VerDef s_SDVersionData; // SDカードから読み込んだファイル一覧 common::ImportDataList s_FileLists; u64 s_ImportProgress = 0; } // SDからファイル一覧を読み込む nn::Result ReadFileList(SdFileSize* sdFileSize, common::ImportDataList* fileList); bool RequiresImportApi(); CheckedNetworkSetting s_CurrentNetowrkSetting1; void ConvertTimeZoneString(const char* str) { s_TimeZone.hour = 0; s_TimeZone.minutes = 0; s_TimeZone.isMinus = false; bool hour = true; bool ten = true; u32 count = 0; for(u32 i = 0; i < TIME_ZONE_LENGTH && count < 2; i++) { switch (str[i]) { case ':': { hour = false; } break; case '"': { // 2回読んだら終了 count++; } break; case '+': { s_TimeZone.isMinus = false; } break; case '-': { s_TimeZone.isMinus = true; } break; default: { if(hour) { if(ten) { s_TimeZone.hour += (str[i] - '0') * 10; ten = false; } else { s_TimeZone.hour += str[i] - '0'; ten = true; } } else { if(ten) { s_TimeZone.minutes += (str[i] - '0') * 10; ten = false; } else { s_TimeZone.minutes += str[i] - '0'; ten = true; } } } break; } } NN_LOG("Converted TimeZone = "); if(s_TimeZone.isMinus) { NN_LOG("-"); } NN_LOG("%02d:%02d\n", s_TimeZone.hour, s_TimeZone.minutes); } namespace { bool CreateEmptyFile(const wchar_t* path) { nn::Result result; bool create = false; result = common::SdMountManager::Mount(); if (result.IsSuccess()) { nn::fs::FileOutputStream fos; result = fos.TryInitialize(path, true); if(result.IsSuccess()) { fos.TryFlush(); create = true; } fos.Finalize(); } common::SdMountManager::Unmount(); return create; } } nn::Result ReadSerialNumber(u8* serial) { static nn::Result result = nn::ResultSuccess(); if(s_ReadSerialNumber) { std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo)); return result; } COMMON_LOGGER("Read Serial Number in SD.\n"); size_t readSize; common::SdReaderWriter sdReader; size_t bufSize = 1024; common::HeapManager readHeap(bufSize); void* buf = readHeap.GetAddr(); if(buf != NULL) { result = sdReader.ReadBufWithCmac(common::SERIAL_PATHNAME, buf, bufSize, &readSize); if(result.IsSuccess()) { std::memcpy(s_SerialNo, buf, sizeof(s_SerialNo)); std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo)); s_ReadSerialNumber = true; } } else { result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return result; } nn::Result ExistsDeviceIdFile() { common::SdReaderWriter sdReader; size_t totalSize; size_t bufSize = 1024; common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if(buf == NULL) { return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return sdReader.ReadBufWithCmac(common::DEVICE_ID_PATHNAME, buf, bufSize, &totalSize); } bool EqualsDeviceIdFileandDeviceId(common::HardwareStateManager& manager) { COMMON_LOGGER("Check Device Id\n"); bit32 sdDeviceId; common::SdReaderWriter sdReader; size_t totalSize; size_t bufSize = 1024; common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf == NULL) { return false; } COMMON_LOGGER_RETURN_FALSE_IF_FAILED( sdReader.ReadBufWithCmac(common::DEVICE_ID_PATHNAME, buf, bufSize, &totalSize)); std::memcpy(&sdDeviceId, buf, sizeof(sdDeviceId)); return (manager.GetDeviceId() == sdDeviceId); } nn::Result EqualsRegionDataandRegion() { static nn::Result result = nn::ResultSuccess(); if(s_CheckedEqualsRegionDataandRegion) { return result; } COMMON_LOGGER("Check Region\n"); nn::cfg::CTR::CfgRegionCode region; region = nn::cfg::CTR::GetRegion(); nn::cfg::CTR::CfgRegionCode sdRegion; common::SdReaderWriter sdReader; size_t readSize; size_t bufSize = 1024; common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf != NULL) { result = sdReader.ReadBufWithCmac(common::REGION_DATA_PATHNAME, buf, bufSize, &readSize); if (result.IsSuccess()) { std::memcpy(&sdRegion, buf, sizeof(sdRegion)); s_CheckedEqualsRegionDataandRegion = true; if(region == sdRegion) { result = nn::ResultSuccess(); } else { result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE); } } } else { result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return result; } void SetCountry(nn::cfg::CTR::CfgCountryCode countryCode) { using namespace nn::cfg::CTR; using namespace nn::cfg::CTR::detail; SimpleAddressIdCfgData simpleAddressId; TwlCountryCodeCfgData countryData; nn::cfg::CTR::system::Initialize(); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&simpleAddressId, sizeof(SimpleAddressIdCfgData), GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID))); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&countryData, sizeof(TwlCountryCodeCfgData), GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE))); nn::cfg::CTR::system::Finalize(); simpleAddressId.id = countryCode << CFG_SIMPLE_ADDRESS_ID_COUNTRY_SHIFT; countryData.country = countryCode; nn::cfg::CTR::system::Initialize(); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID), &simpleAddressId, sizeof(SimpleAddressIdCfgData))); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE), &countryData, sizeof(TwlCountryCodeCfgData))); nn::cfg::CTR::system::FlushConfig(); nn::cfg::CTR::system::Finalize(); } void SetLanguage(nn::cfg::CTR::CfgLanguageCode languageCode) { NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::SetConfig( GET_CFG_KEY(nn::cfg::CTR::detail::NN_CFG_USER_INFO, nn::cfg::CTR::detail::NN_CFG_USER_INFO_LANGUAGE), &languageCode, sizeof(nn::cfg::CTR::detail::LanguageCfgData))); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::FlushConfig()); nn::cfg::nor::CTR::Initialize(); NN_UTIL_PANIC_IF_FAILED(nn::cfg::nor::CTR::SetLanguage(static_cast(languageCode))); nn::cfg::nor::CTR::Finalize(); } nn::Result ImportCountryLanguageData() { nn::Result result = nn::ResultSuccess(); // 設定済みなら何もしない if(nn::cfg::CTR::GetCountry() != nn::cfg::CTR::CFG_COUNTRY_UNKNOWN && nn::cfg::CTR::GetCountry() != nn::cfg::CFG_COUNTRY_UNDEFINED) { return result; } if (common::ExistsCountryLanguageFile()) { size_t bufSize = 1024; common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf != NULL) { common::SdReaderWriter sdReader; size_t readSize; result = sdReader.ReadBufWithCmac(common::COUNTRY_SETTING_PATHNAME, buf, bufSize, &readSize); if (result.IsSuccess()) { // SDから読み出し成功 SetCountry(reinterpret_cast (buf)->country); SetLanguage(reinterpret_cast (buf)->language); } COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } } else { // リージョンから適当な国を指定する nn::cfg::CTR::CfgRegionCode region; region = nn::cfg::CTR::GetRegion(); NN_LOG("Country Setting does not exist. Use Default Setting\n"); switch(region) { case nn::cfg::CTR::CFG_REGION_JAPAN: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_JAPAN); } break; case nn::cfg::CTR::CFG_REGION_AMERICA: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_UNITED_STATES); } break; case nn::cfg::CTR::CFG_REGION_EUROPE: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_FRANCE); } break; case nn::cfg::CTR::CFG_REGION_AUSTRALIA: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_AUSTRALIA); } break; case nn::cfg::CTR::CFG_REGION_CHINA: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_CHINA); } break; case nn::cfg::CTR::CFG_REGION_KOREA: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_SOUTH_KOREA); } break; case nn::cfg::CTR::CFG_REGION_TAIWAN: { SetCountry(nn::cfg::CTR::CFG_COUNTRY_TAIWAN); } break; } } return result; } inline u8 DecimalToBcd(u8 param) { u8 theTen, theOne; theTen = param / 10; theOne = param - theTen * 10; return (theTen << 4 | theOne); } nn::Result ImportMcuRtc(common::HardwareStateManager& manager) { COMMON_LOGGER("Import RTC Data.\n"); nn::Result result = nn::ResultSuccess(); nn::Handle handle = manager.GetMcuHandle(); if(handle.IsValid()) { if (common::CheckFileExists(common::MCU_RTC_PATHNAME)) { size_t bufSize = 1024; NN_LOG("AllocatableSize = %d\n", bufSize); common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf != NULL) { common::SdReaderWriter sdReader; size_t readSize; result = sdReader.ReadBufWithCmac(common::MCU_RTC_PATHNAME, buf, bufSize, &readSize); if (result.IsSuccess()) { // mcuを使ってセットする nn::mcu::CTR::HwCheck mcu(handle); nn::mcu::CTR::RtcData* rtc = reinterpret_cast (buf); NN_LOG("RTC = 20%02d/%02d/%02d %02d:%02d:%02d\n", rtc->m_Year, rtc->m_Month, rtc->m_Day, rtc->m_Hour, rtc->m_Minute, rtc->m_Second); // BCD変換が必要 size_t RTC_PARAM_SIZE = sizeof(nn::mcu::CTR::RtcData); u8 bcd[RTC_PARAM_SIZE]; for (int i = 0; i < RTC_PARAM_SIZE; i++) { bcd[i] = DecimalToBcd(reinterpret_cast (rtc)[i]); } const u8 RETRY = 10; for (u8 i = 0; i < RETRY; i++) { result = mcu.WriteBySend(nn::drivers::mcu::CTR::MCU_RTC_SEC_ADDR, bcd, RTC_PARAM_SIZE); COMMON_LOGGER_RESULT_IF_FAILED(result); if(result.IsSuccess()) { break; } nn::os::Thread::Sleep( nn::fnd::TimeSpan::FromMilliSeconds( nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds() % 100)); } } COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } else { COMMON_LOGGER("Failed Allocate Heap!!\n"); result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } } } else { result = nn::Result(nn::Result::LEVEL_PERMANENT, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_HANDLE); } return result; } bool InitializeFileSystem() { nn::Result result; for (u32 i = 0; i < common::TWL_PATHNAME_MAX; i++) { result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[i], common::TWL_FS_ARCHIVE_KIND[i]); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); nn::fs::Directory dir; std::vector entryList; //カレントディレクトリのエントリ一覧を格納 std::vector::iterator entryIndex; std::wstring currentDirectory = common::NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[i]; result = dir.TryInitialize(currentDirectory.c_str()); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); nn::fs::DirectoryEntry entry; s32 numEntry; for (;;) { result = dir.TryRead(&numEntry, &entry, 1); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); if (numEntry == 0) { // ルートディレクトリを閉じる dir.Finalize(); // ルートディレクトリの子を開く for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++) { // ディレクトリなら削除する if (entryIndex->attributes.isDirectory) { NN_LOG("Try Delete %ls%ls/\n", currentDirectory.c_str(), entryIndex->entryName); result = nn::fs::TryDeleteDirectoryRecursively( (currentDirectory + ::std::wstring(entryIndex->entryName)).c_str()); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); } // ファイルなら削除する else { NN_LOG("Try Delete %ls%ls\n", currentDirectory.c_str(), entryIndex->entryName); result = nn::fs::TryDeleteFile( (currentDirectory + ::std::wstring(entryIndex->entryName)).c_str()); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); } } // 削除完了 break; } else { // vectorに保存する entryList.push_back(entry); if (entry.attributes.isDirectory) { NN_LOG("%ls%ls/\n", currentDirectory.c_str(), entry.entryName); } else { NN_LOG("%ls%ls\n", currentDirectory.c_str(), entry.entryName); } } } result = nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[i]); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); } result = nn::am::DeleteAllTwlUserPrograms(); COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); nn::fs::InitializeCtrFileSystem(); return true; } nn::Result ImportIvs() { nn::Result result = nn::ResultSuccess(); nn::fs::FileOutputStream fos; size_t bufSize = 1024; common::HeapManager encHeap(bufSize); void* enc = encHeap.GetAddr(); if (enc != NULL) { common::SdReaderWriter sdReader; size_t readSize; result = sdReader.ReadBufWithCmac(common::IVS_PATHNAME, enc, bufSize, &readSize); if(result.IsSuccess()) { // SDから読み出し成功 result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); if (result.IsSuccess()) { common::HeapManager decHeap(bufSize); void *dec = decHeap.GetAddr(); if (dec != NULL) { // AES復号化する nn::crypto::SwAesCtrContext swAesCtrContest; swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key)); swAesCtrContest.Decrypt(dec, enc, readSize); // IVS書き込み result = fos.TryInitialize(common::IVS_NAND_PATHNAME, true); if (result.IsSuccess()) { if (result.IsSuccess()) { // 2ndNUPからはAPI経由で書き込む if (RequiresImportApi()) { result = nn::fs::CTR::ImportIntegrityVerificationSeed( *reinterpret_cast(dec)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); COMMON_LOGGER("Import SDCI.\n"); } else { s32 writeSize; result = fos.TryWrite(&writeSize, dec, readSize, true); if (result.IsSuccess()) { COMMON_LOGGER("Import SDCI.\n"); } } } } } else { COMMON_LOGGER("Failed Allocate Heap!!\n"); result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } } nn::fs::Unmount(common::NAND_ARCHIVE_NAME); } COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } else { COMMON_LOGGER("Failed Allocate Heap!!\n"); result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return result; } bool ImportIvsData() { return ImportIvs().IsSuccess(); } bool RequiresImportApi() { return common::CUP_MAJOR_VER_2ND_NUP <= s_SDVersionData.cup.majorVersion; } void ImportThreadFunc() { nn::Result result; s_IsImportSucceeded = true; result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); result = common::SdMountManager::Mount(); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); NN_LOG("AllocatableSize = %d\n", bufSize); if(bufSize > common::FILE_COPY_HEAP_SIZE) { bufSize = common::FILE_COPY_HEAP_SIZE; } common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); void* buf = heap.GetAddr(); if (buf != NULL) { // 吸い出したバージョンによって書き込み関数を変える if(RequiresImportApi()) { common::SaveDataMover saveDataMover; saveDataMover.StartImport(buf, bufSize, &s_ImportProgress); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED( saveDataMover.GetLastResult(), s_IsImportSucceeded ); } else { if (!common::CopyDirectory( &s_FileLists, (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH, buf, bufSize, false, NULL, NULL)) { s_IsImportSucceeded = false; return; } } } common::SdMountManager::Unmount(); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); nn::fs::Unmount(common::NAND_ARCHIVE_NAME); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); NN_LOG("Import Thread Finalize\n"); } namespace { void ImportSaveData() { // SDカードからNANDに読み込み nn::Result result; // ファイルサイズ設定 common::InitializeTransferProgress(s_SdFileSize.ctrFileSize); // SDカードにあるセーブデータディレクトリ以下のデータをNANDにコピー COMMON_LOGGER("Import NAND Data Start...\n"); s_ImportThread.Start(ImportThreadFunc, s_ImportThreadStack); } nn::Result ImportNorData() { COMMON_LOGGER("Import NOR Data.\n"); nn::Result result = nn::ResultSuccess(); nn::cfg::nor::CTR::Initialize(); size_t bufSize = common::GetAllocatableSize() / 2; NN_LOG("AllocatableSize = %d\n", bufSize); if(bufSize > common::FILE_COPY_HEAP_SIZE) { bufSize = common::FILE_COPY_HEAP_SIZE; } common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf != NULL) { common::SdReaderWriter sdReader; size_t readSize; result = sdReader.ReadBufWithCmac(common::NOR_PATHNAME, buf, bufSize, &readSize); if(result.IsSuccess()) { // cfgを使ってセットする result = nn::cfg::nor::CTR::SetNtrSetting(&reinterpret_cast(buf)->ntrConfig.ncd, &reinterpret_cast(buf)->ntrConfig.ncd_ex); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // WiFiコネクションIDが仮の値であればWiFi設定は移行しない // TWL修理に準拠している u64 attestedUserId1 = 0; u64 attestedUserId2 = 0; const u32 WIFI_CONNECTION_USERID_OFFSET1 = 0xf0; const u32 WIFI_CONNECTION_USERID_OFFSET2 = 0x1f0; const u32 USERID_SIZE = 6; const bit64 USERID_MASK = 0x7FFFFFFFFFF; // 43bit void* NtrWifiSettingAddr = &reinterpret_cast(buf)->NtrWiFiSetting; std::memcpy(&attestedUserId1, &reinterpret_cast(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET1], USERID_SIZE); attestedUserId1 &= USERID_MASK; std::memcpy(&attestedUserId2, &reinterpret_cast(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET2], USERID_SIZE); attestedUserId2 &= USERID_MASK; if (attestedUserId1 == attestedUserId2 && attestedUserId1 != 0) { // TWL WiFi設定 result = nn::cfg::nor::CTR::WriteTwlWifiSetting(0, reinterpret_cast (buf)->TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // NTR WiFi設定 result = nn::cfg::nor::CTR::WriteNtrWifiSetting(0, reinterpret_cast (buf)->NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } else { // クリアしておく result = nn::cfg::nor::CTR::ClearTwlWifiSetting(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::nor::CTR::ClearNtrWifiSetting(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } } COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } else { COMMON_LOGGER("Failed Allocate Heap!!\n"); result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return result; } } nn::Result ReadVersionData() { nn::Result result = nn::ResultSuccess(); std::memset(&s_SDVersionData, 0, sizeof(common::VerDef)); size_t bufSize = common::GetAllocatableSize() / 2; NN_LOG("AllocatableSize = %d\n", bufSize); if(bufSize > common::FILE_COPY_HEAP_SIZE) { bufSize = common::FILE_COPY_HEAP_SIZE; } common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf != NULL) { common::SdReaderWriter sdReader; size_t readSize; result = sdReader.ReadBufWithCmac(common::VERSION_DATA_PATHNAME, buf, bufSize, &readSize); if(result.IsSuccess()) { // バージョン情報を保持する std::memcpy(&s_SDVersionData, buf, readSize); NN_LOG("SD Version = %02d.%02d.%02d-%02d\n", s_SDVersionData.cup.majorVersion, s_SDVersionData.cup.minorVersion, s_SDVersionData.cup.microVersion, s_SDVersionData.nup.majorVersion); } COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } else { COMMON_LOGGER("Failed Allocate Heap!!\n"); result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return result; } bool ExistsIvsDirectory(std::string& ivsRoot) { nn::Result result; nn::fs::Directory dir; common::SdMountManager::Mount(); result = dir.TryInitialize(common::SD_NINTENDO_3DS_ROOT_PATH); if(result.IsFailure()) { COMMON_LOGGER_RESULT_IF_FAILED(result); common::SdMountManager::Unmount(); return false; } wchar_t ivs[34]; std::mbstowcs(ivs, ivsRoot.c_str(), ivsRoot.size() + 1); nn::fs::DirectoryEntry entry; s32 numEntry; for (;;) { result = dir.TryRead(&numEntry, &entry, 1); if (result.IsFailure()) { dir.Finalize(); common::SdMountManager::Unmount(); return false; } if (numEntry == 0) { dir.Finalize(); common::SdMountManager::Unmount(); return false; } else { // 比較する if (entry.attributes.isDirectory) { NN_LOG("%ls\n", entry.entryName); if(std::wcscmp(ivs, entry.entryName) == 0) { common::SdMountManager::Unmount(); return true; } } } } } nn::Result Cleanup() { nn::Result result; bool execCleanup; result = nn::am::NeedsCleanup(&execCleanup, nn::fs::MEDIA_TYPE_NAND); if(result.IsSuccess()) { if(execCleanup) { COMMON_LOGGER("Cleanup NAND\n"); return nn::am::DoCleanup(nn::fs::MEDIA_TYPE_NAND); } } return result; } void DeleteAllCheckFiles() { nn::Result result; common::SdMountManager::Mount(); for(u32 i = 0; i < sizeof(CHECK_FILENAME_TABLE) / sizeof(CHECK_FILENAME_TABLE[0]); i++) { if(common::CheckFileExists(CHECK_FILENAME_TABLE[i])) { result = nn::fs::TryDeleteFile(CHECK_FILENAME_TABLE[i]); COMMON_LOGGER_RESULT_IF_FAILED(result); } } common::SdMountManager::Unmount(); } void FinalizeImportThread() { s_ImportThread.Join(); s_ImportThread.Finalize(); } bool IsImportThreadFinished() { return s_ImportThread.IsValid() && !s_ImportThread.IsAlive(); } void CreateWriteFinishedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_WRITE_FINISHED]); common::ClearFileCheck(common::EXISTS_WRITE_FINISHED); } void CreateConsoleInitializedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_CONSOLE_INTIALIZED]); common::ClearFileCheck(common::EXISTS_CONSOLE_INTIALIZED); } void CreateUpdateFinishedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_UPDATE_FINISHED]); common::ClearFileCheck(common::EXISTS_UPDATE_FINISHED); } void CreateRtcSyncFinishedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_RTC_SYNC_FINISHED]); common::ClearFileCheck(common::EXISTS_RTC_SYNC_FINISHED); } void CreateDownloadIvsFinishedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DOWNLOAD_IVS]); common::ClearFileCheck(common::EXISTS_DOWNLOAD_IVS); } void CreateDeleteAccountFinishedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DELETE_ACCOUNT]); common::ClearFileCheck(common::EXISTS_DELETE_ACCOUNT); } void CreateTransferAccountFinishedFile() { CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_TRANSFER_ACCOUNT]); common::ClearFileCheck(common::EXISTS_TRANSFER_ACCOUNT); } u32 GetImportProgress() { if(RequiresImportApi()) { return s_ImportProgress; } else { return common::GetProgress(); } } u32 GetImportProgressTwlNand() { return common::GetProgress(); } bool UpdateNetworkSetting(nn::ac::NetworkSetting& networkSetting) { nn::Result result; bool retval = true; result = nn::ac::InitializeInternal(); if(result.IsFailure()) { retval = false; COMMON_LOGGER("Error: nn::ac::InitializeInternal() failed\n"); } else { //特に入力させる必要のない自動で設定する項目 networkSetting.wireless.enable = true; networkSetting.wireless.multiSsid.enable = false; networkSetting.ip.enableDHCP = true; networkSetting.scanlessConnect.hasConnected = false; networkSetting.proxy.enable = false; networkSetting.other.enableUPnP = false; // 現在のインターネット設定1を一時的に保持 result = nn::ac::LoadNetworkSetting(0, s_CurrentNetowrkSetting1.setting); if(result.IsSuccess()) { s_CurrentNetowrkSetting1.isValid = true; } else { s_CurrentNetowrkSetting1.isValid = false; } result = nn::ac::UpdateNetworkSetting( 0, networkSetting ); if(!result.IsSuccess()) { retval = false; COMMON_LOGGER("Error: SetNetworkSetting (Update Error)\n"); } else { // 設定が変わるので切断しておく nn::ac::CloseAll(); result = nn::ac::FinalizeInternal(); if (!result.IsSuccess()) { retval = false; COMMON_LOGGER("Error: SetNetworkSetting (Finalize Error)\n"); } } } return retval; } void ReadSettingFlag(common::ConfigFileLoader* loader, const wchar_t* paramName, bool* flag, const char* logMessage) { NN_NULL_ASSERT(flag); if (loader->ReadAsChar(paramName) != NULL) { s32 num = loader->ReadAsInteger(paramName); if (num == 1) { *flag = true; COMMON_LOGGER(logMessage); } } } bool ReadSetting(bool* nupOnly, bool* getIvs, bool* checkSd, bool* skipNup, bool* dlPreinstall) { nn::Result result; bool retval = true; common::ConfigFileLoader configfileLoader; common::SdMountManager::Mount(); size_t size = 10240; common::HeapManager heap(size); void* heapAddr = heap.GetAddr(); if(heapAddr != NULL) { result = configfileLoader.Initialize(common::AP_SETTING_PATHNAME, heapAddr, size); if (result.IsSuccess()) { nn::ac::NetworkSetting networkSetting; { const char* ssid = configfileLoader.ReadAsChar(L"SSID"); // SSID if(ssid == NULL) { COMMON_LOGGER("SSID: is missing\n"); retval = false; } else { std::strncpy(reinterpret_cast (networkSetting.wireless.essidSecurity.ssid), ssid, 32); networkSetting.wireless.essidSecurity.ssidLength = std::strlen(ssid) % 33; COMMON_LOGGER("SSID = %s\n", networkSetting.wireless.essidSecurity.ssid); } } { const char* mode = configfileLoader.ReadAsChar(L"MODE"); // MODE if(mode == NULL) { COMMON_LOGGER("MODE: is missing\n"); retval = false; } else { if (std::strcmp(mode, "OPEN") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN; } else if (std::strcmp(mode, "WEP40") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_40BIT; } else if (std::strcmp(mode, "WEP104") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_104BIT; } else if (std::strcmp(mode, "WEP128") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_128BIT; } else if (std::strcmp(mode, "WPA-TKIP") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_TKIP; } else if (std::strcmp(mode, "WPA2-TKIP") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_TKIP; } else if (std::strcmp(mode, "WPA-AES") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_AES; } else if (std::strcmp(mode, "WPA2-AES") == 0) { networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_AES; } else { networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN; } switch (networkSetting.wireless.essidSecurity.securityMode) { case nn::ac::OPEN: { COMMON_LOGGER("MODE = OPEN\n"); } break; case nn::ac::WEP_40BIT: { COMMON_LOGGER("MODE = WEP_40BIT\n"); } break; case nn::ac::WEP_104BIT: { COMMON_LOGGER("MODE = WEP_104BIT\n"); } break; case nn::ac::WEP_128BIT: { COMMON_LOGGER("MODE = WEP_128BIT\n"); } break; case nn::ac::WPA_TKIP: { COMMON_LOGGER("MODE = WPA_TKIP\n"); } break; case nn::ac::WPA2_TKIP: { COMMON_LOGGER("MODE = WPA2_TKIP\n"); } break; case nn::ac::WPA_AES: { COMMON_LOGGER("MODE = WPA_AES\n"); } break; case nn::ac::WPA2_AES: { COMMON_LOGGER("MODE = WPA2_AES\n"); } break; } } } { const char* pass = configfileLoader.ReadAsChar(L"PASS"); // PASS if(pass == NULL) { COMMON_LOGGER("PASS: is missing\n"); retval = false; } else { switch (networkSetting.wireless.essidSecurity.securityMode) { case nn::ac::WEP_40BIT: case nn::ac::WEP_104BIT: case nn::ac::WEP_128BIT: { std::strncpy(reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase), pass, 64); std::memcpy(networkSetting.wireless.essidSecurity.key, networkSetting.wireless.essidSecurity.passphrase, 64); } break; case nn::ac::WPA_TKIP: case nn::ac::WPA2_TKIP: case nn::ac::WPA_AES: case nn::ac::WPA2_AES: { std::strncpy(reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase), pass, 64); size_t phrase_size = std::strlen( reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase)); nn::nwm::Ssid ssid(reinterpret_cast (networkSetting.wireless.essidSecurity.ssid)); nn::nwm::ConvertPasswordToPsk( reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase), phrase_size, ssid, networkSetting.wireless.essidSecurity.key); } break; case nn::ac::OPEN: default: { //do nothing } break; } } } { s32 dnsAuto; // DNS_AUTO if(configfileLoader.ReadAsChar(L"DNS_AUTO") == NULL) { COMMON_LOGGER("DNS_AUTO: is missing\n"); retval = false; } else { dnsAuto = configfileLoader.ReadAsInteger(L"DNS_AUTO"); if (dnsAuto == 1) { networkSetting.ip.autoDNSSetting = true; } else { networkSetting.ip.autoDNSSetting = false; } COMMON_LOGGER("DNS_AUTO = %d\n", networkSetting.ip.autoDNSSetting); } } { const char* dnsPrimary = configfileLoader.ReadAsChar(L"DNS_PRI"); // プライマリDNS if(!networkSetting.ip.autoDNSSetting) { if (dnsPrimary == NULL) { COMMON_LOGGER("DNS_PRI: is missing\n"); retval = false; } else { u8 dns[4]; nn::socket::InAddr addr; if (1 == nn::socket::InetAtoN(dnsPrimary, &addr)) { dns[3] = (0xff & (addr.addr >> 24)); dns[2] = (0xff & (addr.addr >> 16)); dns[1] = (0xff & (addr.addr >> 8)); dns[0] = (0xff & (addr.addr)); } std::memcpy(networkSetting.ip.dns[0], dns, 4); COMMON_LOGGER("DNS_PRI = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[0][0], networkSetting.ip.dns[0][1], networkSetting.ip.dns[0][2], networkSetting.ip.dns[0][3]); } } } { const char* dnsSecondary = configfileLoader.ReadAsChar(L"DNS_SEC"); // セカンダリDNS if(!networkSetting.ip.autoDNSSetting) { if(dnsSecondary == NULL) { COMMON_LOGGER("DNS_SEC: is missing\n"); retval = false; } else { u8 dns[4]; nn::socket::InAddr addr; if (1 == nn::socket::InetAtoN(dnsSecondary, &addr)) { dns[3] = (0xff & (addr.addr >> 24)); dns[2] = (0xff & (addr.addr >> 16)); dns[1] = (0xff & (addr.addr >> 8)); dns[0] = (0xff & (addr.addr)); } std::memcpy(networkSetting.ip.dns[1], dns, 4); COMMON_LOGGER("DNS_SEC = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[1][0], networkSetting.ip.dns[1][1], networkSetting.ip.dns[1][2], networkSetting.ip.dns[1][3]); } } } { const char* ntpServerName = configfileLoader.ReadAsChar(L"NTPSRV"); // NTPサーバ if(ntpServerName == NULL) { COMMON_LOGGER("NTPSRV: is missing\n"); retval = false; } else { std::strlcpy(s_NtpServerName, ntpServerName, sizeof(s_NtpServerName)); COMMON_LOGGER("NTPSRV = %s\n", s_NtpServerName); } } { const char* timeZone = configfileLoader.ReadAsChar(L"TIMEZONE"); // タイムゾーン if(timeZone == NULL) { COMMON_LOGGER("TIMEZONE: is missing\n"); retval = false; } else { std::strlcpy(s_TimeZoneStr, timeZone, sizeof(s_TimeZoneStr)); COMMON_LOGGER("TIMEZONE = %s\n", s_TimeZoneStr); ConvertTimeZoneString(s_TimeZoneStr); } } ReadSettingFlag(&configfileLoader, L"NUP_ONLY", nupOnly, "NUP Only Mode.\n"); ReadSettingFlag(&configfileLoader, L"GET_SDCI", getIvs, "GET SDCI Mode.\n"); ReadSettingFlag(&configfileLoader, L"CHECK_SD", checkSd, "CHECK SD Mode.\n"); ReadSettingFlag(&configfileLoader, L"SKIP_NUP", skipNup, "Skip NUP Mode.\n"); ReadSettingFlag(&configfileLoader, L"DL_PREINSTALL", dlPreinstall, "Download PreInstall Application Mode.\n"); configfileLoader.Finalize(); // 書き込み完了しなければfalse if(!UpdateNetworkSetting(networkSetting)) { retval = false; } } else { NN_LOG("configfileLoader Initialize Failed\n"); COMMON_LOGGER_RESULT_IF_FAILED(result); retval = false; } } else { NN_LOG("Can't Allocate Heap\n"); COMMON_LOGGER_RESULT_IF_FAILED(result); retval = false; } common::SdMountManager::Unmount(); return retval; } char* GetNtpServerName() { return s_NtpServerName; } TimeZone GetTimeZone() { return s_TimeZone; } CheckedNetworkSetting* GetTempNetworkSetting() { return &s_CurrentNetowrkSetting1; } void ImportTwlData(enum common::TWL_PATH_INDEX path, s64 fileSize) { NN_ASSERT(path < common::TWL_PATHNAME_MAX); nn::Result result; s_IsImportSucceeded = true; result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[path], common::TWL_FS_ARCHIVE_KIND[path]); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); result = common::SdMountManager::Mount(); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); NN_LOG("AllocatableSize = %d\n", bufSize); if(bufSize > common::FILE_COPY_HEAP_SIZE) { bufSize = common::FILE_COPY_HEAP_SIZE; } // ファイルサイズ設定 common::InitializeTransferProgress(fileSize); common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); void* buf = heap.GetAddr(); if (buf != NULL) { wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH]; ::std::mbstowcs(archiveName, common::TWL_ARCHIVE_NAME_TABLE[path], std::strlen(common::TWL_ARCHIVE_NAME_TABLE[path]) + 1); std::wstring archiveString(archiveName); if(!common::CopyDirectory( &s_FileLists, (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(), (archiveString + ::std::wstring(L"/")).c_str(), buf, bufSize, false, NULL, NULL)) { s_IsImportSucceeded = false; return; } } common::SdMountManager::Unmount(); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); } void ImportTwlTitleSaveData(s64 fileSize) { nn::Result result; s_IsImportSucceeded = true; result = nn::fs::MountSpecialArchive(common::NAND_TWL_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_TWL_NAND); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); result = common::SdMountManager::Mount(); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); NN_LOG("AllocatableSize = %d\n", bufSize); if(bufSize > common::FILE_COPY_HEAP_SIZE) { bufSize = common::FILE_COPY_HEAP_SIZE; } // ファイルサイズ設定 common::InitializeTransferProgress(fileSize); common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); void* buf = heap.GetAddr(); if (buf != NULL) { if(!common::CopyDirectory( &s_FileLists, (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(), (std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH) + ::std::wstring(L"/")).c_str(), buf, bufSize, false, NULL, NULL)) { s_IsImportSucceeded = false; return; } } common::SdMountManager::Unmount(); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); nn::fs::Unmount(common::NAND_TWL_ARCHIVE_NAME); COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); } void ImportTwlPhotoDataFunc() { COMMON_LOGGER("Import Twl Photo Data.\n"); ImportTwlData(common::TWL_PHOTO, s_SdFileSize.twlPhotoFileSize); } void ImportTwlSoundDataFunc() { COMMON_LOGGER("Import Twl Sound Data.\n"); ImportTwlData(common::TWL_SOUND, s_SdFileSize.twlSoundFileSize); } void ImportTwlSaveDataFunc() { COMMON_LOGGER("Import Twl Save Data.\n"); ImportTwlTitleSaveData(s_SdFileSize.twlFileSize); } void ImportTwlPhotoData() { s_ImportThread.Start(ImportTwlPhotoDataFunc, s_ImportThreadStack); } void ImportTwlSoundData() { s_ImportThread.Start(ImportTwlSoundDataFunc, s_ImportThreadStack); } void ImportTwlSaveData() { s_ImportThread.Start(ImportTwlSaveDataFunc, s_ImportThreadStack); } void ClearFileReadResult() { s_CheckedEqualsRegionDataandRegion = false; s_ReadSerialNumber = false; } nn::Result ExportCalData() { using namespace nn::cfg::CTR::detail; nn::Result result; common::CfgCalData cfgCalData; common::SdReaderWriter sdWriter; COMMON_LOGGER("Export CalData\n"); result = common::SdMountManager::Mount(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData), GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData), GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.fcramCfgData, sizeof(FcramCfgData), GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.rtcCfgData, sizeof(RtcCfgData), GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData), GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.accelCfgData, sizeof(AccelCfgData), GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.codecCfgData, sizeof(CodecCfgData), GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::GetConfig(&cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData), GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = sdWriter.WriteBufWithCmac(common::CFG_CALIBRATION_PATHNAME, &cfgCalData, sizeof(cfgCalData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = common::SdMountManager::Unmount(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); return nn::ResultSuccess(); } nn::Result ImportCalData(common::CfgCalData *data) { using namespace nn::cfg::CTR::detail; nn::Result result = nn::ResultSuccess(); COMMON_LOGGER("Import CalData\n"); common::SdMountManager::Mount(); size_t bufSize = common::GetAllocatableSize() / 2; if(bufSize > common::FILE_COPY_HEAP_SIZE) { bufSize = common::FILE_COPY_HEAP_SIZE; } common::HeapManager heap(bufSize); void* buf = heap.GetAddr(); if (buf != NULL) { common::SdReaderWriter sdReader; size_t readSize; result = sdReader.ReadBufWithCmac(common::CFG_CALIBRATION_PATHNAME, buf, bufSize, &readSize); if(result.IsSuccess()) { // SDから読み出し成功 std::memcpy(data, buf, readSize); } COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } else { result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } common::SdMountManager::Unmount(); return result; } nn::Result InitializeHardwareDependentSetting() { using namespace nn::cfg::CTR::detail; nn::Result result = nn::ResultSuccess(); common::CfgCalData cfgCalData; result = ImportCalData(&cfgCalData); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL), &cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER), &cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY), &cfgCalData.fcramCfgData, sizeof(FcramCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION), &cfgCalData.rtcCfgData, sizeof(RtcCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE), &cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER), &cfgCalData.accelCfgData, sizeof(AccelCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL), &cfgCalData.codecCfgData, sizeof(CodecCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME), &cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData)); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); NN_LOG("Set cfgCalData\n"); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); nn::cfg::CTR::init::ResetCameraCalibration(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); nn::cfg::CTR::init::ResetAnalogStickCalibration(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); return result; } nn::Result SetupVersionAndFileList() { std::memset(&s_SdFileSize, 0, sizeof(s_SdFileSize)); // ファイル一覧を読み込む nn::Result result = ReadFileList(&s_SdFileSize, &s_FileLists); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // バージョンデータを読み込む result = ReadVersionData(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); return result; } nn::Result ReadFileList(SdFileSize* sdFiles, common::ImportDataList* fileList) { nn::Result result = nn::ResultSuccess(); COMMON_LOGGER("Read File List\n"); size_t readSize; common::SdReaderWriter sdReader; s64 fileSize; { nn::fs::FileInputStream file; // サイズ取得のため一時的に開く result = file.TryInitialize(common::FILE_LIST_PATHNAME); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = file.TryGetSize(&fileSize); if (result.IsFailure()) { file.Finalize(); return result; } file.Finalize(); } // 初期化状態の場合は空 if(fileSize == nn::crypto::AES_CMAC_MAC_SIZE) { sdFiles->ctrFileSize = 0; sdFiles->totalFileSize = 0; sdFiles->twlFileSize = 0; sdFiles->twlPhotoFileSize = 0; sdFiles->twlSoundFileSize = 0; return nn::ResultSuccess(); } common::HeapManager heap(fileSize); void* buf = heap.GetAddr(); if(buf != NULL) { result = sdReader.ReadBufWithCmac(common::FILE_LIST_PATHNAME, buf, fileSize, &readSize); if(result.IsSuccess()) { // ファイル一覧 const char comma[] = ","; const char newLine[] = "\n"; char *token = NULL; token = std::strtok(reinterpret_cast(buf), comma); bool parseFileName = false; common::ImportDataEntry entry; entry.fileName = std::string(token); while( token != NULL) { if(parseFileName) { token = std::strtok(NULL, comma); if(token != NULL) { entry.fileName = std::string(token); } } else { token = std::strtok(NULL, newLine); if(token != NULL) { s64 size = std::atoll(token); if(size != -1) { entry.isDirectory = false; sdFiles->totalFileSize += size; wchar_t wcToken[nn::fs::MAX_FILE_PATH_LENGTH]; if(std::mbstowcs(wcToken, entry.fileName.c_str(), entry.fileName.size()) != entry.fileName.size() - 1) { if(std::wcsstr(wcToken, common::SD_SAVEDATA_ROOT_NAME) != NULL) { sdFiles->ctrFileSize += size; } else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME) != NULL) { sdFiles->twlPhotoFileSize += size; } else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME) != NULL) { sdFiles->twlSoundFileSize += size; } else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_ROOT_NAME) != NULL) { sdFiles->twlFileSize += size; } } } else { entry.isDirectory = true; } fileList->push_back(entry); } } parseFileName = !parseFileName; } } } else { result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY); } return result; } bool IsImportSucceeded() { return s_IsImportSucceeded; } void ReadRegionFile(const wchar_t* path, void** decode, size_t* size) { if(path == NULL) { return; } char filePath[256]; std::wcstombs(filePath, path, sizeof(filePath)); char prefix[] = "rom:/regionData/"; char fullPath[256]; std::memset(fullPath, 0, sizeof(fullPath)); strlcpy(fullPath, prefix, sizeof(fullPath)); strlcat(fullPath, filePath, 256 - strlen(fullPath)); NN_LOG("regionData: %s\n", fullPath); nn::fs::FileInputStream file; file.Initialize(fullPath); s64 fileSize = file.GetSize(); common::HeapManager heap(fileSize, AES_BLOCK_SIZE); void* buf = heap.GetAddr(); file.Read(buf, fileSize); *size = nn::cx::GetUncompressedSize(buf); nn::cx::UncompressLZ(buf, *decode); } void RepairSimpleAddress() { nn::cfg::CTR::SimpleAddress sa; nn::cfg::CTR::GetSimpleAddress(&sa); RegionIdModifier rim(sa.id >> 16, s_SDVersionData.nup.majorVersion, nn::cfg::CTR::GetRegion(), sa.regionName[0]); if(rim.IsValid()) { // 壊れていなければ何もしない return; } COMMON_LOGGER("Repair SimpleAddress.\n"); size_t size; PathList filePath[3]; u8 modifiedId; common::HeapManager heap(common::FILE_COPY_HEAP_SIZE / 8 , AES_BLOCK_SIZE); void* buf = heap.GetAddr(); size_t fileNum = rim.GetFilePathNum(); std::memset(filePath, 0, sizeof(filePath)); std::memcpy(filePath, rim.GetFilePath(), sizeof(PathList) * fileNum); for (u8 i = 0; i < fileNum; i++) { ReadRegionFile(filePath[fileNum - i - 1].path, &buf, &size); if (rim.GetValidRegionId(buf, size, &modifiedId)) { NN_LOG("CurrentRegionId = %02x\n", (sa.id >> 16) & 0x00ff); NN_LOG("ValidRegionId = %02x\n", modifiedId); using namespace nn::cfg::CTR; using namespace nn::cfg::CTR::detail; nn::cfg::CTR::system::Initialize(); SimpleAddressIdCfgData simpleAddressId; NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&simpleAddressId, sizeof(SimpleAddressIdCfgData), GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID))); simpleAddressId.id = (simpleAddressId.id & 0xff00ffff) | (modifiedId << CFG_SIMPLE_ADDRESS_ID_REGION_SHIFT); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID), &simpleAddressId, sizeof(SimpleAddressIdCfgData))); NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::FlushConfig()); nn::cfg::CTR::system::Finalize(); } } } void RestoreCurrentInternetSetting() { COMMON_LOGGER("Restore Current Internet Setting\n"); nn::Result result; if (GetTempNetworkSetting()->isValid) { result = nn::ac::CTR::UpdateNetworkSetting(0, GetTempNetworkSetting()->setting); COMMON_LOGGER_RESULT_IF_FAILED(result); } else { // 無効の場合は消去しておく result = nn::ac::CTR::RemoveNetworkSetting(0); COMMON_LOGGER_RESULT_IF_FAILED(result); } result = nn::ac::FlushNetworkSetting(); COMMON_LOGGER_RESULT_IF_FAILED(result); result = nn::ac::FinalizeInternal(); COMMON_LOGGER_RESULT_IF_FAILED(result); } nn::Result ImportData() { static nn::Result result = nn::ResultSuccess(); static bool init = true; if(init) { init = false; // インポート前にACを止める result = nn::ndm::SuspendScheduler(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // NANDのごみを削除する result = Cleanup(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // NORデータを書き込む result = ImportNorData(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // 固体固有calLデータをSDカードに出力する // 本体初期化後はcal値が設定されている result = ExportCalData(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // SDカードのセーブデータをNANDに書き込む ImportSaveData(); } return result; } }