From d26a46feed4ef6caeebfb21e69b10c2b913eb4eb Mon Sep 17 00:00:00 2001 From: tech4me Date: Sat, 25 Aug 2018 22:43:17 -0700 Subject: [PATCH] set: Fixed GetAvailableLanguageCodes() to follow the max_entries Rightnow, in games use GetAvailableLanguageCodes(), there is a WriteBuffer() with size larger than the buffer_size. (Core Critical core\hle\kernel\hle_ipc.cpp:WriteBuffer:296: size (0000000000000088) is greater than buffer_size (0000000000000078)) 0x88 = 17(languages) * 8 0x78 = 15(languages) * 8 GetAvailableLanguageCodes() can only support 15 languages. After firmware 4.0.0 there are 17 supported language instead of 15, to enable this GetAvailableLanguageCodes2() need to be used. So GetAvailableLanguageCodes() will be caped at 15 languages. Reference: http://switchbrew.org/index.php/Settings_services --- src/core/hle/service/set/set.cpp | 51 +++++++++++++++++++++++++++----- src/core/hle/service/set/set.h | 2 ++ 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index a461e72ec4..92b0640e80 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -32,24 +32,59 @@ constexpr std::array available_language_codes = {{ LanguageCode::ZH_HANT, }}; +constexpr size_t pre4_0_0_max_entries = 0xF; +constexpr size_t post4_0_0_max_entries = 0x40; + LanguageCode GetLanguageCodeFromIndex(size_t index) { return available_language_codes.at(index); } -void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { - ctx.WriteBuffer(available_language_codes); +template +static std::array MakeLanguageCodeSubset() { + std::array arr; + std::copy_n(available_language_codes.begin(), size, arr.begin()); + return arr; +} +static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, size_t max_size) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(available_language_codes.size())); + if (available_language_codes.size() > max_size) + rb.Push(static_cast(max_size)); + else + rb.Push(static_cast(available_language_codes.size())); +} + +void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { + if (available_language_codes.size() > pre4_0_0_max_entries) + ctx.WriteBuffer(MakeLanguageCodeSubset()); + else + ctx.WriteBuffer(available_language_codes); + + PushResponseLanguageCode(ctx, pre4_0_0_max_entries); + + LOG_DEBUG(Service_SET, "called"); +} + +void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { + if (available_language_codes.size() > post4_0_0_max_entries) + ctx.WriteBuffer(MakeLanguageCodeSubset()); + else + ctx.WriteBuffer(available_language_codes); + + PushResponseLanguageCode(ctx, post4_0_0_max_entries); LOG_DEBUG(Service_SET, "called"); } void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(available_language_codes.size())); + PushResponseLanguageCode(ctx, pre4_0_0_max_entries); + + LOG_DEBUG(Service_SET, "called"); +} + +void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { + PushResponseLanguageCode(ctx, post4_0_0_max_entries); LOG_DEBUG(Service_SET, "called"); } @@ -69,8 +104,8 @@ SET::SET() : ServiceFramework("set") { {2, nullptr, "MakeLanguageCode"}, {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, {4, nullptr, "GetRegionCode"}, - {5, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes2"}, - {6, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount2"}, + {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, + {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, {7, nullptr, "GetKeyCodeMap"}, {8, nullptr, "GetQuestFlag"}, }; diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 4232b6162b..669e740b73 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -38,7 +38,9 @@ public: private: void GetLanguageCode(Kernel::HLERequestContext& ctx); void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); + void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx); void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); + void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); }; } // namespace Service::Set