summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp17
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h10
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp37
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h12
-rw-r--r--src/core/core.cpp26
-rw-r--r--src/core/core.h14
-rw-r--r--src/core/core_cpu.cpp6
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/file_sys/patch_manager.cpp22
-rw-r--r--src/core/file_sys/patch_manager.h2
-rw-r--r--src/core/file_sys/registered_cache.cpp275
-rw-r--r--src/core/file_sys/registered_cache.h156
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/submission_package.cpp13
-rw-r--r--src/core/file_sys/submission_package.h11
-rw-r--r--src/core/frontend/emu_window.h39
-rw-r--r--src/core/hle/kernel/client_port.h2
-rw-r--r--src/core/hle/kernel/client_session.h2
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/process.h2
-rw-r--r--src/core/hle/kernel/readable_event.h2
-rw-r--r--src/core/hle/kernel/resource_limit.h2
-rw-r--r--src/core/hle/kernel/server_port.h2
-rw-r--r--src/core/hle/kernel/server_session.cpp9
-rw-r--r--src/core/hle/kernel/server_session.h2
-rw-r--r--src/core/hle/kernel/shared_memory.h2
-rw-r--r--src/core/hle/kernel/svc.cpp337
-rw-r--r--src/core/hle/kernel/svc.h6
-rw-r--r--src/core/hle/kernel/svc_wrap.h352
-rw-r--r--src/core/hle/kernel/thread.h2
-rw-r--r--src/core/hle/kernel/writable_event.h2
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp11
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp15
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp16
-rw-r--r--src/core/loader/nso.cpp6
-rw-r--r--src/core/settings.h1
39 files changed, 837 insertions, 591 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 49145911b..dc96e35d5 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -14,6 +14,7 @@
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/vm_manager.h"
@@ -99,7 +100,7 @@ public:
}
void CallSVC(u32 swi) override {
- Kernel::CallSVC(swi);
+ Kernel::CallSVC(parent.system, swi);
}
void AddTicks(u64 ticks) override {
@@ -112,14 +113,14 @@ public:
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
- parent.core_timing.AddTicks(amortized_ticks);
+ parent.system.CoreTiming().AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
- return std::max(parent.core_timing.GetDowncount(), 0);
+ return std::max(parent.system.CoreTiming().GetDowncount(), 0);
}
u64 GetCNTPCT() override {
- return Timing::CpuCyclesToClockCycles(parent.core_timing.GetTicks());
+ return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks());
}
ARM_Dynarmic& parent;
@@ -129,7 +130,7 @@ public:
};
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
- auto* current_process = Core::CurrentProcess();
+ auto* current_process = system.Kernel().CurrentProcess();
auto** const page_table = current_process->VMManager().page_table.pointers.data();
Dynarmic::A64::UserConfig config;
@@ -171,10 +172,10 @@ void ARM_Dynarmic::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
-ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
+ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
- : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
- core_index{core_index}, core_timing{core_timing},
+ : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
+ core_index{core_index}, system{system},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
ThreadContext ctx{};
inner_unicorn.SaveContext(ctx);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index d867c2a50..c1db254e8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,19 +12,15 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
-namespace Core::Timing {
-class CoreTiming;
-}
-
namespace Core {
class ARM_Dynarmic_Callbacks;
class DynarmicExclusiveMonitor;
+class System;
class ARM_Dynarmic final : public ARM_Interface {
public:
- ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
- std::size_t core_index);
+ ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ARM_Dynarmic() override;
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -63,7 +59,7 @@ private:
ARM_Unicorn inner_unicorn;
std::size_t core_index;
- Timing::CoreTiming& core_timing;
+ System& system;
DynarmicExclusiveMonitor& exclusive_monitor;
};
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 27309280c..4e07fe8b5 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -10,7 +10,6 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
-#include "core/memory.h"
namespace Core {
@@ -49,20 +48,6 @@ static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_
}
}
-static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) {
- u32 esr{};
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
-
- auto ec = esr >> 26;
- auto iss = esr & 0xFFFFFF;
-
- switch (ec) {
- case 0x15: // SVC
- Kernel::CallSVC(iss);
- break;
- }
-}
-
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
void* user_data) {
ARM_Interface::ThreadContext ctx{};
@@ -72,7 +57,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
return {};
}
-ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
+ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;
@@ -177,7 +162,7 @@ void ARM_Unicorn::Run() {
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000, 0));
} else {
- ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
+ ExecuteInstructions(std::max(system.CoreTiming().GetDowncount(), 0));
}
}
@@ -190,7 +175,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
- core_timing.AddTicks(num_instructions);
+ system.CoreTiming().AddTicks(num_instructions);
if (GDBStub::IsServerEnabled()) {
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
@@ -273,4 +258,20 @@ void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
last_bkpt_hit = true;
}
+void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
+ u32 esr{};
+ CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
+
+ const auto ec = esr >> 26;
+ const auto iss = esr & 0xFFFFFF;
+
+ auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
+
+ switch (ec) {
+ case 0x15: // SVC
+ Kernel::CallSVC(arm_instance->system, iss);
+ break;
+ }
+}
+
} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index 1e44f0736..209fc16ad 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -9,15 +9,13 @@
#include "core/arm/arm_interface.h"
#include "core/gdbstub/gdbstub.h"
-namespace Core::Timing {
-class CoreTiming;
-}
-
namespace Core {
+class System;
+
class ARM_Unicorn final : public ARM_Interface {
public:
- explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
+ explicit ARM_Unicorn(System& system);
~ARM_Unicorn() override;
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -47,8 +45,10 @@ public:
void RecordBreak(GDBStub::BreakpointAddress bkpt);
private:
+ static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
+
uc_engine* uc{};
- Timing::CoreTiming& core_timing;
+ System& system;
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit = false;
};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4fe77c25b..bc9e887b6 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -17,6 +17,7 @@
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
#include "core/file_sys/mode.h"
+#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
@@ -108,6 +109,8 @@ struct System::Impl {
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr)
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
+ if (content_provider == nullptr)
+ content_provider = std::make_unique<FileSys::ContentProviderUnion>();
/// Create default implementations of applets if one is not provided.
if (profile_selector == nullptr)
@@ -249,6 +252,8 @@ struct System::Impl {
Kernel::KernelCore kernel;
/// RealVfsFilesystem instance
FileSys::VirtualFilesystem virtual_filesystem;
+ /// ContentProviderUnion instance
+ std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
/// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader;
std::unique_ptr<VideoCore::RendererBase> renderer;
@@ -488,6 +493,27 @@ const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
return *impl->software_keyboard;
}
+void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) {
+ impl->content_provider = std::move(provider);
+}
+
+FileSys::ContentProvider& System::GetContentProvider() {
+ return *impl->content_provider;
+}
+
+const FileSys::ContentProvider& System::GetContentProvider() const {
+ return *impl->content_provider;
+}
+
+void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
+ FileSys::ContentProvider* provider) {
+ impl->content_provider->SetSlot(slot, provider);
+}
+
+void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) {
+ impl->content_provider->ClearSlot(slot);
+}
+
void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) {
impl->web_browser = std::move(applet);
}
diff --git a/src/core/core.h b/src/core/core.h
index 4d83b93cc..82b2e087e 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -21,6 +21,9 @@ class WebBrowserApplet;
namespace FileSys {
class CheatList;
+class ContentProvider;
+class ContentProviderUnion;
+enum class ContentProviderUnionSlot;
class VfsFilesystem;
} // namespace FileSys
@@ -270,6 +273,17 @@ public:
Frontend::WebBrowserApplet& GetWebBrowser();
const Frontend::WebBrowserApplet& GetWebBrowser() const;
+ void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
+
+ FileSys::ContentProvider& GetContentProvider();
+
+ const FileSys::ContentProvider& GetContentProvider() const;
+
+ void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
+ FileSys::ContentProvider* provider);
+
+ void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
+
private:
System();
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index e75741db0..ba63c3e61 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -55,13 +55,13 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
: cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} {
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
- arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
+ arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
#else
- arm_interface = std::make_unique<ARM_Unicorn>();
+ arm_interface = std::make_unique<ARM_Unicorn>(system);
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
- arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
+ arm_interface = std::make_unique<ARM_Unicorn>(system);
}
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index dfac9a4b3..dc006e2bb 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -22,6 +22,7 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
@@ -794,7 +795,7 @@ void KeyManager::DeriveBase() {
void KeyManager::DeriveETicket(PartitionDataManager& data) {
// ETicket keys
- const auto es = Service::FileSystem::GetUnionContents().GetEntry(
+ const auto es = Core::System::GetInstance().GetContentProvider().GetEntry(
0x0100000000000033, FileSys::ContentRecordType::Program);
if (es == nullptr)
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index e11217708..78dbadee3 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -10,6 +10,7 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/ips_layer.h"
@@ -69,7 +70,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
}
- const auto installed = Service::FileSystem::GetUnionContents();
+ const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
@@ -155,7 +156,7 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
return out;
}
-std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
+std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::string& name) const {
if (nso.size() < sizeof(Loader::NSOHeader)) {
return nso;
}
@@ -171,18 +172,19 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
if (Settings::values.dump_nso) {
- LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id);
+ LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
+ title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
- const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id));
+ const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
file->Resize(nso.size());
file->WriteBytes(nso);
}
}
- LOG_INFO(Loader, "Patching NSO for build_id={}", build_id);
+ LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
auto patch_dirs = load_dir->GetSubdirectories();
@@ -345,7 +347,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
if (romfs == nullptr)
return romfs;
- const auto installed = Service::FileSystem::GetUnionContents();
+ const auto& installed = Core::System::GetInstance().GetContentProvider();
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
@@ -392,7 +394,7 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
VirtualFile update_raw) const {
std::map<std::string, std::string, std::less<>> out;
- const auto installed = Service::FileSystem::GetUnionContents();
+ const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates
@@ -466,10 +468,10 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
// DLC
const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
- std::vector<RegisteredCacheEntry> dlc_match;
+ std::vector<ContentProviderEntry> dlc_match;
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
- [this, &installed](const RegisteredCacheEntry& entry) {
+ [this, &installed](const ContentProviderEntry& entry) {
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
});
@@ -492,7 +494,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
- const auto installed{Service::FileSystem::GetUnionContents()};
+ const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr)
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index de2672c76..769f8c6f0 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -44,7 +44,7 @@ public:
// Currently tracked NSO patches:
// - IPS
// - IPSwitch
- std::vector<u8> PatchNSO(const std::vector<u8>& nso) const;
+ std::vector<u8> PatchNSO(const std::vector<u8>& nso, const std::string& name) const;
// Checks to see if PatchNSO() will have any effect given the NSO's build ID.
// Used to prevent expensive copies in NSO loader.
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 1c6bacace..3946ff871 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -23,19 +23,19 @@ namespace FileSys {
// The size of blocks to use when vfs raw copying into nand.
constexpr size_t VFS_RC_LARGE_COPY_BLOCK = 0x400000;
-std::string RegisteredCacheEntry::DebugInfo() const {
+std::string ContentProviderEntry::DebugInfo() const {
return fmt::format("title_id={:016X}, content_type={:02X}", title_id, static_cast<u8>(type));
}
-bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
+bool operator<(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs) {
return (lhs.title_id < rhs.title_id) || (lhs.title_id == rhs.title_id && lhs.type < rhs.type);
}
-bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
+bool operator==(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs) {
return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type);
}
-bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
+bool operator!=(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs) {
return !operator==(lhs, rhs);
}
@@ -84,7 +84,7 @@ static std::string GetCNMTName(TitleType type, u64 title_id) {
return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id);
}
-static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
+ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
switch (type) {
case NCAContentType::Program:
// TODO(DarkLordZach): Differentiate between Program and Patch
@@ -104,6 +104,28 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
}
}
+ContentProvider::~ContentProvider() = default;
+
+bool ContentProvider::HasEntry(ContentProviderEntry entry) const {
+ return HasEntry(entry.title_id, entry.type);
+}
+
+VirtualFile ContentProvider::GetEntryUnparsed(ContentProviderEntry entry) const {
+ return GetEntryUnparsed(entry.title_id, entry.type);
+}
+
+VirtualFile ContentProvider::GetEntryRaw(ContentProviderEntry entry) const {
+ return GetEntryRaw(entry.title_id, entry.type);
+}
+
+std::unique_ptr<NCA> ContentProvider::GetEntry(ContentProviderEntry entry) const {
+ return GetEntry(entry.title_id, entry.type);
+}
+
+std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
+ return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
+}
+
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
std::string_view path) const {
const auto file = dir->GetFileRelative(path);
@@ -161,8 +183,8 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
return file;
}
-static std::optional<NcaID> CheckMapForContentRecord(
- const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
+static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id,
+ ContentRecordType type) {
if (map.find(title_id) == map.end())
return {};
@@ -268,7 +290,7 @@ void RegisteredCache::Refresh() {
AccumulateYuzuMeta();
}
-RegisteredCache::RegisteredCache(VirtualDir dir_, RegisteredCacheParsingFunction parsing_function)
+RegisteredCache::RegisteredCache(VirtualDir dir_, ContentProviderParsingFunction parsing_function)
: dir(std::move(dir_)), parser(std::move(parsing_function)) {
Refresh();
}
@@ -279,19 +301,11 @@ bool RegisteredCache::HasEntry(u64 title_id, ContentRecordType type) const {
return GetEntryRaw(title_id, type) != nullptr;
}
-bool RegisteredCache::HasEntry(RegisteredCacheEntry entry) const {
- return GetEntryRaw(entry) != nullptr;
-}
-
VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
const auto id = GetNcaIDFromMetadata(title_id, type);
return id ? GetFileAtID(*id) : nullptr;
}
-VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const {
- return GetEntryUnparsed(entry.title_id, entry.type);
-}
-
std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
const auto meta_iter = meta.find(title_id);
if (meta_iter != meta.end())
@@ -309,10 +323,6 @@ VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) c
return id ? parser(GetFileAtID(*id), *id) : nullptr;
}
-VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
- return GetEntryRaw(entry.title_id, entry.type);
-}
-
std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const {
const auto raw = GetEntryRaw(title_id, type);
if (raw == nullptr)
@@ -320,10 +330,6 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t
return std::make_unique<NCA>(raw, nullptr, 0, keys);
}
-std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
- return GetEntry(entry.title_id, entry.type);
-}
-
template <typename T>
void RegisteredCache::IterateAllMetadata(
std::vector<T>& out, std::function<T(const CNMT&, const ContentRecord&)> proc,
@@ -348,25 +354,14 @@ void RegisteredCache::IterateAllMetadata(
}
}
-std::vector<RegisteredCacheEntry> RegisteredCache::ListEntries() const {
- std::vector<RegisteredCacheEntry> out;
- IterateAllMetadata<RegisteredCacheEntry>(
- out,
- [](const CNMT& c, const ContentRecord& r) {
- return RegisteredCacheEntry{c.GetTitleID(), r.type};
- },
- [](const CNMT& c, const ContentRecord& r) { return true; });
- return out;
-}
-
-std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
+std::vector<ContentProviderEntry> RegisteredCache::ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
- std::vector<RegisteredCacheEntry> out;
- IterateAllMetadata<RegisteredCacheEntry>(
+ std::vector<ContentProviderEntry> out;
+ IterateAllMetadata<ContentProviderEntry>(
out,
[](const CNMT& c, const ContentRecord& r) {
- return RegisteredCacheEntry{c.GetTitleID(), r.type};
+ return ContentProviderEntry{c.GetTitleID(), r.type};
},
[&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
if (title_type && *title_type != c.GetType())
@@ -521,37 +516,56 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
}) != yuzu_meta.end();
}
-RegisteredCacheUnion::RegisteredCacheUnion(std::vector<RegisteredCache*> caches)
- : caches(std::move(caches)) {}
+ContentProviderUnion::~ContentProviderUnion() = default;
-void RegisteredCacheUnion::Refresh() {
- for (const auto& c : caches)
- c->Refresh();
+void ContentProviderUnion::SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider) {
+ providers[slot] = provider;
}
-bool RegisteredCacheUnion::HasEntry(u64 title_id, ContentRecordType type) const {
- return std::any_of(caches.begin(), caches.end(), [title_id, type](const auto& cache) {
- return cache->HasEntry(title_id, type);
- });
+void ContentProviderUnion::ClearSlot(ContentProviderUnionSlot slot) {
+ providers[slot] = nullptr;
}
-bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const {
- return HasEntry(entry.title_id, entry.type);
+void ContentProviderUnion::Refresh() {
+ for (auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
+
+ provider.second->Refresh();
+ }
}
-std::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const {
- for (const auto& c : caches) {
- const auto res = c->GetEntryVersion(title_id);
- if (res)
+bool ContentProviderUnion::HasEntry(u64 title_id, ContentRecordType type) const {
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
+
+ if (provider.second->HasEntry(title_id, type))
+ return true;
+ }
+
+ return false;
+}
+
+std::optional<u32> ContentProviderUnion::GetEntryVersion(u64 title_id) const {
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
+
+ const auto res = provider.second->GetEntryVersion(title_id);
+ if (res != std::nullopt)
return res;
}
- return {};
+ return std::nullopt;
}
-VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
- for (const auto& c : caches) {
- const auto res = c->GetEntryUnparsed(title_id, type);
+VirtualFile ContentProviderUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
+
+ const auto res = provider.second->GetEntryUnparsed(title_id, type);
if (res != nullptr)
return res;
}
@@ -559,13 +573,12 @@ VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordTy
return nullptr;
}
-VirtualFile RegisteredCacheUnion::GetEntryUnparsed(RegisteredCacheEntry entry) const {
- return GetEntryUnparsed(entry.title_id, entry.type);
-}
+VirtualFile ContentProviderUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const {
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
-VirtualFile RegisteredCacheUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const {
- for (const auto& c : caches) {
- const auto res = c->GetEntryRaw(title_id, type);
+ const auto res = provider.second->GetEntryRaw(title_id, type);
if (res != nullptr)
return res;
}
@@ -573,30 +586,56 @@ VirtualFile RegisteredCacheUnion::GetEntryRaw(u64 title_id, ContentRecordType ty
return nullptr;
}
-VirtualFile RegisteredCacheUnion::GetEntryRaw(RegisteredCacheEntry entry) const {
- return GetEntryRaw(entry.title_id, entry.type);
-}
+std::unique_ptr<NCA> ContentProviderUnion::GetEntry(u64 title_id, ContentRecordType type) const {
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
-std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const {
- const auto raw = GetEntryRaw(title_id, type);
- if (raw == nullptr)
- return nullptr;
- return std::make_unique<NCA>(raw);
+ auto res = provider.second->GetEntry(title_id, type);
+ if (res != nullptr)
+ return res;
+ }
+
+ return nullptr;
}
-std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const {
- return GetEntry(entry.title_id, entry.type);
+std::vector<ContentProviderEntry> ContentProviderUnion::ListEntriesFilter(
+ std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
+ std::optional<u64> title_id) const {
+ std::vector<ContentProviderEntry> out;
+
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
+
+ const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
+ std::copy(vec.begin(), vec.end(), std::back_inserter(out));
+ }
+
+ std::sort(out.begin(), out.end());
+ out.erase(std::unique(out.begin(), out.end()), out.end());
+ return out;
}
-std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
- std::vector<RegisteredCacheEntry> out;
- for (const auto& c : caches) {
- c->IterateAllMetadata<RegisteredCacheEntry>(
- out,
- [](const CNMT& c, const ContentRecord& r) {
- return RegisteredCacheEntry{c.GetTitleID(), r.type};
- },
- [](const CNMT& c, const ContentRecord& r) { return true; });
+std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>>
+ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnionSlot> origin,
+ std::optional<TitleType> title_type,
+ std::optional<ContentRecordType> record_type,
+ std::optional<u64> title_id) const {
+ std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> out;
+
+ for (const auto& provider : providers) {
+ if (provider.second == nullptr)
+ continue;
+
+ if (origin.has_value() && *origin != provider.first)
+ continue;
+
+ const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
+ std::transform(vec.begin(), vec.end(), std::back_inserter(out),
+ [&provider](const ContentProviderEntry& entry) {
+ return std::make_pair(provider.first, entry);
+ });
}
std::sort(out.begin(), out.end());
@@ -604,25 +643,61 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
return out;
}
-std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
+ManualContentProvider::~ManualContentProvider() = default;
+
+void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type,
+ u64 title_id, VirtualFile file) {
+ entries.insert_or_assign({title_type, content_type, title_id}, file);
+}
+
+void ManualContentProvider::ClearAllEntries() {
+ entries.clear();
+}
+
+void ManualContentProvider::Refresh() {}
+
+bool ManualContentProvider::HasEntry(u64 title_id, ContentRecordType type) const {
+ return GetEntryRaw(title_id, type) != nullptr;
+}
+
+std::optional<u32> ManualContentProvider::GetEntryVersion(u64 title_id) const {
+ return std::nullopt;
+}
+
+VirtualFile ManualContentProvider::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
+ return GetEntryRaw(title_id, type);
+}
+
+VirtualFile ManualContentProvider::GetEntryRaw(u64 title_id, ContentRecordType type) const {
+ const auto iter =
+ std::find_if(entries.begin(), entries.end(), [title_id, type](const auto& entry) {
+ const auto [title_type, content_type, e_title_id] = entry.first;
+ return content_type == type && e_title_id == title_id;
+ });
+ if (iter == entries.end())
+ return nullptr;
+ return iter->second;
+}
+
+std::unique_ptr<NCA> ManualContentProvider::GetEntry(u64 title_id, ContentRecordType type) const {
+ const auto res = GetEntryRaw(title_id, type);
+ if (res == nullptr)
+ return nullptr;
+ return std::make_unique<NCA>(res, nullptr, 0, keys);
+}
+
+std::vector<ContentProviderEntry> ManualContentProvider::ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
- std::vector<RegisteredCacheEntry> out;
- for (const auto& c : caches) {
- c->IterateAllMetadata<RegisteredCacheEntry>(
- out,
- [](const CNMT& c, const ContentRecord& r) {
- return RegisteredCacheEntry{c.GetTitleID(), r.type};
- },
- [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
- if (title_type && *title_type != c.GetType())
- return false;
- if (record_type && *record_type != r.type)
- return false;
- if (title_id && *title_id != c.GetTitleID())
- return false;
- return true;
- });
+ std::vector<ContentProviderEntry> out;
+
+ for (const auto& entry : entries) {
+ const auto [e_title_type, e_content_type, e_title_id] = entry.first;
+ if ((title_type == std::nullopt || e_title_type == *title_type) &&
+ (record_type == std::nullopt || e_content_type == *record_type) &&
+ (title_id == std::nullopt || e_title_id == *title_id)) {
+ out.emplace_back(ContentProviderEntry{e_title_id, e_content_type});
+ }
}
std::sort(out.begin(), out.end());
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 3b77af4e0..ec9052653 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -21,12 +21,13 @@ class NSP;
class XCI;
enum class ContentRecordType : u8;
+enum class NCAContentType : u8;
enum class TitleType : u8;
struct ContentRecord;
using NcaID = std::array<u8, 0x10>;
-using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
+using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile&, size_t)>;
enum class InstallResult {
@@ -36,7 +37,7 @@ enum class InstallResult {
ErrorMetaFailed,
};
-struct RegisteredCacheEntry {
+struct ContentProviderEntry {
u64 title_id;
ContentRecordType type;
@@ -47,12 +48,46 @@ constexpr u64 GetUpdateTitleID(u64 base_title_id) {
return base_title_id | 0x800;
}
+ContentRecordType GetCRTypeFromNCAType(NCAContentType type);
+
// boost flat_map requires operator< for O(log(n)) lookups.
-bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
+bool operator<(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
// std unique requires operator== to identify duplicates.
-bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
-bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
+bool operator==(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
+bool operator!=(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
+
+class ContentProvider {
+public:
+ virtual ~ContentProvider();
+
+ virtual void Refresh() = 0;
+
+ virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0;
+ virtual bool HasEntry(ContentProviderEntry entry) const;
+
+ virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0;
+
+ virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0;
+ virtual VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const;
+
+ virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0;
+ virtual VirtualFile GetEntryRaw(ContentProviderEntry entry) const;
+
+ virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0;
+ virtual std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const;
+
+ virtual std::vector<ContentProviderEntry> ListEntries() const;
+
+ // If a parameter is not std::nullopt, it will be filtered for from all entries.
+ virtual std::vector<ContentProviderEntry> ListEntriesFilter(
+ std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
+ std::optional<u64> title_id = {}) const = 0;
+
+protected:
+ // A single instance of KeyManager to be used by GetEntry()
+ Core::Crypto::KeyManager keys;
+};
/*
* A class that catalogues NCAs in the registered directory structure.
@@ -67,39 +102,32 @@ bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs
* (This impl also supports substituting the nca dir for an nca file, as that's more convenient
* when 4GB splitting can be ignored.)
*/
-class RegisteredCache {
- friend class RegisteredCacheUnion;
-
+class RegisteredCache : public ContentProvider {
public:
// Parsing function defines the conversion from raw file to NCA. If there are other steps
// besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
// parsing function.
explicit RegisteredCache(VirtualDir dir,
- RegisteredCacheParsingFunction parsing_function =
+ ContentProviderParsingFunction parsing_function =
[](const VirtualFile& file, const NcaID& id) { return file; });
- ~RegisteredCache();
+ ~RegisteredCache() override;
- void Refresh();
+ void Refresh() override;
- bool HasEntry(u64 title_id, ContentRecordType type) const;
- bool HasEntry(RegisteredCacheEntry entry) const;
+ bool HasEntry(u64 title_id, ContentRecordType type) const override;
- std::optional<u32> GetEntryVersion(u64 title_id) const;
+ std::optional<u32> GetEntryVersion(u64 title_id) const override;
- VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
- VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
+ VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
- VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
- VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
+ VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
- std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
- std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
+ std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
- std::vector<RegisteredCacheEntry> ListEntries() const;
// If a parameter is not std::nullopt, it will be filtered for from all entries.
- std::vector<RegisteredCacheEntry> ListEntriesFilter(
+ std::vector<ContentProviderEntry> ListEntriesFilter(
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
- std::optional<u64> title_id = {}) const;
+ std::optional<u64> title_id = {}) const override;
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
// there is a meta NCA and all of them are accessible.
@@ -131,46 +159,70 @@ private:
bool RawInstallYuzuMeta(const CNMT& cnmt);
VirtualDir dir;
- RegisteredCacheParsingFunction parser;
- Core::Crypto::KeyManager keys;
+ ContentProviderParsingFunction parser;
// maps tid -> NcaID of meta
- boost::container::flat_map<u64, NcaID> meta_id;
+ std::map<u64, NcaID> meta_id;
// maps tid -> meta
- boost::container::flat_map<u64, CNMT> meta;
+ std::map<u64, CNMT> meta;
// maps tid -> meta for CNMT in yuzu_meta
- boost::container::flat_map<u64, CNMT> yuzu_meta;
+ std::map<u64, CNMT> yuzu_meta;
};
-// Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface.
-class RegisteredCacheUnion {
-public:
- explicit RegisteredCacheUnion(std::vector<RegisteredCache*> caches);
-
- void Refresh();
-
- bool HasEntry(u64 title_id, ContentRecordType type) const;
- bool HasEntry(RegisteredCacheEntry entry) const;
-
- std::optional<u32> GetEntryVersion(u64 title_id) const;
-
- VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
- VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
-
- VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
- VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
-
- std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
- std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
+enum class ContentProviderUnionSlot {
+ SysNAND, ///< System NAND
+ UserNAND, ///< User NAND
+ SDMC, ///< SD Card
+ FrontendManual, ///< Frontend-defined game list or similar
+};
- std::vector<RegisteredCacheEntry> ListEntries() const;
- // If a parameter is not std::nullopt, it will be filtered for from all entries.
- std::vector<RegisteredCacheEntry> ListEntriesFilter(
+// Combines multiple ContentProvider(s) (i.e. SysNAND, UserNAND, SDMC) into one interface.
+class ContentProviderUnion : public ContentProvider {
+public:
+ ~ContentProviderUnion() override;
+
+ void SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider);
+ void ClearSlot(ContentProviderUnionSlot slot);
+
+ void Refresh() override;
+ bool HasEntry(u64 title_id, ContentRecordType type) const override;
+ std::optional<u32> GetEntryVersion(u64 title_id) const override;
+ VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
+ VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
+ std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
+ std::vector<ContentProviderEntry> ListEntriesFilter(
+ std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
+ std::optional<u64> title_id) const override;
+
+ std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ListEntriesFilterOrigin(
+ std::optional<ContentProviderUnionSlot> origin = {},
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const;
private:
- std::vector<RegisteredCache*> caches;
+ std::map<ContentProviderUnionSlot, ContentProvider*> providers;
+};
+
+class ManualContentProvider : public ContentProvider {
+public:
+ ~ManualContentProvider() override;
+
+ void AddEntry(TitleType title_type, ContentRecordType content_type, u64 title_id,
+ VirtualFile file);
+ void ClearAllEntries();
+
+ void Refresh() override;
+ bool HasEntry(u64 title_id, ContentRecordType type) const override;
+ std::optional<u32> GetEntryVersion(u64 title_id) const override;
+ VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
+ VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
+ std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
+ std::vector<ContentProviderEntry> ListEntriesFilter(
+ std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
+ std::optional<u64> title_id) const override;
+
+private:
+ std::map<std::tuple<TitleType, ContentRecordType, u64>, VirtualFile> entries;
};
} // namespace FileSys
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 6ad1e4f86..b2ccb2926 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
switch (storage) {
case StorageId::None:
- res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
+ res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index e1a4210db..c69caae0f 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -143,11 +143,12 @@ std::multimap<u64, std::shared_ptr<NCA>> NSP::GetNCAsByTitleID() const {
return out;
}
-std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> NSP::GetNCAs() const {
+std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>>
+NSP::GetNCAs() const {
return ncas;
}
-std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type) const {
+std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType title_type) const {
if (extracted)
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
@@ -155,14 +156,14 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type) const {
if (title_id_iter == ncas.end())
return nullptr;
- const auto type_iter = title_id_iter->second.find(type);
+ const auto type_iter = title_id_iter->second.find({title_type, type});
if (type_iter == title_id_iter->second.end())
return nullptr;
return type_iter->second;
}
-VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type) const {
+VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type, TitleType title_type) const {
if (extracted)
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
const auto nca = GetNCA(title_id, type);
@@ -240,7 +241,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
const CNMT cnmt(inner_file);
auto& ncas_title = ncas[cnmt.GetTitleID()];
- ncas_title[ContentRecordType::Meta] = nca;
+ ncas_title[{cnmt.GetType(), ContentRecordType::Meta}] = nca;
for (const auto& rec : cnmt.GetContentRecords()) {
const auto id_string = Common::HexArrayToString(rec.nca_id, false);
const auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
@@ -258,7 +259,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
(next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
(cnmt.GetTitleID() & 0x800) != 0)) {
- ncas_title[rec.type] = std::move(next_nca);
+ ncas_title[{cnmt.GetType(), rec.type}] = std::move(next_nca);
}
}
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 9a28ed5bb..ee9b6ce17 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -42,9 +42,12 @@ public:
// Type 0 Only (Collection of NCAs + Certificate + Ticket + Meta XML)
std::vector<std::shared_ptr<NCA>> GetNCAsCollapsed() const;
std::multimap<u64, std::shared_ptr<NCA>> GetNCAsByTitleID() const;
- std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> GetNCAs() const;
- std::shared_ptr<NCA> GetNCA(u64 title_id, ContentRecordType type) const;
- VirtualFile GetNCAFile(u64 title_id, ContentRecordType type) const;
+ std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> GetNCAs()
+ const;
+ std::shared_ptr<NCA> GetNCA(u64 title_id, ContentRecordType type,
+ TitleType title_type = TitleType::Application) const;
+ VirtualFile GetNCAFile(u64 title_id, ContentRecordType type,
+ TitleType title_type = TitleType::Application) const;
std::vector<Core::Crypto::Key128> GetTitlekey() const;
std::vector<VirtualFile> GetFiles() const override;
@@ -67,7 +70,7 @@ private:
std::shared_ptr<PartitionFilesystem> pfs;
// Map title id -> {map type -> NCA}
- std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas;
+ std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
std::vector<VirtualFile> ticket_files;
Core::Crypto::KeyManager keys;
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index d0bcb4660..70a522556 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -13,6 +13,23 @@
namespace Core::Frontend {
/**
+ * Represents a graphics context that can be used for background computation or drawing. If the
+ * graphics backend doesn't require the context, then the implementation of these methods can be
+ * stubs
+ */
+class GraphicsContext {
+public:
+ /// Makes the graphics context current for the caller thread
+ virtual void MakeCurrent() = 0;
+
+ /// Releases (dunno if this is the "right" word) the context from the caller thread
+ virtual void DoneCurrent() = 0;
+
+ /// Swap buffers to display the next frame
+ virtual void SwapBuffers() = 0;
+};
+
+/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
*
@@ -30,7 +47,7 @@ namespace Core::Frontend {
* - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
* re-read the upper points again and think about it if you don't see this.
*/
-class EmuWindow {
+class EmuWindow : public GraphicsContext {
public:
/// Data structure to store emuwindow configuration
struct WindowConfig {
@@ -40,17 +57,21 @@ public:
std::pair<unsigned, unsigned> min_client_area_size;
};
- /// Swap buffers to display the next frame
- virtual void SwapBuffers() = 0;
-
/// Polls window events
virtual void PollEvents() = 0;
- /// Makes the graphics context current for the caller thread
- virtual void MakeCurrent() = 0;
-
- /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
- virtual void DoneCurrent() = 0;
+ /**
+ * Returns a GraphicsContext that the frontend provides that is shared with the emu window. This
+ * context can be used from other threads for background graphics computation. If the frontend
+ * is using a graphics backend that doesn't need anything specific to run on a different thread,
+ * then it can use a stubbed implemenation for GraphicsContext.
+ *
+ * If the return value is null, then the core should assume that the frontend cannot provide a
+ * Shared Context
+ */
+ virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const {
+ return nullptr;
+ }
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 6cd607206..4921ad4f0 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -25,7 +25,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::ClientPort;
+ static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index b1f39aad7..09cdff588 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -29,7 +29,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::ClientSession;
+ static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 26c6b95ab..4e94048da 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -106,6 +106,8 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
is_64bit_process = metadata.Is64BitProgram();
vm_manager.Reset(metadata.GetAddressSpaceType());
+ // Ensure that the potentially resized page table is seen by CPU backends.
+ Memory::SetCurrentPageTable(&vm_manager.page_table);
const auto& caps = metadata.GetKernelCapabilities();
const auto capability_init_result =
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index f060f2a3b..dda52f4c0 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -85,7 +85,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::Process;
+ static constexpr HandleType HANDLE_TYPE = HandleType::Process;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
index 2eb9dcbb7..84215f572 100644
--- a/src/core/hle/kernel/readable_event.h
+++ b/src/core/hle/kernel/readable_event.h
@@ -31,7 +31,7 @@ public:
return reset_type;
}
- static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
+ static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 70e09858a..2613a6bb5 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -41,7 +41,7 @@ public:
return GetTypeName();
}
- static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
+ static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index fef573b71..dc88a1ebd 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -43,7 +43,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::ServerPort;
+ static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index a6b2cf06a..696a82cd9 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -28,11 +28,9 @@ ServerSession::~ServerSession() {
// the emulated application.
// Decrease the port's connection count.
- if (parent->port)
+ if (parent->port) {
parent->port->ConnectionClosed();
-
- // TODO(Subv): Wake up all the ClientSession's waiting threads and set
- // the SendSyncRequest result to 0xC920181A.
+ }
parent->server = nullptr;
}
@@ -74,9 +72,6 @@ void ServerSession::ClientDisconnected() {
handler->ClientDisconnected(this);
}
- // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set
- // their WaitSynchronization result to 0xC920181A.
-
// Clean up the list of client threads with pending requests, they are unneeded now that the
// client endpoint is closed.
pending_requesting_threads.clear();
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 09b835ff8..738df30f8 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -46,7 +46,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::ServerSession;
+ static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 37e18c443..c2b6155e1 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -76,7 +76,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
+ static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 2fd07ab34..e5d4d6b55 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -131,16 +131,15 @@ enum class ResourceLimitValueType {
LimitValue,
};
-ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type,
- ResourceLimitValueType value_type) {
+ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
+ u32 resource_type, ResourceLimitValueType value_type) {
const auto type = static_cast<ResourceType>(resource_type);
if (!IsValidResourceType(type)) {
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
return ERR_INVALID_ENUM_VALUE;
}
- const auto& kernel = Core::System::GetInstance().Kernel();
- const auto* const current_process = kernel.CurrentProcess();
+ const auto* const current_process = system.Kernel().CurrentProcess();
ASSERT(current_process != nullptr);
const auto resource_limit_object =
@@ -160,7 +159,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_ty
} // Anonymous namespace
/// Set the process heap to a given Size. It can both extend and shrink the heap.
-static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
+static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) {
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
@@ -175,7 +174,7 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
return ERR_INVALID_SIZE;
}
- auto& vm_manager = Core::System::GetInstance().Kernel().CurrentProcess()->VMManager();
+ auto& vm_manager = system.Kernel().CurrentProcess()->VMManager();
const auto alloc_result = vm_manager.SetHeapSize(heap_size);
if (alloc_result.Failed()) {
return alloc_result.Code();
@@ -185,7 +184,7 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
return RESULT_SUCCESS;
}
-static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
+static ResultCode SetMemoryPermission(Core::System& system, VAddr addr, u64 size, u32 prot) {
LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot);
if (!Common::Is4KBAligned(addr)) {
@@ -217,7 +216,7 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
return ERR_INVALID_MEMORY_PERMISSIONS;
}
- auto* const current_process = Core::CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
auto& vm_manager = current_process->VMManager();
if (!vm_manager.IsWithinAddressSpace(addr, size)) {
@@ -242,7 +241,8 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
return vm_manager.ReprotectRange(addr, size, converted_permissions);
}
-static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attribute) {
+static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
+ u32 attribute) {
LOG_DEBUG(Kernel_SVC,
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
size, mask, attribute);
@@ -280,7 +280,7 @@ static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attr
return ERR_INVALID_COMBINATION;
}
- auto& vm_manager = Core::CurrentProcess()->VMManager();
+ auto& vm_manager = system.Kernel().CurrentProcess()->VMManager();
if (!vm_manager.IsWithinAddressSpace(address, size)) {
LOG_ERROR(Kernel_SVC,
"Given address (0x{:016X}) is outside the bounds of the address space.", address);
@@ -291,11 +291,11 @@ static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attr
}
/// Maps a memory range into a different range.
-static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
+static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
- auto& vm_manager = Core::CurrentProcess()->VMManager();
+ auto& vm_manager = system.Kernel().CurrentProcess()->VMManager();
const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
if (result.IsError()) {
@@ -306,11 +306,11 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
}
/// Unmaps a region that was previously mapped with svcMapMemory
-static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
+static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
- auto& vm_manager = Core::CurrentProcess()->VMManager();
+ auto& vm_manager = system.Kernel().CurrentProcess()->VMManager();
const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
if (result.IsError()) {
@@ -321,7 +321,8 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
}
/// Connect to an OS service given the port name, returns the handle to the port to out
-static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) {
+static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
+ VAddr port_name_address) {
if (!Memory::IsValidVirtualAddress(port_name_address)) {
LOG_ERROR(Kernel_SVC,
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
@@ -340,8 +341,8 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
- auto& kernel = Core::System::GetInstance().Kernel();
- auto it = kernel.FindNamedPort(port_name);
+ auto& kernel = system.Kernel();
+ const auto it = kernel.FindNamedPort(port_name);
if (!kernel.IsValidNamedPort(it)) {
LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
return ERR_NOT_FOUND;
@@ -353,14 +354,14 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
CASCADE_RESULT(client_session, client_port->Connect());
// Return the client session
- auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
CASCADE_RESULT(*out_handle, handle_table.Create(client_session));
return RESULT_SUCCESS;
}
/// Makes a blocking IPC call to an OS service.
-static ResultCode SendSyncRequest(Handle handle) {
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle);
if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
@@ -369,18 +370,18 @@ static ResultCode SendSyncRequest(Handle handle) {
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
- Core::System::GetInstance().PrepareReschedule();
+ system.PrepareReschedule();
// TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
// responds and cause a reschedule.
- return session->SendSyncRequest(GetCurrentThread());
+ return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread());
}
/// Get the ID for the specified thread.
-static ResultCode GetThreadId(u64* thread_id, Handle thread_handle) {
+static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
@@ -392,10 +393,10 @@ static ResultCode GetThreadId(u64* thread_id, Handle thread_handle) {
}
/// Gets the ID of the specified process or a specified thread's owning process.
-static ResultCode GetProcessId(u64* process_id, Handle handle) {
+static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Process> process = handle_table.Get<Process>(handle);
if (process) {
*process_id = process->GetProcessID();
@@ -437,8 +438,8 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thr
};
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count,
- s64 nano_seconds) {
+static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address,
+ u64 handle_count, s64 nano_seconds) {
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
handles_address, handle_count, nano_seconds);
@@ -457,11 +458,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
return ERR_OUT_OF_RANGE;
}
- auto* const thread = GetCurrentThread();
+ auto* const thread = system.CurrentScheduler().GetCurrentThread();
using ObjectPtr = Thread::ThreadWaitObjects::value_type;
Thread::ThreadWaitObjects objects(handle_count);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
for (u64 i = 0; i < handle_count; ++i) {
const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
@@ -507,16 +508,16 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
thread->WakeAfterDelay(nano_seconds);
thread->SetWakeupCallback(DefaultThreadWakeupCallback);
- Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
+ system.CpuCore(thread->GetProcessorID()).PrepareReschedule();
return RESULT_TIMEOUT;
}
/// Resumes a thread waiting on WaitSynchronization
-static ResultCode CancelSynchronization(Handle thread_handle) {
+static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
@@ -531,8 +532,8 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
}
/// Attempts to locks a mutex, creating it if it does not already exist
-static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
- Handle requesting_thread_handle) {
+static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_handle,
+ VAddr mutex_addr, Handle requesting_thread_handle) {
LOG_TRACE(Kernel_SVC,
"called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, "
"requesting_current_thread_handle=0x{:08X}",
@@ -549,13 +550,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
return ERR_INVALID_ADDRESS;
}
- auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
return current_process->GetMutex().TryAcquire(mutex_addr, holding_thread_handle,
requesting_thread_handle);
}
/// Unlock a mutex
-static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
+static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) {
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
@@ -569,7 +570,7 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
return ERR_INVALID_ADDRESS;
}
- auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
return current_process->GetMutex().Release(mutex_addr);
}
@@ -592,7 +593,7 @@ struct BreakReason {
};
/// Break program execution
-static void Break(u32 reason, u64 info1, u64 info2) {
+static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
BreakReason break_reason{reason};
bool has_dumped_buffer{};
@@ -670,22 +671,24 @@ static void Break(u32 reason, u64 info1, u64 info2) {
Debug_Emulated,
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
reason, info1, info2);
+
handle_debug_buffer(info1, info2);
- Core::System::GetInstance()
- .ArmInterface(static_cast<std::size_t>(GetCurrentThread()->GetProcessorID()))
- .LogBacktrace();
+
+ auto* const current_thread = system.CurrentScheduler().GetCurrentThread();
+ const auto thread_processor_id = current_thread->GetProcessorID();
+ system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
ASSERT(false);
- Core::CurrentProcess()->PrepareForTermination();
+ system.Kernel().CurrentProcess()->PrepareForTermination();
// Kill the current thread
- GetCurrentThread()->Stop();
- Core::System::GetInstance().PrepareReschedule();
+ current_thread->Stop();
+ system.PrepareReschedule();
}
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
-static void OutputDebugString(VAddr address, u64 len) {
+static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) {
if (len == 0) {
return;
}
@@ -696,7 +699,8 @@ static void OutputDebugString(VAddr address, u64 len) {
}
/// Gets system/memory information for the current process
-static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) {
+static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle,
+ u64 info_sub_id) {
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
@@ -754,7 +758,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
return ERR_INVALID_ENUM_VALUE;
}
- const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& current_process_handle_table =
+ system.Kernel().CurrentProcess()->GetHandleTable();
const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
if (!process) {
return ERR_INVALID_HANDLE;
@@ -844,7 +849,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
return ERR_INVALID_COMBINATION;
}
- Process* const current_process = Core::CurrentProcess();
+ Process* const current_process = system.Kernel().CurrentProcess();
HandleTable& handle_table = current_process->GetHandleTable();
const auto resource_limit = current_process->GetResourceLimit();
if (!resource_limit) {
@@ -875,7 +880,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
return ERR_INVALID_COMBINATION;
}
- *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id);
+ *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id);
return RESULT_SUCCESS;
case GetInfoType::PrivilegedProcessId:
@@ -892,15 +897,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
return ERR_INVALID_COMBINATION;
}
- const auto thread =
- Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
+ const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>(
+ static_cast<Handle>(handle));
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
return ERR_INVALID_HANDLE;
}
- const auto& system = Core::System::GetInstance();
const auto& core_timing = system.CoreTiming();
const auto& scheduler = system.CurrentScheduler();
const auto* const current_thread = scheduler.GetCurrentThread();
@@ -927,13 +931,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
}
/// Sets the thread activity
-static ResultCode SetThreadActivity(Handle handle, u32 activity) {
+static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity);
if (activity > static_cast<u32>(ThreadActivity::Paused)) {
return ERR_INVALID_ENUM_VALUE;
}
- const auto* current_process = Core::CurrentProcess();
+ const auto* current_process = system.Kernel().CurrentProcess();
const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
@@ -950,7 +954,7 @@ static ResultCode SetThreadActivity(Handle handle, u32 activity) {
return ERR_INVALID_HANDLE;
}
- if (thread == GetCurrentThread()) {
+ if (thread == system.CurrentScheduler().GetCurrentThread()) {
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
return ERR_BUSY;
}
@@ -960,10 +964,10 @@ static ResultCode SetThreadActivity(Handle handle, u32 activity) {
}
/// Gets the thread context
-static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
+static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
- const auto* current_process = Core::CurrentProcess();
+ const auto* current_process = system.Kernel().CurrentProcess();
const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
@@ -980,7 +984,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
return ERR_INVALID_HANDLE;
}
- if (thread == GetCurrentThread()) {
+ if (thread == system.CurrentScheduler().GetCurrentThread()) {
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
return ERR_BUSY;
}
@@ -1001,10 +1005,10 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
}
/// Gets the priority for the specified thread
-static ResultCode GetThreadPriority(u32* priority, Handle handle) {
+static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) {
LOG_TRACE(Kernel_SVC, "called");
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
@@ -1016,7 +1020,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
}
/// Sets the priority for the specified thread
-static ResultCode SetThreadPriority(Handle handle, u32 priority) {
+static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
LOG_TRACE(Kernel_SVC, "called");
if (priority > THREADPRIO_LOWEST) {
@@ -1027,7 +1031,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
return ERR_INVALID_THREAD_PRIORITY;
}
- const auto* const current_process = Core::CurrentProcess();
+ const auto* const current_process = system.Kernel().CurrentProcess();
SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) {
@@ -1037,18 +1041,18 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
thread->SetPriority(priority);
- Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
+ system.CpuCore(thread->GetProcessorID()).PrepareReschedule();
return RESULT_SUCCESS;
}
/// Get which CPU core is executing the current thread
-static u32 GetCurrentProcessorNumber() {
+static u32 GetCurrentProcessorNumber(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called");
- return GetCurrentThread()->GetProcessorID();
+ return system.CurrentScheduler().GetCurrentThread()->GetProcessorID();
}
-static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
- u32 permissions) {
+static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr,
+ u64 size, u32 permissions) {
LOG_TRACE(Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
shared_memory_handle, addr, size, permissions);
@@ -1082,7 +1086,7 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
return ERR_INVALID_MEMORY_PERMISSIONS;
}
- auto* const current_process = Core::CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
if (!shared_memory) {
LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
@@ -1100,7 +1104,8 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
return shared_memory->Map(*current_process, addr, permissions_type, MemoryPermission::DontCare);
}
-static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
+static ResultCode UnmapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr,
+ u64 size) {
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
shared_memory_handle, addr, size);
@@ -1125,7 +1130,7 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
return ERR_INVALID_ADDRESS_STATE;
}
- auto* const current_process = Core::CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
if (!shared_memory) {
LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
@@ -1143,10 +1148,11 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
return shared_memory->Unmap(*current_process, addr, size);
}
-static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_address,
- Handle process_handle, VAddr address) {
+static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
+ VAddr page_info_address, Handle process_handle,
+ VAddr address) {
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
if (!process) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
@@ -1172,20 +1178,20 @@ static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_
return RESULT_SUCCESS;
}
-static ResultCode QueryMemory(VAddr memory_info_address, VAddr page_info_address,
- VAddr query_address) {
+static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address,
+ VAddr page_info_address, VAddr query_address) {
LOG_TRACE(Kernel_SVC,
"called, memory_info_address=0x{:016X}, page_info_address=0x{:016X}, "
"query_address=0x{:016X}",
memory_info_address, page_info_address, query_address);
- return QueryProcessMemory(memory_info_address, page_info_address, CurrentProcess,
+ return QueryProcessMemory(system, memory_info_address, page_info_address, CurrentProcess,
query_address);
}
/// Exits the current process
-static void ExitProcess() {
- auto* current_process = Core::CurrentProcess();
+static void ExitProcess(Core::System& system) {
+ auto* current_process = system.Kernel().CurrentProcess();
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
@@ -1194,20 +1200,20 @@ static void ExitProcess() {
current_process->PrepareForTermination();
// Kill the current thread
- GetCurrentThread()->Stop();
+ system.CurrentScheduler().GetCurrentThread()->Stop();
- Core::System::GetInstance().PrepareReschedule();
+ system.PrepareReschedule();
}
/// Creates a new thread
-static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
- u32 priority, s32 processor_id) {
+static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
+ VAddr stack_top, u32 priority, s32 processor_id) {
LOG_TRACE(Kernel_SVC,
"called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
entry_point, arg, stack_top, priority, processor_id, *out_handle);
- auto* const current_process = Core::CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
if (processor_id == THREADPROCESSORID_IDEAL) {
// Set the target CPU to the one specified by the process.
@@ -1239,7 +1245,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
}
const std::string name = fmt::format("thread-{:X}", entry_point);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
CASCADE_RESULT(SharedPtr<Thread> thread,
Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
*current_process));
@@ -1253,16 +1259,16 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
thread->SetGuestHandle(*new_guest_handle);
*out_handle = *new_guest_handle;
- Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
+ system.CpuCore(thread->GetProcessorID()).PrepareReschedule();
return RESULT_SUCCESS;
}
/// Starts the thread for the provided handle
-static ResultCode StartThread(Handle thread_handle) {
+static ResultCode StartThread(Core::System& system, Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
@@ -1275,16 +1281,14 @@ static ResultCode StartThread(Handle thread_handle) {
thread->ResumeFromWait();
if (thread->GetStatus() == ThreadStatus::Ready) {
- Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
+ system.CpuCore(thread->GetProcessorID()).PrepareReschedule();
}
return RESULT_SUCCESS;
}
/// Called when a thread exits
-static void ExitThread() {
- auto& system = Core::System::GetInstance();
-
+static void ExitThread(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
auto* const current_thread = system.CurrentScheduler().GetCurrentThread();
@@ -1294,7 +1298,7 @@ static void ExitThread() {
}
/// Sleep the current thread
-static void SleepThread(s64 nanoseconds) {
+static void SleepThread(Core::System& system, s64 nanoseconds) {
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
enum class SleepType : s64 {
@@ -1303,7 +1307,6 @@ static void SleepThread(s64 nanoseconds) {
YieldAndWaitForLoadBalancing = -2,
};
- auto& system = Core::System::GetInstance();
auto& scheduler = system.CurrentScheduler();
auto* const current_thread = scheduler.GetCurrentThread();
@@ -1332,8 +1335,9 @@ static void SleepThread(s64 nanoseconds) {
}
/// Wait process wide key atomic
-static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
- Handle thread_handle, s64 nano_seconds) {
+static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_addr,
+ VAddr condition_variable_addr, Handle thread_handle,
+ s64 nano_seconds) {
LOG_TRACE(
Kernel_SVC,
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
@@ -1353,7 +1357,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
return ERR_INVALID_ADDRESS;
}
- auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
const auto& handle_table = current_process->GetHandleTable();
SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
ASSERT(thread);
@@ -1363,7 +1367,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
return release_result;
}
- SharedPtr<Thread> current_thread = GetCurrentThread();
+ SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread();
current_thread->SetCondVarWaitAddress(condition_variable_addr);
current_thread->SetMutexWaitAddress(mutex_addr);
current_thread->SetWaitHandle(thread_handle);
@@ -1374,19 +1378,20 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
// Note: Deliberately don't attempt to inherit the lock owner's priority.
- Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
+ system.CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
return RESULT_SUCCESS;
}
/// Signal process wide key
-static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) {
+static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_variable_addr,
+ s32 target) {
LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
condition_variable_addr, target);
- const auto RetrieveWaitingThreads = [](std::size_t core_index,
- std::vector<SharedPtr<Thread>>& waiting_threads,
- VAddr condvar_addr) {
- const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
+ const auto RetrieveWaitingThreads = [&system](std::size_t core_index,
+ std::vector<SharedPtr<Thread>>& waiting_threads,
+ VAddr condvar_addr) {
+ const auto& scheduler = system.Scheduler(core_index);
const auto& thread_list = scheduler.GetThreadList();
for (const auto& thread : thread_list) {
@@ -1425,9 +1430,8 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
// liberate Cond Var Thread.
thread->SetCondVarWaitAddress(0);
- std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex();
-
- auto& monitor = Core::System::GetInstance().Monitor();
+ const std::size_t current_core = system.CurrentCoreIndex();
+ auto& monitor = system.Monitor();
// Atomically read the value of the mutex.
u32 mutex_val = 0;
@@ -1456,7 +1460,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
thread->SetLockOwner(nullptr);
thread->SetMutexWaitAddress(0);
thread->SetWaitHandle(0);
- Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
+ system.CpuCore(thread->GetProcessorID()).PrepareReschedule();
} else {
// Atomically signal that the mutex now has a waiting thread.
do {
@@ -1472,7 +1476,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
// The mutex is already owned by some other thread, make this thread wait on it.
const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
auto owner = handle_table.Get<Thread>(owner_handle);
ASSERT(owner);
ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
@@ -1487,14 +1491,17 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
}
// Wait for an address (via Address Arbiter)
-static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) {
+static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, s32 value,
+ s64 timeout) {
LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}",
address, type, value, timeout);
+
// If the passed address is a kernel virtual address, return invalid memory state.
if (Memory::IsKernelVirtualAddress(address)) {
LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
return ERR_INVALID_ADDRESS_STATE;
}
+
// If the address is not properly aligned to 4 bytes, return invalid address.
if (!Common::IsWordAligned(address)) {
LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
@@ -1502,20 +1509,22 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
}
const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type);
- auto& address_arbiter =
- Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter();
+ auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter();
return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout);
}
// Signals to an address (via Address Arbiter)
-static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) {
+static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value,
+ s32 num_to_wake) {
LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}",
address, type, value, num_to_wake);
+
// If the passed address is a kernel virtual address, return invalid memory state.
if (Memory::IsKernelVirtualAddress(address)) {
LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
return ERR_INVALID_ADDRESS_STATE;
}
+
// If the address is not properly aligned to 4 bytes, return invalid address.
if (!Common::IsWordAligned(address)) {
LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
@@ -1523,16 +1532,15 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
}
const auto signal_type = static_cast<AddressArbiter::SignalType>(type);
- auto& address_arbiter =
- Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter();
+ auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter();
return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake);
}
/// This returns the total CPU ticks elapsed since the CPU was powered-on
-static u64 GetSystemTick() {
+static u64 GetSystemTick(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called");
- auto& core_timing = Core::System::GetInstance().CoreTiming();
+ auto& core_timing = system.CoreTiming();
const u64 result{core_timing.GetTicks()};
// Advance time to defeat dumb games that busy-wait for the frame to end.
@@ -1542,18 +1550,18 @@ static u64 GetSystemTick() {
}
/// Close a handle
-static ResultCode CloseHandle(Handle handle) {
+static ResultCode CloseHandle(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
- auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
return handle_table.Close(handle);
}
/// Clears the signaled state of an event or process.
-static ResultCode ResetSignal(Handle handle) {
+static ResultCode ResetSignal(Core::System& system, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
auto event = handle_table.Get<ReadableEvent>(handle);
if (event) {
@@ -1570,7 +1578,8 @@ static ResultCode ResetSignal(Handle handle) {
}
/// Creates a TransferMemory object
-static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
+static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size,
+ u32 permissions) {
LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
permissions);
@@ -1598,7 +1607,7 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
return ERR_INVALID_MEMORY_PERMISSIONS;
}
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms);
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
@@ -1611,7 +1620,8 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
return RESULT_SUCCESS;
}
-static ResultCode MapTransferMemory(Handle handle, VAddr address, u64 size, u32 permission_raw) {
+static ResultCode MapTransferMemory(Core::System& system, Handle handle, VAddr address, u64 size,
+ u32 permission_raw) {
LOG_DEBUG(Kernel_SVC,
"called. handle=0x{:08X}, address=0x{:016X}, size=0x{:016X}, permissions=0x{:08X}",
handle, address, size, permission_raw);
@@ -1645,7 +1655,7 @@ static ResultCode MapTransferMemory(Handle handle, VAddr address, u64 size, u32
return ERR_INVALID_STATE;
}
- const auto& kernel = Core::System::GetInstance().Kernel();
+ const auto& kernel = system.Kernel();
const auto* const current_process = kernel.CurrentProcess();
const auto& handle_table = current_process->GetHandleTable();
@@ -1667,7 +1677,8 @@ static ResultCode MapTransferMemory(Handle handle, VAddr address, u64 size, u32
return transfer_memory->MapMemory(address, size, permissions);
}
-static ResultCode UnmapTransferMemory(Handle handle, VAddr address, u64 size) {
+static ResultCode UnmapTransferMemory(Core::System& system, Handle handle, VAddr address,
+ u64 size) {
LOG_DEBUG(Kernel_SVC, "called. handle=0x{:08X}, address=0x{:016X}, size=0x{:016X}", handle,
address, size);
@@ -1692,7 +1703,7 @@ static ResultCode UnmapTransferMemory(Handle handle, VAddr address, u64 size) {
return ERR_INVALID_ADDRESS_STATE;
}
- const auto& kernel = Core::System::GetInstance().Kernel();
+ const auto& kernel = system.Kernel();
const auto* const current_process = kernel.CurrentProcess();
const auto& handle_table = current_process->GetHandleTable();
@@ -1714,10 +1725,11 @@ static ResultCode UnmapTransferMemory(Handle handle, VAddr address, u64 size) {
return transfer_memory->UnmapMemory(address, size);
}
-static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
+static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core,
+ u64* mask) {
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
@@ -1731,11 +1743,12 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
return RESULT_SUCCESS;
}
-static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
+static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
+ u64 mask) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle,
mask, core);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
@@ -1780,8 +1793,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
return RESULT_SUCCESS;
}
-static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions,
- u32 remote_permissions) {
+static ResultCode CreateSharedMemory(Core::System& system, Handle* handle, u64 size,
+ u32 local_permissions, u32 remote_permissions) {
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
local_permissions, remote_permissions);
if (size == 0) {
@@ -1817,7 +1830,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
return ERR_INVALID_MEMORY_PERMISSIONS;
}
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
auto process = kernel.CurrentProcess();
auto& handle_table = process->GetHandleTable();
auto shared_mem_handle = SharedMemory::Create(kernel, process, size, local_perms, remote_perms);
@@ -1826,10 +1839,10 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
return RESULT_SUCCESS;
}
-static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) {
+static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
LOG_DEBUG(Kernel_SVC, "called");
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
const auto [readable_event, writable_event] =
WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent");
@@ -1854,10 +1867,10 @@ static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) {
return RESULT_SUCCESS;
}
-static ResultCode ClearEvent(Handle handle) {
+static ResultCode ClearEvent(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
auto writable_event = handle_table.Get<WritableEvent>(handle);
if (writable_event) {
@@ -1875,10 +1888,10 @@ static ResultCode ClearEvent(Handle handle) {
return ERR_INVALID_HANDLE;
}
-static ResultCode SignalEvent(Handle handle) {
+static ResultCode SignalEvent(Core::System& system, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
- HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable();
+ HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
auto writable_event = handle_table.Get<WritableEvent>(handle);
if (!writable_event) {
@@ -1890,7 +1903,7 @@ static ResultCode SignalEvent(Handle handle) {
return RESULT_SUCCESS;
}
-static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
+static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
// This function currently only allows retrieving a process' status.
@@ -1898,7 +1911,7 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
Status,
};
- const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const auto process = handle_table.Get<Process>(process_handle);
if (!process) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
@@ -1916,10 +1929,10 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
return RESULT_SUCCESS;
}
-static ResultCode CreateResourceLimit(Handle* out_handle) {
+static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
LOG_DEBUG(Kernel_SVC, "called");
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
auto resource_limit = ResourceLimit::Create(kernel);
auto* const current_process = kernel.CurrentProcess();
@@ -1934,11 +1947,11 @@ static ResultCode CreateResourceLimit(Handle* out_handle) {
return RESULT_SUCCESS;
}
-static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit,
- u32 resource_type) {
+static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value,
+ Handle resource_limit, u32 resource_type) {
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
- const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type,
+ const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type,
ResourceLimitValueType::LimitValue);
if (limit_value.Failed()) {
return limit_value.Code();
@@ -1948,11 +1961,11 @@ static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_lim
return RESULT_SUCCESS;
}
-static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit,
- u32 resource_type) {
+static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value,
+ Handle resource_limit, u32 resource_type) {
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
- const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type,
+ const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type,
ResourceLimitValueType::CurrentValue);
if (current_value.Failed()) {
return current_value.Code();
@@ -1962,7 +1975,8 @@ static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_l
return RESULT_SUCCESS;
}
-static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) {
+static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit,
+ u32 resource_type, u64 value) {
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
resource_type, value);
@@ -1972,8 +1986,7 @@ static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource
return ERR_INVALID_ENUM_VALUE;
}
- auto& kernel = Core::System::GetInstance().Kernel();
- auto* const current_process = kernel.CurrentProcess();
+ auto* const current_process = system.Kernel().CurrentProcess();
ASSERT(current_process != nullptr);
auto resource_limit_object =
@@ -1997,8 +2010,8 @@ static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource
return RESULT_SUCCESS;
}
-static ResultCode GetProcessList(u32* out_num_processes, VAddr out_process_ids,
- u32 out_process_ids_size) {
+static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
+ VAddr out_process_ids, u32 out_process_ids_size) {
LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}",
out_process_ids, out_process_ids_size);
@@ -2010,7 +2023,7 @@ static ResultCode GetProcessList(u32* out_num_processes, VAddr out_process_ids,
return ERR_OUT_OF_RANGE;
}
- const auto& kernel = Core::System::GetInstance().Kernel();
+ const auto& kernel = system.Kernel();
const auto& vm_manager = kernel.CurrentProcess()->VMManager();
const auto total_copy_size = out_process_ids_size * sizeof(u64);
@@ -2034,8 +2047,8 @@ static ResultCode GetProcessList(u32* out_num_processes, VAddr out_process_ids,
return RESULT_SUCCESS;
}
-ResultCode GetThreadList(u32* out_num_threads, VAddr out_thread_ids, u32 out_thread_ids_size,
- Handle debug_handle) {
+ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids,
+ u32 out_thread_ids_size, Handle debug_handle) {
// TODO: Handle this case when debug events are supported.
UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
@@ -2049,7 +2062,7 @@ ResultCode GetThreadList(u32* out_num_threads, VAddr out_thread_ids, u32 out_thr
return ERR_OUT_OF_RANGE;
}
- const auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
+ const auto* const current_process = system.Kernel().CurrentProcess();
const auto& vm_manager = current_process->VMManager();
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
@@ -2076,7 +2089,7 @@ ResultCode GetThreadList(u32* out_num_threads, VAddr out_thread_ids, u32 out_thr
namespace {
struct FunctionDef {
- using Func = void();
+ using Func = void(Core::System&);
u32 id;
Func* func;
@@ -2225,7 +2238,7 @@ static const FunctionDef* GetSVCInfo(u32 func_num) {
MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
-void CallSVC(u32 immediate) {
+void CallSVC(Core::System& system, u32 immediate) {
MICROPROFILE_SCOPE(Kernel_SVC);
// Lock the global kernel mutex when we enter the kernel HLE.
@@ -2234,7 +2247,7 @@ void CallSVC(u32 immediate) {
const FunctionDef* info = GetSVCInfo(immediate);
if (info) {
if (info->func) {
- info->func();
+ info->func(system);
} else {
LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
}
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index c37ae0f98..c5539ac1c 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -6,8 +6,12 @@
#include "common/common_types.h"
+namespace Core {
+class System;
+}
+
namespace Kernel {
-void CallSVC(u32 immediate);
+void CallSVC(Core::System& system, u32 immediate);
} // namespace Kernel
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index b3733680f..b3690b5f3 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -11,278 +11,312 @@
namespace Kernel {
-static inline u64 Param(int n) {
- return Core::CurrentArmInterface().GetReg(n);
+static inline u64 Param(const Core::System& system, int n) {
+ return system.CurrentArmInterface().GetReg(n);
}
/**
* HLE a function return from the current ARM userland process
- * @param res Result to return
+ * @param system System context
+ * @param result Result to return
*/
-static inline void FuncReturn(u64 res) {
- Core::CurrentArmInterface().SetReg(0, res);
+static inline void FuncReturn(Core::System& system, u64 result) {
+ system.CurrentArmInterface().SetReg(0, result);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type ResultCode
-template <ResultCode func(u64)>
-void SvcWrap() {
- FuncReturn(func(Param(0)).raw);
+template <ResultCode func(Core::System&, u64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0)).raw);
}
-template <ResultCode func(u32)>
-void SvcWrap() {
- FuncReturn(func(static_cast<u32>(Param(0))).raw);
+template <ResultCode func(Core::System&, u32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
}
-template <ResultCode func(u32, u32)>
-void SvcWrap() {
- FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
+template <ResultCode func(Core::System&, u32, u32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(
+ system,
+ func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
}
-template <ResultCode func(u32*)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*)>
+void SvcWrap(Core::System& system) {
u32 param = 0;
- const u32 retval = func(&param).raw;
- Core::CurrentArmInterface().SetReg(1, param);
- FuncReturn(retval);
+ const u32 retval = func(system, &param).raw;
+ system.CurrentArmInterface().SetReg(1, param);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32*, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u32)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- u32 retval = func(&param_1, static_cast<u32>(Param(1))).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32*, u32*)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u32*)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
- const u32 retval = func(&param_1, &param_2).raw;
+ const u32 retval = func(system, &param_1, &param_2).raw;
- auto& arm_interface = Core::CurrentArmInterface();
+ auto& arm_interface = system.CurrentArmInterface();
arm_interface.SetReg(1, param_1);
arm_interface.SetReg(2, param_2);
- FuncReturn(retval);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32*, u64)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u64)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- const u32 retval = func(&param_1, Param(1)).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, Param(system, 1)).raw;
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32*, u64, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u64, u32)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- const u32 retval = func(&param_1, Param(1), static_cast<u32>(Param(2))).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval =
+ func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u64*, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u64*, u32)>
+void SvcWrap(Core::System& system) {
u64 param_1 = 0;
- const u32 retval = func(&param_1, static_cast<u32>(Param(1))).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u64, s32)>
-void SvcWrap() {
- FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw);
+template <ResultCode func(Core::System&, u64, s32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), static_cast<s32>(Param(system, 1))).raw);
}
-template <ResultCode func(u64, u32)>
-void SvcWrap() {
- FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
+template <ResultCode func(Core::System&, u64, u32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw);
}
-template <ResultCode func(u64*, u64)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u64*, u64)>
+void SvcWrap(Core::System& system) {
u64 param_1 = 0;
- u32 retval = func(&param_1, Param(1)).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, Param(system, 1)).raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u64*, u32, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u64*, u32, u32)>
+void SvcWrap(Core::System& system) {
u64 param_1 = 0;
- u32 retval = func(&param_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1)),
+ static_cast<u32>(Param(system, 2)))
+ .raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32, u64)>
-void SvcWrap() {
- FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw);
+template <ResultCode func(Core::System&, u32, u64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
}
-template <ResultCode func(u32, u32, u64)>
-void SvcWrap() {
- FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw);
+template <ResultCode func(Core::System&, u32, u32, u64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
+ static_cast<u32>(Param(system, 1)), Param(system, 2))
+ .raw);
}
-template <ResultCode func(u32, u32*, u64*)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32, u32*, u64*)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
u64 param_2 = 0;
- ResultCode retval = func(static_cast<u32>(Param(2)), &param_1, &param_2);
- Core::CurrentArmInterface().SetReg(1, param_1);
- Core::CurrentArmInterface().SetReg(2, param_2);
- FuncReturn(retval.raw);
-}
+ const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), &param_1, &param_2);
-template <ResultCode func(u64, u64, u32, u32)>
-void SvcWrap() {
- FuncReturn(
- func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
+ system.CurrentArmInterface().SetReg(1, param_1);
+ system.CurrentArmInterface().SetReg(2, param_2);
+ FuncReturn(system, retval.raw);
}
-template <ResultCode func(u64, u64, u32, u64)>
-void SvcWrap() {
- FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2)), Param(3)).raw);
+template <ResultCode func(Core::System&, u64, u64, u32, u32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
+ static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
+ .raw);
}
-template <ResultCode func(u32, u64, u32)>
-void SvcWrap() {
- FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw);
+template <ResultCode func(Core::System&, u64, u64, u32, u64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
+ static_cast<u32>(Param(system, 2)), Param(system, 3))
+ .raw);
}
-template <ResultCode func(u64, u64, u64)>
-void SvcWrap() {
- FuncReturn(func(Param(0), Param(1), Param(2)).raw);
+template <ResultCode func(Core::System&, u32, u64, u32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
+ static_cast<u32>(Param(system, 2)))
+ .raw);
}
-template <ResultCode func(u64, u64, u32)>
-void SvcWrap() {
- FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
+template <ResultCode func(Core::System&, u64, u64, u64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw);
}
-template <ResultCode func(u32, u64, u64, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u64, u64, u32)>
+void SvcWrap(Core::System& system) {
FuncReturn(
- func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw);
+ system,
+ func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
+}
+
+template <ResultCode func(Core::System&, u32, u64, u64, u32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
+ Param(system, 2), static_cast<u32>(Param(system, 3)))
+ .raw);
}
-template <ResultCode func(u32, u64, u64)>
-void SvcWrap() {
- FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw);
+template <ResultCode func(Core::System&, u32, u64, u64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(
+ system,
+ func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
}
-template <ResultCode func(u32*, u64, u64, s64)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u64, u64, s64)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- ResultCode retval =
- func(&param_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3)));
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval.raw);
+ const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
+ static_cast<s64>(Param(system, 3)))
+ .raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u64, u64, u32, s64)>
-void SvcWrap() {
- FuncReturn(
- func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw);
+template <ResultCode func(Core::System&, u64, u64, u32, s64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
+ static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
+ .raw);
}
-template <ResultCode func(u64*, u64, u64, u64)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u64*, u64, u64, u64)>
+void SvcWrap(Core::System& system) {
u64 param_1 = 0;
- u32 retval = func(&param_1, Param(1), Param(2), Param(3)).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval =
+ func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u64, u64, u64, u32, s32)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- u32 retval = func(&param_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)),
- static_cast<s32>(Param(5)))
- .raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3),
+ static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5)))
+ .raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u32*, u64, u64, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, u32*, u64, u64, u32)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- u32 retval = func(&param_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2),
+ static_cast<u32>(Param(system, 3)))
+ .raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(Handle*, u64, u32, u32)>
-void SvcWrap() {
+template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
+void SvcWrap(Core::System& system) {
u32 param_1 = 0;
- u32 retval =
- func(&param_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw;
- Core::CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(retval);
+ const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
+ static_cast<u32>(Param(system, 3)))
+ .raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
}
-template <ResultCode func(u64, u32, s32, s64)>
-void SvcWrap() {
- FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
- static_cast<s64>(Param(3)))
- .raw);
+template <ResultCode func(Core::System&, u64, u32, s32, s64)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
+ static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
+ .raw);
}
-template <ResultCode func(u64, u32, s32, s32)>
-void SvcWrap() {
- FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
- static_cast<s32>(Param(3)))
- .raw);
+template <ResultCode func(Core::System&, u64, u32, s32, s32)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
+ static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
+ .raw);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32
-template <u32 func()>
-void SvcWrap() {
- FuncReturn(func());
+template <u32 func(Core::System&)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u64
-template <u64 func()>
-void SvcWrap() {
- FuncReturn(func());
+template <u64 func(Core::System&)>
+void SvcWrap(Core::System& system) {
+ FuncReturn(system, func(system));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Function wrappers that return type void
-template <void func()>
-void SvcWrap() {
- func();
+template <void func(Core::System&)>
+void SvcWrap(Core::System& system) {
+ func(system);
}
-template <void func(s64)>
-void SvcWrap() {
- func(static_cast<s64>(Param(0)));
+template <void func(Core::System&, s64)>
+void SvcWrap(Core::System& system) {
+ func(system, static_cast<s64>(Param(system, 0)));
}
-template <void func(u64, u64 len)>
-void SvcWrap() {
- func(Param(0), Param(1));
+template <void func(Core::System&, u64, u64)>
+void SvcWrap(Core::System& system) {
+ func(system, Param(system, 0), Param(system, 1));
}
-template <void func(u64, u64, u64)>
-void SvcWrap() {
- func(Param(0), Param(1), Param(2));
+template <void func(Core::System&, u64, u64, u64)>
+void SvcWrap(Core::System& system) {
+ func(system, Param(system, 0), Param(system, 1), Param(system, 2));
}
-template <void func(u32, u64, u64)>
-void SvcWrap() {
- func(static_cast<u32>(Param(0)), Param(1), Param(2));
+template <void func(Core::System&, u32, u64, u64)>
+void SvcWrap(Core::System& system) {
+ func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2));
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 73e5d1bb4..83c83e45a 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -106,7 +106,7 @@ public:
return "Thread";
}
- static const HandleType HANDLE_TYPE = HandleType::Thread;
+ static constexpr HandleType HANDLE_TYPE = HandleType::Thread;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h
index c9068dd3d..d00c92a6b 100644
--- a/src/core/hle/kernel/writable_event.h
+++ b/src/core/hle/kernel/writable_event.h
@@ -37,7 +37,7 @@ public:
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
+ static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 9b0aa7f5f..7e17df98a 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -86,7 +86,7 @@ static FileSys::VirtualFile GetManualRomFS() {
if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
return out;
- const auto& installed{FileSystem::GetUnionContents()};
+ const auto& installed{Core::System::GetInstance().GetContentProvider()};
const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
FileSys::ContentRecordType::Manual);
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index b506bc3dd..2d768d9fc 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -33,11 +33,11 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
static std::vector<u64> AccumulateAOCTitleIDs() {
std::vector<u64> add_on_content;
- const auto rcu = FileSystem::GetUnionContents();
+ const auto& rcu = Core::System::GetInstance().GetContentProvider();
const auto list =
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
- [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
+ [](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 4c2b371c3..1ebfeb4bf 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -391,11 +391,6 @@ void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
}
-FileSys::RegisteredCacheUnion GetUnionContents() {
- return FileSys::RegisteredCacheUnion{
- {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
-}
-
FileSys::RegisteredCache* GetSystemNANDContents() {
LOG_TRACE(Service_FS, "Opening System NAND Contents");
@@ -460,6 +455,10 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (bis_factory == nullptr) {
bis_factory =
std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory);
+ Core::System::GetInstance().RegisterContentProvider(
+ FileSys::ContentProviderUnionSlot::SysNAND, bis_factory->GetSystemNANDContents());
+ Core::System::GetInstance().RegisterContentProvider(
+ FileSys::ContentProviderUnionSlot::UserNAND, bis_factory->GetUserNANDContents());
}
if (save_data_factory == nullptr) {
@@ -468,6 +467,8 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (sdmc_factory == nullptr) {
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
+ Core::System::GetInstance().RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC,
+ sdmc_factory->GetSDMCContents());
}
}
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 7cfc0d902..6481f237c 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -54,8 +54,6 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
FileSys::SaveDataSize new_value);
-FileSys::RegisteredCacheUnion GetUnionContents();
-
FileSys::RegisteredCache* GetSystemNANDContents();
FileSys::RegisteredCache* GetUserNANDContents();
FileSys::RegisteredCache* GetSDMCContents();
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 657baddb8..0249b6992 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -115,11 +115,12 @@ private:
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const u64 unk = rp.Pop<u64>();
+ const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
- LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
+ LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
+ length);
// Error checking
if (length < 0) {
@@ -148,11 +149,12 @@ private:
void Write(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const u64 unk = rp.Pop<u64>();
+ const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
- LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
+ LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
+ length);
// Error checking
if (length < 0) {
@@ -250,10 +252,7 @@ private:
u64 next_entry_index = 0;
void Read(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 unk = rp.Pop<u64>();
-
- LOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk);
+ LOG_DEBUG(Service_FS, "called.");
// Calculate how many entries we can fit in the output buffer
const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index c7f5bbf28..3c5c53e24 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -21,12 +21,13 @@
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/perf_stats.h"
+#include "core/settings.h"
#include "video_core/renderer_base.h"
namespace Service::NVFlinger {
-constexpr std::size_t SCREEN_REFRESH_RATE = 60;
-constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
+constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
+constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30);
NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} {
displays.emplace_back(0, "Default");
@@ -36,13 +37,15 @@ NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_t
displays.emplace_back(4, "Null");
// Schedule the screen composition events
- composition_event =
- core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) {
+ const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : frame_ticks;
+
+ composition_event = core_timing.RegisterEvent(
+ "ScreenComposition", [this, ticks](u64 userdata, s64 cycles_late) {
Compose();
- this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event);
+ this->core_timing.ScheduleEvent(ticks - cycles_late, composition_event);
});
- core_timing.ScheduleEvent(frame_ticks, composition_event);
+ core_timing.ScheduleEvent(ticks, composition_event);
}
NVFlinger::~NVFlinger() {
@@ -62,6 +65,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
const auto itr =
std::find_if(displays.begin(), displays.end(),
[&](const VI::Display& display) { return display.GetName() == name; });
+
if (itr == displays.end()) {
return {};
}
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index ffe2eea8a..d7c47c197 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -21,6 +21,8 @@
#include "core/memory.h"
#include "core/settings.h"
+#pragma optimize("", off)
+
namespace Loader {
namespace {
struct MODHeader {
@@ -136,13 +138,13 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
// Apply patches if necessary
if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
- std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size());
+ std::vector<u8> pi_header;
pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header),
reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader));
pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.begin(),
program_image.end());
- pi_header = pm->PatchNSO(pi_header);
+ pi_header = pm->PatchNSO(pi_header, file.GetName());
std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.begin());
}
diff --git a/src/core/settings.h b/src/core/settings.h
index d543eb32f..b84390745 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -393,6 +393,7 @@ struct Values {
bool use_disk_shader_cache;
bool use_accurate_gpu_emulation;
bool use_asynchronous_gpu_emulation;
+ bool force_30fps_mode;
float bg_red;
float bg_green;