From b179b86f14d216879097cf14142f44081bfd6157 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Tue, 6 Mar 2018 10:43:24 +0200
Subject: [PATCH 1/2] Service/CFG: convert to ServiceFramework

---
 .../configuration/configure_system.cpp        |  36 +-
 src/citra_qt/configuration/configure_system.h |   7 +
 src/core/hle/service/apt/applet_manager.cpp   |   2 +-
 src/core/hle/service/apt/apt.cpp              |   2 +-
 src/core/hle/service/cfg/cfg.cpp              | 266 +++++----
 src/core/hle/service/cfg/cfg.h                | 537 +++++++++---------
 src/core/hle/service/cfg/cfg_i.cpp            | 104 ++--
 src/core/hle/service/cfg/cfg_i.h              |  12 +-
 src/core/hle/service/cfg/cfg_nor.cpp          |  18 +-
 src/core/hle/service/cfg/cfg_nor.h            |   6 +-
 src/core/hle/service/cfg/cfg_s.cpp            |  55 +-
 src/core/hle/service/cfg/cfg_s.h              |  10 +-
 src/core/hle/service/cfg/cfg_u.cpp            |  34 +-
 src/core/hle/service/cfg/cfg_u.h              |  10 +-
 src/core/hle/service/service.cpp              |   3 +-
 src/core/loader/ncch.cpp                      |   2 +-
 16 files changed, 554 insertions(+), 550 deletions(-)

diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp
index dd4b5caff..398ecb7c7 100644
--- a/src/citra_qt/configuration/configure_system.cpp
+++ b/src/citra_qt/configuration/configure_system.cpp
@@ -42,22 +42,16 @@ void ConfigureSystem::setConfiguration() {
     enabled = !Core::System::GetInstance().IsPoweredOn();
 
     if (!enabled) {
+        cfg = Service::CFG::GetCurrentModule();
         ReadSystemSettings();
         ui->group_system_settings->setEnabled(false);
     } else {
         // 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.
         Service::FS::RegisterArchiveTypes();
-        ResultCode result = Service::CFG::LoadConfigNANDSaveFile();
+        cfg = std::make_shared<Service::CFG::Module>();
         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();
         ui->label_disable_info->hide();
     }
@@ -65,14 +59,14 @@ void ConfigureSystem::setConfiguration() {
 
 void ConfigureSystem::ReadSystemSettings() {
     // set username
-    username = Service::CFG::GetUsername();
+    username = cfg->GetUsername();
     // TODO(wwylele): Use this when we move to Qt 5.5
     // ui->edit_username->setText(QString::fromStdU16String(username));
     ui->edit_username->setText(
         QString::fromUtf16(reinterpret_cast<const ushort*>(username.data())));
 
     // set birthday
-    std::tie(birthmonth, birthday) = Service::CFG::GetBirthday();
+    std::tie(birthmonth, birthday) = cfg->GetBirthday();
     ui->combo_birthmonth->setCurrentIndex(birthmonth - 1);
     updateBirthdayComboBox(
         birthmonth -
@@ -80,15 +74,15 @@ void ConfigureSystem::ReadSystemSettings() {
     ui->combo_birthday->setCurrentIndex(birthday - 1);
 
     // set system language
-    language_index = Service::CFG::GetSystemLanguage();
+    language_index = cfg->GetSystemLanguage();
     ui->combo_language->setCurrentIndex(language_index);
 
     // set sound output mode
-    sound_index = Service::CFG::GetSoundOutputMode();
+    sound_index = cfg->GetSoundOutputMode();
     ui->combo_sound->setCurrentIndex(sound_index);
 
     // set the console id
-    u64 console_id = Service::CFG::GetConsoleUniqueId();
+    u64 console_id = cfg->GetConsoleUniqueId();
     ui->label_console_id->setText(
         tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
 }
@@ -105,7 +99,7 @@ void ConfigureSystem::applyConfiguration() {
     std::u16string new_username(
         reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16()));
     if (new_username != username) {
-        Service::CFG::SetUsername(new_username);
+        cfg->SetUsername(new_username);
         modified = true;
     }
 
@@ -113,27 +107,27 @@ void ConfigureSystem::applyConfiguration() {
     int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1;
     int new_birthday = ui->combo_birthday->currentIndex() + 1;
     if (birthmonth != new_birthmonth || birthday != new_birthday) {
-        Service::CFG::SetBirthday(new_birthmonth, new_birthday);
+        cfg->SetBirthday(new_birthmonth, new_birthday);
         modified = true;
     }
 
     // apply language
     int new_language = ui->combo_language->currentIndex();
     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;
     }
 
     // apply sound
     int new_sound = ui->combo_sound->currentIndex();
     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;
     }
 
     // update the config savegame if any item is modified.
     if (modified)
-        Service::CFG::UpdateConfigNANDSavegame();
+        cfg->UpdateConfigNANDSavegame();
 }
 
 void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) {
@@ -173,9 +167,9 @@ void ConfigureSystem::refreshConsoleID() {
         return;
     u32 random_number;
     u64 console_id;
-    Service::CFG::GenerateConsoleUniqueId(random_number, console_id);
-    Service::CFG::SetConsoleUniqueId(random_number, console_id);
-    Service::CFG::UpdateConfigNANDSavegame();
+    cfg->GenerateConsoleUniqueId(random_number, console_id);
+    cfg->SetConsoleUniqueId(random_number, console_id);
+    cfg->UpdateConfigNANDSavegame();
     ui->label_console_id->setText("Console ID: 0x" + QString::number(console_id, 16).toUpper());
 }
 
diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h
index 094887791..47542b062 100644
--- a/src/citra_qt/configuration/configure_system.h
+++ b/src/citra_qt/configuration/configure_system.h
@@ -11,6 +11,12 @@ namespace Ui {
 class ConfigureSystem;
 }
 
+namespace Service {
+namespace CFG {
+class Module;
+} // namespace CFG
+} // namespace Service
+
 class ConfigureSystem : public QWidget {
     Q_OBJECT
 
@@ -32,6 +38,7 @@ private:
     std::unique_ptr<Ui::ConfigureSystem> ui;
     bool enabled;
 
+    std::shared_ptr<Service::CFG::Module> cfg;
     std::u16string username;
     int birthmonth, birthday;
     int language_index;
diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp
index d8a6d79b9..fafd73bb4 100644
--- a/src/core/hle/service/apt/applet_manager.cpp
+++ b/src/core/hle/service/apt/applet_manager.cpp
@@ -79,7 +79,7 @@ static u64 GetTitleIdForApplet(AppletId 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) {
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 240ff91e9..28f358b4b 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -103,7 +103,7 @@ static u32 DecompressLZ11(const u8* in, u8* out) {
 
 bool Module::LoadSharedFont() {
     u8 font_region_code;
-    switch (CFG::GetRegionValue()) {
+    switch (CFG::GetCurrentModule()->GetRegionValue()) {
     case 4: // CHN
         font_region_code = 2;
         break;
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 3c4f24770..a5e7df9b4 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -3,7 +3,6 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
-#include <array>
 #include <cryptopp/osrng.h>
 #include <cryptopp/sha.h>
 #include "common/file_util.h"
@@ -13,7 +12,6 @@
 #include "core/file_sys/archive_systemsavedata.h"
 #include "core/file_sys/errors.h"
 #include "core/file_sys/file_backend.h"
-#include "core/hle/ipc.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/result.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_s.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"
 
 namespace Service {
@@ -113,35 +108,44 @@ static const std::array<float, 8> STEREO_CAMERA_SETTINGS = {
 static_assert(sizeof(STEREO_CAMERA_SETTINGS) == 0x20,
               "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 = {
     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) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
-    u32 country_code_id = cmd_buff[1];
+std::shared_ptr<Module> GetCurrentModule() {
+    auto cfg = current_cfg.lock();
+    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]) {
         LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id);
-        cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
-                                 ErrorSummary::WrongArgument, ErrorLevel::Permanent)
-                          .raw;
+        rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
+                           ErrorSummary::WrongArgument, ErrorLevel::Permanent));
+        rb.Skip(1, false);
         return;
     }
 
-    cmd_buff[1] = 0;
-    cmd_buff[2] = country_codes[country_code_id];
+    rb.Push(RESULT_SUCCESS);
+    // 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) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
-    u16 country_code = static_cast<u16>(cmd_buff[1]);
+void Module::Interface::GetCountryCodeID(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x0A, 1, 0);
+    u16 country_code = rp.Pop<u16>();
     u16 country_code_id = 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) {
         LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff,
                   country_code >> 8);
-        cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
-                                 ErrorSummary::WrongArgument, ErrorLevel::Permanent)
-                          .raw;
-        cmd_buff[2] = 0xFFFF;
+        rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
+                           ErrorSummary::WrongArgument, ErrorLevel::Permanent));
+        rb.Push<u16>(0x00FF);
         return;
     }
 
-    cmd_buff[1] = 0;
-    cmd_buff[2] = country_code_id;
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u16>(country_code_id);
 }
 
