citra-emu
/
citra-canary
Archived
1
0
Fork 0

Service/CFG: convert to ServiceFramework

This commit is contained in:
wwylele 2018-03-06 10:43:24 +02:00
parent 5dd8ac99e3
commit b179b86f14
No known key found for this signature in database
GPG Key ID: 0E87F3187357C16C
16 changed files with 554 additions and 550 deletions

View File

@ -42,22 +42,16 @@ void ConfigureSystem::setConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn(); enabled = !Core::System::GetInstance().IsPoweredOn();
if (!enabled) { if (!enabled) {
cfg = Service::CFG::GetCurrentModule();
ReadSystemSettings(); ReadSystemSettings();
ui->group_system_settings->setEnabled(false); ui->group_system_settings->setEnabled(false);
} else { } else {
// This tab is enabled only when game is not running (i.e. all service are not initialized). // This tab is enabled only when game is not running (i.e. all service are not initialized).
// Temporarily register archive types and load the config savegame file to memory. // Temporarily register archive types and load the config savegame file to memory.
Service::FS::RegisterArchiveTypes(); Service::FS::RegisterArchiveTypes();
ResultCode result = Service::CFG::LoadConfigNANDSaveFile(); cfg = std::make_shared<Service::CFG::Module>();
Service::FS::UnregisterArchiveTypes(); Service::FS::UnregisterArchiveTypes();
if (result.IsError()) {
ui->label_disable_info->setText(tr("Failed to load system settings data."));
ui->group_system_settings->setEnabled(false);
enabled = false;
return;
}
ReadSystemSettings(); ReadSystemSettings();
ui->label_disable_info->hide(); ui->label_disable_info->hide();
} }
@ -65,14 +59,14 @@ void ConfigureSystem::setConfiguration() {
void ConfigureSystem::ReadSystemSettings() { void ConfigureSystem::ReadSystemSettings() {
// set username // set username
username = Service::CFG::GetUsername(); username = cfg->GetUsername();
// TODO(wwylele): Use this when we move to Qt 5.5 // TODO(wwylele): Use this when we move to Qt 5.5
// ui->edit_username->setText(QString::fromStdU16String(username)); // ui->edit_username->setText(QString::fromStdU16String(username));
ui->edit_username->setText( ui->edit_username->setText(
QString::fromUtf16(reinterpret_cast<const ushort*>(username.data()))); QString::fromUtf16(reinterpret_cast<const ushort*>(username.data())));
// set birthday // set birthday
std::tie(birthmonth, birthday) = Service::CFG::GetBirthday(); std::tie(birthmonth, birthday) = cfg->GetBirthday();
ui->combo_birthmonth->setCurrentIndex(birthmonth - 1); ui->combo_birthmonth->setCurrentIndex(birthmonth - 1);
updateBirthdayComboBox( updateBirthdayComboBox(
birthmonth - birthmonth -
@ -80,15 +74,15 @@ void ConfigureSystem::ReadSystemSettings() {
ui->combo_birthday->setCurrentIndex(birthday - 1); ui->combo_birthday->setCurrentIndex(birthday - 1);
// set system language // set system language
language_index = Service::CFG::GetSystemLanguage(); language_index = cfg->GetSystemLanguage();
ui->combo_language->setCurrentIndex(language_index); ui->combo_language->setCurrentIndex(language_index);
// set sound output mode // set sound output mode
sound_index = Service::CFG::GetSoundOutputMode(); sound_index = cfg->GetSoundOutputMode();
ui->combo_sound->setCurrentIndex(sound_index); ui->combo_sound->setCurrentIndex(sound_index);
// set the console id // set the console id
u64 console_id = Service::CFG::GetConsoleUniqueId(); u64 console_id = cfg->GetConsoleUniqueId();
ui->label_console_id->setText( ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper())); tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
} }
@ -105,7 +99,7 @@ void ConfigureSystem::applyConfiguration() {
std::u16string new_username( std::u16string new_username(
reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16())); reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16()));
if (new_username != username) { if (new_username != username) {
Service::CFG::SetUsername(new_username); cfg->SetUsername(new_username);
modified = true; modified = true;
} }
@ -113,27 +107,27 @@ void ConfigureSystem::applyConfiguration() {
int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1; int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1;
int new_birthday = ui->combo_birthday->currentIndex() + 1; int new_birthday = ui->combo_birthday->currentIndex() + 1;
if (birthmonth != new_birthmonth || birthday != new_birthday) { if (birthmonth != new_birthmonth || birthday != new_birthday) {
Service::CFG::SetBirthday(new_birthmonth, new_birthday); cfg->SetBirthday(new_birthmonth, new_birthday);
modified = true; modified = true;
} }
// apply language // apply language
int new_language = ui->combo_language->currentIndex(); int new_language = ui->combo_language->currentIndex();
if (language_index != new_language) { if (language_index != new_language) {
Service::CFG::SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language)); cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language));
modified = true; modified = true;
} }
// apply sound // apply sound
int new_sound = ui->combo_sound->currentIndex(); int new_sound = ui->combo_sound->currentIndex();
if (sound_index != new_sound) { if (sound_index != new_sound) {
Service::CFG::SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound)); cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound));
modified = true; modified = true;
} }
// update the config savegame if any item is modified. // update the config savegame if any item is modified.
if (modified) if (modified)
Service::CFG::UpdateConfigNANDSavegame(); cfg->UpdateConfigNANDSavegame();
} }
void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) { void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) {
@ -173,9 +167,9 @@ void ConfigureSystem::refreshConsoleID() {
return; return;
u32 random_number; u32 random_number;
u64 console_id; u64 console_id;
Service::CFG::GenerateConsoleUniqueId(random_number, console_id); cfg->GenerateConsoleUniqueId(random_number, console_id);
Service::CFG::SetConsoleUniqueId(random_number, console_id); cfg->SetConsoleUniqueId(random_number, console_id);
Service::CFG::UpdateConfigNANDSavegame(); cfg->UpdateConfigNANDSavegame();
ui->label_console_id->setText("Console ID: 0x" + QString::number(console_id, 16).toUpper()); ui->label_console_id->setText("Console ID: 0x" + QString::number(console_id, 16).toUpper());
} }

View File

