ams_mitm: Implement system settings mitm

This commit is contained in:
Michael Scire 2019-11-26 20:58:39 -08:00 committed by SciresM
parent 55610694c8
commit c10ba67973
25 changed files with 655 additions and 30 deletions

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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<DebugThrowThreadStackSize> 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());
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::mitm {
void ThrowResultForDebug(Result res);
}

View file

@ -26,7 +26,7 @@ namespace ams::mitm::fs {
/* Helpers. */ /* Helpers. */
Result EnsureSdInitialized() { Result EnsureSdInitialized() {
R_UNLESS(mitm::IsInitialized(), ams::fs::ResultSdCardNotPresent()); R_UNLESS(serviceIsActive(&g_sd_filesystem.s), ams::fs::ResultSdCardNotPresent());
return ResultSuccess(); return ResultSuccess();
} }

View file

@ -16,6 +16,7 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "amsmitm_initialization.hpp" #include "amsmitm_initialization.hpp"
#include "amsmitm_fs_utils.hpp" #include "amsmitm_fs_utils.hpp"
#include "bpc_mitm/bpc_ams_power_utils.hpp"
namespace ams::mitm { namespace ams::mitm {
@ -35,11 +36,15 @@ namespace ams::mitm {
/* Wait for the SD card to be ready. */ /* Wait for the SD card to be ready. */
cfg::WaitSdCardInitialized(); cfg::WaitSdCardInitialized();
/* TODO: Other initialization tasks. */
/* Open global SD card file system, so that other threads can begin using the SD. */ /* Open global SD card file system, so that other threads can begin using the SD. */
mitm::fs::OpenGlobalSdCardFileSystem(); 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. */ /* Signal to waiters that we are ready. */
g_init_event.Signal(); g_init_event.Signal();
} }

View file

@ -15,6 +15,7 @@
*/ */
#include "amsmitm_initialization.hpp" #include "amsmitm_initialization.hpp"
#include "amsmitm_module_management.hpp" #include "amsmitm_module_management.hpp"
#include "bpc_mitm/bpc_ams_power_utils.hpp"
extern "C" { extern "C" {
extern u32 __start__; extern u32 __start__;
@ -50,8 +51,7 @@ namespace ams {
/* Override. */ /* Override. */
void ExceptionHandler(FatalErrorContext *ctx) { void ExceptionHandler(FatalErrorContext *ctx) {
/* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */ /* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */
/* Utils::RebootToFatalError(ctx); */ mitm::bpc::RebootForFatalError(ctx);
while (1) { /* ... */ }
} }
} }

View file

@ -41,10 +41,6 @@ namespace ams::mitm::bpc {
/* Wait until initialization is complete. */ /* Wait until initialization is complete. */
mitm::WaitInitialized(); 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. */ /* Create bpc:ams. */
{ {
Handle bpcams_h; Handle bpcams_h;

View file

@ -13,9 +13,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "../amsmitm_initialization.hpp"
#include "setmitm_module.hpp" #include "setmitm_module.hpp"
#include "set_mitm_service.hpp" #include "set_mitm_service.hpp"
#include "setsys_mitm_service.hpp" #include "setsys_mitm_service.hpp"
#include "settings_sd_kvs.hpp"
namespace ams::mitm::settings { namespace ams::mitm::settings {
@ -40,6 +42,9 @@ namespace ams::mitm::settings {
/* Wait until initialization is complete. */ /* Wait until initialization is complete. */
mitm::WaitInitialized(); mitm::WaitInitialized();
/* Load settings off the SD card. */
ams::settings::fwdbg::InitializeSdCardKeyValueStore();
/* Create mitm servers. */ /* Create mitm servers. */
R_ASSERT(g_server_manager.RegisterMitmServer<SetMitmService>(SetMitmServiceName)); R_ASSERT(g_server_manager.RegisterMitmServer<SetMitmService>(SetMitmServiceName));
R_ASSERT(g_server_manager.RegisterMitmServer<SetSysMitmService>(SetSysMitmServiceName)); R_ASSERT(g_server_manager.RegisterMitmServer<SetSysMitmService>(SetSysMitmServiceName));

View file

@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "setsys_mitm_service.hpp" #include "setsys_mitm_service.hpp"
#include "settings_sd_kvs.hpp"
namespace ams::mitm::settings { namespace ams::mitm::settings {
@ -98,5 +99,22 @@ namespace ams::mitm::settings {
return GetFirmwareVersionImpl(out.GetPointer(), this->client_info); return GetFirmwareVersionImpl(out.GetPointer(), this->client_info);
} }
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> 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<u64> 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();
}
} }

View file

@ -23,6 +23,9 @@ namespace ams::mitm::settings {
enum class CommandId { enum class CommandId {
GetFirmwareVersion = 3, GetFirmwareVersion = 3,
GetFirmwareVersion2 = 4, GetFirmwareVersion2 = 4,
GetSettingsItemValueSize = 37,
GetSettingsItemValue = 38,
}; };
public: public:
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) { static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
@ -36,10 +39,14 @@ namespace ams::mitm::settings {
protected: protected:
Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out); Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out);
Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out); Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out);
Result GetSettingsItemValueSize(sf::Out<u64> out_size, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key);
Result GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key);
public: public:
DEFINE_SERVICE_DISPATCH_TABLE { DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(GetFirmwareVersion), MAKE_SERVICE_COMMAND_META(GetFirmwareVersion),
MAKE_SERVICE_COMMAND_META(GetFirmwareVersion2), MAKE_SERVICE_COMMAND_META(GetFirmwareVersion2),
MAKE_SERVICE_COMMAND_META(GetSettingsItemValueSize),
MAKE_SERVICE_COMMAND_META(GetSettingsItemValue),
}; };
}; };

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<SdKeyValueStoreEntry>::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<unsigned char>(*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<typename T>
Result ParseSettingsItemIntegralValue(SdKeyValueStoreEntry &out, const char *value_str) {
R_TRY(AllocateValue(&out.value, sizeof(T)));
out.value_size = sizeof(T);
T value = static_cast<T>(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<unsigned char>(*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<u8 *>(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<u8>(new_value, value_str)));
} else if (strncasecmp(type, "u16", type_len) == 0) {
R_TRY((ParseSettingsItemIntegralValue<u16>(new_value, value_str)));
} else if (strncasecmp(type, "u32", type_len) == 0) {
R_TRY((ParseSettingsItemIntegralValue<u32>(new_value, value_str)));
} else if (strncasecmp(type, "u64", type_len) == 0) {
R_TRY((ParseSettingsItemIntegralValue<u64>(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<Result *>(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();
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
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);
}

View file

@ -191,14 +191,13 @@ namespace ams::dmnt::cheat::impl {
/* Learn whether we should enable cheats by default. */ /* Learn whether we should enable cheats by default. */
{ {
u64 size_out;
u8 en = 0; 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); this->enable_cheats_by_default = (en != 0);
} }
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); this->always_save_cheat_toggles = (en != 0);
} }
} }

View file

@ -59,13 +59,12 @@ namespace ams::fatal::srv {
this->UpdateLanguageCode(); this->UpdateLanguageCode();
/* Read information from settings. */ /* Read information from settings. */
u64 set_size_out; settings::fwdbg::GetSettingsItemValue(&this->transition_to_fatal, sizeof(this->transition_to_fatal), "fatal", "transition_to_fatal");
setsysGetSettingsItemValue("fatal", "transition_to_fatal", &this->transition_to_fatal, sizeof(this->transition_to_fatal), &set_size_out); settings::fwdbg::GetSettingsItemValue(&this->show_extra_info, sizeof(this->show_extra_info), "fatal", "show_extra_info");
setsysGetSettingsItemValue("fatal", "show_extra_info", &this->show_extra_info, sizeof(this->show_extra_info), &set_size_out); settings::fwdbg::GetSettingsItemValue(&this->quest_reboot_interval_second, sizeof(this->quest_reboot_interval_second), "fatal", "quest_reboot_interval_second");
setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &this->quest_reboot_interval_second, sizeof(this->quest_reboot_interval_second), &set_size_out);
/* Atmosphere extension for automatic reboot. */ /* 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; this->fatal_auto_reboot_enabled = this->fatal_auto_reboot_interval != 0;
} }

View file

@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# INCLUDES is a list of directories containing header files # INCLUDES is a list of directories containing header files
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR)) 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 DATA := data
INCLUDES := include INCLUDES := include

View file

@ -271,6 +271,9 @@ namespace ams::result::impl {
#define R_CONVERT_ALL(convert_type) \ #define R_CONVERT_ALL(convert_type) \
R_CATCH_ALL() { return static_cast<::ams::Result>(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 \ #define R_END_TRY_CATCH \
else if (R_FAILED(R_CURRENT_RESULT)) { \ else if (R_FAILED(R_CURRENT_RESULT)) { \
return R_CURRENT_RESULT; \ return R_CURRENT_RESULT; \

View file

@ -21,11 +21,11 @@ namespace ams::settings {
R_DEFINE_NAMESPACE_RESULT_MODULE(105); 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_RANGE(InternalError, 100, 149);
R_DEFINE_ERROR_RESULT(ItemKeyAllocationFailed, 101); R_DEFINE_ERROR_RESULT(SettingsItemKeyAllocationFailed, 101);
R_DEFINE_ERROR_RESULT(ItemValueAllocationFailed, 102); R_DEFINE_ERROR_RESULT(SettingsItemValueAllocationFailed, 102);
R_DEFINE_ERROR_RANGE(InvalidArgument, 200, 399); R_DEFINE_ERROR_RANGE(InvalidArgument, 200, 399);
R_DEFINE_ERROR_RESULT(SettingsNameNull, 201); R_DEFINE_ERROR_RESULT(SettingsNameNull, 201);

View file

@ -17,3 +17,5 @@
#pragma once #pragma once
#include "settings/settings_types.hpp" #include "settings/settings_types.hpp"
#include "settings/settings_fwdbg_types.hpp"
#include "settings/settings_fwdbg_api.hpp"

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <atmosphere/common.hpp>
#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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <atmosphere/common.hpp>
#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<SettingsName>::value && sizeof(SettingsName) > SettingsNameLengthMax);
struct SettingsItemKey : sf::LargeData {
char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))];
};
static_assert(std::is_pod<SettingsItemKey>::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax);
}

View file

@ -176,8 +176,7 @@ namespace ams::boot2 {
/* Contact set:sys, retrieve boot!force_maintenance. */ /* Contact set:sys, retrieve boot!force_maintenance. */
{ {
u8 force_maintenance = 1; u8 force_maintenance = 1;
u64 size_out; settings::fwdbg::GetSettingsItemValue(&force_maintenance, sizeof(force_maintenance), "boot", "force_maintenance");
setsysGetSettingsItemValue("boot", "force_maintenance", &force_maintenance, sizeof(force_maintenance), &size_out);
if (force_maintenance != 0) { if (force_maintenance != 0) {
return true; return true;
} }

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
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;
}
}

View file

@ -45,7 +45,7 @@ namespace ams::sf::cmif {
/* Forward forwardable results, otherwise ensure we can send result to user. */ /* Forward forwardable results, otherwise ensure we can send result to user. */
R_TRY_CATCH(command_result) { 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_CATCH_ALL() { AMS_ASSERT(out_header != nullptr); }
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
@ -92,7 +92,7 @@ namespace ams::sf::cmif {
R_CATCH(sm::mitm::ResultShouldForwardToSession) { R_CATCH(sm::mitm::ResultShouldForwardToSession) {
return ctx.session->ForwardRequest(ctx); 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_CATCH_ALL() { AMS_ASSERT(out_header != nullptr); }
} R_END_TRY_CATCH; } R_END_TRY_CATCH;

View file

@ -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 /* 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'). */ this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
#ifndef INI_MAX_LINE #ifndef INI_MAX_LINE
#define INI_MAX_LINE 200 #define INI_MAX_LINE 0x480
#endif #endif
/* Nonzero to allow heap line buffer to grow via realloc(), zero for a /* Nonzero to allow heap line buffer to grow via realloc(), zero for a

View file

@ -315,15 +315,14 @@ namespace ams::ro::impl {
bool ShouldEaseNroRestriction() { bool ShouldEaseNroRestriction() {
/* Retrieve whether we should ease restrictions from set:sys. */ /* Retrieve whether we should ease restrictions from set:sys. */
bool should_ease = false; u8 should_ease = 0;
u64 size_out; if (settings::fwdbg::GetSettingsItemValue(&should_ease, sizeof(should_ease), "ro", "ease_nro_restriction") != sizeof(should_ease)) {
if (R_FAILED(setsysGetSettingsItemValue("ro", "ease_nro_restriction", &should_ease, sizeof(should_ease), &size_out))) {
return false; return false;
} }
/* Nintendo only allows easing restriction on dev, we will allow on production, as well. */ /* Nintendo only allows easing restriction on dev, we will allow on production, as well. */
/* should_ease &= IsDevelopmentFunctionEnabled(); */ /* should_ease &= IsDevelopmentFunctionEnabled(); */
return should_ease; return should_ease != 0;
} }
/* Context utilities. */ /* Context utilities. */