-u32 GetRegionValue() {
+u32 Module::GetRegionValue() {
     if (Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT)
         return preferred_region_code;
 
     return Settings::values.region_value;
 }
 
-void SecureInfoGetRegion(Service::Interface* self) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
+void Module::Interface::SecureInfoGetRegion(Kernel::HLERequestContext& ctx, u16 id) {
+    IPC::RequestParser rp(ctx, id, 0, 0);
 
-    cmd_buff[1] = RESULT_SUCCESS.raw;
-    cmd_buff[2] = GetRegionValue();
+    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u8>(cfg->GetRegionValue());
 }
 
-void GenHashConsoleUnique(Service::Interface* self) {
-    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
+void Module::Interface::GenHashConsoleUnique(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x03, 1, 0);
     const u32 app_id_salt = rp.Pop<u32>() & 0x000FFFFF;
 
     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
 
     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);
     if (result.IsSuccess()) {
         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);
 }
 
-void GetRegionCanadaUSA(Service::Interface* self) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
+void Module::Interface::GetRegionCanadaUSA(Kernel::HLERequestContext& ctx) {
+    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;
-    if (canada_or_usa == GetRegionValue()) {
-        cmd_buff[2] = 1;
+    if (canada_or_usa == cfg->GetRegionValue()) {
+        rb.Push(true);
     } else {
-        cmd_buff[2] = 0;
+        rb.Push(false);
     }
 }
 
-void GetSystemModel(Service::Interface* self) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
+void Module::Interface::GetSystemModel(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x05, 0, 0);
+    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
     u32 data;
 
     // TODO(Subv): Find out the correct error codes
-    cmd_buff[1] =
-        Service::CFG::GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data))
-            .raw;
-    cmd_buff[2] = data & 0xFF;
+    rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
+    rb.Push<u8>(data & 0xFF);
 }
 
-void GetModelNintendo2DS(Service::Interface* self) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
+void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x06, 0, 0);
+    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
     u32 data;
 
     // TODO(Subv): Find out the correct error codes
-    cmd_buff[1] =
-        Service::CFG::GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data))
-            .raw;
-
+    rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
     u8 model = data & 0xFF;
-    if (model == Service::CFG::NINTENDO_2DS)
-        cmd_buff[2] = 0;
-    else
-        cmd_buff[2] = 1;
+    rb.Push(model != Service::CFG::NINTENDO_2DS);
 }
 
-void GetConfigInfoBlk2(Service::Interface* self) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
-    u32 size = cmd_buff[1];
-    u32 block_id = cmd_buff[2];
-    VAddr data_pointer = cmd_buff[4];
+void Module::Interface::GetConfigInfoBlk2(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x01, 2, 2);
+    u32 size = rp.Pop<u32>();
+    u32 block_id = rp.Pop<u32>();
+    auto& buffer = rp.PopMappedBuffer();
 
-    if (!Memory::IsValidVirtualAddress(data_pointer)) {
-        cmd_buff[1] = -1; // TODO(Subv): Find the right error code
-        return;
-    }
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
+    std::vector<u8> data(size);
+    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);
-    cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data.data()).raw;
-    Memory::WriteBlock(data_pointer, data.data(), data.size());
+    buffer.Read(data.data(), 0, 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) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
-    u32 size = cmd_buff[1];
-    u32 block_id = cmd_buff[2];
-    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 Module::Interface::UpdateConfigNANDSavegame(Kernel::HLERequestContext& ctx, u16 id) {
+    IPC::RequestParser rp(ctx, id, 0, 0);
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+    rb.Push(cfg->UpdateConfigNANDSavegame());
 }
 
