From c10ba679739c49790344653c9d7fc6b6e8b8bd46 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 26 Nov 2019 20:58:39 -0800 Subject: [PATCH] ams_mitm: Implement system settings mitm --- .../ams_mitm/source/amsmitm_debug.cpp | 54 +++ .../ams_mitm/source/amsmitm_debug.hpp | 23 ++ .../ams_mitm/source/amsmitm_fs_utils.cpp | 2 +- .../source/amsmitm_initialization.cpp | 9 +- stratosphere/ams_mitm/source/amsmitm_main.cpp | 4 +- .../source/bpc_mitm/bpcmitm_module.cpp | 4 - .../source/set_mitm/setmitm_module.cpp | 5 + .../source/set_mitm/setsys_mitm_service.cpp | 18 + .../source/set_mitm/setsys_mitm_service.hpp | 7 + .../set_mitm/settings_fwdbg_api_override.cpp | 43 +++ .../source/set_mitm/settings_sd_kvs.cpp | 346 ++++++++++++++++++ .../source/set_mitm/settings_sd_kvs.hpp | 26 ++ .../dmnt/source/cheat/impl/dmnt_cheat_api.cpp | 5 +- stratosphere/fatal/source/fatal_config.cpp | 9 +- stratosphere/libstratosphere/Makefile | 2 +- .../atmosphere/results/results_common.hpp | 3 + .../atmosphere/results/settings_results.hpp | 6 +- .../include/stratosphere/settings.hpp | 2 + .../settings/settings_fwdbg_api.hpp | 28 ++ .../settings/settings_fwdbg_types.hpp | 38 ++ .../source/boot2/boot2_api.cpp | 3 +- .../source/settings/settings_fwdbg_api.cpp | 35 ++ .../sf/cmif/sf_cmif_service_dispatch.cpp | 4 +- .../libstratosphere/source/util/ini.h | 2 +- .../ro/source/impl/ro_service_impl.cpp | 7 +- 25 files changed, 655 insertions(+), 30 deletions(-) create mode 100644 stratosphere/ams_mitm/source/amsmitm_debug.cpp create mode 100644 stratosphere/ams_mitm/source/amsmitm_debug.hpp create mode 100644 stratosphere/ams_mitm/source/set_mitm/settings_fwdbg_api_override.cpp create mode 100644 stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp create mode 100644 stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp create mode 100644 stratosphere/libstratosphere/source/settings/settings_fwdbg_api.cpp diff --git a/stratosphere/ams_mitm/source/amsmitm_debug.cpp b/stratosphere/ams_mitm/source/amsmitm_debug.cpp new file mode 100644 index 000000000..2b09d8bd6 --- /dev/null +++ b/stratosphere/ams_mitm/source/amsmitm_debug.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "amsmitm_debug.hpp" + +namespace ams::mitm { + + namespace { + + os::Mutex g_throw_lock; + bool g_threw; + Result g_throw_result; + + + void DebugThrowThreadFunc(void *arg); + + constexpr size_t DebugThrowThreadStackSize = 0x4000; + constexpr int DebugThrowThreadPriority = 49; + os::StaticThread g_debug_throw_thread(&DebugThrowThreadFunc, nullptr, DebugThrowThreadPriority); + + void DebugThrowThreadFunc(void *arg) { + /* TODO: Better heuristic for fatal startup than sleep. */ + svcSleepThread(10'000'000'000ul); + fatalThrow(g_throw_result.GetValue()); + } + + } + + void ThrowResultForDebug(Result res) { + std::scoped_lock lk(g_throw_lock); + + if (g_threw) { + return; + } + + g_throw_result = res; + g_threw = true; + R_ASSERT(g_debug_throw_thread.Start()); + } + +} diff --git a/stratosphere/ams_mitm/source/amsmitm_debug.hpp b/stratosphere/ams_mitm/source/amsmitm_debug.hpp new file mode 100644 index 000000000..b77443852 --- /dev/null +++ b/stratosphere/ams_mitm/source/amsmitm_debug.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::mitm { + + void ThrowResultForDebug(Result res); + +} diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp index 70e924897..af7b8d454 100644 --- a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp @@ -26,7 +26,7 @@ namespace ams::mitm::fs { /* Helpers. */ Result EnsureSdInitialized() { - R_UNLESS(mitm::IsInitialized(), ams::fs::ResultSdCardNotPresent()); + R_UNLESS(serviceIsActive(&g_sd_filesystem.s), ams::fs::ResultSdCardNotPresent()); return ResultSuccess(); } diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp index 1537e81bb..fe3e2a80b 100644 --- a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp @@ -16,6 +16,7 @@ #include #include "amsmitm_initialization.hpp" #include "amsmitm_fs_utils.hpp" +#include "bpc_mitm/bpc_ams_power_utils.hpp" namespace ams::mitm { @@ -35,11 +36,15 @@ namespace ams::mitm { /* Wait for the SD card to be ready. */ cfg::WaitSdCardInitialized(); - /* TODO: Other initialization tasks. */ - /* Open global SD card file system, so that other threads can begin using the SD. */ mitm::fs::OpenGlobalSdCardFileSystem(); + /* Initialize the reboot manager (load a payload off the SD). */ + /* Discard result, since it doesn't need to succeed. */ + mitm::bpc::LoadRebootPayload(); + + /* TODO: Other initialization tasks. */ + /* Signal to waiters that we are ready. */ g_init_event.Signal(); } diff --git a/stratosphere/ams_mitm/source/amsmitm_main.cpp b/stratosphere/ams_mitm/source/amsmitm_main.cpp index 505e5346c..1da942444 100644 --- a/stratosphere/ams_mitm/source/amsmitm_main.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_main.cpp @@ -15,6 +15,7 @@ */ #include "amsmitm_initialization.hpp" #include "amsmitm_module_management.hpp" +#include "bpc_mitm/bpc_ams_power_utils.hpp" extern "C" { extern u32 __start__; @@ -50,8 +51,7 @@ namespace ams { /* Override. */ void ExceptionHandler(FatalErrorContext *ctx) { /* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */ - /* Utils::RebootToFatalError(ctx); */ - while (1) { /* ... */ } + mitm::bpc::RebootForFatalError(ctx); } } diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp index b55c0f6c9..3e75f4e9f 100644 --- a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp @@ -41,10 +41,6 @@ namespace ams::mitm::bpc { /* Wait until initialization is complete. */ mitm::WaitInitialized(); - /* Initialize the reboot manager (load a payload off the SD). */ - /* Discard result, since it doesn't need to succeed. */ - LoadRebootPayload(); - /* Create bpc:ams. */ { Handle bpcams_h; diff --git a/stratosphere/ams_mitm/source/set_mitm/setmitm_module.cpp b/stratosphere/ams_mitm/source/set_mitm/setmitm_module.cpp index 33f5ff094..801561e48 100644 --- a/stratosphere/ams_mitm/source/set_mitm/setmitm_module.cpp +++ b/stratosphere/ams_mitm/source/set_mitm/setmitm_module.cpp @@ -13,9 +13,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "../amsmitm_initialization.hpp" #include "setmitm_module.hpp" #include "set_mitm_service.hpp" #include "setsys_mitm_service.hpp" +#include "settings_sd_kvs.hpp" namespace ams::mitm::settings { @@ -40,6 +42,9 @@ namespace ams::mitm::settings { /* Wait until initialization is complete. */ mitm::WaitInitialized(); + /* Load settings off the SD card. */ + ams::settings::fwdbg::InitializeSdCardKeyValueStore(); + /* Create mitm servers. */ R_ASSERT(g_server_manager.RegisterMitmServer(SetMitmServiceName)); R_ASSERT(g_server_manager.RegisterMitmServer(SetSysMitmServiceName)); diff --git a/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.cpp b/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.cpp index d425c23e0..18df2ee9f 100644 --- a/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.cpp +++ b/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ #include "setsys_mitm_service.hpp" +#include "settings_sd_kvs.hpp" namespace ams::mitm::settings { @@ -98,5 +99,22 @@ namespace ams::mitm::settings { return GetFirmwareVersionImpl(out.GetPointer(), this->client_info); } + Result SetSysMitmService::GetSettingsItemValueSize(sf::Out out_size, const settings::fwdbg::SettingsName &name, const settings::fwdbg::SettingsItemKey &key) { + R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValueSize(out_size.GetPointer(), name.value, key.value)) { + R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged) + R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession()); + } R_END_TRY_CATCH; + + return ResultSuccess(); + } + + Result SetSysMitmService::GetSettingsItemValue(sf::Out out_size, const sf::OutBuffer &out, const settings::fwdbg::SettingsName &name, const settings::fwdbg::SettingsItemKey &key) { + R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValue(out_size.GetPointer(), out.GetPointer(), out.GetSize(), name.value, key.value)) { + R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged) + R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession()); + } R_END_TRY_CATCH; + + return ResultSuccess(); + } } diff --git a/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.hpp b/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.hpp index 3d9de15fd..4baf95623 100644 --- a/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.hpp +++ b/stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.hpp @@ -23,6 +23,9 @@ namespace ams::mitm::settings { enum class CommandId { GetFirmwareVersion = 3, GetFirmwareVersion2 = 4, + + GetSettingsItemValueSize = 37, + GetSettingsItemValue = 38, }; public: static bool ShouldMitm(const sm::MitmProcessInfo &client_info) { @@ -36,10 +39,14 @@ namespace ams::mitm::settings { protected: Result GetFirmwareVersion(sf::Out out); Result GetFirmwareVersion2(sf::Out out); + Result GetSettingsItemValueSize(sf::Out out_size, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key); + Result GetSettingsItemValue(sf::Out out_size, const sf::OutBuffer &out, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key); public: DEFINE_SERVICE_DISPATCH_TABLE { MAKE_SERVICE_COMMAND_META(GetFirmwareVersion), MAKE_SERVICE_COMMAND_META(GetFirmwareVersion2), + MAKE_SERVICE_COMMAND_META(GetSettingsItemValueSize), + MAKE_SERVICE_COMMAND_META(GetSettingsItemValue), }; }; diff --git a/stratosphere/ams_mitm/source/set_mitm/settings_fwdbg_api_override.cpp b/stratosphere/ams_mitm/source/set_mitm/settings_fwdbg_api_override.cpp new file mode 100644 index 000000000..9ee780b5d --- /dev/null +++ b/stratosphere/ams_mitm/source/set_mitm/settings_fwdbg_api_override.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "settings_sd_kvs.hpp" + +namespace ams::settings::fwdbg { + + size_t GetSettingsItemValueSize(const char *name, const char *key) { + u64 size = 0; + + if (R_SUCCEEDED(GetSdCardKeyValueStoreSettingsItemValueSize(&size, name, key))) { + return size; + } + + R_ASSERT(setsysGetSettingsItemValueSize(name, key, &size)); + return size; + } + + size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key) { + u64 size = 0; + + if (R_SUCCEEDED(GetSdCardKeyValueStoreSettingsItemValue(&size, dst, dst_size, name, key))) { + return size; + } + + R_ASSERT(setsysGetSettingsItemValue(name, key, dst, dst_size, &size)); + return size; + } + +} diff --git a/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp new file mode 100644 index 000000000..463c3f498 --- /dev/null +++ b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "../amsmitm_debug.hpp" +#include "../amsmitm_fs_utils.hpp" +#include "settings_sd_kvs.hpp" + +namespace ams::settings::fwdbg { + + namespace { + + struct SdKeyValueStoreEntry { + const char *name; + const char *key; + void *value; + size_t value_size; + + constexpr inline bool HasValue() const { return this->value != nullptr; } + + constexpr inline void GetNameAndKey(char *dst) const { + size_t offset = 0; + for (size_t i = 0; i < std::strlen(this->name); i++) { + dst[offset++] = this->name[i]; + } + dst[offset++] = '!'; + for (size_t i = 0; i < std::strlen(this->key); i++) { + dst[offset++] = this->key[i]; + } + dst[offset] = 0; + } + }; + + static_assert(std::is_pod::value); + + constexpr inline bool operator==(const SdKeyValueStoreEntry &lhs, const SdKeyValueStoreEntry &rhs) { + if (lhs.HasValue() != rhs.HasValue()) { + return false; + } + return lhs.HasValue() && std::strcmp(lhs.name, rhs.name) == 0 && std::strcmp(lhs.key, rhs.key) == 0; + } + + inline bool operator<(const SdKeyValueStoreEntry &lhs, const SdKeyValueStoreEntry &rhs) { + AMS_ASSERT(lhs.HasValue()); + AMS_ASSERT(rhs.HasValue()); + + char lhs_name_key[SettingsNameLengthMax + 1 + SettingsItemKeyLengthMax + 1]; + char rhs_name_key[SettingsNameLengthMax + 1 + SettingsItemKeyLengthMax + 1]; + + lhs.GetNameAndKey(lhs_name_key); + rhs.GetNameAndKey(rhs_name_key); + + return std::strcmp(lhs_name_key, rhs_name_key) < 0; + } + + constexpr size_t MaxEntries = 0x200; + constexpr size_t SettingsItemValueStorageSize = 0x10000; + + SettingsName g_names[MaxEntries]; + SettingsItemKey g_item_keys[MaxEntries]; + u8 g_value_storage[SettingsItemValueStorageSize]; + size_t g_allocated_value_storage_size; + + SdKeyValueStoreEntry g_entries[MaxEntries]; + size_t g_num_entries; + + constexpr bool IsValidSettingsFormat(const char *str, size_t len) { + AMS_ASSERT(str != nullptr); + + if (len > 0 && str[len - 1] == '.') { + return false; + } + + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + + if ('a' <= c && c <= 'z') { + continue; + } + + if ('0' <= c && c <= '9') { + continue; + } + + if (c == '-' || c == '.' || c == '_') { + continue; + } + + return false; + } + + return true; + } + + constexpr bool IsHexadecimal(const char *str) { + while (*str) { + if (std::isxdigit(static_cast(*str))) { + str++; + } else { + return false; + } + } + return true; + } + + constexpr inline char hextoi(char c) { + if ('a' <= c && c <= 'f') return c - 'a' + 0xA; + if ('A' <= c && c <= 'F') return c - 'A' + 0xA; + if ('0' <= c && c <= '9') return c - '0'; + return 0; + } + + Result ValidateSettingsName(const char *name) { + R_UNLESS(name != nullptr, ResultSettingsNameNull()); + const size_t len = strnlen(name, SettingsNameLengthMax + 1); + R_UNLESS(len > 0, ResultSettingsNameEmpty()); + R_UNLESS(len <= SettingsNameLengthMax, ResultSettingsNameTooLong()); + R_UNLESS(IsValidSettingsFormat(name, len), ResultSettingsNameInvalidFormat()); + return ResultSuccess(); + } + + Result ValidateSettingsItemKey(const char *key) { + R_UNLESS(key != nullptr, ResultSettingsNameNull()); + const size_t len = strnlen(key, SettingsItemKeyLengthMax + 1); + R_UNLESS(len > 0, ResultSettingsItemKeyEmpty()); + R_UNLESS(len <= SettingsNameLengthMax, ResultSettingsItemKeyTooLong()); + R_UNLESS(IsValidSettingsFormat(key, len), ResultSettingsItemKeyInvalidFormat()); + return ResultSuccess(); + } + + Result AllocateValue(void **out, size_t size) { + R_UNLESS(g_allocated_value_storage_size + size <= sizeof(g_value_storage), ResultSettingsItemValueAllocationFailed()); + + *out = g_value_storage + g_allocated_value_storage_size; + g_allocated_value_storage_size += size; + return ResultSuccess(); + } + + Result FindSettingsName(const char **out, const char *name) { + for (auto &stored : g_names) { + if (std::strcmp(stored.value, name) == 0) { + *out = stored.value; + return ResultSuccess(); + } else if (std::strcmp(stored.value, "") == 0) { + *out = stored.value; + std::strcpy(stored.value, name); + return ResultSuccess(); + } + } + return ResultSettingsItemKeyAllocationFailed(); + } + + Result FindSettingsItemKey(const char **out, const char *key) { + for (auto &stored : g_item_keys) { + if (std::strcmp(stored.value, key) == 0) { + *out = stored.value; + return ResultSuccess(); + } else if (std::strcmp(stored.value, "") == 0) { + std::strcpy(stored.value, key); + *out = stored.value; + return ResultSuccess(); + } + } + return ResultSettingsItemKeyAllocationFailed(); + } + + template + Result ParseSettingsItemIntegralValue(SdKeyValueStoreEntry &out, const char *value_str) { + R_TRY(AllocateValue(&out.value, sizeof(T))); + out.value_size = sizeof(T); + + T value = static_cast(strtoul(value_str, nullptr, 0)); + std::memcpy(out.value, &value, sizeof(T)); + return ResultSuccess(); + } + + Result GetEntry(SdKeyValueStoreEntry **out, const char *name, const char *key) { + /* Validate name/key. */ + R_TRY(ValidateSettingsName(name)); + R_TRY(ValidateSettingsItemKey(key)); + + u8 dummy_value = 0; + SdKeyValueStoreEntry test_entry { .name = name, .key = key, .value = &dummy_value, .value_size = sizeof(dummy_value) }; + + auto *begin = g_entries; + auto *end = begin + g_num_entries; + auto it = std::lower_bound(begin, end, test_entry); + R_UNLESS(it != end, ResultSettingsItemNotFound()); + R_UNLESS(*it == test_entry, ResultSettingsItemNotFound()); + + *out = &*it; + return ResultSuccess(); + } + + Result ParseSettingsItemValueImpl(const char *name, const char *key, const char *val_tup) { + const char *delimiter = strchr(val_tup, '!'); + const char *value_str = delimiter + 1; + const char *type = val_tup; + + R_UNLESS(delimiter != nullptr, ResultSettingsItemValueInvalidFormat()); + + while (std::isspace(static_cast(*type)) && type != delimiter) { + type++; + } + + const size_t type_len = delimiter - type; + const size_t value_len = strlen(value_str); + R_UNLESS(type_len > 0, ResultSettingsItemValueInvalidFormat()); + R_UNLESS(value_len > 0, ResultSettingsItemValueInvalidFormat()); + + /* Create new value. */ + SdKeyValueStoreEntry new_value = {}; + + /* Find name and key. */ + R_TRY(FindSettingsName(&new_value.name, name)); + R_TRY(FindSettingsItemKey(&new_value.key, key)); + + if (strncasecmp(type, "str", type_len) == 0 || strncasecmp(type, "string", type_len) == 0) { + const size_t size = value_len + 1; + R_TRY(AllocateValue(&new_value.value, size)); + std::memcpy(new_value.value, value_str, size); + new_value.value_size = size; + } else if (strncasecmp(type, "hex", type_len) == 0 || strncasecmp(type, "bytes", type_len) == 0) { + R_UNLESS(value_len > 0, ResultSettingsItemValueInvalidFormat()); + R_UNLESS(value_len % 2 == 0, ResultSettingsItemValueInvalidFormat()); + R_UNLESS(IsHexadecimal(value_str), ResultSettingsItemValueInvalidFormat()); + + const size_t size = value_len / 2; + R_TRY(AllocateValue(&new_value.value, size)); + new_value.value_size = size; + + u8 *data = reinterpret_cast(new_value.value); + for (size_t i = 0; i < size; i++) { + data[i >> 1] = hextoi(value_str[i]) << (4 * (i & 1)); + } + } else if (strncasecmp(type, "u8", type_len) == 0) { + R_TRY((ParseSettingsItemIntegralValue(new_value, value_str))); + } else if (strncasecmp(type, "u16", type_len) == 0) { + R_TRY((ParseSettingsItemIntegralValue(new_value, value_str))); + } else if (strncasecmp(type, "u32", type_len) == 0) { + R_TRY((ParseSettingsItemIntegralValue(new_value, value_str))); + } else if (strncasecmp(type, "u64", type_len) == 0) { + R_TRY((ParseSettingsItemIntegralValue(new_value, value_str))); + } else { + return ResultSettingsItemValueInvalidFormat(); + } + + /* Insert the entry. */ + bool inserted = false; + for (auto &entry : g_entries) { + if (!entry.HasValue() || entry == new_value) { + entry = new_value; + inserted = true; + break; + } + } + + R_UNLESS(inserted, ResultSettingsItemValueAllocationFailed()); + return ResultSuccess(); + } + + Result ParseSettingsItemValue(const char *name, const char *key, const char *value) { + R_TRY(ValidateSettingsName(name)); + R_TRY(ValidateSettingsItemKey(key)); + return ParseSettingsItemValueImpl(name, key, value); + } + + static int SystemSettingsIniHandler(void *user, const char *name, const char *key, const char *value) { + Result *parse_res = reinterpret_cast(user); + + /* Once we fail to parse a value, don't parse further. */ + if (R_FAILED(*parse_res)) { + return 0; + } + + *parse_res = ParseSettingsItemValue(name, key, value); + return R_SUCCEEDED(*parse_res) ? 1 : 0; + } + + Result LoadSdCardKeyValueStore() { + /* Open file. */ + FsFile config_file; + R_TRY(ams::mitm::fs::OpenAtmosphereSdFile(&config_file, "/system_settings.ini", FsOpenMode_Read)); + ON_SCOPE_EXIT { fsFileClose(&config_file); }; + + Result parse_result = ResultSuccess(); + util::ini::ParseFile(&config_file, &parse_result, SystemSettingsIniHandler); + R_TRY(parse_result); + + for (size_t i = 0; i < util::size(g_entries); i++) { + if (!g_entries[i].HasValue()) { + g_num_entries = i; + break; + } + } + + if (g_num_entries) { + std::sort(g_entries, g_entries + g_num_entries); + } + + return ResultSuccess(); + } + + } + + void InitializeSdCardKeyValueStore() { + const Result parse_result = LoadSdCardKeyValueStore(); + if (R_FAILED(parse_result)) { + ams::mitm::ThrowResultForDebug(parse_result); + } + } + + Result GetSdCardKeyValueStoreSettingsItemValueSize(size_t *out_size, const char *name, const char *key) { + SdKeyValueStoreEntry *entry = nullptr; + R_TRY(GetEntry(&entry, name, key)); + + *out_size = entry->value_size; + return ResultSuccess(); + } + + Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key) { + R_UNLESS(dst != nullptr, ResultSettingsItemValueBufferNull()); + + SdKeyValueStoreEntry *entry = nullptr; + R_TRY(GetEntry(&entry, name, key)); + + const size_t size = std::min(entry->value_size, dst_size); + if (size > 0) { + std::memcpy(dst, entry->value, size); + } + *out_size = size; + return ResultSuccess(); + } + +} diff --git a/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp new file mode 100644 index 000000000..779778c79 --- /dev/null +++ b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::settings::fwdbg { + + void InitializeSdCardKeyValueStore(); + + Result GetSdCardKeyValueStoreSettingsItemValueSize(size_t *out_size, const char *name, const char *key); + Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key); + +} diff --git a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp index ad15b9815..7a7a695bc 100644 --- a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp +++ b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp @@ -191,14 +191,13 @@ namespace ams::dmnt::cheat::impl { /* Learn whether we should enable cheats by default. */ { - u64 size_out; u8 en = 0; - if (R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "dmnt_cheats_enabled_by_default", &en, sizeof(en), &size_out))) { + if (settings::fwdbg::GetSettingsItemValue(&en, sizeof(en), "atmosphere", "dmnt_cheats_enabled_by_default") == sizeof(en)) { this->enable_cheats_by_default = (en != 0); } en = 0; - if (R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "dmnt_always_save_cheat_toggles", &en, sizeof(en), &size_out))) { + if (settings::fwdbg::GetSettingsItemValue( &en, sizeof(en), "atmosphere", "dmnt_always_save_cheat_toggles") == sizeof(en)) { this->always_save_cheat_toggles = (en != 0); } } diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp index 4f7f84e87..39a7406f0 100644 --- a/stratosphere/fatal/source/fatal_config.cpp +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -59,13 +59,12 @@ namespace ams::fatal::srv { this->UpdateLanguageCode(); /* Read information from settings. */ - u64 set_size_out; - setsysGetSettingsItemValue("fatal", "transition_to_fatal", &this->transition_to_fatal, sizeof(this->transition_to_fatal), &set_size_out); - setsysGetSettingsItemValue("fatal", "show_extra_info", &this->show_extra_info, sizeof(this->show_extra_info), &set_size_out); - setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &this->quest_reboot_interval_second, sizeof(this->quest_reboot_interval_second), &set_size_out); + settings::fwdbg::GetSettingsItemValue(&this->transition_to_fatal, sizeof(this->transition_to_fatal), "fatal", "transition_to_fatal"); + settings::fwdbg::GetSettingsItemValue(&this->show_extra_info, sizeof(this->show_extra_info), "fatal", "show_extra_info"); + settings::fwdbg::GetSettingsItemValue(&this->quest_reboot_interval_second, sizeof(this->quest_reboot_interval_second), "fatal", "quest_reboot_interval_second"); /* Atmosphere extension for automatic reboot. */ - if (R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "fatal_auto_reboot_interval", &this->fatal_auto_reboot_interval, sizeof(this->fatal_auto_reboot_interval), &set_size_out))) { + if (settings::fwdbg::GetSettingsItemValue(&this->fatal_auto_reboot_interval, sizeof(this->fatal_auto_reboot_interval), "atmosphere", "fatal_auto_reboot_interval") == sizeof(this->fatal_auto_reboot_interval)) { this->fatal_auto_reboot_enabled = this->fatal_auto_reboot_interval != 0; } diff --git a/stratosphere/libstratosphere/Makefile b/stratosphere/libstratosphere/Makefile index 63448b6da..7fe393514 100644 --- a/stratosphere/libstratosphere/Makefile +++ b/stratosphere/libstratosphere/Makefile @@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules # INCLUDES is a list of directories containing header files #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) -SOURCES := source source/ams source/hos source/result source/os source/os/impl source/dd source/sf source/sf/cmif source/sf/hipc source/dmnt source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb source/boot2 +SOURCES := source source/ams source/hos source/result source/os source/os/impl source/dd source/sf source/sf/cmif source/sf/hipc source/dmnt source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb source/settings source/boot2 DATA := data INCLUDES := include diff --git a/stratosphere/libstratosphere/include/atmosphere/results/results_common.hpp b/stratosphere/libstratosphere/include/atmosphere/results/results_common.hpp index b0b50d433..3166e4736 100644 --- a/stratosphere/libstratosphere/include/atmosphere/results/results_common.hpp +++ b/stratosphere/libstratosphere/include/atmosphere/results/results_common.hpp @@ -271,6 +271,9 @@ namespace ams::result::impl { #define R_CONVERT_ALL(convert_type) \ R_CATCH_ALL() { return static_cast<::ams::Result>(convert_type); } +#define R_CATCH_RETHROW(catch_type) \ + R_CONVERT(catch_type, R_CURRENT_RESULT) + #define R_END_TRY_CATCH \ else if (R_FAILED(R_CURRENT_RESULT)) { \ return R_CURRENT_RESULT; \ diff --git a/stratosphere/libstratosphere/include/atmosphere/results/settings_results.hpp b/stratosphere/libstratosphere/include/atmosphere/results/settings_results.hpp index 6f015cdf6..fed3ff33e 100644 --- a/stratosphere/libstratosphere/include/atmosphere/results/settings_results.hpp +++ b/stratosphere/libstratosphere/include/atmosphere/results/settings_results.hpp @@ -21,11 +21,11 @@ namespace ams::settings { R_DEFINE_NAMESPACE_RESULT_MODULE(105); - R_DEFINE_ERROR_RESULT(ItemNotFound, 11); + R_DEFINE_ERROR_RESULT(SettingsItemNotFound, 11); R_DEFINE_ERROR_RANGE(InternalError, 100, 149); - R_DEFINE_ERROR_RESULT(ItemKeyAllocationFailed, 101); - R_DEFINE_ERROR_RESULT(ItemValueAllocationFailed, 102); + R_DEFINE_ERROR_RESULT(SettingsItemKeyAllocationFailed, 101); + R_DEFINE_ERROR_RESULT(SettingsItemValueAllocationFailed, 102); R_DEFINE_ERROR_RANGE(InvalidArgument, 200, 399); R_DEFINE_ERROR_RESULT(SettingsNameNull, 201); diff --git a/stratosphere/libstratosphere/include/stratosphere/settings.hpp b/stratosphere/libstratosphere/include/stratosphere/settings.hpp index 2751a061b..66b9bf023 100644 --- a/stratosphere/libstratosphere/include/stratosphere/settings.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/settings.hpp @@ -17,3 +17,5 @@ #pragma once #include "settings/settings_types.hpp" +#include "settings/settings_fwdbg_types.hpp" +#include "settings/settings_fwdbg_api.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp b/stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp new file mode 100644 index 000000000..22f118359 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "settings_fwdbg_types.hpp" + +namespace ams::settings::fwdbg { + + bool IsDebugModeEnabled(); + + size_t GetSettingsItemValueSize(const char *name, const char *key); + size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key); + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp b/stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp new file mode 100644 index 000000000..0440d5a3f --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../sf/sf_buffer_tags.hpp" + +namespace ams::settings::fwdbg { + + constexpr size_t SettingsNameLengthMax = 0x40; + constexpr size_t SettingsItemKeyLengthMax = 0x40; + + struct SettingsName : sf::LargeData { + char value[util::AlignUp(SettingsNameLengthMax + 1, alignof(u64))]; + }; + + static_assert(std::is_pod::value && sizeof(SettingsName) > SettingsNameLengthMax); + + struct SettingsItemKey : sf::LargeData { + char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))]; + }; + + static_assert(std::is_pod::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax); + +} diff --git a/stratosphere/libstratosphere/source/boot2/boot2_api.cpp b/stratosphere/libstratosphere/source/boot2/boot2_api.cpp index 63e57b842..e1a351467 100644 --- a/stratosphere/libstratosphere/source/boot2/boot2_api.cpp +++ b/stratosphere/libstratosphere/source/boot2/boot2_api.cpp @@ -176,8 +176,7 @@ namespace ams::boot2 { /* Contact set:sys, retrieve boot!force_maintenance. */ { u8 force_maintenance = 1; - u64 size_out; - setsysGetSettingsItemValue("boot", "force_maintenance", &force_maintenance, sizeof(force_maintenance), &size_out); + settings::fwdbg::GetSettingsItemValue(&force_maintenance, sizeof(force_maintenance), "boot", "force_maintenance"); if (force_maintenance != 0) { return true; } diff --git a/stratosphere/libstratosphere/source/settings/settings_fwdbg_api.cpp b/stratosphere/libstratosphere/source/settings/settings_fwdbg_api.cpp new file mode 100644 index 000000000..c63b087f1 --- /dev/null +++ b/stratosphere/libstratosphere/source/settings/settings_fwdbg_api.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::settings::fwdbg { + + /* TODO: Implement when libnx wrapper is added. */ + bool IsDebugModeEnabled(); + + size_t WEAK GetSettingsItemValueSize(const char *name, const char *key) { + u64 size = 0; + R_ASSERT(setsysGetSettingsItemValueSize(name, key, &size)); + return size; + } + + size_t WEAK GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key) { + u64 size = 0; + R_ASSERT(setsysGetSettingsItemValue(name, key, dst, dst_size, &size)); + return size; + } + +} diff --git a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp index 41e61f37a..40b726918 100644 --- a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp +++ b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp @@ -45,7 +45,7 @@ namespace ams::sf::cmif { /* Forward forwardable results, otherwise ensure we can send result to user. */ R_TRY_CATCH(command_result) { - R_CATCH(sf::impl::ResultRequestContextChanged) { return R_CURRENT_RESULT; } + R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged) R_CATCH_ALL() { AMS_ASSERT(out_header != nullptr); } } R_END_TRY_CATCH; @@ -92,7 +92,7 @@ namespace ams::sf::cmif { R_CATCH(sm::mitm::ResultShouldForwardToSession) { return ctx.session->ForwardRequest(ctx); } - R_CATCH(sf::impl::ResultRequestContextChanged) { return R_CURRENT_RESULT; } + R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged) R_CATCH_ALL() { AMS_ASSERT(out_header != nullptr); } } R_END_TRY_CATCH; diff --git a/stratosphere/libstratosphere/source/util/ini.h b/stratosphere/libstratosphere/source/util/ini.h index f45ba40ba..047235e88 100644 --- a/stratosphere/libstratosphere/source/util/ini.h +++ b/stratosphere/libstratosphere/source/util/ini.h @@ -102,7 +102,7 @@ int ini_parse_string(const char* string, ini_handler handler, void* user); /* Maximum line length for any line in INI file (stack or heap). Note that this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ #ifndef INI_MAX_LINE -#define INI_MAX_LINE 200 +#define INI_MAX_LINE 0x480 #endif /* Nonzero to allow heap line buffer to grow via realloc(), zero for a diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index 7a81445af..9190eae4c 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -315,15 +315,14 @@ namespace ams::ro::impl { bool ShouldEaseNroRestriction() { /* Retrieve whether we should ease restrictions from set:sys. */ - bool should_ease = false; - u64 size_out; - if (R_FAILED(setsysGetSettingsItemValue("ro", "ease_nro_restriction", &should_ease, sizeof(should_ease), &size_out))) { + u8 should_ease = 0; + if (settings::fwdbg::GetSettingsItemValue(&should_ease, sizeof(should_ease), "ro", "ease_nro_restriction") != sizeof(should_ease)) { return false; } /* Nintendo only allows easing restriction on dev, we will allow on production, as well. */ /* should_ease &= IsDevelopmentFunctionEnabled(); */ - return should_ease; + return should_ease != 0; } /* Context utilities. */