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. */