-void SetConfigInfoBlk4(Service::Interface* self) {
-    u32* cmd_buff = Kernel::GetCommandBuffer();
-    u32 block_id = cmd_buff[1];
-    u32 size = cmd_buff[2];
-    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 Module::Interface::FormatConfig(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x0806, 0, 0);
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+    rb.Push(cfg->FormatConfig());
 }
 
-void UpdateConfigNANDSavegame(Service::Interface* self) {
-    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) {
+ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 flag) {
     // Read the header
     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);
 }
 
-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;
     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
     memcpy(output, pointer, size);
@@ -354,14 +348,14 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
     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;
     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
     memcpy(pointer, input, size);
     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());
     if (config->total_entries >= CONFIG_FILE_MAX_BLOCK_ENTRIES)
         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;
 }
 
-ResultCode DeleteConfigNANDSaveFile() {
+ResultCode Module::DeleteConfigNANDSaveFile() {
     FileSys::Path path("/config");
     return Service::FS::DeleteFileFromArchive(cfg_system_save_data_archive, path);
 }
 
-ResultCode UpdateConfigNANDSavegame() {
+ResultCode Module::UpdateConfigNANDSavegame() {
     FileSys::Mode mode = {};
     mode.write_flag.Assign(1);
     mode.create_flag.Assign(1);
@@ -414,7 +408,7 @@ ResultCode UpdateConfigNANDSavegame() {
     return RESULT_SUCCESS;
 }
 
-ResultCode FormatConfig() {
+ResultCode Module::FormatConfig() {
     ResultCode res = DeleteConfigNANDSaveFile();
     // 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) {
@@ -533,7 +527,7 @@ ResultCode FormatConfig() {
     return RESULT_SUCCESS;
 }
 
-ResultCode LoadConfigNANDSaveFile() {
+ResultCode Module::LoadConfigNANDSaveFile() {
     // Open the SystemSaveData archive 0x00010017
     FileSys::Path archive_path(cfg_system_savedata_id);
     auto archive_result =
@@ -570,18 +564,11 @@ ResultCode LoadConfigNANDSaveFile() {
     return FormatConfig();
 }
 
-void Init() {
-    AddService(new CFG_I);
-    AddService(new CFG_NOR);
-    AddService(new CFG_S);
-    AddService(new CFG_U);
-
+Module::Module() {
     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
 static SystemLanguage AdjustLanguageInfoBlock(u32 region, SystemLanguage language) {
@@ -610,7 +597,7 @@ static SystemLanguage AdjustLanguageInfoBlock(u32 region, SystemLanguage languag
     return language;
 }
 
-void SetPreferredRegionCode(u32 region_code) {
+void Module::SetPreferredRegionCode(u32 region_code) {
     preferred_region_code = 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);
     UsernameBlock block{};
     name.copy(block.username, name.size());
     SetConfigInfoBlock(UsernameBlockID, sizeof(block), 4, &block);
 }
 
-std::u16string GetUsername() {
+std::u16string Module::GetUsername() {
     UsernameBlock block;
     GetConfigInfoBlock(UsernameBlockID, sizeof(block), 8, &block);
 
@@ -646,40 +633,40 @@ std::u16string GetUsername() {
     return username;
 }
 
-void SetBirthday(u8 month, u8 day) {
+void Module::SetBirthday(u8 month, u8 day) {
     BirthdayBlock block = {month, day};
     SetConfigInfoBlock(BirthdayBlockID, sizeof(block), 4, &block);
 }
 
-std::tuple<u8, u8> GetBirthday() {
+std::tuple<u8, u8> Module::GetBirthday() {
     BirthdayBlock block;
     GetConfigInfoBlock(BirthdayBlockID, sizeof(block), 8, &block);
     return std::make_tuple(block.month, block.day);
 }
 
-void SetSystemLanguage(SystemLanguage language) {
+void Module::SetSystemLanguage(SystemLanguage language) {
     u8 block = language;
     SetConfigInfoBlock(LanguageBlockID, sizeof(block), 4, &block);
 }
 
-SystemLanguage GetSystemLanguage() {
+SystemLanguage Module::GetSystemLanguage() {
     u8 block;
     GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block);
     return static_cast<SystemLanguage>(block);
 }
 
-void SetSoundOutputMode(SoundOutputMode mode) {
+void Module::SetSoundOutputMode(SoundOutputMode mode) {
     u8 block = mode;
     SetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 4, &block);
 }
 
-SoundOutputMode GetSoundOutputMode() {
+SoundOutputMode Module::GetSoundOutputMode() {
     u8 block;
     GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &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;
     random_number = rng.GenerateWord32(0, 0xFFFF);
     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);
 }
 
-ResultCode SetConsoleUniqueId(u32 random_number, u64 console_id) {
+ResultCode Module::SetConsoleUniqueId(u32 random_number, u64 console_id) {
     u64_le console_id_le = console_id;
     ResultCode res =
         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;
 }
 
-u64 GetConsoleUniqueId() {
+u64 Module::GetConsoleUniqueId() {
     u64_le console_id_le;
     GetConfigInfoBlock(ConsoleUniqueID2BlockID, sizeof(console_id_le), 0xE, &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 Service
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index 9ef773c87..62c85f824 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -5,15 +5,12 @@
 #pragma once
 
 #include <array>
+#include <memory>
 #include <string>
 #include "common/common_types.h"
-
-union ResultCode;
+#include "core/hle/service/fs/archive.h"
 
 namespace Service {
-
-class Interface;
-
 namespace CFG {
 
 enum SystemModel {
@@ -82,289 +79,321 @@ static const std::array<u16, 187> country_codes = {{
     C("SM"), C("VA"), C("BM"),                                              // 184-186
 }};
 
-/**
- * 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(Service::Interface* self);
+class Module final {
+public:
+    Module();
+    ~Module();
 
-/**
- * CFG::GetCountryCodeID service function
- *  Inputs:
- *      1 : Country Code 2-char string
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- *      2 : Country Code ID
- */
-void GetCountryCodeID(Service::Interface* self);
+    class Interface : public ServiceFramework<Interface> {
+    public:
+        Interface(std::shared_ptr<Module> cfg, const char* name, u32 max_session);
+        ~Interface();
 
-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
- *  Inputs:
- *      1 : None
- *  Outputs:
- *      0 : Result Header code
- *      1 : Result of function, 0 on success, otherwise error code
- *      2 : Region value loaded from SecureInfo offset 0x100
- */
-void SecureInfoGetRegion(Service::Interface* self);
+        /**
+         * CFG::GetCountryCodeID service function
+         *  Inputs:
+         *      1 : Country Code 2-char string
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         *      2 : Country Code ID
+         */
+        void GetCountryCodeID(Kernel::HLERequestContext& ctx);
 
-/**
- * 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);
+        u32 GetRegionValue();
 
-/**
- * CFG::GetRegionCanadaUSA service function
- *  Inputs:
- *      1 : None
- *  Outputs:
- *      0 : Result Header code
- *      1 : Result of function, 0 on success, otherwise error code
- *      2 : 1 if the system is a Canada or USA model, 0 otherwise
- */
-void GetRegionCanadaUSA(Service::Interface* self);
+        /**
+         * CFG::SecureInfoGetRegion service function
+         *  Inputs:
+         *      1 : None
+         *  Outputs:
+         *      0 : Result Header code
+         *      1 : Result of function, 0 on success, otherwise error code
+         *      2 : Region value loaded from SecureInfo offset 0x100
+         */
+        void SecureInfoGetRegion(Kernel::HLERequestContext& ctx, u16 id);
 
-/**
- * CFG::GetSystemModel service function
- *  Inputs:
- *      0 : 0x00050000
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- *      2 : Model of the console
- */
-void GetSystemModel(Service::Interface* self);
+        /**
+         * 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(Kernel::HLERequestContext& ctx);
 
-/**
- * CFG::GetModelNintendo2DS service function
- *  Inputs:
- *      0 : 0x00060000
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- *      2 : 0 if the system is a Nintendo 2DS, 1 otherwise
- */
-void GetModelNintendo2DS(Service::Interface* self);
+        /**
+         * CFG::GetRegionCanadaUSA service function
+         *  Inputs:
+         *      1 : None
+         *  Outputs:
+         *      0 : Result Header code
+         *      1 : Result of function, 0 on success, otherwise error code
+         *      2 : 1 if the system is a Canada or USA model, 0 otherwise
+         */
+        void GetRegionCanadaUSA(Kernel::HLERequestContext& ctx);
 
-/**
- * CFG::GetConfigInfoBlk2 service function
- *  Inputs:
- *      0 : 0x00010082
- *      1 : Size
- *      2 : Block ID
- *      3 : Descriptor for the output buffer
- *      4 : Output buffer pointer
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- */
-void GetConfigInfoBlk2(Service::Interface* self);
+        /**
+         * CFG::GetSystemModel service function
+         *  Inputs:
+         *      0 : 0x00050000
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         *      2 : Model of the console
+         */
+        void GetSystemModel(Kernel::HLERequestContext& ctx);
 
-/**
- * CFG::GetConfigInfoBlk8 service function
- *  Inputs:
- *      0 : 0x04010082 / 0x08010082
- *      1 : Size
- *      2 : Block ID
- *      3 : Descriptor for the output buffer
- *      4 : Output buffer pointer
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- */
-void GetConfigInfoBlk8(Service::Interface* self);
+        /**
+         * CFG::GetModelNintendo2DS service function
+         *  Inputs:
+         *      0 : 0x00060000
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         *      2 : 0 if the system is a Nintendo 2DS, 1 otherwise
+         */
+        void GetModelNintendo2DS(Kernel::HLERequestContext& ctx);
 
-/**
- * CFG::SetConfigInfoBlk4 service function
- *  Inputs:
- *      0 : 0x04020082 / 0x08020082
- *      1 : Block ID
- *      2 : Size
- *      3 : Descriptor for the output buffer
- *      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(Service::Interface* self);
+        /**
+         * CFG::GetConfigInfoBlk2 service function
+         *  Inputs:
+         *      0 : 0x00010082
+         *      1 : Size
+         *      2 : Block ID
+         *      3 : Descriptor for the output buffer
+         *      4 : Output buffer pointer
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         */
+        void GetConfigInfoBlk2(Kernel::HLERequestContext& ctx);
 
-/**
- * CFG::UpdateConfigNANDSavegame service function
- *  Inputs:
- *      0 : 0x04030000 / 0x08030000
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- */
-void UpdateConfigNANDSavegame(Service::Interface* self);
+        /**
+         * CFG::GetConfigInfoBlk8 service function
+         *  Inputs:
+         *      0 : 0x04010082 / 0x08010082
+         *      1 : Size
+         *      2 : Block ID
+         *      3 : Descriptor for the output buffer
+         *      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
- *  Inputs:
- *      0 : 0x08060000
- *  Outputs:
- *      1 : Result of function, 0 on success, otherwise error code
- */
-void FormatConfig(Service::Interface* self);
+        /**
+         * CFG::SetConfigInfoBlk4 service function
+         *  Inputs:
+         *      0 : 0x04020082 / 0x08020082
+         *      1 : Block ID
+         *      2 : Size
+         *      3 : Descriptor for the output buffer
+         *      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
- * and writes the output to output. The input size must match exactly the size of the requested
- * block.
- *
- * @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);
+        /**
+         * CFG::UpdateConfigNANDSavegame service function
+         *  Inputs:
+         *      0 : 0x04030000 / 0x08030000
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         */
+        void UpdateConfigNANDSavegame(Kernel::HLERequestContext& ctx, u16 id);
 
-/**
- * Reads data from input and writes to a block with the specified id and flag
- * in the Config savegame buffer. The input size must match exactly the size of the target block.
- *
- * @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);
+        /**
+         * CFG::FormatConfig service function
+         *  Inputs:
+         *      0 : 0x08060000
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         */
+        void FormatConfig(Kernel::HLERequestContext& ctx);
 
-/**
- * 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);
+        /// A helper function for dispatching service functions that have multiple IDs
+        template <void (Interface::*function)(Kernel::HLERequestContext& ctx, u16 id), u16 id>
+        void D(Kernel::HLERequestContext& ctx) {
+            (this->*function)(ctx, id);
+        }
 
-/**
- * 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();
+    private:
+        std::shared_ptr<Module> cfg;
+    };
 
-/**
- * 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:
+    ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 flag);
 
-/**
- * Re-creates the config savegame file in memory and the filesystem with the default blocks
- * @returns ResultCode indicating the result of the operation, 0 on success
- */
-ResultCode FormatConfig();
+    /**
+     * Reads a block with the specified id and flag from the Config savegame buffer
+     * and writes the output to output. The input size must match exactly the size of the requested
+     * block.
+     *
+     * @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
- * @returns ResultCode indicating the result of the operation, 0 on success
- */
-ResultCode LoadConfigNANDSaveFile();
+    /**
+     * Reads data from input and writes to a block with the specified id and flag
+     * in the Config savegame buffer. The input size must match exactly the size of the target
+     * block.
+     *
+     * @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
- * is auto.
- * @param region_code the preferred region code to set
- */
-void SetPreferredRegionCode(u32 region_code);
+    /**
+     * Re-creates the config savegame file in memory and the filesystem with the default blocks
+     * @returns ResultCode indicating the result of the operation, 0 on success
+     */
+    ResultCode FormatConfig();
 
-// Utilities for frontend to set config data.
-// Note: before calling these functions, LoadConfigNANDSaveFile should be called,
-// and UpdateConfigNANDSavegame should be called after making changes to config data.
+    /**
+     * Open the config savegame file and load it to the memory buffer
+     * @returns ResultCode indicating the result of the operation, 0 on success
+     */
+    ResultCode LoadConfigNANDSaveFile();
 
-/**
- * Sets the username in config savegame.
- * @param name the username to set. The maximum size is 10 in char16_t.
- */
-void SetUsername(const std::u16string& name);
+public:
+    u32 GetRegionValue();
 
-/**
- * Gets the username from config savegame.
- * @returns the username
- */
-std::u16string GetUsername();
+    /**
+     * Set the region code preferred by the game so that CFG will adjust to it when the region
+     * setting
+     * is auto.
+     * @param region_code the preferred region code to set
+     */
+    void SetPreferredRegionCode(u32 region_code);
 
-/**
- * Sets the profile birthday in config savegame.
- * @param month the month of birthday.
- * @param day the day of the birthday.
- */
-void SetBirthday(u8 month, u8 day);
+    // Utilities for frontend to set config data.
+    // Note: UpdateConfigNANDSavegame should be called after making changes to config data.
 
-/**
- * Gets the profile birthday from the config savegame.
- * @returns a tuple of (month, day) of birthday
- */
-std::tuple<u8, u8> GetBirthday();
+    /**
+     * Sets the username in config savegame.
+     * @param name the username to set. The maximum size is 10 in char16_t.
+     */
+    void SetUsername(const std::u16string& name);
 
-/**
- * Sets the system language in config savegame.
- * @param language the system language to set.
- */
-void SetSystemLanguage(SystemLanguage language);
+    /**
+     * Gets the username from config savegame.
+     * @returns the username
+     */
+    std::u16string GetUsername();
 
-/**
- * Gets the system language from config savegame.
- * @returns the system language
- */
-SystemLanguage GetSystemLanguage();
+    /**
+     * Sets the profile birthday in config savegame.
+     * @param month the month of birthday.
+     * @param day the day of the birthday.
+     */
+    void SetBirthday(u8 month, u8 day);
 
-/**
- * Sets the sound output mode in config savegame.
- * @param mode the sound output mode to set
- */
-void SetSoundOutputMode(SoundOutputMode mode);
+    /**
+     * Gets the profile birthday from the config savegame.
+     * @returns a tuple of (month, day) of birthday
+     */
+    std::tuple<u8, u8> GetBirthday();
 
-/**
- * Gets the sound output mode from config savegame.
- * @returns the sound output mode
- */
-SoundOutputMode GetSoundOutputMode();
+    /**
+     * Sets the system language in config savegame.
+     * @param language the system language to set.
+     */
+    void SetSystemLanguage(SystemLanguage language);
 
-/**
- * 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);
+    /**
+     * Gets the system language from config savegame.
+     * @returns the system language
+     */
+    SystemLanguage GetSystemLanguage();
 
-/**
- * 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);
+    /**
+     * Sets the sound output mode in config savegame.
+     * @param mode the sound output mode to set
+     */
+    void SetSoundOutputMode(SoundOutputMode mode);
 
-/**
- * Gets the console unique id from config savegame.
- * @returns the console unique id
- */
-u64 GetConsoleUniqueId();
+    /**
+     * Gets the sound output mode from config savegame.
+     * @returns the sound output mode
+     */
+    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 Service
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
index e8db0fc42..b43112fdb 100644
--- a/src/core/hle/service/cfg/cfg_i.cpp
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -2,63 +2,63 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/cfg/cfg.h"
 #include "core/hle/service/cfg/cfg_i.h"
 
 namespace Service {
 namespace CFG {
 
-const Interface::FunctionInfo FunctionTable[] = {
-    // cfg common
-    {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
-    {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
-    {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
-    {0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
-    {0x00050000, GetSystemModel, "GetSystemModel"},
-    {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
-    {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
-    {0x00080080, nullptr, "GoThroughTable"},
-    {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
-    {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
-    {0x000B0000, nullptr, "IsFangateSupported"},
-    // cfg:i
-    {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
-    {0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
-    {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
-    {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
-    {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
-    {0x04060000, SecureInfoGetRegion, "SecureInfoGetRegion"},
-    {0x04070000, nullptr, "SecureInfoGetByte101"},
-    {0x04080042, nullptr, "SecureInfoGetSerialNo"},
-    {0x04090000, nullptr, "UpdateConfigBlk00040003"},
-    {0x08010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
-    {0x08020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
-    {0x08030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
-    {0x080400C2, nullptr, "CreateConfigInfoBlk"},
-    {0x08050000, nullptr, "DeleteConfigNANDSavefile"},
-    {0x08060000, FormatConfig, "FormatConfig"},
-    {0x08080000, nullptr, "UpdateConfigBlk1"},
-    {0x08090000, nullptr, "UpdateConfigBlk2"},
-    {0x080A0000, nullptr, "UpdateConfigBlk3"},
-    {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
-    {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
-    {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
-    {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
-    {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
-    {0x08100000, nullptr, "GetLocalFriendCodeSeed"},
-    {0x08110084, nullptr, "SetSecureInfo"},
-    {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
-    {0x08130000, nullptr, "VerifySigSecureInfo"},
-    {0x08140042, nullptr, "SecureInfoGetData"},
-    {0x08150042, nullptr, "SecureInfoGetSignature"},
-    {0x08160000, SecureInfoGetRegion, "SecureInfoGetRegion"},
-    {0x08170000, nullptr, "SecureInfoGetByte101"},
-    {0x08180042, nullptr, "SecureInfoGetSerialNo"},
-};
-
-CFG_I::CFG_I() {
-    Register(FunctionTable);
+CFG_I::CFG_I(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:i", 23) {
+    static const FunctionInfo functions[] = {
+        // cfg common
+        {0x00010082, &CFG_I::GetConfigInfoBlk2, "GetConfigInfoBlk2"},
+        {0x00020000, &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0002>, "SecureInfoGetRegion"},
+        {0x00030040, &CFG_I::GenHashConsoleUnique, "GenHashConsoleUnique"},
+        {0x00040000, &CFG_I::GetRegionCanadaUSA, "GetRegionCanadaUSA"},
+        {0x00050000, &CFG_I::GetSystemModel, "GetSystemModel"},
+        {0x00060000, &CFG_I::GetModelNintendo2DS, "GetModelNintendo2DS"},
+        {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
+        {0x00080080, nullptr, "GoThroughTable"},
+        {0x00090040, &CFG_I::GetCountryCodeString, "GetCountryCodeString"},
+        {0x000A0040, &CFG_I::GetCountryCodeID, "GetCountryCodeID"},
+        {0x000B0000, nullptr, "IsFangateSupported"},
+        // cfg:i
+        {0x04010082, &CFG_I::D<&CFG_I::GetConfigInfoBlk8, 0x0401>, "GetConfigInfoBlk8"},
+        {0x04020082, &CFG_I::D<&CFG_I::SetConfigInfoBlk4, 0x0402>, "SetConfigInfoBlk4"},
+        {0x04030000, &CFG_I::D<&CFG_I::UpdateConfigNANDSavegame, 0x0403>,
+         "UpdateConfigNANDSavegame"},
+        {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
+        {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
+        {0x04060000, &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0406>, "SecureInfoGetRegion"},
+        {0x04070000, nullptr, "SecureInfoGetByte101"},
+        {0x04080042, nullptr, "SecureInfoGetSerialNo"},
+        {0x04090000, nullptr, "UpdateConfigBlk00040003"},
+        {0x08010082, &CFG_I::D<&CFG_I::GetConfigInfoBlk8, 0x0801>, "GetConfigInfoBlk8"},
+        {0x08020082, &CFG_I::D<&CFG_I::SetConfigInfoBlk4, 0x0802>, "SetConfigInfoBlk4"},
+        {0x08030000, &CFG_I::D<&CFG_I::UpdateConfigNANDSavegame, 0x0803>,
+         "UpdateConfigNANDSavegame"},
+        {0x080400C2, nullptr, "CreateConfigInfoBlk"},
+        {0x08050000, nullptr, "DeleteConfigNANDSavefile"},
+        {0x08060000, &CFG_I::FormatConfig, "FormatConfig"},
+        {0x08080000, nullptr, "UpdateConfigBlk1"},
+        {0x08090000, nullptr, "UpdateConfigBlk2"},
+        {0x080A0000, nullptr, "UpdateConfigBlk3"},
+        {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
+        {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
+        {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
+        {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
+        {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
+        {0x08100000, nullptr, "GetLocalFriendCodeSeed"},
+        {0x08110084, nullptr, "SetSecureInfo"},
+        {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
+        {0x08130000, nullptr, "VerifySigSecureInfo"},
+        {0x08140042, nullptr, "SecureInfoGetData"},
+        {0x08150042, nullptr, "SecureInfoGetSignature"},
+        {0x08160000, &CFG_I::D<&CFG_I::SecureInfoGetRegion, 0x0816>, "SecureInfoGetRegion"},
+        {0x08170000, nullptr, "SecureInfoGetByte101"},
+        {0x08180042, nullptr, "SecureInfoGetSerialNo"},
+    };
+    RegisterHandlers(functions);
 }
 
 } // namespace CFG
-} // namespace Service
\ No newline at end of file
+} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h
index 8cfd47633..0fd972c0e 100644
--- a/src/core/hle/service/cfg/cfg_i.h
+++ b/src/core/hle/service/cfg/cfg_i.h
@@ -4,19 +4,15 @@
 
 #pragma once
 
-#include "core/hle/service/service.h"
+#include "core/hle/service/cfg/cfg.h"
 
 namespace Service {
 namespace CFG {
 
-class CFG_I final : public Interface {
+class CFG_I final : public Module::Interface {
 public:
-    CFG_I();
-
-    std::string GetPortName() const override {
-        return "cfg:i";
-    }
+    explicit CFG_I(std::shared_ptr<Module> cfg);
 };
 
 } // namespace CFG
-} // namespace Service
\ No newline at end of file
+} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_nor.cpp b/src/core/hle/service/cfg/cfg_nor.cpp
index 4ce02d115..685a1461e 100644
--- a/src/core/hle/service/cfg/cfg_nor.cpp
+++ b/src/core/hle/service/cfg/cfg_nor.cpp
@@ -2,21 +2,19 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/cfg/cfg.h"
 #include "core/hle/service/cfg/cfg_nor.h"
 
 namespace Service {
 namespace CFG {
 
-const Interface::FunctionInfo FunctionTable[] = {
-    {0x00010040, nullptr, "Initialize"},
-    {0x00020000, nullptr, "Shutdown"},
-    {0x00050082, nullptr, "ReadData"},
-    {0x00060082, nullptr, "WriteData"},
-};
-
-CFG_NOR::CFG_NOR() {
-    Register(FunctionTable);
+CFG_NOR::CFG_NOR() : ServiceFramework("cfg:nor", 23) {
+    static const FunctionInfo functions[] = {
+        {0x00010040, nullptr, "Initialize"},
+        {0x00020000, nullptr, "Shutdown"},
+        {0x00050082, nullptr, "ReadData"},
+        {0x00060082, nullptr, "WriteData"},
+    };
+    RegisterHandlers(functions);
 }
 
 } // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg_nor.h b/src/core/hle/service/cfg/cfg_nor.h
index c337718e7..197c927db 100644
--- a/src/core/hle/service/cfg/cfg_nor.h
+++ b/src/core/hle/service/cfg/cfg_nor.h
@@ -9,13 +9,9 @@
 namespace Service {
 namespace CFG {
 
-class CFG_NOR final : public Interface {
+class CFG_NOR final : public ServiceFramework<CFG_NOR> {
 public:
     CFG_NOR();
-
-    std::string GetPortName() const override {
-        return "cfg:nor";
-    }
 };
 
 } // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index 9386fe33d..4449b2b6c 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -2,39 +2,38 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/cfg/cfg.h"
 #include "core/hle/service/cfg/cfg_s.h"
 
 namespace Service {
 namespace CFG {
 
-const Interface::FunctionInfo FunctionTable[] = {
-    // cfg common
-    {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
-    {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
-    {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
-    {0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
-    {0x00050000, GetSystemModel, "GetSystemModel"},
-    {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
-    {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
-    {0x00080080, nullptr, "GoThroughTable"},
-    {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
-    {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
-    {0x000B0000, nullptr, "IsFangateSupported"},
-    // cfg:s
-    {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
-    {0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
-    {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
-    {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
-    {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
-    {0x04060000, nullptr, "SecureInfoGetRegion"},
-    {0x04070000, nullptr, "SecureInfoGetByte101"},
-    {0x04080042, nullptr, "SecureInfoGetSerialNo"},
-    {0x04090000, nullptr, "UpdateConfigBlk00040003"},
-};
-
-CFG_S::CFG_S() {
-    Register(FunctionTable);
+CFG_S::CFG_S(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:s", 23) {
+    static const FunctionInfo functions[] = {
+        // cfg common
+        {0x00010082, &CFG_S::GetConfigInfoBlk2, "GetConfigInfoBlk2"},
+        {0x00020000, &CFG_S::D<&CFG_S::SecureInfoGetRegion, 0x0002>, "SecureInfoGetRegion"},
+        {0x00030040, &CFG_S::GenHashConsoleUnique, "GenHashConsoleUnique"},
+        {0x00040000, &CFG_S::GetRegionCanadaUSA, "GetRegionCanadaUSA"},
+        {0x00050000, &CFG_S::GetSystemModel, "GetSystemModel"},
+        {0x00060000, &CFG_S::GetModelNintendo2DS, "GetModelNintendo2DS"},
+        {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
+        {0x00080080, nullptr, "GoThroughTable"},
+        {0x00090040, &CFG_S::GetCountryCodeString, "GetCountryCodeString"},
+        {0x000A0040, &CFG_S::GetCountryCodeID, "GetCountryCodeID"},
+        {0x000B0000, nullptr, "IsFangateSupported"},
+        // cfg:s
+        {0x04010082, &CFG_S::D<&CFG_S::GetConfigInfoBlk8, 0x0401>, "GetConfigInfoBlk8"},
+        {0x04020082, &CFG_S::D<&CFG_S::SetConfigInfoBlk4, 0x0402>, "SetConfigInfoBlk4"},
+        {0x04030000, &CFG_S::D<&CFG_S::UpdateConfigNANDSavegame, 0x0403>,
+         "UpdateConfigNANDSavegame"},
+        {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
+        {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
+        {0x04060000, &CFG_S::D<&CFG_S::SecureInfoGetRegion, 0x0406>, "SecureInfoGetRegion"},
+        {0x04070000, nullptr, "SecureInfoGetByte101"},
+        {0x04080042, nullptr, "SecureInfoGetSerialNo"},
+        {0x04090000, nullptr, "UpdateConfigBlk00040003"},
+    };
+    RegisterHandlers(functions);
 }
 
 } // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h
index 99fea46ee..98853954e 100644
--- a/src/core/hle/service/cfg/cfg_s.h
+++ b/src/core/hle/service/cfg/cfg_s.h
@@ -4,18 +4,14 @@
 
 #pragma once
 
-#include "core/hle/service/service.h"
+#include "core/hle/service/cfg/cfg.h"
 
 namespace Service {
 namespace CFG {
 
-class CFG_S final : public Interface {
+class CFG_S final : public Module::Interface {
 public:
-    CFG_S();
-
-    std::string GetPortName() const override {
-        return "cfg:s";
-    }
+    explicit CFG_S(std::shared_ptr<Module> cfg);
 };
 
 } // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index 7b66fee22..4b554e175 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -2,29 +2,27 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/cfg/cfg.h"
 #include "core/hle/service/cfg/cfg_u.h"
 
 namespace Service {
 namespace CFG {
 
-const Interface::FunctionInfo FunctionTable[] = {
-    // cfg common
-    {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
-    {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
-    {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
-    {0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
-    {0x00050000, GetSystemModel, "GetSystemModel"},
-    {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
-    {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
-    {0x00080080, nullptr, "GoThroughTable"},
-    {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
-    {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
-    {0x000B0000, nullptr, "IsFangateSupported"},
-};
-
-CFG_U::CFG_U() {
-    Register(FunctionTable);
+CFG_U::CFG_U(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:u", 23) {
+    static const FunctionInfo functions[] = {
+        // cfg common
+        {0x00010082, &CFG_U::GetConfigInfoBlk2, "GetConfigInfoBlk2"},
+        {0x00020000, &CFG_U::D<&CFG_U::SecureInfoGetRegion, 0x0002>, "SecureInfoGetRegion"},
+        {0x00030040, &CFG_U::GenHashConsoleUnique, "GenHashConsoleUnique"},
+        {0x00040000, &CFG_U::GetRegionCanadaUSA, "GetRegionCanadaUSA"},
+        {0x00050000, &CFG_U::GetSystemModel, "GetSystemModel"},
+        {0x00060000, &CFG_U::GetModelNintendo2DS, "GetModelNintendo2DS"},
+        {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
+        {0x00080080, nullptr, "GoThroughTable"},
+        {0x00090040, &CFG_U::GetCountryCodeString, "GetCountryCodeString"},
+        {0x000A0040, &CFG_U::GetCountryCodeID, "GetCountryCodeID"},
+        {0x000B0000, nullptr, "IsFangateSupported"},
+    };
+    RegisterHandlers(functions);
 }
 
 } // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h
index fc7844714..b3ad8b31b 100644
--- a/src/core/hle/service/cfg/cfg_u.h
+++ b/src/core/hle/service/cfg/cfg_u.h
@@ -4,18 +4,14 @@
 
 #pragma once
 
-#include "core/hle/service/service.h"
+#include "core/hle/service/cfg/cfg.h"
 
 namespace Service {
 namespace CFG {
 
-class CFG_U final : public Interface {
+class CFG_U final : public Module::Interface {
 public:
-    CFG_U();
-
-    std::string GetPortName() const override {
-        return "cfg:u";
-    }
+    explicit CFG_U(std::shared_ptr<Module> cfg);
 };
 
 } // namespace CFG
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 534a65706..dde75a29f 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -242,7 +242,7 @@ void Init() {
     BOSS::Init();
     CAM::InstallInterfaces(*SM::g_service_manager);
     CECD::Init();
-    CFG::Init();
+    CFG::InstallInterfaces(*SM::g_service_manager);
     DLP::Init();
     FRD::InstallInterfaces(*SM::g_service_manager);
     GSP::InstallInterfaces(*SM::g_service_manager);
@@ -273,7 +273,6 @@ void Init() {
 void Shutdown() {
     NDM::Shutdown();
     DLP::Shutdown();
-    CFG::Shutdown();
     CECD::Shutdown();
     BOSS::Shutdown();
     FS::ArchiveShutdown();
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 29b84e387..1ee437d64 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -135,7 +135,7 @@ void AppLoader_NCCH::ParseRegionLockoutInfo() {
         constexpr u32 REGION_COUNT = 7;
         for (u32 region = 0; region < REGION_COUNT; ++region) {
             if (region_lockout & 1) {
-                Service::CFG::SetPreferredRegionCode(region);
+                Service::CFG::GetCurrentModule()->SetPreferredRegionCode(region);
                 break;
             }
             region_lockout >>= 1;

From ea82203780d8f0666d48cc07a3700fb121f6e30c Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Sat, 10 Mar 2018 13:25:22 +0200
Subject: [PATCH 2/2] ipc_helper: remove interface for operating on command
 buffer directly

Now IPC helpers are only supposed to use on top of ServiceFramework
---
 src/core/hle/ipc_helpers.h       | 35 ++------------------------------
 src/core/hle/service/service.cpp |  1 +
 2 files changed, 3 insertions(+), 33 deletions(-)

diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 98575da03..dc6c7bf7d 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -10,7 +10,6 @@
 #include <utility>
 #include <vector>
 #include "core/hle/ipc.h"
-#include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/kernel.h"
 
@@ -18,7 +17,7 @@ namespace IPC {
 
 class RequestHelperBase {
 protected:
-    Kernel::HLERequestContext* context = nullptr;
+    Kernel::HLERequestContext* context;
     u32* cmdbuf;
     ptrdiff_t index = 1;
     Header header;
@@ -27,9 +26,6 @@ public:
     RequestHelperBase(Kernel::HLERequestContext& context, Header desired_header)
         : context(&context), cmdbuf(context.CommandBuffer()), header(desired_header) {}
 
-    RequestHelperBase(u32* command_buffer, Header command_header)
-        : cmdbuf(command_buffer), header(command_header) {}
-
     /// Returns the total size of the request in words
     size_t TotalSize() const {
         return 1 /* command header */ + header.normal_params_size + header.translate_params_size;
@@ -62,19 +58,6 @@ public:
         : RequestBuilder(
               context, Header{MakeHeader(command_id, normal_params_size, translate_params_size)}) {}
 
-    RequestBuilder(u32* command_buffer, Header command_header)
-        : RequestHelperBase(command_buffer, command_header) {
-        cmdbuf[0] = header.raw;
-    }
-
-    explicit RequestBuilder(u32* command_buffer, u32 command_header)
-        : RequestBuilder(command_buffer, Header{command_header}) {}
-
-    RequestBuilder(u32* command_buffer, u16 command_id, unsigned normal_params_size,
-                   unsigned translate_params_size)
-        : RequestBuilder(command_buffer,
-                         MakeHeader(command_id, normal_params_size, translate_params_size)) {}
-
     // Validate on destruction, as there shouldn't be any case where we don't want it
     ~RequestBuilder() {
         ValidateHeader();
@@ -217,27 +200,13 @@ public:
                         Header{MakeHeader(command_id, normal_params_size, translate_params_size)}) {
     }
 
-    RequestParser(u32* command_buffer, Header command_header)
-        : RequestHelperBase(command_buffer, command_header) {}
-
-    explicit RequestParser(u32* command_buffer, u32 command_header)
-        : RequestParser(command_buffer, Header{command_header}) {}
-
-    RequestParser(u32* command_buffer, u16 command_id, unsigned normal_params_size,
-                  unsigned translate_params_size)
-        : RequestParser(command_buffer,
-                        MakeHeader(command_id, normal_params_size, translate_params_size)) {}
-
     RequestBuilder MakeBuilder(u32 normal_params_size, u32 translate_params_size,
                                bool validateHeader = true) {
         if (validateHeader)
             ValidateHeader();
         Header builderHeader{MakeHeader(static_cast<u16>(header.command_id), normal_params_size,
                                         translate_params_size)};
-        if (context != nullptr)
-            return {*context, builderHeader};
-        else
-            return {cmdbuf, builderHeader};
+        return {*context, builderHeader};
     }
 
     template <typename T>
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index dde75a29f..9e50617bb 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -9,6 +9,7 @@
 #include "common/string_util.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"