Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 "set_mitm_service.hpp"
|
||||
#include "set_shim.h"
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
using namespace ams::settings;
|
||||
|
||||
namespace {
|
||||
|
||||
constinit os::ProcessId g_application_process_id = os::InvalidProcessId;
|
||||
constinit cfg::OverrideLocale g_application_locale;
|
||||
constinit bool g_valid_language;
|
||||
constinit bool g_valid_region;
|
||||
}
|
||||
|
||||
SetMitmService::SetMitmService(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : sf::MitmServiceImplBase(std::forward<std::shared_ptr<::Service>>(s), c) {
|
||||
if (m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
os::ProcessId application_process_id;
|
||||
if (R_SUCCEEDED(ams::pm::dmnt::GetApplicationProcessId(std::addressof(application_process_id))) && g_application_process_id == application_process_id) {
|
||||
m_locale = g_application_locale;
|
||||
m_is_valid_language = g_valid_language;
|
||||
m_is_valid_region = g_valid_region;
|
||||
m_got_locale = true;
|
||||
} else {
|
||||
this->InvalidateLocale();
|
||||
}
|
||||
} else {
|
||||
this->InvalidateLocale();
|
||||
}
|
||||
}
|
||||
|
||||
Result SetMitmService::EnsureLocale() {
|
||||
/* Optimization: if locale has already been gotten, we can stop. */
|
||||
if (AMS_LIKELY(m_got_locale)) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
const bool is_ns = m_client_info.program_id == ncm::SystemProgramId::Ns;
|
||||
|
||||
if (!m_got_locale) {
|
||||
ncm::ProgramId program_id = m_client_info.program_id;
|
||||
os::ProcessId application_process_id = os::InvalidProcessId;
|
||||
|
||||
if (is_ns) {
|
||||
/* When NS asks for a locale, refresh to get the current application locale. */
|
||||
R_TRY(ams::pm::dmnt::GetApplicationProcessId(std::addressof(application_process_id)));
|
||||
R_TRY(ams::pm::info::GetProgramId(std::addressof(program_id), application_process_id));
|
||||
}
|
||||
m_locale = cfg::GetOverrideLocale(program_id);
|
||||
m_is_valid_language = settings::IsValidLanguageCode(m_locale.language_code);
|
||||
m_is_valid_region = settings::IsValidRegionCode(m_locale.region_code);
|
||||
m_got_locale = true;
|
||||
|
||||
if (is_ns) {
|
||||
g_application_locale = m_locale;
|
||||
g_valid_language = m_is_valid_language;
|
||||
g_valid_region = m_is_valid_region;
|
||||
g_application_process_id = application_process_id;
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void SetMitmService::InvalidateLocale() {
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
std::memset(std::addressof(m_locale), 0xCC, sizeof(m_locale));
|
||||
m_is_valid_language = false;
|
||||
m_is_valid_region = false;
|
||||
m_got_locale = false;
|
||||
}
|
||||
|
||||
Result SetMitmService::GetLanguageCode(sf::Out<settings::LanguageCode> out) {
|
||||
this->EnsureLocale();
|
||||
|
||||
/* If there's no override locale, just use the actual one. */
|
||||
if (AMS_UNLIKELY(!m_is_valid_language)) {
|
||||
static_assert(sizeof(u64) == sizeof(settings::LanguageCode));
|
||||
R_TRY(setGetLanguageCodeFwd(m_forward_service.get(), reinterpret_cast<u64 *>(std::addressof(m_locale.language_code))));
|
||||
|
||||
m_is_valid_language = true;
|
||||
if (m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
g_application_locale.language_code = m_locale.language_code;
|
||||
g_valid_language = true;
|
||||
}
|
||||
}
|
||||
|
||||
out.SetValue(m_locale.language_code);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetMitmService::GetRegionCode(sf::Out<settings::RegionCode> out) {
|
||||
this->EnsureLocale();
|
||||
|
||||
/* If there's no override locale, just use the actual one. */
|
||||
if (AMS_UNLIKELY(!m_is_valid_region)) {
|
||||
static_assert(sizeof(::SetRegion) == sizeof(settings::RegionCode));
|
||||
R_TRY(setGetRegionCodeFwd(m_forward_service.get(), reinterpret_cast<::SetRegion *>(std::addressof(m_locale.region_code))));
|
||||
|
||||
m_is_valid_region = true;
|
||||
if (m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
g_application_locale.region_code = m_locale.region_code;
|
||||
g_valid_region = true;
|
||||
}
|
||||
}
|
||||
|
||||
out.SetValue(m_locale.region_code);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
|
||||
#define AMS_SETTINGS_MITM_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, GetLanguageCode, (sf::Out<ams::settings::LanguageCode> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetRegionCode, (sf::Out<ams::settings::RegionCode> out), (out))
|
||||
|
||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::settings, ISetMitmInterface, AMS_SETTINGS_MITM_INTERFACE_INFO, 0x7F7BAF0A)
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
class SetMitmService : public sf::MitmServiceImplBase {
|
||||
private:
|
||||
os::SdkMutex m_lock{};
|
||||
cfg::OverrideLocale m_locale;
|
||||
bool m_got_locale = false;
|
||||
bool m_is_valid_language = false;
|
||||
bool m_is_valid_region = false;
|
||||
public:
|
||||
SetMitmService(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c);
|
||||
public:
|
||||
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
|
||||
/* We will mitm:
|
||||
* - ns and games, to allow for overriding game locales.
|
||||
*/
|
||||
const bool is_game = (ncm::IsApplicationId(client_info.program_id) && !client_info.override_status.IsHbl());
|
||||
return client_info.program_id == ncm::SystemProgramId::Ns || is_game;
|
||||
}
|
||||
private:
|
||||
void InvalidateLocale();
|
||||
Result EnsureLocale();
|
||||
public:
|
||||
Result GetLanguageCode(sf::Out<ams::settings::LanguageCode> out);
|
||||
Result GetRegionCode(sf::Out<ams::settings::RegionCode> out);
|
||||
};
|
||||
static_assert(IsISetMitmInterface<SetMitmService>);
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 "set_shim.h"
|
||||
|
||||
static Result _setCmdNoInOut64(Service* srv, u64 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _setCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
/* Forwarding shims. */
|
||||
Result setGetLanguageCodeFwd(Service *s, u64* out) {
|
||||
return _setCmdNoInOut64(s, out, 0);
|
||||
}
|
||||
|
||||
Result setGetRegionCodeFwd(Service *s, SetRegion *out) {
|
||||
s32 code=0;
|
||||
Result rc = _setCmdNoInOutU32(s, (u32*)&code, 4);
|
||||
if (R_SUCCEEDED(rc) && out) *out = code;
|
||||
return rc;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @file set_shim.h
|
||||
* @brief Settings Services (fs) IPC wrapper for set.mitm.
|
||||
* @author SciresM
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Forwarding shims. */
|
||||
Result setGetLanguageCodeFwd(Service *s, u64* out);
|
||||
Result setGetRegionCodeFwd(Service *s, SetRegion *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_initialization.hpp"
|
||||
#include "setmitm_module.hpp"
|
||||
#include "set_mitm_service.hpp"
|
||||
#include "setsys_mitm_service.hpp"
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
namespace {
|
||||
|
||||
enum PortIndex {
|
||||
PortIndex_SetMitm,
|
||||
PortIndex_SetSysMitm,
|
||||
PortIndex_Count,
|
||||
};
|
||||
|
||||
constexpr sm::ServiceName SetMitmServiceName = sm::ServiceName::Encode("set");
|
||||
constexpr sm::ServiceName SetSysMitmServiceName = sm::ServiceName::Encode("set:sys");
|
||||
|
||||
struct ServerOptions {
|
||||
static constexpr size_t PointerBufferSize = 0x200;
|
||||
static constexpr size_t MaxDomains = 0;
|
||||
static constexpr size_t MaxDomainObjects = 0;
|
||||
static constexpr bool CanDeferInvokeRequest = false;
|
||||
static constexpr bool CanManageMitmServers = true;
|
||||
};
|
||||
|
||||
constexpr size_t MaxSessions = 60;
|
||||
|
||||
class ServerManager final : public sf::hipc::ServerManager<PortIndex_Count, ServerOptions, MaxSessions> {
|
||||
private:
|
||||
virtual Result OnNeedsToAccept(int port_index, Server *server) override;
|
||||
};
|
||||
|
||||
ServerManager g_server_manager;
|
||||
|
||||
Result ServerManager::OnNeedsToAccept(int port_index, Server *server) {
|
||||
/* Acknowledge the mitm session. */
|
||||
std::shared_ptr<::Service> fsrv;
|
||||
sm::MitmProcessInfo client_info;
|
||||
server->AcknowledgeMitmSession(std::addressof(fsrv), std::addressof(client_info));
|
||||
|
||||
switch (port_index) {
|
||||
case PortIndex_SetMitm:
|
||||
R_RETURN(this->AcceptMitmImpl(server, sf::CreateSharedObjectEmplaced<ISetMitmInterface, SetMitmService>(decltype(fsrv)(fsrv), client_info), fsrv));
|
||||
case PortIndex_SetSysMitm:
|
||||
R_RETURN(this->AcceptMitmImpl(server, sf::CreateSharedObjectEmplaced<ISetSysMitmInterface, SetSysMitmService>(decltype(fsrv)(fsrv), client_info), fsrv));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MitmModule::ThreadFunction(void *) {
|
||||
/* Wait until initialization is complete. */
|
||||
mitm::WaitInitialized();
|
||||
|
||||
/* Create mitm servers. */
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<SetMitmService>(PortIndex_SetMitm, SetMitmServiceName)));
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<SetSysMitmService>(PortIndex_SetSysMitm, SetSysMitmServiceName)));
|
||||
|
||||
/* Loop forever, servicing our services. */
|
||||
g_server_manager.LoopProcess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include "../amsmitm_module.hpp"
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, AMS_GET_SYSTEM_THREAD_PRIORITY(settings, IpcServer) - 1);
|
||||
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 "setsys_mitm_service.hpp"
|
||||
#include "settings_sd_kvs.hpp"
|
||||
#include "setsys_shim.h"
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
using namespace ams::settings;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char ExternalBluetoothDatabasePath[] = "@Sdcard:/atmosphere/bluetooth_devices.db";
|
||||
|
||||
constinit os::SdkMutex g_firmware_version_lock;
|
||||
constinit bool g_cached_firmware_version;
|
||||
constinit settings::FirmwareVersion g_firmware_version;
|
||||
constinit settings::FirmwareVersion g_ams_firmware_version;
|
||||
|
||||
void CacheFirmwareVersion() {
|
||||
if (AMS_LIKELY(g_cached_firmware_version)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lk(g_firmware_version_lock);
|
||||
|
||||
if (AMS_UNLIKELY(g_cached_firmware_version)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mount firmware version data archive. */
|
||||
{
|
||||
R_ABORT_UNLESS(ams::fs::MountSystemData("sysver", ncm::SystemDataId::SystemVersion));
|
||||
ON_SCOPE_EXIT { ams::fs::Unmount("sysver"); };
|
||||
|
||||
/* Firmware version file must exist. */
|
||||
ams::fs::FileHandle file;
|
||||
R_ABORT_UNLESS(ams::fs::OpenFile(std::addressof(file), "sysver:/file", fs::OpenMode_Read));
|
||||
ON_SCOPE_EXIT { ams::fs::CloseFile(file); };
|
||||
|
||||
/* Must be possible to read firmware version from file. */
|
||||
R_ABORT_UNLESS(ams::fs::ReadFile(file, 0, std::addressof(g_firmware_version), sizeof(g_firmware_version)));
|
||||
|
||||
g_ams_firmware_version = g_firmware_version;
|
||||
}
|
||||
|
||||
/* Modify the atmosphere firmware version to display a custom version string. */
|
||||
{
|
||||
const auto api_info = exosphere::GetApiInfo();
|
||||
const char emummc_char = emummc::IsActive() ? 'E' : 'S';
|
||||
|
||||
/* NOTE: We have carefully accounted for the size of the string we print. */
|
||||
/* No truncation occurs assuming two-digits for all version number components. */
|
||||
char display_version[sizeof(g_ams_firmware_version.display_version)];
|
||||
|
||||
util::SNPrintf(display_version, sizeof(display_version), "%s|AMS %u.%u.%u|%c", g_ams_firmware_version.display_version, api_info.GetMajorVersion(), api_info.GetMinorVersion(), api_info.GetMicroVersion(), emummc_char);
|
||||
|
||||
std::memcpy(g_ams_firmware_version.display_version, display_version, sizeof(display_version));
|
||||
}
|
||||
|
||||
g_cached_firmware_version = true;
|
||||
}
|
||||
|
||||
Result GetFirmwareVersionImpl(settings::FirmwareVersion *out, const sm::MitmProcessInfo &client_info) {
|
||||
/* Ensure that we have the firmware version cached. */
|
||||
CacheFirmwareVersion();
|
||||
|
||||
/* We want to give a special firmware version to the home menu title, and nothing else. */
|
||||
/* This means qlaunch + maintenance menu, and nothing else. */
|
||||
if (client_info.program_id == ncm::SystemAppletId::Qlaunch || client_info.program_id == ncm::SystemAppletId::MaintenanceMenu) {
|
||||
*out = g_ams_firmware_version;
|
||||
} else {
|
||||
*out = g_firmware_version;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
bool IsExternalBluetoothDatabaseEnabled() {
|
||||
u8 en = 0;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "enable_external_bluetooth_db");
|
||||
return en;
|
||||
}
|
||||
|
||||
bool HasExternalBluetoothDatabase() {
|
||||
bool file_exists;
|
||||
R_ABORT_UNLESS(fs::HasFile(std::addressof(file_exists), ExternalBluetoothDatabasePath));
|
||||
return file_exists;
|
||||
}
|
||||
|
||||
Result ReadExternalBluetoothDatabase(s32 *entries_read, settings::BluetoothDevicesSettings *db, size_t db_max_size) {
|
||||
/* Open the external database file. */
|
||||
fs::FileHandle file;
|
||||
R_TRY(fs::OpenFile(std::addressof(file), ExternalBluetoothDatabasePath, fs::OpenMode_Read));
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
/* Read the number of database entries stored in external database. */
|
||||
u64 total_entries;
|
||||
R_TRY(fs::ReadFile(file, 0, std::addressof(total_entries), sizeof(total_entries)));
|
||||
|
||||
u64 db_offset = sizeof(total_entries);
|
||||
if (total_entries > db_max_size) {
|
||||
/* Pairings are stored from least to most recent. Add offset to skip the older entries that won't fit. */
|
||||
db_offset += (total_entries - db_max_size) * sizeof(settings::BluetoothDevicesSettings);
|
||||
|
||||
/* Cap number of database entries read to size of database on this firmware. */
|
||||
total_entries = db_max_size;
|
||||
}
|
||||
|
||||
/* Read database entries. */
|
||||
R_TRY(fs::ReadFile(file, db_offset, db, total_entries * sizeof(settings::BluetoothDevicesSettings)));
|
||||
|
||||
/* Convert entries to the old format if running on a firmware below 13.0.0. */
|
||||
if (hos::GetVersion() < hos::Version_13_0_0) {
|
||||
for (size_t i = 0; i < total_entries; ++i) {
|
||||
/* Copy the newer name field to the older one. */
|
||||
util::TSNPrintf(db[i].name, sizeof(db[i].name), "%s", db[i].name2);
|
||||
|
||||
/* Clear the newer name field. */
|
||||
std::memset(db[i].name2, 0, sizeof(db[i].name2));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the output. */
|
||||
*entries_read = static_cast<s32>(total_entries);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StoreExternalBluetoothDatabase(const settings::BluetoothDevicesSettings *db, u64 total_entries) {
|
||||
/* Open the external database file. */
|
||||
fs::FileHandle file;
|
||||
R_TRY(fs::OpenFile(std::addressof(file), ExternalBluetoothDatabasePath, fs::OpenMode_Write));
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
/* Ensure the file is the appropriate size for the number of entries. */
|
||||
R_TRY(fs::SetFileSize(file, sizeof(total_entries) + total_entries * sizeof(settings::BluetoothDevicesSettings)));
|
||||
|
||||
/* Write the number of database entries. */
|
||||
R_TRY(fs::WriteFile(file, 0, std::addressof(total_entries), sizeof(total_entries), fs::WriteOption::None));
|
||||
|
||||
/* Write the database entries. */
|
||||
u64 db_offset = sizeof(total_entries);
|
||||
if (hos::GetVersion() < hos::Version_13_0_0) {
|
||||
/* Convert entries to the new format if running on a firmware below 13.0.0. */
|
||||
for (size_t i = 0; i < total_entries; ++i) {
|
||||
/* Make a copy of the current database entry. */
|
||||
settings::BluetoothDevicesSettings tmp = db[i];
|
||||
|
||||
/* Copy the older name field to the newer one. */
|
||||
util::TSNPrintf(tmp.name2, sizeof(tmp.name2), "%s", tmp.name);
|
||||
|
||||
/* Clear the original name field. */
|
||||
std::memset(tmp.name, 0, sizeof(tmp.name));
|
||||
|
||||
/* Write the converted database entry. */
|
||||
R_TRY(fs::WriteFile(file, db_offset, std::addressof(tmp), sizeof(settings::BluetoothDevicesSettings), fs::WriteOption::None));
|
||||
|
||||
/* Advance to the next database entry. */
|
||||
db_offset += sizeof(settings::BluetoothDevicesSettings);
|
||||
}
|
||||
|
||||
/* Flush the data we've written. */
|
||||
R_TRY(fs::FlushFile(file));
|
||||
} else {
|
||||
/* We can just write the database to the file. */
|
||||
R_TRY(fs::WriteFile(file, db_offset, db, total_entries * sizeof(settings::BluetoothDevicesSettings), fs::WriteOption::Flush));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetFirmwareVersion(sf::Out<settings::FirmwareVersion> out) {
|
||||
R_TRY(GetFirmwareVersionImpl(out.GetPointer(), m_client_info));
|
||||
|
||||
/* GetFirmwareVersion sanitizes the revision fields. */
|
||||
out.GetPointer()->revision_major = 0;
|
||||
out.GetPointer()->revision_minor = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetFirmwareVersion2(sf::Out<settings::FirmwareVersion> out) {
|
||||
R_RETURN(GetFirmwareVersionImpl(out.GetPointer(), m_client_info));
|
||||
}
|
||||
|
||||
Result SetSysMitmService::SetBluetoothDevicesSettings(const sf::InMapAliasArray<settings::BluetoothDevicesSettings> &settings) {
|
||||
/* We only want to perform additional logic when the external database setting is enabled. */
|
||||
R_UNLESS(IsExternalBluetoothDatabaseEnabled(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Create the external database if it doesn't exist. */
|
||||
if (!HasExternalBluetoothDatabase()) {
|
||||
R_TRY(fs::CreateFile(ExternalBluetoothDatabasePath, 0));
|
||||
}
|
||||
|
||||
/* Backup the local database to the sd card. */
|
||||
R_TRY(StoreExternalBluetoothDatabase(settings.GetPointer(), settings.GetSize()));
|
||||
|
||||
/* Ensure that the updated database is stored to the system save as usual. */
|
||||
static_assert(sizeof(settings::BluetoothDevicesSettings) == sizeof(::SetSysBluetoothDevicesSettings));
|
||||
R_TRY(setsysSetBluetoothDevicesSettingsFwd(m_forward_service.get(), reinterpret_cast<const ::SetSysBluetoothDevicesSettings *>(settings.GetPointer()), settings.GetSize()));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetBluetoothDevicesSettings(sf::Out<s32> out_count, const sf::OutMapAliasArray<settings::BluetoothDevicesSettings> &out) {
|
||||
/* We only want to perform additional logic when the external database setting is enabled. */
|
||||
R_UNLESS(IsExternalBluetoothDatabaseEnabled(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
if (!HasExternalBluetoothDatabase()) {
|
||||
/* Fetch the local database from the system save. */
|
||||
static_assert(sizeof(settings::BluetoothDevicesSettings) == sizeof(::SetSysBluetoothDevicesSettings));
|
||||
R_TRY(setsysGetBluetoothDevicesSettingsFwd(m_forward_service.get(), out_count.GetPointer(), reinterpret_cast<::SetSysBluetoothDevicesSettings *>(out.GetPointer()), out.GetSize()));
|
||||
|
||||
/* Create the external database file. */
|
||||
R_TRY(fs::CreateFile(ExternalBluetoothDatabasePath, 0));
|
||||
|
||||
/* Backup the local database to the sd card. */
|
||||
R_TRY(StoreExternalBluetoothDatabase(out.GetPointer(), out_count.GetValue()));
|
||||
} else {
|
||||
/* Read the external database from the sd card. */
|
||||
R_TRY(ReadExternalBluetoothDatabase(out_count.GetPointer(), out.GetPointer(), out.GetSize()));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> out_size, const settings::SettingsName &name, const settings::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;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const settings::SettingsName &name, const settings::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;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetDebugModeFlag(sf::Out<bool> out) {
|
||||
/* If we're not processing for am, just return the real flag value. */
|
||||
R_UNLESS(m_client_info.program_id == ncm::SystemProgramId::Am, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Retrieve the user configuration. */
|
||||
u8 en = 0;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "enable_am_debug_mode");
|
||||
|
||||
out.SetValue(en != 0);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
|
||||
#define AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, GetFirmwareVersion, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetFirmwareVersion2, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 11, Result, SetBluetoothDevicesSettings, (const sf::InMapAliasArray<ams::settings::BluetoothDevicesSettings> &settings), (settings)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 12, Result, GetBluetoothDevicesSettings, (sf::Out<s32> out_count, const sf::OutMapAliasArray<ams::settings::BluetoothDevicesSettings> &out), (out_count, out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 37, Result, GetSettingsItemValueSize, (sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, name, key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 38, Result, GetSettingsItemValue, (sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, out, name, key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 62, Result, GetDebugModeFlag, (sf::Out<bool> out), (out))
|
||||
|
||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::settings, ISetSysMitmInterface, AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO, 0x0E82ED13)
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
class SetSysMitmService : public sf::MitmServiceImplBase {
|
||||
public:
|
||||
using MitmServiceImplBase::MitmServiceImplBase;
|
||||
public:
|
||||
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
|
||||
/* We will mitm:
|
||||
* - everything, because we want to intercept all settings requests.
|
||||
*/
|
||||
AMS_UNUSED(client_info);
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out);
|
||||
Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out);
|
||||
Result SetBluetoothDevicesSettings(const sf::InMapAliasArray<ams::settings::BluetoothDevicesSettings> &settings);
|
||||
Result GetBluetoothDevicesSettings(sf::Out<s32> out_count, const sf::OutMapAliasArray<ams::settings::BluetoothDevicesSettings> &out);
|
||||
Result GetSettingsItemValueSize(sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key);
|
||||
Result GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key);
|
||||
Result GetDebugModeFlag(sf::Out<bool> out);
|
||||
};
|
||||
static_assert(IsISetSysMitmInterface<SetSysMitmService>);
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 "setsys_shim.h"
|
||||
|
||||
Result setsysSetBluetoothDevicesSettingsFwd(Service *s, const SetSysBluetoothDevicesSettings *settings, s32 count) {
|
||||
return serviceDispatch(s, 11,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||
.buffers = { { settings, count * sizeof(SetSysBluetoothDevicesSettings) } },
|
||||
);
|
||||
}
|
||||
|
||||
Result setsysGetBluetoothDevicesSettingsFwd(Service *s, s32 *total_out, SetSysBluetoothDevicesSettings *settings, s32 count) {
|
||||
return serviceDispatchOut(s, 12, *total_out,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { settings, count * sizeof(SetSysBluetoothDevicesSettings) } },
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @file setsys_shim.h
|
||||
* @brief Settings Services (fs) IPC wrapper for setsys.mitm.
|
||||
* @author ndeadly
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Forwarding shims. */
|
||||
Result setsysSetBluetoothDevicesSettingsFwd(Service *s, const SetSysBluetoothDevicesSettings *settings, s32 count);
|
||||
Result setsysGetBluetoothDevicesSettingsFwd(Service *s, s32 *total_out, SetSysBluetoothDevicesSettings *settings, s32 count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_ABORT_UNLESS(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_ABORT_UNLESS(setsysGetSettingsItemValue(name, key, dst, dst_size, &size));
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,460 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_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(util::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_ABORT_UNLESS(lhs.HasValue());
|
||||
AMS_ABORT_UNLESS(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_ABORT_UNLESS(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, settings::ResultNullSettingsName());
|
||||
const size_t len = strnlen(name, SettingsNameLengthMax + 1);
|
||||
R_UNLESS(len > 0, settings::ResultEmptySettingsName());
|
||||
R_UNLESS(len <= SettingsNameLengthMax, settings::ResultTooLongSettingsName());
|
||||
R_UNLESS(IsValidSettingsFormat(name, len), settings::ResultInvalidFormatSettingsName());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ValidateSettingsItemKey(const char *key) {
|
||||
R_UNLESS(key != nullptr, settings::ResultNullSettingsName());
|
||||
const size_t len = strnlen(key, SettingsItemKeyLengthMax + 1);
|
||||
R_UNLESS(len > 0, settings::ResultEmptySettingsItemKey());
|
||||
R_UNLESS(len <= SettingsNameLengthMax, settings::ResultTooLongSettingsItemKey());
|
||||
R_UNLESS(IsValidSettingsFormat(key, len), settings::ResultInvalidFormatSettingsItemKey());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result AllocateValue(void **out, size_t size) {
|
||||
R_UNLESS(g_allocated_value_storage_size + size <= sizeof(g_value_storage), settings::ResultSettingsItemValueAllocationFailed());
|
||||
|
||||
*out = g_value_storage + g_allocated_value_storage_size;
|
||||
g_allocated_value_storage_size += size;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result FindSettingsName(const char **out, const char *name) {
|
||||
for (auto &stored : g_names) {
|
||||
if (std::strcmp(stored.value, name) == 0) {
|
||||
*out = stored.value;
|
||||
R_SUCCEED();
|
||||
} else if (std::strcmp(stored.value, "") == 0) {
|
||||
*out = stored.value;
|
||||
std::strcpy(stored.value, name);
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
R_THROW(settings::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;
|
||||
R_SUCCEED();
|
||||
} else if (std::strcmp(stored.value, "") == 0) {
|
||||
std::strcpy(stored.value, key);
|
||||
*out = stored.value;
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
R_THROW(settings::ResultSettingsItemKeyAllocationFailed());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Result ParseSettingsItemIntegralValue(SdKeyValueStoreEntry &out, const char *value_str) {
|
||||
R_TRY(AllocateValue(std::addressof(out.value), sizeof(T)));
|
||||
out.value_size = sizeof(T);
|
||||
|
||||
T value = static_cast<T>(strtoul(value_str, nullptr, 0));
|
||||
std::memcpy(out.value, std::addressof(value), sizeof(T));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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 = std::addressof(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, settings::ResultSettingsItemNotFound());
|
||||
R_UNLESS(*it == test_entry, settings::ResultSettingsItemNotFound());
|
||||
|
||||
*out = std::addressof(*it);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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, settings::ResultInvalidFormatSettingsItemValue());
|
||||
|
||||
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, settings::ResultInvalidFormatSettingsItemValue());
|
||||
R_UNLESS(value_len > 0, settings::ResultInvalidFormatSettingsItemValue());
|
||||
|
||||
/* Create new value. */
|
||||
SdKeyValueStoreEntry new_value = {};
|
||||
|
||||
/* Find name and key. */
|
||||
R_TRY(FindSettingsName(std::addressof(new_value.name), name));
|
||||
R_TRY(FindSettingsItemKey(std::addressof(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(std::addressof(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, settings::ResultInvalidFormatSettingsItemValue());
|
||||
R_UNLESS(value_len % 2 == 0, settings::ResultInvalidFormatSettingsItemValue());
|
||||
R_UNLESS(IsHexadecimal(value_str), settings::ResultInvalidFormatSettingsItemValue());
|
||||
|
||||
const size_t size = value_len / 2;
|
||||
R_TRY(AllocateValue(std::addressof(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 {
|
||||
R_THROW(settings::ResultInvalidFormatSettingsItemValue());
|
||||
}
|
||||
|
||||
/* 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, settings::ResultSettingsItemValueAllocationFailed());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ParseSettingsItemValue(const char *name, const char *key, const char *value) {
|
||||
R_TRY(ValidateSettingsName(name));
|
||||
R_TRY(ValidateSettingsItemKey(key));
|
||||
R_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. */
|
||||
/* It's okay if the file isn't readable/present, because we already loaded defaults. */
|
||||
std::unique_ptr<ams::fs::fsa::IFile> file;
|
||||
{
|
||||
FsFile f;
|
||||
R_SUCCEED_IF(R_FAILED(ams::mitm::fs::OpenAtmosphereSdFile(std::addressof(f), "/config/system_settings.ini", fs::OpenMode_Read)));
|
||||
file = std::make_unique<ams::fs::RemoteFile>(f);
|
||||
}
|
||||
AMS_ABORT_UNLESS(file != nullptr);
|
||||
|
||||
Result parse_result = ResultSuccess();
|
||||
util::ini::ParseFile(file.get(), std::addressof(parse_result), SystemSettingsIniHandler);
|
||||
R_TRY(parse_result);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void LoadDefaultCustomSettings() {
|
||||
/* Disable uploading error reports to Nintendo. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("eupld", "upload_enabled", "u8!0x0"));
|
||||
|
||||
/* Enable USB 3.0 superspeed for homebrew */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("usb", "usb30_force_enabled", spl::IsUsb30ForceEnabled() ? "u8!0x1" : "u8!0x0"));
|
||||
|
||||
/* Control whether RO should ease its validation of NROs. */
|
||||
/* (note: this is normally not necessary, and ips patches can be used.) */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("ro", "ease_nro_restriction", "u8!0x1"));
|
||||
|
||||
/* Control whether lm should log to the SD card. */
|
||||
/* Note that this setting does nothing when log manager is not enabled. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("lm", "enable_sd_card_logging", "u8!0x1"));
|
||||
|
||||
/* Control the output directory for SD card logs. */
|
||||
/* Note that this setting does nothing when log manager is not enabled/sd card logging is not enabled. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("lm", "sd_card_log_output_directory", "str!atmosphere/binlogs"));
|
||||
|
||||
/* Control whether erpt reports should always be preserved, instead of automatically cleaning periodically. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("erpt", "disable_automatic_report_cleanup", "u8!0x0"));
|
||||
|
||||
/* Atmosphere custom settings. */
|
||||
|
||||
/* Reboot from fatal automatically after some number of milliseconds. */
|
||||
/* If field is not present or 0, fatal will wait indefinitely for user input. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "fatal_auto_reboot_interval", "u64!0x0"));
|
||||
|
||||
/* Make the power menu's "reboot" button reboot to payload. */
|
||||
/* Set to "normal" for normal reboot, "rcm" for rcm reboot. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "power_menu_reboot_function", "str!payload"));
|
||||
|
||||
/* Enable writing to BIS partitions for HBL. */
|
||||
/* This is probably undesirable for normal usage. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_hbl_bis_write", "u8!0x0"));
|
||||
|
||||
/* Controls whether dmnt cheats should be toggled on or off by */
|
||||
/* default. 1 = toggled on by default, 0 = toggled off by default. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "dmnt_cheats_enabled_by_default", "u8!0x1"));
|
||||
|
||||
/* Controls whether dmnt should always save cheat toggle state */
|
||||
/* for restoration on new game launch. 1 = always save toggles, */
|
||||
/* 0 = only save toggles if toggle file exists. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "dmnt_always_save_cheat_toggles", "u8!0x0"));
|
||||
|
||||
/* Controls whether fs.mitm should redirect save files */
|
||||
/* to directories on the sd card. */
|
||||
/* 0 = Do not redirect, 1 = Redirect. */
|
||||
/* NOTE: EXPERIMENTAL */
|
||||
/* If you do not know what you are doing, do not touch this yet. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "fsmitm_redirect_saves_to_sd", "u8!0x0"));
|
||||
|
||||
/* Controls whether am sees system settings "DebugModeFlag" as */
|
||||
/* enabled or disabled. */
|
||||
/* 0 = Disabled (not debug mode), 1 = Enabled (debug mode) */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_am_debug_mode", "u8!0x0"));
|
||||
|
||||
/* Controls whether dns.mitm is enabled. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_dns_mitm", "u8!0x1"));
|
||||
|
||||
/* Controls whether dns.mitm uses the default redirections in addition to */
|
||||
/* whatever is specified in the user's hosts file. */
|
||||
/* 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents) */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "add_defaults_to_dns_hosts", "u8!0x1"));
|
||||
|
||||
/* Controls whether dns.mitm logs to the sd card for debugging. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_dns_mitm_debug_log", "u8!0x0"));
|
||||
|
||||
/* Controls whether htc is enabled. */
|
||||
/* TODO: Change this to default 1 when tma2 is ready for inclusion in atmosphere releases. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_htc", "u8!0x0"));
|
||||
|
||||
/* Controls whether atmosphere's dmnt.gen2 gdbstub should run as a standalone via sockets. */
|
||||
/* Note that this setting is ignored (and treated as 0) when htc is enabled. */
|
||||
/* Note that this setting may disappear in the future. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_standalone_gdbstub", "u8!0x0"));
|
||||
|
||||
/* Controls whether atmosphere's log manager is enabled. */
|
||||
/* Note that this setting is ignored (and treated as 1) when htc is enabled. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_log_manager", "u8!0x0"));
|
||||
|
||||
/* Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs) */
|
||||
/* NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_external_bluetooth_db", "u8!0x0"));
|
||||
|
||||
/* Hbloader custom settings. */
|
||||
|
||||
/* Controls the size of the homebrew heap when running as applet. */
|
||||
/* If set to zero, all available applet memory is used as heap. */
|
||||
/* The default is zero. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("hbloader", "applet_heap_size", "u64!0x0"));
|
||||
|
||||
/* Controls the amount of memory to reserve when running as applet */
|
||||
/* for usage by other applets. This setting has no effect if */
|
||||
/* applet_heap_size is non-zero. The default is 0x8600000. */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("hbloader", "applet_heap_reservation_size", "u64!0x8600000"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeSdCardKeyValueStore() {
|
||||
/* Load in hardcoded defaults. */
|
||||
/* These will be overwritten if present on the SD card. */
|
||||
LoadDefaultCustomSettings();
|
||||
|
||||
/* Parse custom settings off the SD card. */
|
||||
R_ABORT_UNLESS(LoadSdCardKeyValueStore());
|
||||
|
||||
/* Determine how many custom settings are present. */
|
||||
for (size_t i = 0; i < util::size(g_entries); i++) {
|
||||
if (!g_entries[i].HasValue()) {
|
||||
g_num_entries = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that the custom settings entries are sorted. */
|
||||
if (g_num_entries) {
|
||||
std::sort(g_entries, g_entries + g_num_entries);
|
||||
}
|
||||
}
|
||||
|
||||
Result GetSdCardKeyValueStoreSettingsItemValueSize(size_t *out_size, const char *name, const char *key) {
|
||||
SdKeyValueStoreEntry *entry = nullptr;
|
||||
R_TRY(GetEntry(std::addressof(entry), name, key));
|
||||
|
||||
*out_size = entry->value_size;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key) {
|
||||
R_UNLESS(dst != nullptr, settings::ResultNullSettingsItemValueBuffer());
|
||||
|
||||
SdKeyValueStoreEntry *entry = nullptr;
|
||||
R_TRY(GetEntry(std::addressof(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;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user