@ -11,6 +11,12 @@ namespace Ui {
class ConfigureSystem; class ConfigureSystem;
} }
namespace Service {
namespace CFG {
class Module;
} // namespace CFG
} // namespace Service
class ConfigureSystem : public QWidget { class ConfigureSystem : public QWidget {
Q_OBJECT Q_OBJECT
@ -32,6 +38,7 @@ private:
std::unique_ptr<Ui::ConfigureSystem> ui; std::unique_ptr<Ui::ConfigureSystem> ui;
bool enabled; bool enabled;
std::shared_ptr<Service::CFG::Module> cfg;
std::u16string username; std::u16string username;
int birthmonth, birthday; int birthmonth, birthday;
int language_index; int language_index;

View File

@ -79,7 +79,7 @@ static u64 GetTitleIdForApplet(AppletId id) {
ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x%03X", static_cast<u32>(id)); ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x%03X", static_cast<u32>(id));
return itr->title_ids[CFG::GetRegionValue()]; return itr->title_ids[CFG::GetCurrentModule()->GetRegionValue()];
} }
AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) { AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) {

View File

@ -103,7 +103,7 @@ static u32 DecompressLZ11(const u8* in, u8* out) {
bool Module::LoadSharedFont() { bool Module::LoadSharedFont() {
u8 font_region_code; u8 font_region_code;
switch (CFG::GetRegionValue()) { switch (CFG::GetCurrentModule()->GetRegionValue()) {
case 4: // CHN case 4: // CHN
font_region_code = 2; font_region_code = 2;
break; break;

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm> #include <algorithm>
#include <array>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include <cryptopp/sha.h> #include <cryptopp/sha.h>
#include "common/file_util.h" #include "common/file_util.h"
@ -13,7 +12,6 @@
#include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/file_backend.h" #include "core/file_sys/file_backend.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg.h"
@ -21,9 +19,6 @@
#include "core/hle/service/cfg/cfg_nor.h" #include "core/hle/service/cfg/cfg_nor.h"
#include "core/hle/service/cfg/cfg_s.h" #include "core/hle/service/cfg/cfg_s.h"
#include "core/hle/service/cfg/cfg_u.h" #include "core/hle/service/cfg/cfg_u.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/service.h"
#include "core/memory.h"
#include "core/settings.h" #include "core/settings.h"
namespace Service { namespace Service {
@ -113,35 +108,44 @@ static const std::array<float, 8> STEREO_CAMERA_SETTINGS = {
static_assert(sizeof(STEREO_CAMERA_SETTINGS) == 0x20, static_assert(sizeof(STEREO_CAMERA_SETTINGS) == 0x20,
"STEREO_CAMERA_SETTINGS must be exactly 0x20 bytes"); "STEREO_CAMERA_SETTINGS must be exactly 0x20 bytes");
static const u32 CONFIG_SAVEFILE_SIZE = 0x8000;
static std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer;
static Service::FS::ArchiveHandle cfg_system_save_data_archive;
static const std::vector<u8> cfg_system_savedata_id = { static const std::vector<u8> cfg_system_savedata_id = {
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00,
}; };
static u32 preferred_region_code = 0; static std::weak_ptr<Module> current_cfg;
void GetCountryCodeString(Service::Interface* self) { std::shared_ptr<Module> GetCurrentModule() {
u32* cmd_buff = Kernel::GetCommandBuffer(); auto cfg = current_cfg.lock();
u32 country_code_id = cmd_buff[1]; ASSERT_MSG(cfg, "No CFG module running!");
return cfg;
}
Module::Interface::Interface(std::shared_ptr<Module> cfg, const char* name, u32 max_session)
: ServiceFramework(name, max_session), cfg(std::move(cfg)) {}
Module::Interface::~Interface() = default;
void Module::Interface::GetCountryCodeString(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x09, 1, 0);
u16 country_code_id = rp.Pop<u16>();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) { if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) {
LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id); LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id);
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
ErrorSummary::WrongArgument, ErrorLevel::Permanent) ErrorSummary::WrongArgument, ErrorLevel::Permanent));
.raw; rb.Skip(1, false);
return; return;
} }
cmd_buff[1] = 0; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = country_codes[country_code_id]; // the real CFG service copies only three bytes (including the null-terminator) here
rb.Push<u32>(country_codes[country_code_id]);
} }
void GetCountryCodeID(Service::Interface* self) { void Module::Interface::GetCountryCodeID(Kernel::HLERequestContext& ctx) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, 0x0A, 1, 0);
u16 country_code = static_cast<u16>(cmd_buff[1]); u16 country_code = rp.Pop<u16>();
u16 country_code_id = 0; u16 country_code_id = 0;
// The following algorithm will fail if the first country code isn't 0. // The following algorithm will fail if the first country code isn't 0.
@ -154,42 +158,43 @@ void GetCountryCodeID(Service::Interface* self) {
} }
} }
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (0 == country_code_id) { if (0 == country_code_id) {
LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff, LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff,
country_code >> 8); country_code >> 8);
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
ErrorSummary::WrongArgument, ErrorLevel::Permanent) ErrorSummary::WrongArgument, ErrorLevel::Permanent));
.raw; rb.Push<u16>(0x00FF);
cmd_buff[2] = 0xFFFF;
return; return;
} }
cmd_buff[1] = 0; rb.Push(RESULT_SUCCESS);
cmd_buff[2] = country_code_id; rb.Push<u16>(country_code_id);
} }
u32 GetRegionValue() { u32 Module::GetRegionValue() {
if (Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT) if (Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT)
return preferred_region_code; return preferred_region_code;
return Settings::values.region_value; return Settings::values.region_value;
} }
void SecureInfoGetRegion(Service::Interface* self) { void Module::Interface::SecureInfoGetRegion(Kernel::HLERequestContext& ctx, u16 id) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, id, 0, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
cmd_buff[2] = GetRegionValue(); rb.Push(RESULT_SUCCESS);
rb.Push<u8>(cfg->GetRegionValue());
} }
void GenHashConsoleUnique(Service::Interface* self) { void Module::Interface::GenHashConsoleUnique(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); IPC::RequestParser rp(ctx, 0x03, 1, 0);
const u32 app_id_salt = rp.Pop<u32>() & 0x000FFFFF; const u32 app_id_salt = rp.Pop<u32>() & 0x000FFFFF;
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
std::array<u8, 12> buffer; std::array<u8, 12> buffer;
const ResultCode result = GetConfigInfoBlock(ConsoleUniqueID2BlockID, 8, 2, buffer.data()); const ResultCode result = cfg->GetConfigInfoBlock(ConsoleUniqueID2BlockID, 8, 2, buffer.data());
rb.Push(result); rb.Push(result);
if (result.IsSuccess()) { if (result.IsSuccess()) {
std::memcpy(&buffer[8], &app_id_salt, sizeof(u32)); std::memcpy(&buffer[8], &app_id_salt, sizeof(u32));
@ -208,105 +213,94 @@ void GenHashConsoleUnique(Service::Interface* self) {
LOG_DEBUG(Service_CFG, "called app_id_salt=0x%X", app_id_salt); LOG_DEBUG(Service_CFG, "called app_id_salt=0x%X", app_id_salt);
} }
void GetRegionCanadaUSA(Service::Interface* self) { void Module::Interface::GetRegionCanadaUSA(Kernel::HLERequestContext& ctx) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, 0x04, 0, 0);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; rb.Push(RESULT_SUCCESS);
u8 canada_or_usa = 1; u8 canada_or_usa = 1;
if (canada_or_usa == GetRegionValue()) { if (canada_or_usa == cfg->GetRegionValue()) {
cmd_buff[2] = 1; rb.Push(true);
} else { } else {
cmd_buff[2] = 0; rb.Push(false);
} }
} }
void GetSystemModel(Service::Interface* self) { void Module::Interface::GetSystemModel(Kernel::HLERequestContext& ctx) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, 0x05, 0, 0);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
u32 data; u32 data;
// TODO(Subv): Find out the correct error codes // TODO(Subv): Find out the correct error codes
cmd_buff[1] = rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
Service::CFG::GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)) rb.Push<u8>(data & 0xFF);
.raw;
cmd_buff[2] = data & 0xFF;
} }
void GetModelNintendo2DS(Service::Interface* self) { void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, 0x06, 0, 0);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
u32 data; u32 data;
// TODO(Subv): Find out the correct error codes // TODO(Subv): Find out the correct error codes
cmd_buff[1] = rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
Service::CFG::GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data))
.raw;
u8 model = data & 0xFF; u8 model = data & 0xFF;
if (model == Service::CFG::NINTENDO_2DS) rb.Push(model != Service::CFG::NINTENDO_2DS);
cmd_buff[2] = 0;
else
cmd_buff[2] = 1;
} }
void GetConfigInfoBlk2(Service::Interface* self) { void Module::Interface::GetConfigInfoBlk2(Kernel::HLERequestContext& ctx) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, 0x01, 2, 2);
u32 size = cmd_buff[1]; u32 size = rp.Pop<u32>();
u32 block_id = cmd_buff[2]; u32 block_id = rp.Pop<u32>();
VAddr data_pointer = cmd_buff[4]; auto& buffer = rp.PopMappedBuffer();
if (!Memory::IsValidVirtualAddress(data_pointer)) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
cmd_buff[1] = -1; // TODO(Subv): Find the right error code std::vector<u8> data(size);
return; rb.Push(cfg->GetConfigInfoBlock(block_id, size, 0x2, data.data()));
} buffer.Write(data.data(), 0, data.size());
rb.PushMappedBuffer(buffer);
}
void Module::Interface::GetConfigInfoBlk8(Kernel::HLERequestContext& ctx, u16 id) {
IPC::RequestParser rp(ctx, id, 2, 2);
u32 size = rp.Pop<u32>();
u32 block_id = rp.Pop<u32>();
auto& buffer = rp.PopMappedBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
std::vector<u8> data(size);
rb.Push(cfg->GetConfigInfoBlock(block_id, size, 0x8, data.data()));
buffer.Write(data.data(), 0, data.size());
rb.PushMappedBuffer(buffer);
}
void Module::Interface::SetConfigInfoBlk4(Kernel::HLERequestContext& ctx, u16 id) {
IPC::RequestParser rp(ctx, id, 2, 2);
u32 block_id = rp.Pop<u32>();
u32 size = rp.Pop<u32>();
auto& buffer = rp.PopMappedBuffer();
std::vector<u8> data(size); std::vector<u8> data(size);
cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data.data()).raw; buffer.Read(data.data(), 0, data.size());
Memory::WriteBlock(data_pointer, data.data(), data.size());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(cfg->SetConfigInfoBlock(block_id, size, 0x4, data.data()));
rb.PushMappedBuffer(buffer);
} }
void GetConfigInfoBlk8(Service::Interface* self) { void Module::Interface::UpdateConfigNANDSavegame(Kernel::HLERequestContext& ctx, u16 id) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, id, 0, 0);
u32 size = cmd_buff[1]; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
u32 block_id = cmd_buff[2]; rb.Push(cfg->UpdateConfigNANDSavegame());
VAddr data_pointer = cmd_buff[4];
if (!Memory::IsValidVirtualAddress(data_pointer)) {
cmd_buff[1] = -1; // TODO(Subv): Find the right error code
return;
}
std::vector<u8> data(size);
cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data.data()).raw;
Memory::WriteBlock(data_pointer, data.data(), data.size());
} }
void SetConfigInfoBlk4(Service::Interface* self) { void Module::Interface::FormatConfig(Kernel::HLERequestContext& ctx) {
u32* cmd_buff = Kernel::GetCommandBuffer(); IPC::RequestParser rp(ctx, 0x0806, 0, 0);
u32 block_id = cmd_buff[1]; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
u32 size = cmd_buff[2]; rb.Push(cfg->FormatConfig());
VAddr data_pointer = cmd_buff[4];
if (!Memory::IsValidVirtualAddress(data_pointer)) {
cmd_buff[1] = -1; // TODO(Subv): Find the right error code
return;
}
std::vector<u8> data(size);
Memory::ReadBlock(data_pointer, data.data(), data.size());
cmd_buff[1] = Service::CFG::SetConfigInfoBlock(block_id, size, 0x4, data.data()).raw;
} }
void UpdateConfigNANDSavegame(Service::Interface* self) { ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 flag) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = Service::CFG::UpdateConfigNANDSavegame().raw;
}
void FormatConfig(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = Service::CFG::FormatConfig().raw;
}
static ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 flag) {
// Read the header // Read the header
SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data()); SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
@ -346,7 +340,7 @@ static ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 fl
return MakeResult<void*>(pointer); return MakeResult<void*>(pointer);
} }
ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) { ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
void* pointer; void* pointer;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(output, pointer, size); memcpy(output, pointer, size);
@ -354,14 +348,14 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) { ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) {
void* pointer; void* pointer;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(pointer, input, size); memcpy(pointer, input, size);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* data) { ResultCode Module::CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* data) {
SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data()); SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
if (config->total_entries >= CONFIG_FILE_MAX_BLOCK_ENTRIES) if (config->total_entries >= CONFIG_FILE_MAX_BLOCK_ENTRIES)
return ResultCode(-1); // TODO(Subv): Find the right error code return ResultCode(-1); // TODO(Subv): Find the right error code
@ -393,12 +387,12 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* da
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode DeleteConfigNANDSaveFile() { ResultCode Module::DeleteConfigNANDSaveFile() {
FileSys::Path path("/config"); FileSys::Path path("/config");
return Service::FS::DeleteFileFromArchive(cfg_system_save_data_archive, path); return Service::FS::DeleteFileFromArchive(cfg_system_save_data_archive, path);
} }
ResultCode UpdateConfigNANDSavegame() { ResultCode Module::UpdateConfigNANDSavegame() {
FileSys::Mode mode = {}; FileSys::Mode mode = {};
mode.write_flag.Assign(1); mode.write_flag.Assign(1);
mode.create_flag.Assign(1); mode.create_flag.Assign(1);
@ -414,7 +408,7 @@ ResultCode UpdateConfigNANDSavegame() {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode FormatConfig() { ResultCode Module::FormatConfig() {
ResultCode res = DeleteConfigNANDSaveFile(); ResultCode res = DeleteConfigNANDSaveFile();
// The delete command fails if the file doesn't exist, so we have to check that too // The delete command fails if the file doesn't exist, so we have to check that too
if (!res.IsSuccess() && res != FileSys::ERROR_FILE_NOT_FOUND) { if (!res.IsSuccess() && res != FileSys::ERROR_FILE_NOT_FOUND) {
@ -533,7 +527,7 @@ ResultCode FormatConfig() {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode LoadConfigNANDSaveFile() { ResultCode Module::LoadConfigNANDSaveFile() {
// Open the SystemSaveData archive 0x00010017 // Open the SystemSaveData archive 0x00010017
FileSys::Path archive_path(cfg_system_savedata_id); FileSys::Path archive_path(cfg_system_savedata_id);
auto archive_result = auto archive_result =
@ -570,18 +564,11 @@ ResultCode LoadConfigNANDSaveFile() {
return FormatConfig(); return FormatConfig();
} }
void Init() { Module::Module() {
AddService(new CFG_I);
AddService(new CFG_NOR);
AddService(new CFG_S);
AddService(new CFG_U);
LoadConfigNANDSaveFile(); LoadConfigNANDSaveFile();
preferred_region_code = 0;
} }
void Shutdown() {} Module::~Module() = default;
/// Checks if the language is available in the chosen region, and returns a proper one /// Checks if the language is available in the chosen region, and returns a proper one
static SystemLanguage AdjustLanguageInfoBlock(u32 region, SystemLanguage language) { static SystemLanguage AdjustLanguageInfoBlock(u32 region, SystemLanguage language) {
@ -610,7 +597,7 @@ static SystemLanguage AdjustLanguageInfoBlock(u32 region, SystemLanguage languag
return language; return language;
} }
void SetPreferredRegionCode(u32 region_code) { void Module::SetPreferredRegionCode(u32 region_code) {
preferred_region_code = region_code; preferred_region_code = region_code;
LOG_INFO(Service_CFG, "Preferred region code set to %u", preferred_region_code); LOG_INFO(Service_CFG, "Preferred region code set to %u", preferred_region_code);
@ -626,14 +613,14 @@ void SetPreferredRegionCode(u32 region_code) {
} }
} }
void SetUsername(const std::u16string& name) { void Module::SetUsername(const std::u16string& name) {
ASSERT(name.size() <= 10); ASSERT(name.size() <= 10);
UsernameBlock block{}; UsernameBlock block{};
name.copy(block.username, name.size()); name.copy(block.username, name.size());
SetConfigInfoBlock(UsernameBlockID, sizeof(block), 4, &block); SetConfigInfoBlock(UsernameBlockID, sizeof(block), 4, &block);
} }
std::u16string GetUsername() { std::u16string Module::GetUsername() {
UsernameBlock block; UsernameBlock block;
GetConfigInfoBlock(UsernameBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(UsernameBlockID, sizeof(block), 8, &block);
@ -646,40 +633,40 @@ std::u16string GetUsername() {
return username; return username;
} }
void SetBirthday(u8 month, u8 day) { void Module::SetBirthday(u8 month, u8 day) {
BirthdayBlock block = {month, day}; BirthdayBlock block = {month, day};
SetConfigInfoBlock(BirthdayBlockID, sizeof(block), 4, &block); SetConfigInfoBlock(BirthdayBlockID, sizeof(block), 4, &block);
} }
std::tuple<u8, u8> GetBirthday() { std::tuple<u8, u8> Module::GetBirthday() {
BirthdayBlock block; BirthdayBlock block;
GetConfigInfoBlock(BirthdayBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(BirthdayBlockID, sizeof(block), 8, &block);
return std::make_tuple(block.month, block.day); return std::make_tuple(block.month, block.day);
} }
void SetSystemLanguage(SystemLanguage language) { void Module::SetSystemLanguage(SystemLanguage language) {
u8 block = language; u8 block = language;
SetConfigInfoBlock(LanguageBlockID, sizeof(block), 4, &block); SetConfigInfoBlock(LanguageBlockID, sizeof(block), 4, &block);
} }
SystemLanguage GetSystemLanguage() { SystemLanguage Module::GetSystemLanguage() {
u8 block; u8 block;
GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block);
return static_cast<SystemLanguage>(block); return static_cast<SystemLanguage>(block);
} }
void SetSoundOutputMode(SoundOutputMode mode) { void Module::SetSoundOutputMode(SoundOutputMode mode) {
u8 block = mode; u8 block = mode;
SetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 4, &block); SetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 4, &block);
} }
SoundOutputMode GetSoundOutputMode() { SoundOutputMode Module::GetSoundOutputMode() {
u8 block; u8 block;
GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block);
return static_cast<SoundOutputMode>(block); return static_cast<SoundOutputMode>(block);
} }
void GenerateConsoleUniqueId(u32& random_number, u64& console_id) { void Module::GenerateConsoleUniqueId(u32& random_number, u64& console_id) {
CryptoPP::AutoSeededRandomPool rng; CryptoPP::AutoSeededRandomPool rng;
random_number = rng.GenerateWord32(0, 0xFFFF); random_number = rng.GenerateWord32(0, 0xFFFF);
u64_le local_friend_code_seed; u64_le local_friend_code_seed;
@ -688,7 +675,7 @@ void GenerateConsoleUniqueId(u32& random_number, u64& console_id) {
console_id = (local_friend_code_seed & 0x3FFFFFFFF) | (static_cast<u64>(random_number) << 48); console_id = (local_friend_code_seed & 0x3FFFFFFFF) | (static_cast<u64>(random_number) << 48);
} }
ResultCode SetConsoleUniqueId(u32 random_number, u64 console_id) { ResultCode Module::SetConsoleUniqueId(u32 random_number, u64 console_id) {
u64_le console_id_le = console_id; u64_le console_id_le = console_id;
ResultCode res = ResultCode res =
SetConfigInfoBlock(ConsoleUniqueID1BlockID, sizeof(console_id_le), 0xE, &console_id_le); SetConfigInfoBlock(ConsoleUniqueID1BlockID, sizeof(console_id_le), 0xE, &console_id_le);
@ -708,11 +695,20 @@ ResultCode SetConsoleUniqueId(u32 random_number, u64 console_id) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
u64 GetConsoleUniqueId() { u64 Module::GetConsoleUniqueId() {
u64_le console_id_le; u64_le console_id_le;
GetConfigInfoBlock(ConsoleUniqueID2BlockID, sizeof(console_id_le), 0xE, &console_id_le); GetConfigInfoBlock(ConsoleUniqueID2BlockID, sizeof(console_id_le), 0xE, &console_id_le);
return console_id_le; return console_id_le;
} }
void InstallInterfaces(SM::ServiceManager& service_manager) {
auto cfg = std::make_shared<Module>();
std::make_shared<CFG_I>(cfg)->InstallAsService(service_manager);
std::make_shared<CFG_S>(cfg)->InstallAsService(service_manager);
std::make_shared<CFG_U>(cfg)->InstallAsService(service_manager);
std::make_shared<CFG_NOR>()->InstallAsService(service_manager);
current_cfg = cfg;
}
} // namespace CFG } // namespace CFG
} // namespace Service } // namespace Service

View File

@ -5,15 +5,12 @@
#pragma once #pragma once
#include <array> #include <array>
#include <memory>
#include <string> #include <string>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/fs/archive.h"
union ResultCode;
namespace Service { namespace Service {
class Interface;
namespace CFG { namespace CFG {
enum SystemModel { enum SystemModel {
@ -82,289 +79,321 @@ static const std::array<u16, 187> country_codes = {{
C("SM"), C("VA"), C("BM"), // 184-186 C("SM"), C("VA"), C("BM"), // 184-186
}}; }};
/** class Module final {
* CFG::GetCountryCodeString service function public:
* Inputs: Module();
* 1 : Country Code ID ~Module();
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Country's 2-char string
*/
void GetCountryCodeString(Service::Interface* self);
/** class Interface : public ServiceFramework<Interface> {
* CFG::GetCountryCodeID service function public:
* Inputs: Interface(std::shared_ptr<Module> cfg, const char* name, u32 max_session);
* 1 : Country Code 2-char string ~Interface();
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Country Code ID
*/
void GetCountryCodeID(Service::Interface* self);
u32 GetRegionValue(); /**
* CFG::GetCountryCodeString service function
* Inputs:
* 1 : Country Code ID
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Country's 2-char string
*/
void GetCountryCodeString(Kernel::HLERequestContext& ctx);
/** /**
* CFG::SecureInfoGetRegion service function * CFG::GetCountryCodeID service function
* Inputs: * Inputs:
* 1 : None * 1 : Country Code 2-char string
* Outputs: * Outputs:
* 0 : Result Header code * 1 : Result of function, 0 on success, otherwise error code
* 1 : Result of function, 0 on success, otherwise error code * 2 : Country Code ID
* 2 : Region value loaded from SecureInfo offset 0x100 */
*/ void GetCountryCodeID(Kernel::HLERequestContext& ctx);
void SecureInfoGetRegion(Service::Interface* self);
/** u32 GetRegionValue();
* CFG::GenHashConsoleUnique service function
* Inputs:
* 1 : 20 bit application ID salt
* Outputs:
* 0 : Result Header code
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Hash/"ID" lower word
* 3 : Hash/"ID" upper word
*/
void GenHashConsoleUnique(Service::Interface* self);
/** /**
* CFG::GetRegionCanadaUSA service function * CFG::SecureInfoGetRegion service function
* Inputs: * Inputs:
* 1 : None * 1 : None
* Outputs: * Outputs:
* 0 : Result Header code * 0 : Result Header code
* 1 : Result of function, 0 on success, otherwise error code * 1 : Result of function, 0 on success, otherwise error code
* 2 : 1 if the system is a Canada or USA model, 0 otherwise * 2 : Region value loaded from SecureInfo offset 0x100
*/ */
void GetRegionCanadaUSA(Service::Interface* self); void SecureInfoGetRegion(Kernel::HLERequestContext& ctx, u16 id);
/** /**
* CFG::GetSystemModel service function * CFG::GenHashConsoleUnique service function
* Inputs: * Inputs:
* 0 : 0x00050000 * 1 : 20 bit application ID salt
* Outputs: * Outputs:
* 1 : Result of function, 0 on success, otherwise error code * 0 : Result Header code
* 2 : Model of the console * 1 : Result of function, 0 on success, otherwise error code
*/ * 2 : Hash/"ID" lower word
void GetSystemModel(Service::Interface* self); * 3 : Hash/"ID" upper word
*/
void GenHashConsoleUnique(Kernel::HLERequestContext& ctx);
/** /**
* CFG::GetModelNintendo2DS service function * CFG::GetRegionCanadaUSA service function
* Inputs: * Inputs:
* 0 : 0x00060000 * 1 : None
* Outputs: * Outputs:
* 1 : Result of function, 0 on success, otherwise error code * 0 : Result Header code
* 2 : 0 if the system is a Nintendo 2DS, 1 otherwise * 1 : Result of function, 0 on success, otherwise error code
*/ * 2 : 1 if the system is a Canada or USA model, 0 otherwise
void GetModelNintendo2DS(Service::Interface* self); */
void GetRegionCanadaUSA(Kernel::HLERequestContext& ctx);
/** /**
* CFG::GetConfigInfoBlk2 service function * CFG::GetSystemModel service function
* Inputs: * Inputs:
* 0 : 0x00010082 * 0 : 0x00050000
* 1 : Size * Outputs:
* 2 : Block ID * 1 : Result of function, 0 on success, otherwise error code
* 3 : Descriptor for the output buffer * 2 : Model of the console
* 4 : Output buffer pointer */
* Outputs: void GetSystemModel(Kernel::HLERequestContext& ctx);
* 1 : Result of function, 0 on success, otherwise error code
*/
void GetConfigInfoBlk2(Service::Interface* self);
/** /**
* CFG::GetConfigInfoBlk8 service function * CFG::GetModelNintendo2DS service function
* Inputs: * Inputs:
* 0 : 0x04010082 / 0x08010082 * 0 : 0x00060000
* 1 : Size * Outputs:
* 2 : Block ID * 1 : Result of function, 0 on success, otherwise error code
* 3 : Descriptor for the output buffer * 2 : 0 if the system is a Nintendo 2DS, 1 otherwise
* 4 : Output buffer pointer */
* Outputs: void GetModelNintendo2DS(Kernel::HLERequestContext& ctx);
* 1 : Result of function, 0 on success, otherwise error code
*/
void GetConfigInfoBlk8(Service::Interface* self);
/** /**
* CFG::SetConfigInfoBlk4 service function * CFG::GetConfigInfoBlk2 service function
* Inputs: * Inputs:
* 0 : 0x04020082 / 0x08020082 * 0 : 0x00010082
* 1 : Block ID * 1 : Size
* 2 : Size * 2 : Block ID
* 3 : Descriptor for the output buffer * 3 : Descriptor for the output buffer
* 4 : Output buffer pointer * 4 : Output buffer pointer
* Outputs: * Outputs:
* 1 : Result of function, 0 on success, otherwise error code * 1 : Result of function, 0 on success, otherwise error code
* Note: */
* The parameters order is different from GetConfigInfoBlk2/8's, void GetConfigInfoBlk2(Kernel::HLERequestContext& ctx);
* where Block ID and Size are switched.
*/
void SetConfigInfoBlk4(Service::Interface* self);
/** /**
* CFG::UpdateConfigNANDSavegame service function * CFG::GetConfigInfoBlk8 service function
* Inputs: * Inputs:
* 0 : 0x04030000 / 0x08030000 * 0 : 0x04010082 / 0x08010082
* Outputs: * 1 : Size
* 1 : Result of function, 0 on success, otherwise error code * 2 : Block ID
*/ * 3 : Descriptor for the output buffer
void UpdateConfigNANDSavegame(Service::Interface* self); * 4 : Output buffer pointer
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void GetConfigInfoBlk8(Kernel::HLERequestContext& ctx, u16 id);
/** /**
* CFG::FormatConfig service function * CFG::SetConfigInfoBlk4 service function
* Inputs: * Inputs:
* 0 : 0x08060000 * 0 : 0x04020082 / 0x08020082
* Outputs: * 1 : Block ID
* 1 : Result of function, 0 on success, otherwise error code * 2 : Size
*/ * 3 : Descriptor for the output buffer
void FormatConfig(Service::Interface* self); * 4 : Output buffer pointer
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* Note:
* The parameters order is different from GetConfigInfoBlk2/8's,
* where Block ID and Size are switched.
*/
void SetConfigInfoBlk4(Kernel::HLERequestContext& ctx, u16 id);
/** /**
* Reads a block with the specified id and flag from the Config savegame buffer * CFG::UpdateConfigNANDSavegame service function
* and writes the output to output. The input size must match exactly the size of the requested * Inputs:
* block. * 0 : 0x04030000 / 0x08030000
* * Outputs:
* @param block_id The id of the block we want to read * 1 : Result of function, 0 on success, otherwise error code
* @param size The size of the block we want to read */
* @param flag The requested block must have this flag set void UpdateConfigNANDSavegame(Kernel::HLERequestContext& ctx, u16 id);
* @param output A pointer where we will write the read data
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output);
/** /**
* Reads data from input and writes to a block with the specified id and flag * CFG::FormatConfig service function
* in the Config savegame buffer. The input size must match exactly the size of the target block. * Inputs:
* * 0 : 0x08060000
* @param block_id The id of the block we want to write * Outputs:
* @param size The size of the block we want to write * 1 : Result of function, 0 on success, otherwise error code
* @param flag The target block must have this flag set */
* @param input A pointer where we will read data and write to Config savegame buffer void FormatConfig(Kernel::HLERequestContext& ctx);
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input);
/** /// A helper function for dispatching service functions that have multiple IDs
* Creates a block with the specified id and writes the input data to the cfg savegame buffer in template <void (Interface::*function)(Kernel::HLERequestContext& ctx, u16 id), u16 id>
* memory. The config savegame file in the filesystem is not updated. void D(Kernel::HLERequestContext& ctx) {
* (this->*function)(ctx, id);
* @param block_id The id of the block we want to create }
* @param size The size of the block we want to create
* @param flags The flags of the new block
* @param data A pointer containing the data we will write to the new block
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* data);
/** private:
* Deletes the config savegame file from the filesystem, the buffer in memory is not affected std::shared_ptr<Module> cfg;
* @returns ResultCode indicating the result of the operation, 0 on success };
*/
ResultCode DeleteConfigNANDSaveFile();
/** private:
* Writes the config savegame memory buffer to the config savegame file in the filesystem ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 flag);
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode UpdateConfigNANDSavegame();
/** /**
* Re-creates the config savegame file in memory and the filesystem with the default blocks * Reads a block with the specified id and flag from the Config savegame buffer
* @returns ResultCode indicating the result of the operation, 0 on success * and writes the output to output. The input size must match exactly the size of the requested
*/ * block.
ResultCode FormatConfig(); *
* @param block_id The id of the block we want to read
* @param size The size of the block we want to read
* @param flag The requested block must have this flag set
* @param output A pointer where we will write the read data
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output);
/** /**
* Open the config savegame file and load it to the memory buffer * Reads data from input and writes to a block with the specified id and flag
* @returns ResultCode indicating the result of the operation, 0 on success * in the Config savegame buffer. The input size must match exactly the size of the target
*/ * block.
ResultCode LoadConfigNANDSaveFile(); *
* @param block_id The id of the block we want to write
* @param size The size of the block we want to write
* @param flag The target block must have this flag set
* @param input A pointer where we will read data and write to Config savegame buffer
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input);
/// Initialize the config service /**
void Init(); * Creates a block with the specified id and writes the input data to the cfg savegame buffer in
* memory. The config savegame file in the filesystem is not updated.
*
* @param block_id The id of the block we want to create
* @param size The size of the block we want to create
* @param flags The flags of the new block
* @param data A pointer containing the data we will write to the new block
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* data);
/// Shutdown the config service /**
void Shutdown(); * Deletes the config savegame file from the filesystem, the buffer in memory is not affected
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode DeleteConfigNANDSaveFile();
/** /**
* Set the region code preferred by the game so that CFG will adjust to it when the region setting * Re-creates the config savegame file in memory and the filesystem with the default blocks
* is auto. * @returns ResultCode indicating the result of the operation, 0 on success
* @param region_code the preferred region code to set */
*/ ResultCode FormatConfig();
void SetPreferredRegionCode(u32 region_code);
// Utilities for frontend to set config data. /**
// Note: before calling these functions, LoadConfigNANDSaveFile should be called, * Open the config savegame file and load it to the memory buffer
// and UpdateConfigNANDSavegame should be called after making changes to config data. * @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode LoadConfigNANDSaveFile();
/** public:
* Sets the username in config savegame. u32 GetRegionValue();
* @param name the username to set. The maximum size is 10 in char16_t.
*/
void SetUsername(const std::u16string& name);
/** /**
* Gets the username from config savegame. * Set the region code preferred by the game so that CFG will adjust to it when the region
* @returns the username * setting
*/ * is auto.
std::u16string GetUsername(); * @param region_code the preferred region code to set
*/
void SetPreferredRegionCode(u32 region_code);
/** // Utilities for frontend to set config data.
* Sets the profile birthday in config savegame. // Note: UpdateConfigNANDSavegame should be called after making changes to config data.
* @param month the month of birthday.
* @param day the day of the birthday.
*/
void SetBirthday(u8 month, u8 day);
/** /**
* Gets the profile birthday from the config savegame. * Sets the username in config savegame.
* @returns a tuple of (month, day) of birthday * @param name the username to set. The maximum size is 10 in char16_t.
*/ */
std::tuple<u8, u8> GetBirthday(); void SetUsername(const std::u16string& name);
/** /**
* Sets the system language in config savegame. * Gets the username from config savegame.
* @param language the system language to set. * @returns the username
*/ */
void SetSystemLanguage(SystemLanguage language); std::u16string GetUsername();
/** /**
* Gets the system language from config savegame. * Sets the profile birthday in config savegame.
* @returns the system language * @param month the month of birthday.
*/ * @param day the day of the birthday.
SystemLanguage GetSystemLanguage(); */
void SetBirthday(u8 month, u8 day);
/** /**
* Sets the sound output mode in config savegame. * Gets the profile birthday from the config savegame.
* @param mode the sound output mode to set * @returns a tuple of (month, day) of birthday
*/ */
void SetSoundOutputMode(SoundOutputMode mode); std::tuple<u8, u8> GetBirthday();
/** /**
* Gets the sound output mode from config savegame. * Sets the system language in config savegame.
* @returns the sound output mode * @param language the system language to set.
*/ */
SoundOutputMode GetSoundOutputMode(); void SetSystemLanguage(SystemLanguage language);
/** /**
* Generates a new random console unique id. * Gets the system language from config savegame.
* @param random_number a random generated 16bit number stored at 0x90002, used for generating the * @returns the system language
* console_id */
* @param console_id the randomly created console id SystemLanguage GetSystemLanguage();
*/
void GenerateConsoleUniqueId(u32& random_number, u64& console_id);
/** /**
* Sets the random_number and the console unique id in the config savegame. * Sets the sound output mode in config savegame.
* @param random_number the random_number to set * @param mode the sound output mode to set
* @param console_id the console id to set */
*/ void SetSoundOutputMode(SoundOutputMode mode);
ResultCode SetConsoleUniqueId(u32 random_number, u64 console_id);
/** /**
* Gets the console unique id from config savegame. * Gets the sound output mode from config savegame.
* @returns the console unique id * @returns the sound output mode
*/ */
u64 GetConsoleUniqueId(); SoundOutputMode GetSoundOutputMode();
/**
* Generates a new random console unique id.
* @param random_number a random generated 16bit number stored at 0x90002, used for generating
* the
* console_id
* @param console_id the randomly created console id
*/
void GenerateConsoleUniqueId(u32& random_number, u64& console_id);
/**
* Sets the random_number and the console unique id in the config savegame.
* @param random_number the random_number to set
* @param console_id the console id to set
*/
ResultCode SetConsoleUniqueId(u32 random_number, u64 console_id);
/**
* Gets the console unique id from config savegame.
* @returns the console unique id
*/
u64 GetConsoleUniqueId();
/**
* Writes the config savegame memory buffer to the config savegame file in the filesystem
* @returns ResultCode indicating the result of the operation, 0 on success
*/
ResultCode UpdateConfigNANDSavegame();
private:
static constexpr u32 CONFIG_SAVEFILE_SIZE = 0x8000;
std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer;
Service::FS::ArchiveHandle cfg_system_save_data_archive;
u32 preferred_region_code = 0;
};
void InstallInterfaces(SM::ServiceManager& service_manager);
std::shared_ptr<Module> GetCurrentModule();
} // namespace CFG } // namespace CFG
} // namespace Service } // namespace Service

View File

@ -2,63 +2,63 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_i.h" #include "core/hle/service/cfg/cfg_i.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
const Interface::FunctionInfo FunctionTable[] = { CFG_I::CFG_I(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:i", 23) {
// cfg common static const FunctionInfo functions[] = {
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, // cfg common
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, {0x00010082, &CFG_I::GetConfigInfoBlk2, "GetConfigInfoBlk2"},
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"}, {0x00020000, &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0002>, "SecureInfoGetRegion"},
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"}, {0x00030040, &CFG_I::GenHashConsoleUnique, "GenHashConsoleUnique"},
{0x00050000, GetSystemModel, "GetSystemModel"}, {0x00040000, &CFG_I::GetRegionCanadaUSA, "GetRegionCanadaUSA"},
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"}, {0x00050000, &CFG_I::GetSystemModel, "GetSystemModel"},
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"}, {0x00060000, &CFG_I::GetModelNintendo2DS, "GetModelNintendo2DS"},
{0x00080080, nullptr, "GoThroughTable"}, {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"}, {0x00080080, nullptr, "GoThroughTable"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, {0x00090040, &CFG_I::GetCountryCodeString, "GetCountryCodeString"},
{0x000B0000, nullptr, "IsFangateSupported"}, {0x000A0040, &CFG_I::GetCountryCodeID, "GetCountryCodeID"},
// cfg:i {0x000B0000, nullptr, "IsFangateSupported"},
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, // cfg:i
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, {0x04010082, &CFG_I::D<&CFG_I::GetConfigInfoBlk8, 0x0401>, "GetConfigInfoBlk8"},
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, {0x04020082, &CFG_I::D<&CFG_I::SetConfigInfoBlk4, 0x0402>, "SetConfigInfoBlk4"},
{0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, {0x04030000, &CFG_I::D<&CFG_I::UpdateConfigNANDSavegame, 0x0403>,
{0x04050000, nullptr, "GetLocalFriendCodeSeed"}, "UpdateConfigNANDSavegame"},
{0x04060000, SecureInfoGetRegion, "SecureInfoGetRegion"}, {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
{0x04070000, nullptr, "SecureInfoGetByte101"}, {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
{0x04080042, nullptr, "SecureInfoGetSerialNo"}, {0x04060000, &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0406>, "SecureInfoGetRegion"},
{0x04090000, nullptr, "UpdateConfigBlk00040003"}, {0x04070000, nullptr, "SecureInfoGetByte101"},
{0x08010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, {0x04080042, nullptr, "SecureInfoGetSerialNo"},
{0x08020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, {0x04090000, nullptr, "UpdateConfigBlk00040003"},
{0x08030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, {0x08010082, &CFG_I::D<&CFG_I::GetConfigInfoBlk8, 0x0801>, "GetConfigInfoBlk8"},
{0x080400C2, nullptr, "CreateConfigInfoBlk"}, {0x08020082, &CFG_I::D<&CFG_I::SetConfigInfoBlk4, 0x0802>, "SetConfigInfoBlk4"},
{0x08050000, nullptr, "DeleteConfigNANDSavefile"}, {0x08030000, &CFG_I::D<&CFG_I::UpdateConfigNANDSavegame, 0x0803>,
{0x08060000, FormatConfig, "FormatConfig"}, "UpdateConfigNANDSavegame"},
{0x08080000, nullptr, "UpdateConfigBlk1"}, {0x080400C2, nullptr, "CreateConfigInfoBlk"},
{0x08090000, nullptr, "UpdateConfigBlk2"}, {0x08050000, nullptr, "DeleteConfigNANDSavefile"},
{0x080A0000, nullptr, "UpdateConfigBlk3"}, {0x08060000, &CFG_I::FormatConfig, "FormatConfig"},
{0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"}, {0x08080000, nullptr, "UpdateConfigBlk1"},
{0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"}, {0x08090000, nullptr, "UpdateConfigBlk2"},
{0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"}, {0x080A0000, nullptr, "UpdateConfigBlk3"},
{0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"}, {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
{0x080F0042, nullptr, "GetLocalFriendCodeSeedData"}, {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
{0x08100000, nullptr, "GetLocalFriendCodeSeed"}, {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
{0x08110084, nullptr, "SetSecureInfo"}, {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
{0x08120000, nullptr, "DeleteCreateNANDSecureInfo"}, {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
{0x08130000, nullptr, "VerifySigSecureInfo"}, {0x08100000, nullptr, "GetLocalFriendCodeSeed"},
{0x08140042, nullptr, "SecureInfoGetData"}, {0x08110084, nullptr, "SetSecureInfo"},
{0x08150042, nullptr, "SecureInfoGetSignature"}, {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
{0x08160000, SecureInfoGetRegion, "SecureInfoGetRegion"}, {0x08130000, nullptr, "VerifySigSecureInfo"},
{0x08170000, nullptr, "SecureInfoGetByte101"}, {0x08140042, nullptr, "SecureInfoGetData"},
{0x08180042, nullptr, "SecureInfoGetSerialNo"}, {0x08150042, nullptr, "SecureInfoGetSignature"},
}; {0x08160000, &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0816>, "SecureInfoGetRegion"},
{0x08170000, nullptr, "SecureInfoGetByte101"},
CFG_I::CFG_I() { {0x08180042, nullptr, "SecureInfoGetSerialNo"},
Register(FunctionTable); };
RegisterHandlers(functions);
} }
} // namespace CFG } // namespace CFG
} // namespace Service } // namespace Service

View File

@ -4,19 +4,15 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/cfg/cfg.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
class CFG_I final : public Interface { class CFG_I final : public Module::Interface {
public: public:
CFG_I(); explicit CFG_I(std::shared_ptr<Module> cfg);
std::string GetPortName() const override {
return "cfg:i";
}
}; };
} // namespace CFG } // namespace CFG
} // namespace Service } // namespace Service

View File

@ -2,21 +2,19 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_nor.h" #include "core/hle/service/cfg/cfg_nor.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
const Interface::FunctionInfo FunctionTable[] = { CFG_NOR::CFG_NOR() : ServiceFramework("cfg:nor", 23) {
{0x00010040, nullptr, "Initialize"}, static const FunctionInfo functions[] = {
{0x00020000, nullptr, "Shutdown"}, {0x00010040, nullptr, "Initialize"},
{0x00050082, nullptr, "ReadData"}, {0x00020000, nullptr, "Shutdown"},
{0x00060082, nullptr, "WriteData"}, {0x00050082, nullptr, "ReadData"},
}; {0x00060082, nullptr, "WriteData"},
};
CFG_NOR::CFG_NOR() { RegisterHandlers(functions);
Register(FunctionTable);
} }
} // namespace CFG } // namespace CFG

View File

@ -9,13 +9,9 @@
namespace Service { namespace Service {
namespace CFG { namespace CFG {
class CFG_NOR final : public Interface { class CFG_NOR final : public ServiceFramework<CFG_NOR> {
public: public:
CFG_NOR(); CFG_NOR();
std::string GetPortName() const override {
return "cfg:nor";
}
}; };
} // namespace CFG } // namespace CFG

View File

@ -2,39 +2,38 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_s.h" #include "core/hle/service/cfg/cfg_s.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
const Interface::FunctionInfo FunctionTable[] = { CFG_S::CFG_S(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:s", 23) {
// cfg common static const FunctionInfo functions[] = {
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, // cfg common
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, {0x00010082, &CFG_S::GetConfigInfoBlk2, "GetConfigInfoBlk2"},
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"}, {0x00020000, &CFG_S::D<&CFG_S::SecureInfoGetRegion, 0x0002>, "SecureInfoGetRegion"},
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"}, {0x00030040, &CFG_S::GenHashConsoleUnique, "GenHashConsoleUnique"},
{0x00050000, GetSystemModel, "GetSystemModel"}, {0x00040000, &CFG_S::GetRegionCanadaUSA, "GetRegionCanadaUSA"},
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"}, {0x00050000, &CFG_S::GetSystemModel, "GetSystemModel"},
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"}, {0x00060000, &CFG_S::GetModelNintendo2DS, "GetModelNintendo2DS"},
{0x00080080, nullptr, "GoThroughTable"}, {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"}, {0x00080080, nullptr, "GoThroughTable"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, {0x00090040, &CFG_S::GetCountryCodeString, "GetCountryCodeString"},
{0x000B0000, nullptr, "IsFangateSupported"}, {0x000A0040, &CFG_S::GetCountryCodeID, "GetCountryCodeID"},
// cfg:s {0x000B0000, nullptr, "IsFangateSupported"},
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, // cfg:s
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, {0x04010082, &CFG_S::D<&CFG_S::GetConfigInfoBlk8, 0x0401>, "GetConfigInfoBlk8"},
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, {0x04020082, &CFG_S::D<&CFG_S::SetConfigInfoBlk4, 0x0402>, "SetConfigInfoBlk4"},
{0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, {0x04030000, &CFG_S::D<&CFG_S::UpdateConfigNANDSavegame, 0x0403>,
{0x04050000, nullptr, "GetLocalFriendCodeSeed"}, "UpdateConfigNANDSavegame"},
{0x04060000, nullptr, "SecureInfoGetRegion"}, {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
{0x04070000, nullptr, "SecureInfoGetByte101"}, {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
{0x04080042, nullptr, "SecureInfoGetSerialNo"}, {0x04060000, &CFG_S::D<&CFG_S::SecureInfoGetRegion, 0x0406>, "SecureInfoGetRegion"},
{0x04090000, nullptr, "UpdateConfigBlk00040003"}, {0x04070000, nullptr, "SecureInfoGetByte101"},
}; {0x04080042, nullptr, "SecureInfoGetSerialNo"},
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
CFG_S::CFG_S() { };
Register(FunctionTable); RegisterHandlers(functions);
} }
} // namespace CFG } // namespace CFG

View File

@ -4,18 +4,14 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/cfg/cfg.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
class CFG_S final : public Interface { class CFG_S final : public Module::Interface {
public: public:
CFG_S(); explicit CFG_S(std::shared_ptr<Module> cfg);
std::string GetPortName() const override {
return "cfg:s";
}
}; };
} // namespace CFG } // namespace CFG

View File

@ -2,29 +2,27 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_u.h" #include "core/hle/service/cfg/cfg_u.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
const Interface::FunctionInfo FunctionTable[] = { CFG_U::CFG_U(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:u", 23) {
// cfg common static const FunctionInfo functions[] = {
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, // cfg common
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, {0x00010082, &CFG_U::GetConfigInfoBlk2, "GetConfigInfoBlk2"},
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"}, {0x00020000, &CFG_U::D<&CFG_U::SecureInfoGetRegion, 0x0002>, "SecureInfoGetRegion"},
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"}, {0x00030040, &CFG_U::GenHashConsoleUnique, "GenHashConsoleUnique"},
{0x00050000, GetSystemModel, "GetSystemModel"}, {0x00040000, &CFG_U::GetRegionCanadaUSA, "GetRegionCanadaUSA"},
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"}, {0x00050000, &CFG_U::GetSystemModel, "GetSystemModel"},
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"}, {0x00060000, &CFG_U::GetModelNintendo2DS, "GetModelNintendo2DS"},
{0x00080080, nullptr, "GoThroughTable"}, {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"}, {0x00080080, nullptr, "GoThroughTable"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, {0x00090040, &CFG_U::GetCountryCodeString, "GetCountryCodeString"},
{0x000B0000, nullptr, "IsFangateSupported"}, {0x000A0040, &CFG_U::GetCountryCodeID, "GetCountryCodeID"},
}; {0x000B0000, nullptr, "IsFangateSupported"},
};
CFG_U::CFG_U() { RegisterHandlers(functions);
Register(FunctionTable);
} }
} // namespace CFG } // namespace CFG

View File

@ -4,18 +4,14 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/cfg/cfg.h"
namespace Service { namespace Service {
namespace CFG { namespace CFG {
class CFG_U final : public Interface { class CFG_U final : public Module::Interface {
public: public:
CFG_U(); explicit CFG_U(std::shared_ptr<Module> cfg);
std::string GetPortName() const override {
return "cfg:u";
}
}; };
} // namespace CFG } // namespace CFG

View File

@ -242,7 +242,7 @@ void Init() {
BOSS::Init(); BOSS::Init();
CAM::InstallInterfaces(*SM::g_service_manager); CAM::InstallInterfaces(*SM::g_service_manager);
CECD::Init(); CECD::Init();
CFG::Init(); CFG::InstallInterfaces(*SM::g_service_manager);
DLP::Init(); DLP::Init();
FRD::InstallInterfaces(*SM::g_service_manager); FRD::InstallInterfaces(*SM::g_service_manager);
GSP::InstallInterfaces(*SM::g_service_manager); GSP::InstallInterfaces(*SM::g_service_manager);
@ -273,7 +273,6 @@ void Init() {
void Shutdown() { void Shutdown() {
NDM::Shutdown(); NDM::Shutdown();
DLP::Shutdown(); DLP::Shutdown();
CFG::Shutdown();
CECD::Shutdown(); CECD::Shutdown();
BOSS::Shutdown(); BOSS::Shutdown();
FS::ArchiveShutdown(); FS::ArchiveShutdown();

View File

@ -135,7 +135,7 @@ void AppLoader_NCCH::ParseRegionLockoutInfo() {
constexpr u32 REGION_COUNT = 7; constexpr u32 REGION_COUNT = 7;
for (u32 region = 0; region < REGION_COUNT; ++region) { for (u32 region = 0; region < REGION_COUNT; ++region) {
if (region_lockout & 1) { if (region_lockout & 1) {
Service::CFG::SetPreferredRegionCode(region); Service::CFG::GetCurrentModule()->SetPreferredRegionCode(region);
break; break;
} }
region_lockout >>= 1; region_lockout >>= 1;