summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/arm_interface.cpp27
-rw-r--r--src/core/arm/arm_interface.h8
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp48
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h1
-rw-r--r--src/core/core.cpp16
-rw-r--r--src/core/core.h11
-rw-r--r--src/core/core_cpu.cpp5
-rw-r--r--src/core/core_cpu.h18
-rw-r--r--src/core/core_timing.cpp53
-rw-r--r--src/core/core_timing.h45
-rw-r--r--src/core/cpu_core_manager.cpp2
-rw-r--r--src/core/file_sys/directory.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp16
-rw-r--r--src/core/file_sys/romfs.cpp7
-rw-r--r--src/core/file_sys/romfs.h4
-rw-r--r--src/core/gdbstub/gdbstub.cpp36
-rw-r--r--src/core/hardware_interrupt_manager.cpp13
-rw-r--r--src/core/hardware_interrupt_manager.h4
-rw-r--r--src/core/hle/ipc_helpers.h22
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp52
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/client_port.cpp17
-rw-r--r--src/core/hle/kernel/client_port.h12
-rw-r--r--src/core/hle/kernel/client_session.cpp41
-rw-r--r--src/core/hle/kernel/client_session.h29
-rw-r--r--src/core/hle/kernel/handle_table.cpp10
-rw-r--r--src/core/hle/kernel/handle_table.h8
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp43
-rw-r--r--src/core/hle/kernel/hle_ipc.h51
-rw-r--r--src/core/hle/kernel/kernel.cpp55
-rw-r--r--src/core/hle/kernel/kernel.h15
-rw-r--r--src/core/hle/kernel/mutex.cpp28
-rw-r--r--src/core/hle/kernel/object.cpp1
-rw-r--r--src/core/hle/kernel/object.h31
-rw-r--r--src/core/hle/kernel/process.cpp55
-rw-r--r--src/core/hle/kernel/process.h26
-rw-r--r--src/core/hle/kernel/resource_limit.cpp4
-rw-r--r--src/core/hle/kernel/resource_limit.h8
-rw-r--r--src/core/hle/kernel/scheduler.cpp10
-rw-r--r--src/core/hle/kernel/scheduler.h12
-rw-r--r--src/core/hle/kernel/server_port.cpp8
-rw-r--r--src/core/hle/kernel/server_port.h14
-rw-r--r--src/core/hle/kernel/server_session.cpp118
-rw-r--r--src/core/hle/kernel/server_session.h66
-rw-r--r--src/core/hle/kernel/session.cpp32
-rw-r--r--src/core/hle/kernel/session.h57
-rw-r--r--src/core/hle/kernel/shared_memory.cpp15
-rw-r--r--src/core/hle/kernel/shared_memory.h19
-rw-r--r--src/core/hle/kernel/svc.cpp144
-rw-r--r--src/core/hle/kernel/thread.cpp54
-rw-r--r--src/core/hle/kernel/thread.h48
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp6
-rw-r--r--src/core/hle/kernel/transfer_memory.h10
-rw-r--r--src/core/hle/kernel/vm_manager.cpp13
-rw-r--r--src/core/hle/kernel/wait_object.cpp17
-rw-r--r--src/core/hle/kernel/wait_object.h16
-rw-r--r--src/core/hle/kernel/writable_event.cpp6
-rw-r--r--src/core/hle/kernel/writable_event.h8
-rw-r--r--src/core/hle/service/acc/acc_su.cpp3
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp1
-rw-r--r--src/core/hle/service/am/am.cpp66
-rw-r--r--src/core/hle/service/am/am.h7
-rw-r--r--src/core/hle/service/am/applets/applets.cpp6
-rw-r--r--src/core/hle/service/am/applets/applets.h6
-rw-r--r--src/core/hle/service/am/idle.cpp2
-rw-r--r--src/core/hle/service/am/omm.cpp2
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp1
-rw-r--r--src/core/hle/service/audio/audctl.cpp1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.cpp5
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp2
-rw-r--r--src/core/hle/service/bcat/backend/backend.h2
-rw-r--r--src/core/hle/service/bcat/module.cpp10
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp1
-rw-r--r--src/core/hle/service/erpt/erpt.cpp3
-rw-r--r--src/core/hle/service/es/es.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp17
-rw-r--r--src/core/hle/service/friend/friend.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp29
-rw-r--r--src/core/hle/service/hid/hid.h4
-rw-r--r--src/core/hle/service/hid/irs.h2
-rw-r--r--src/core/hle/service/ldr/ldr.cpp5
-rw-r--r--src/core/hle/service/lm/lm.cpp23
-rw-r--r--src/core/hle/service/mii/mii.cpp2
-rw-r--r--src/core/hle/service/ncm/ncm.cpp6
-rw-r--r--src/core/hle/service/nfc/nfc.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp4
-rw-r--r--src/core/hle/service/nfp/nfp.h2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp8
-rw-r--r--src/core/hle/service/nim/nim.cpp2
-rw-r--r--src/core/hle/service/npns/npns.cpp7
-rw-r--r--src/core/hle/service/ns/ns.cpp27
-rw-r--r--src/core/hle/service/ns/pl_u.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp4
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h4
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h4
-rw-r--r--src/core/hle/service/pm/pm.cpp14
-rw-r--r--src/core/hle/service/prepo/prepo.cpp1
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/service.h2
-rw-r--r--src/core/hle/service/set/set.cpp1
-rw-r--r--src/core/hle/service/set/set_cal.cpp11
-rw-r--r--src/core/hle/service/set/set_fd.cpp4
-rw-r--r--src/core/hle/service/set/set_sys.cpp11
-rw-r--r--src/core/hle/service/sm/controller.cpp5
-rw-r--r--src/core/hle/service/sm/sm.cpp39
-rw-r--r--src/core/hle/service/sm/sm.h16
-rw-r--r--src/core/hle/service/sockets/nsd.cpp5
-rw-r--r--src/core/hle/service/ssl/ssl.cpp5
-rw-r--r--src/core/hle/service/time/interface.cpp1
-rw-r--r--src/core/hle/service/time/time.cpp13
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h4
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp2
-rw-r--r--src/core/hle/service/vi/display/vi_display.h2
-rw-r--r--src/core/hle/service/vi/vi.cpp8
-rw-r--r--src/core/memory.cpp1008
-rw-r--r--src/core/memory.h396
-rw-r--r--src/core/memory/cheat_engine.cpp9
-rw-r--r--src/core/memory/cheat_engine.h7
-rw-r--r--src/core/memory_setup.h43
-rw-r--r--src/core/reporter.cpp16
-rw-r--r--src/core/tools/freezer.cpp32
-rw-r--r--src/core/tools/freezer.h10
134 files changed, 2207 insertions, 1294 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f2e774a6b..7fd226050 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -170,6 +170,7 @@ add_library(core STATIC
hle/kernel/server_port.h
hle/kernel/server_session.cpp
hle/kernel/server_session.h
+ hle/kernel/session.cpp
hle/kernel/session.h
hle/kernel/shared_memory.cpp
hle/kernel/shared_memory.h
@@ -509,7 +510,6 @@ add_library(core STATIC
memory/dmnt_cheat_vm.h
memory.cpp
memory.h
- memory_setup.h
perf_stats.cpp
perf_stats.h
reporter.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 372612c9b..7e846ddd5 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -13,7 +13,6 @@
#include "core/memory.h"
namespace Core {
-
namespace {
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
@@ -61,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size.");
using Symbols = std::vector<std::pair<ELFSymbol, std::string>>;
-Symbols GetSymbols(VAddr text_offset) {
- const auto mod_offset = text_offset + Memory::Read32(text_offset + 4);
+Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) {
+ const auto mod_offset = text_offset + memory.Read32(text_offset + 4);
if (mod_offset < text_offset || (mod_offset & 0b11) != 0 ||
- Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
+ memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
return {};
}
- const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset;
+ const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset;
VAddr string_table_offset{};
VAddr symbol_table_offset{};
@@ -77,8 +76,8 @@ Symbols GetSymbols(VAddr text_offset) {
VAddr dynamic_index = dynamic_offset;
while (true) {
- const auto tag = Memory::Read64(dynamic_index);
- const auto value = Memory::Read64(dynamic_index + 0x8);
+ const u64 tag = memory.Read64(dynamic_index);
+ const u64 value = memory.Read64(dynamic_index + 0x8);
dynamic_index += 0x10;
if (tag == ELF_DYNAMIC_TAG_NULL) {
@@ -106,11 +105,11 @@ Symbols GetSymbols(VAddr text_offset) {
VAddr symbol_index = symbol_table_address;
while (symbol_index < string_table_address) {
ELFSymbol symbol{};
- Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
+ memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
VAddr string_offset = string_table_address + symbol.name_index;
std::string name;
- for (u8 c = Memory::Read8(string_offset); c != 0; c = Memory::Read8(++string_offset)) {
+ for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) {
name += static_cast<char>(c);
}
@@ -142,28 +141,28 @@ constexpr u64 SEGMENT_BASE = 0x7100000000ull;
std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
std::vector<BacktraceEntry> out;
+ auto& memory = system.Memory();
auto fp = GetReg(29);
auto lr = GetReg(30);
-
while (true) {
out.push_back({"", 0, lr, 0});
if (!fp) {
break;
}
- lr = Memory::Read64(fp + 8) - 4;
- fp = Memory::Read64(fp);
+ lr = memory.Read64(fp + 8) - 4;
+ fp = memory.Read64(fp);
}
std::map<VAddr, std::string> modules;
- auto& loader{System::GetInstance().GetAppLoader()};
+ auto& loader{system.GetAppLoader()};
if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) {
return {};
}
std::map<std::string, Symbols> symbols;
for (const auto& module : modules) {
- symbols.insert_or_assign(module.second, GetSymbols(module.first));
+ symbols.insert_or_assign(module.second, GetSymbols(module.first, memory));
}
for (auto& entry : out) {
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 45e94e625..47b964eb7 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -17,11 +17,13 @@ enum class VMAPermission : u8;
}
namespace Core {
+class System;
/// Generic ARMv8 CPU interface
class ARM_Interface : NonCopyable {
public:
- virtual ~ARM_Interface() {}
+ explicit ARM_Interface(System& system_) : system{system_} {}
+ virtual ~ARM_Interface() = default;
struct ThreadContext {
std::array<u64, 31> cpu_registers;
@@ -163,6 +165,10 @@ public:
/// fp+0 : pointer to previous frame record
/// fp+8 : value of lr for frame
void LogBacktrace() const;
+
+protected:
+ /// System context that this ARM interface is running under.
+ System& system;
};
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index a0705b2b8..f8c7f0efd 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -28,36 +28,38 @@ public:
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
u8 MemoryRead8(u64 vaddr) override {
- return Memory::Read8(vaddr);
+ return parent.system.Memory().Read8(vaddr);
}
u16 MemoryRead16(u64 vaddr) override {
- return Memory::Read16(vaddr);
+ return parent.system.Memory().Read16(vaddr);
}
u32 MemoryRead32(u64 vaddr) override {
- return Memory::Read32(vaddr);
+ return parent.system.Memory().Read32(vaddr);
}
u64 MemoryRead64(u64 vaddr) override {
- return Memory::Read64(vaddr);
+ return parent.system.Memory().Read64(vaddr);
}
Vector MemoryRead128(u64 vaddr) override {
- return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)};
+ auto& memory = parent.system.Memory();
+ return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
}
void MemoryWrite8(u64 vaddr, u8 value) override {
- Memory::Write8(vaddr, value);
+ parent.system.Memory().Write8(vaddr, value);
}
void MemoryWrite16(u64 vaddr, u16 value) override {
- Memory::Write16(vaddr, value);
+ parent.system.Memory().Write16(vaddr, value);
}
void MemoryWrite32(u64 vaddr, u32 value) override {
- Memory::Write32(vaddr, value);
+ parent.system.Memory().Write32(vaddr, value);
}
void MemoryWrite64(u64 vaddr, u64 value) override {
- Memory::Write64(vaddr, value);
+ parent.system.Memory().Write64(vaddr, value);
}
void MemoryWrite128(u64 vaddr, Vector value) override {
- Memory::Write64(vaddr, value[0]);
- Memory::Write64(vaddr + 8, value[1]);
+ auto& memory = parent.system.Memory();
+ memory.Write64(vaddr, value[0]);
+ memory.Write64(vaddr + 8, value[1]);
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
@@ -171,9 +173,10 @@ void ARM_Dynarmic::Step() {
ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
- : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
- core_index{core_index}, system{system},
- exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
+ : ARM_Interface{system},
+ cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
+ core_index{core_index}, exclusive_monitor{
+ dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic::~ARM_Dynarmic() = default;
@@ -264,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
jit = MakeJit(page_table, new_address_space_size_in_bits);
}
-DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
+DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count)
+ : monitor(core_count), memory{memory_} {}
+
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
@@ -277,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
}
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
- return monitor.DoExclusiveOperation(core_index, vaddr, 1,
- [&] { Memory::Write8(vaddr, value); });
+ return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 2,
- [&] { Memory::Write16(vaddr, value); });
+ [&] { memory.Write16(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 4,
- [&] { Memory::Write32(vaddr, value); });
+ [&] { memory.Write32(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 8,
- [&] { Memory::Write64(vaddr, value); });
+ [&] { memory.Write64(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
- Memory::Write64(vaddr + 0, value[0]);
- Memory::Write64(vaddr + 8, value[1]);
+ memory.Write64(vaddr + 0, value[0]);
+ memory.Write64(vaddr + 8, value[1]);
});
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 504d46c68..9cd475cfb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,6 +12,10 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
+namespace Memory {
+class Memory;
+}
+
namespace Core {
class ARM_Dynarmic_Callbacks;
@@ -58,13 +62,12 @@ private:
ARM_Unicorn inner_unicorn;
std::size_t core_index;
- System& system;
DynarmicExclusiveMonitor& exclusive_monitor;
};
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
- explicit DynarmicExclusiveMonitor(std::size_t core_count);
+ explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count);
~DynarmicExclusiveMonitor() override;
void SetExclusive(std::size_t core_index, VAddr addr) override;
@@ -79,6 +82,7 @@ public:
private:
friend class ARM_Dynarmic;
Dynarmic::A64::ExclusiveMonitor monitor;
+ Memory::Memory& memory;
};
} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 9698172db..48182c99a 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -60,7 +60,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
return false;
}
-ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
+ARM_Unicorn::ARM_Unicorn(System& system) : ARM_Interface{system} {
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index b39426ea0..3c5b155f9 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -45,7 +45,6 @@ private:
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
uc_engine* uc{};
- System& system;
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit = false;
};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index eba17218a..c45fb960c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -39,6 +39,7 @@
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
+#include "core/memory.h"
#include "core/memory/cheat_engine.h"
#include "core/perf_stats.h"
#include "core/reporter.h"
@@ -112,8 +113,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
}
struct System::Impl {
explicit Impl(System& system)
- : kernel{system}, fs_controller{system}, cpu_core_manager{system}, reporter{system},
- applet_manager{system} {}
+ : kernel{system}, fs_controller{system}, memory{system},
+ cpu_core_manager{system}, reporter{system}, applet_manager{system} {}
Cpu& CurrentCpuCore() {
return cpu_core_manager.GetCurrentCore();
@@ -341,7 +342,8 @@ struct System::Impl {
std::unique_ptr<VideoCore::RendererBase> renderer;
std::unique_ptr<Tegra::GPU> gpu_core;
std::shared_ptr<Tegra::DebugContext> debug_context;
- std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager;
+ std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
+ Memory::Memory memory;
CpuCoreManager cpu_core_manager;
bool is_powered_on = false;
bool exit_lock = false;
@@ -498,6 +500,14 @@ const ExclusiveMonitor& System::Monitor() const {
return impl->cpu_core_manager.GetExclusiveMonitor();
}
+Memory::Memory& System::Memory() {
+ return impl->memory;
+}
+
+const Memory::Memory& System::Memory() const {
+ return impl->memory;
+}
+
Tegra::GPU& System::GPU() {
return *impl->gpu_core;
}
diff --git a/src/core/core.h b/src/core/core.h
index 984074ce3..91184e433 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,6 +7,7 @@
#include <cstddef>
#include <memory>
#include <string>
+#include <vector>
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
@@ -85,6 +86,10 @@ namespace Core::Hardware {
class InterruptManager;
}
+namespace Memory {
+class Memory;
+}
+
namespace Core {
class ARM_Interface;
@@ -224,6 +229,12 @@ public:
/// Gets a constant reference to the exclusive monitor
const ExclusiveMonitor& Monitor() const;
+ /// Gets a mutable reference to the system memory instance.
+ Memory::Memory& Memory();
+
+ /// Gets a constant reference to the system memory instance.
+ const Memory::Memory& Memory() const;
+
/// Gets a mutable reference to the GPU interface
Tegra::GPU& GPU();
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 233ea572c..cf3fe0b0b 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -66,9 +66,10 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
Cpu::~Cpu() = default;
-std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
+std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
+ [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
#ifdef ARCHITECTURE_x86_64
- return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
+ return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
#else
// TODO(merry): Passthrough exclusive monitor
return nullptr;
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index cafca8df7..78f5021a2 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -24,6 +24,10 @@ namespace Core::Timing {
class CoreTiming;
}
+namespace Memory {
+class Memory;
+}
+
namespace Core {
class ARM_Interface;
@@ -86,7 +90,19 @@ public:
void Shutdown();
- static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores);
+ /**
+ * Creates an exclusive monitor to handle exclusive reads/writes.
+ *
+ * @param memory The current memory subsystem that the monitor may wish
+ * to keep track of.
+ *
+ * @param num_cores The number of cores to assume about the CPU.
+ *
+ * @returns The constructed exclusive monitor instance, or nullptr if the current
+ * CPU backend is unable to use an exclusive monitor.
+ */
+ static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
+ std::size_t num_cores);
private:
void Reschedule();
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 0e9570685..aa09fa453 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -17,11 +17,15 @@ namespace Core::Timing {
constexpr int MAX_SLICE_LENGTH = 10000;
+std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
+ return std::make_shared<EventType>(std::move(callback), std::move(name));
+}
+
struct CoreTiming::Event {
s64 time;
u64 fifo_order;
u64 userdata;
- const EventType* type;
+ std::weak_ptr<EventType> type;
// Sort by time, unless the times are the same, in which case sort by
// the order added to the queue
@@ -54,36 +58,15 @@ void CoreTiming::Initialize() {
event_fifo_id = 0;
const auto empty_timed_callback = [](u64, s64) {};
- ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
+ ev_lost = CreateEvent("_lost_event", empty_timed_callback);
}
void CoreTiming::Shutdown() {
ClearPendingEvents();
- UnregisterAllEvents();
-}
-
-EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
- std::lock_guard guard{inner_mutex};
- // check for existing type with same name.
- // we want event type names to remain unique so that we can use them for serialization.
- ASSERT_MSG(event_types.find(name) == event_types.end(),
- "CoreTiming Event \"{}\" is already registered. Events should only be registered "
- "during Init to avoid breaking save states.",
- name.c_str());
-
- auto info = event_types.emplace(name, EventType{callback, nullptr});
- EventType* event_type = &info.first->second;
- event_type->name = &info.first->first;
- return event_type;
-}
-
-void CoreTiming::UnregisterAllEvents() {
- ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
- event_types.clear();
}
-void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
- ASSERT(event_type != nullptr);
+void CoreTiming::ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type,
+ u64 userdata) {
std::lock_guard guard{inner_mutex};
const s64 timeout = GetTicks() + cycles_into_future;
@@ -93,13 +76,15 @@ void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_ty
}
event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
+
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
-void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
+void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) {
std::lock_guard guard{inner_mutex};
+
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
- return e.type == event_type && e.userdata == userdata;
+ return e.type.lock().get() == event_type.get() && e.userdata == userdata;
});
// Removing random items breaks the invariant so we have to re-establish it.
@@ -130,10 +115,12 @@ void CoreTiming::ClearPendingEvents() {
event_queue.clear();
}
-void CoreTiming::RemoveEvent(const EventType* event_type) {
+void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
std::lock_guard guard{inner_mutex};
- const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
- [&](const Event& e) { return e.type == event_type; });
+
+ const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
+ return e.type.lock().get() == event_type.get();
+ });
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
@@ -181,7 +168,11 @@ void CoreTiming::Advance() {
std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
event_queue.pop_back();
inner_mutex.unlock();
- evt.type->callback(evt.userdata, global_timer - evt.time);
+
+ if (auto event_type{evt.type.lock()}) {
+ event_type->callback(evt.userdata, global_timer - evt.time);
+ }
+
inner_mutex.lock();
}
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 3bb88c810..d50f4eb8a 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -6,11 +6,12 @@
#include <chrono>
#include <functional>
+#include <memory>
#include <mutex>
#include <optional>
#include <string>
-#include <unordered_map>
#include <vector>
+
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
@@ -21,10 +22,13 @@ using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>;
/// Contains the characteristics of a particular event.
struct EventType {
+ EventType(TimedCallback&& callback, std::string&& name)
+ : callback{std::move(callback)}, name{std::move(name)} {}
+
/// The event's callback function.
TimedCallback callback;
/// A pointer to the name of the event.
- const std::string* name;
+ const std::string name;
};
/**
@@ -57,31 +61,17 @@ public:
/// Tears down all timing related functionality.
void Shutdown();
- /// Registers a core timing event with the given name and callback.
- ///
- /// @param name The name of the core timing event to register.
- /// @param callback The callback to execute for the event.
- ///
- /// @returns An EventType instance representing the registered event.
- ///
- /// @pre The name of the event being registered must be unique among all
- /// registered events.
- ///
- EventType* RegisterEvent(const std::string& name, TimedCallback callback);
-
- /// Unregisters all registered events thus far. Note: not thread unsafe
- void UnregisterAllEvents();
-
/// After the first Advance, the slice lengths and the downcount will be reduced whenever an
/// event is scheduled earlier than the current values.
///
/// Scheduling from a callback will not update the downcount until the Advance() completes.
- void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
+ void ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type,
+ u64 userdata = 0);
- void UnscheduleEvent(const EventType* event_type, u64 userdata);
+ void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
/// We only permit one event of each type in the queue at a time.
- void RemoveEvent(const EventType* event_type);
+ void RemoveEvent(const std::shared_ptr<EventType>& event_type);
void ForceExceptionCheck(s64 cycles);
@@ -148,13 +138,18 @@ private:
std::vector<Event> event_queue;
u64 event_fifo_id = 0;
- // Stores each element separately as a linked list node so pointers to elements
- // remain stable regardless of rehashes/resizing.
- std::unordered_map<std::string, EventType> event_types;
-
- EventType* ev_lost = nullptr;
+ std::shared_ptr<EventType> ev_lost;
std::mutex inner_mutex;
};
+/// Creates a core timing event with the given name and callback.
+///
+/// @param name The name of the core timing event to create.
+/// @param callback The callback to execute for the event.
+///
+/// @returns An EventType instance representing the created event.
+///
+std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback);
+
} // namespace Core::Timing
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 8efd410bb..f04a34133 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -25,7 +25,7 @@ CpuCoreManager::~CpuCoreManager() = default;
void CpuCoreManager::Initialize() {
barrier = std::make_unique<CpuBarrier>();
- exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
+ exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index 7b5c509fb..0d73eecc9 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -15,7 +15,7 @@
namespace FileSys {
-enum EntryType : u8 {
+enum class EntryType : u8 {
Directory = 0,
File = 1,
};
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index df0ecb15c..e226e9711 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -76,7 +76,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
- std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
+ std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
@@ -127,7 +127,7 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
std::vector<VirtualFile> out;
out.reserve(patch_dirs.size());
for (const auto& subdir : patch_dirs) {
- if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
+ if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend())
continue;
auto exefs_dir = subdir->GetSubdirectory("exefs");
@@ -284,12 +284,17 @@ std::vector<Memory::CheatEntry> PatchManager::CreateCheatList(
return {};
}
+ const auto& disabled = Settings::values.disabled_addons[title_id];
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<Memory::CheatEntry> out;
for (const auto& subdir : patch_dirs) {
+ if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) {
+ continue;
+ }
+
auto cheats_dir = subdir->GetSubdirectory("cheats");
if (cheats_dir != nullptr) {
auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true);
@@ -331,8 +336,9 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
layers.reserve(patch_dirs.size() + 1);
layers_ext.reserve(patch_dirs.size() + 1);
for (const auto& subdir : patch_dirs) {
- if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
+ if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) {
continue;
+ }
auto romfs_dir = subdir->GetSubdirectory("romfs");
if (romfs_dir != nullptr)
@@ -381,7 +387,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
- std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
+ std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
if (!update_disabled && update != nullptr) {
const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
@@ -431,7 +437,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
auto [nacp, discard_icon_file] = update.GetControlMetadata();
const auto update_disabled =
- std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
+ std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
const auto update_label = update_disabled ? "[D] Update" : "Update";
if (nacp != nullptr) {
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index ebbdf081e..c909d1ce4 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <memory>
+
#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/fsmitm_romfsbuild.h"
@@ -12,7 +14,7 @@
#include "core/file_sys/vfs_vector.h"
namespace FileSys {
-
+namespace {
constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF;
struct TableLocation {
@@ -51,7 +53,7 @@ struct FileEntry {
static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
template <typename Entry>
-static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) {
+std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) {
Entry entry{};
if (file->ReadObject(&entry, offset) != sizeof(Entry))
return {};
@@ -99,6 +101,7 @@ void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file
this_dir_offset = entry.first.sibling;
}
}
+} // Anonymous namespace
VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
RomFSHeader header{};
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index 1c89be8a4..2fd07ed04 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -5,10 +5,6 @@
#pragma once
#include <array>
-#include <map>
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-#include "common/swap.h"
#include "core/file_sys/vfs.h"
namespace FileSys {
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 54ed680db..37cb28848 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -508,8 +508,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
bp->second.len, bp->second.addr, static_cast<int>(type));
if (type == BreakpointType::Execute) {
- Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ auto& system = Core::System::GetInstance();
+ system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
+ system.InvalidateCpuInstructionCaches();
}
p.erase(addr);
}
@@ -969,12 +970,13 @@ static void ReadMemory() {
SendReply("E01");
}
- if (!Memory::IsValidVirtualAddress(addr)) {
+ auto& memory = Core::System::GetInstance().Memory();
+ if (!memory.IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
std::vector<u8> data(len);
- Memory::ReadBlock(addr, data.data(), len);
+ memory.ReadBlock(addr, data.data(), len);
MemToGdbHex(reply, data.data(), len);
reply[len * 2] = '\0';
@@ -984,22 +986,23 @@ static void ReadMemory() {
/// Modify location in memory with data received from the gdb client.
static void WriteMemory() {
auto start_offset = command_buffer + 1;
- auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
- VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
+ const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
+ const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
start_offset = addr_pos + 1;
- auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
- u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
+ const auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
+ const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
- if (!Memory::IsValidVirtualAddress(addr)) {
+ auto& system = Core::System::GetInstance();
+ auto& memory = system.Memory();
+ if (!memory.IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
std::vector<u8> data(len);
-
GdbHexToMem(data.data(), len_pos + 1, len);
- Memory::WriteBlock(addr, data.data(), len);
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ memory.WriteBlock(addr, data.data(), len);
+ system.InvalidateCpuInstructionCaches();
SendReply("OK");
}
@@ -1055,12 +1058,15 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
breakpoint.active = true;
breakpoint.addr = addr;
breakpoint.len = len;
- Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
+
+ auto& system = Core::System::GetInstance();
+ auto& memory = system.Memory();
+ memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
if (type == BreakpointType::Execute) {
- Memory::WriteBlock(addr, btrap.data(), btrap.size());
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ memory.WriteBlock(addr, btrap.data(), btrap.size());
+ system.InvalidateCpuInstructionCaches();
}
p.insert({addr, breakpoint});
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index c2115db2d..c629d9fa1 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,13 +11,12 @@
namespace Core::Hardware {
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
- gpu_interrupt_event =
- system.CoreTiming().RegisterEvent("GPUInterrupt", [this](u64 message, s64) {
- auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
- const u32 syncpt = static_cast<u32>(message >> 32);
- const u32 value = static_cast<u32>(message);
- nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
- });
+ gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) {
+ auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
+ const u32 syncpt = static_cast<u32>(message >> 32);
+ const u32 value = static_cast<u32>(message);
+ nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
+ });
}
InterruptManager::~InterruptManager() = default;
diff --git a/src/core/hardware_interrupt_manager.h b/src/core/hardware_interrupt_manager.h
index 494db883a..5fa306ae0 100644
--- a/src/core/hardware_interrupt_manager.h
+++ b/src/core/hardware_interrupt_manager.h
@@ -4,6 +4,8 @@
#pragma once
+#include <memory>
+
#include "common/common_types.h"
namespace Core {
@@ -25,7 +27,7 @@ public:
private:
Core::System& system;
- Core::Timing::EventType* gpu_interrupt_event{};
+ std::shared_ptr<Core::Timing::EventType> gpu_interrupt_event;
};
} // namespace Core::Hardware
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 5bb139483..0dc6a4a43 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -19,6 +19,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/session.h"
#include "core/hle/result.h"
namespace IPC {
@@ -139,10 +140,9 @@ public:
context->AddDomainObject(std::move(iface));
} else {
auto& kernel = Core::System::GetInstance().Kernel();
- auto [server, client] =
- Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
- iface->ClientConnected(server);
+ auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
context->AddMoveObject(std::move(client));
+ iface->ClientConnected(std::move(server));
}
}
@@ -203,10 +203,10 @@ public:
void PushRaw(const T& value);
template <typename... O>
- void PushMoveObjects(Kernel::SharedPtr<O>... pointers);
+ void PushMoveObjects(std::shared_ptr<O>... pointers);
template <typename... O>
- void PushCopyObjects(Kernel::SharedPtr<O>... pointers);
+ void PushCopyObjects(std::shared_ptr<O>... pointers);
private:
u32 normal_params_size{};
@@ -298,7 +298,7 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value
}
template <typename... O>
-inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
+inline void ResponseBuilder::PushCopyObjects(std::shared_ptr<O>... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
context->AddCopyObject(std::move(object));
@@ -306,7 +306,7 @@ inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
}
template <typename... O>
-inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
+inline void ResponseBuilder::PushMoveObjects(std::shared_ptr<O>... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
context->AddMoveObject(std::move(object));
@@ -357,10 +357,10 @@ public:
T PopRaw();
template <typename T>
- Kernel::SharedPtr<T> GetMoveObject(std::size_t index);
+ std::shared_ptr<T> GetMoveObject(std::size_t index);
template <typename T>
- Kernel::SharedPtr<T> GetCopyObject(std::size_t index);
+ std::shared_ptr<T> GetCopyObject(std::size_t index);
template <class T>
std::shared_ptr<T> PopIpcInterface() {
@@ -465,12 +465,12 @@ void RequestParser::Pop(First& first_value, Other&... other_values) {
}
template <typename T>
-Kernel::SharedPtr<T> RequestParser::GetMoveObject(std::size_t index) {
+std::shared_ptr<T> RequestParser::GetMoveObject(std::size_t index) {
return context->GetMoveObject<T>(index);
}
template <typename T>
-Kernel::SharedPtr<T> RequestParser::GetCopyObject(std::size_t index) {
+std::shared_ptr<T> RequestParser::GetCopyObject(std::size_t index) {
return context->GetCopyObject<T>(index);
}
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index de0a9064e..98d07fa5b 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -21,7 +21,7 @@
namespace Kernel {
namespace {
// Wake up num_to_wake (or all) threads in a vector.
-void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {
+void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake) {
auto& system = Core::System::GetInstance();
// Only process up to 'target' threads, unless 'target' is <= 0, in which case process
// them all.
@@ -59,35 +59,41 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v
}
ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
- const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
+ const std::vector<std::shared_ptr<Thread>> waiting_threads =
+ GetThreadsWaitingOnAddress(address);
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
}
ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
s32 num_to_wake) {
+ auto& memory = system.Memory();
+
// Ensure that we can write to the address.
- if (!Memory::IsValidVirtualAddress(address)) {
+ if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
- if (static_cast<s32>(Memory::Read32(address)) != value) {
+ if (static_cast<s32>(memory.Read32(address)) != value) {
return ERR_INVALID_STATE;
}
- Memory::Write32(address, static_cast<u32>(value + 1));
+ memory.Write32(address, static_cast<u32>(value + 1));
return SignalToAddressOnly(address, num_to_wake);
}
ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
s32 num_to_wake) {
+ auto& memory = system.Memory();
+
// Ensure that we can write to the address.
- if (!Memory::IsValidVirtualAddress(address)) {
+ if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
// Get threads waiting on the address.
- const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
+ const std::vector<std::shared_ptr<Thread>> waiting_threads =
+ GetThreadsWaitingOnAddress(address);
// Determine the modified value depending on the waiting count.
s32 updated_value;
@@ -107,11 +113,11 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
}
}
- if (static_cast<s32>(Memory::Read32(address)) != value) {
+ if (static_cast<s32>(memory.Read32(address)) != value) {
return ERR_INVALID_STATE;
}
- Memory::Write32(address, static_cast<u32>(updated_value));
+ memory.Write32(address, static_cast<u32>(updated_value));
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
}
@@ -132,18 +138,20 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s
ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
bool should_decrement) {
+ auto& memory = system.Memory();
+
// Ensure that we can read the address.
- if (!Memory::IsValidVirtualAddress(address)) {
+ if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
- const s32 cur_value = static_cast<s32>(Memory::Read32(address));
+ const s32 cur_value = static_cast<s32>(memory.Read32(address));
if (cur_value >= value) {
return ERR_INVALID_STATE;
}
if (should_decrement) {
- Memory::Write32(address, static_cast<u32>(cur_value - 1));
+ memory.Write32(address, static_cast<u32>(cur_value - 1));
}
// Short-circuit without rescheduling, if timeout is zero.
@@ -155,15 +163,19 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
}
ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
+ auto& memory = system.Memory();
+
// Ensure that we can read the address.
- if (!Memory::IsValidVirtualAddress(address)) {
+ if (!memory.IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
+
// Only wait for the address if equal.
- if (static_cast<s32>(Memory::Read32(address)) != value) {
+ if (static_cast<s32>(memory.Read32(address)) != value) {
return ERR_INVALID_STATE;
}
- // Short-circuit without rescheduling, if timeout is zero.
+
+ // Short-circuit without rescheduling if timeout is zero.
if (timeout == 0) {
return RESULT_TIMEOUT;
}
@@ -172,21 +184,21 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
}
ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) {
- SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread();
+ Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
current_thread->SetArbiterWaitAddress(address);
current_thread->SetStatus(ThreadStatus::WaitArb);
current_thread->InvalidateWakeupCallback();
-
current_thread->WakeAfterDelay(timeout);
system.PrepareReschedule(current_thread->GetProcessorID());
return RESULT_TIMEOUT;
}
-std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const {
+std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(
+ VAddr address) const {
// Retrieve all threads that are waiting for this address.
- std::vector<SharedPtr<Thread>> threads;
+ std::vector<std::shared_ptr<Thread>> threads;
const auto& scheduler = system.GlobalScheduler();
const auto& thread_list = scheduler.GetThreadList();
@@ -198,7 +210,7 @@ std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr
// Sort them by priority, such that the highest priority ones come first.
std::sort(threads.begin(), threads.end(),
- [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
+ [](const std::shared_ptr<Thread>& lhs, const std::shared_ptr<Thread>& rhs) {
return lhs->GetPriority() < rhs->GetPriority();
});
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index ed0d0e69f..608918de5 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -72,7 +72,7 @@ private:
ResultCode WaitForAddressImpl(VAddr address, s64 timeout);
// Gets the threads waiting on an address.
- std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
+ std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
Core::System& system;
};
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index 744b1697d..00bb939a0 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -9,38 +9,35 @@
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/session.h"
namespace Kernel {
ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
ClientPort::~ClientPort() = default;
-SharedPtr<ServerPort> ClientPort::GetServerPort() const {
+std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
return server_port;
}
-ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
- // Note: Threads do not wait for the server endpoint to call
- // AcceptSession before returning from this call.
-
+ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
if (active_sessions >= max_sessions) {
return ERR_MAX_CONNECTIONS_REACHED;
}
active_sessions++;
- // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
- auto [server, client] = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
+ auto [client, server] = Kernel::Session::Create(kernel, name);
if (server_port->HasHLEHandler()) {
- server_port->GetHLEHandler()->ClientConnected(server);
+ server_port->GetHLEHandler()->ClientConnected(std::move(server));
} else {
- server_port->AppendPendingSession(server);
+ server_port->AppendPendingSession(std::move(server));
}
// Wake the threads waiting on the ServerPort
server_port->WakeupAllWaitingThreads();
- return MakeResult(client);
+ return MakeResult(std::move(client));
}
void ClientPort::ConnectionClosed() {
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 4921ad4f0..715edd18c 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -17,6 +17,9 @@ class ServerPort;
class ClientPort final : public Object {
public:
+ explicit ClientPort(KernelCore& kernel);
+ ~ClientPort() override;
+
friend class ServerPort;
std::string GetTypeName() const override {
return "ClientPort";
@@ -30,7 +33,7 @@ public:
return HANDLE_TYPE;
}
- SharedPtr<ServerPort> GetServerPort() const;
+ std::shared_ptr<ServerPort> GetServerPort() const;
/**
* Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
@@ -38,7 +41,7 @@ public:
* waiting on it to awake.
* @returns ClientSession The client endpoint of the created Session pair, or error code.
*/
- ResultVal<SharedPtr<ClientSession>> Connect();
+ ResultVal<std::shared_ptr<ClientSession>> Connect();
/**
* Signifies that a previously active connection has been closed,
@@ -47,10 +50,7 @@ public:
void ConnectionClosed();
private:
- explicit ClientPort(KernelCore& kernel);
- ~ClientPort() override;
-
- SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
+ std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
u32 active_sessions = 0; ///< Number of currently open sessions to this port
std::string name; ///< Name of client port (optional)
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index c17baa50a..4669a14ad 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -12,29 +12,44 @@
namespace Kernel {
-ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {}
+ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {}
+
ClientSession::~ClientSession() {
// This destructor will be called automatically when the last ClientSession handle is closed by
// the emulated application.
-
- // A local reference to the ServerSession is necessary to guarantee it
- // will be kept alive until after ClientDisconnected() returns.
- SharedPtr<ServerSession> server = parent->server;
- if (server) {
- server->ClientDisconnected();
+ if (parent->Server()) {
+ parent->Server()->ClientDisconnected();
}
+}
+
+bool ClientSession::ShouldWait(const Thread* thread) const {
+ UNIMPLEMENTED();
+ return {};
+}
- parent->client = nullptr;
+void ClientSession::Acquire(Thread* thread) {
+ UNIMPLEMENTED();
}
-ResultCode ClientSession::SendSyncRequest(SharedPtr<Thread> thread) {
+ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
+ std::shared_ptr<Session> parent,
+ std::string name) {
+ std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)};
+
+ client_session->name = std::move(name);
+ client_session->parent = std::move(parent);
+
+ return MakeResult(std::move(client_session));
+}
+
+ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) {
// Keep ServerSession alive until we're done working with it.
- SharedPtr<ServerSession> server = parent->server;
- if (server == nullptr)
+ if (!parent->Server()) {
return ERR_SESSION_CLOSED_BY_REMOTE;
+ }
// Signal the server session that new data is available
- return server->HandleSyncRequest(std::move(thread));
+ return parent->Server()->HandleSyncRequest(std::move(thread), memory);
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 09cdff588..b4289a9a8 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -6,20 +6,28 @@
#include <memory>
#include <string>
-#include "core/hle/kernel/object.h"
+
+#include "core/hle/kernel/wait_object.h"
+#include "core/hle/result.h"
union ResultCode;
+namespace Memory {
+class Memory;
+}
+
namespace Kernel {
class KernelCore;
class Session;
-class ServerSession;
class Thread;
-class ClientSession final : public Object {
+class ClientSession final : public WaitObject {
public:
- friend class ServerSession;
+ explicit ClientSession(KernelCore& kernel);
+ ~ClientSession() override;
+
+ friend class Session;
std::string GetTypeName() const override {
return "ClientSession";
@@ -34,11 +42,16 @@ public:
return HANDLE_TYPE;
}
- ResultCode SendSyncRequest(SharedPtr<Thread> thread);
+ ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
+
+ bool ShouldWait(const Thread* thread) const override;
+
+ void Acquire(Thread* thread) override;
private:
- explicit ClientSession(KernelCore& kernel);
- ~ClientSession() override;
+ static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
+ std::shared_ptr<Session> parent,
+ std::string name = "Unknown");
/// The parent session, which links to the server endpoint.
std::shared_ptr<Session> parent;
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 2cc5d536b..e441a27fc 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -44,7 +44,7 @@ ResultCode HandleTable::SetSize(s32 handle_table_size) {
return RESULT_SUCCESS;
}
-ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
+ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) {
DEBUG_ASSERT(obj != nullptr);
const u16 slot = next_free_slot;
@@ -70,7 +70,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
}
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
- SharedPtr<Object> object = GetGeneric(handle);
+ std::shared_ptr<Object> object = GetGeneric(handle);
if (object == nullptr) {
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
return ERR_INVALID_HANDLE;
@@ -99,11 +99,11 @@ bool HandleTable::IsValid(Handle handle) const {
return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;
}
-SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
+std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
if (handle == CurrentThread) {
- return GetCurrentThread();
+ return SharedFrom(GetCurrentThread());
} else if (handle == CurrentProcess) {
- return Core::System::GetInstance().CurrentProcess();
+ return SharedFrom(Core::System::GetInstance().CurrentProcess());
}
if (!IsValid(handle)) {
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index 44901391b..9fcb4cc15 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -68,7 +68,7 @@ public:
* @return The created Handle or one of the following errors:
* - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded.
*/
- ResultVal<Handle> Create(SharedPtr<Object> obj);
+ ResultVal<Handle> Create(std::shared_ptr<Object> obj);
/**
* Returns a new handle that points to the same object as the passed in handle.
@@ -92,7 +92,7 @@ public:
* Looks up a handle.
* @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
*/
- SharedPtr<Object> GetGeneric(Handle handle) const;
+ std::shared_ptr<Object> GetGeneric(Handle handle) const;
/**
* Looks up a handle while verifying its type.
@@ -100,7 +100,7 @@ public:
* type differs from the requested one.
*/
template <class T>
- SharedPtr<T> Get(Handle handle) const {
+ std::shared_ptr<T> Get(Handle handle) const {
return DynamicObjectCast<T>(GetGeneric(handle));
}
@@ -109,7 +109,7 @@ public:
private:
/// Stores the Object referenced by the handle or null if the slot is empty.
- std::array<SharedPtr<Object>, MAX_COUNT> objects;
+ std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
/**
* The value of `next_generation` when the handle was created, used to check for validity. For
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index a7b5849b0..2db28dcf0 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -32,23 +32,25 @@ SessionRequestHandler::SessionRequestHandler() = default;
SessionRequestHandler::~SessionRequestHandler() = default;
-void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) {
+void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) {
server_session->SetHleHandler(shared_from_this());
connected_sessions.push_back(std::move(server_session));
}
-void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& server_session) {
+void SessionRequestHandler::ClientDisconnected(
+ const std::shared_ptr<ServerSession>& server_session) {
server_session->SetHleHandler(nullptr);
boost::range::remove_erase(connected_sessions, server_session);
}
-SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
+std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
const std::string& reason, u64 timeout, WakeupCallback&& callback,
- SharedPtr<WritableEvent> writable_event) {
+ std::shared_ptr<WritableEvent> writable_event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
- thread->SetWakeupCallback([context = *this, callback](
- ThreadWakeupReason reason, SharedPtr<Thread> thread,
- SharedPtr<WaitObject> object, std::size_t index) mutable -> bool {
+ thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason,
+ std::shared_ptr<Thread> thread,
+ std::shared_ptr<WaitObject> object,
+ std::size_t index) mutable -> bool {
ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
callback(thread, context, reason);
context.WriteToOutgoingCommandBuffer(*thread);
@@ -72,11 +74,13 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
thread->WakeAfterDelay(timeout);
}
+ is_thread_waiting = true;
+
return writable_event;
}
-HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session,
- SharedPtr<Thread> thread)
+HLERequestContext::HLERequestContext(std::shared_ptr<Kernel::ServerSession> server_session,
+ std::shared_ptr<Thread> thread)
: server_session(std::move(server_session)), thread(std::move(thread)) {
cmd_buf[0] = 0;
}
@@ -212,10 +216,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
auto& owner_process = *thread.GetOwnerProcess();
auto& handle_table = owner_process.GetHandleTable();
+ auto& memory = Core::System::GetInstance().Memory();
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
- Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
- dst_cmdbuf.size() * sizeof(u32));
+ memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
+ dst_cmdbuf.size() * sizeof(u32));
// The header was already built in the internal command buffer. Attempt to parse it to verify
// the integrity and then copy it over to the target command buffer.
@@ -271,8 +276,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
}
// Copy the translated command buffer back into the thread's command buffer area.
- Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
- dst_cmdbuf.size() * sizeof(u32));
+ memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
+ dst_cmdbuf.size() * sizeof(u32));
return RESULT_SUCCESS;
}
@@ -280,15 +285,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
std::vector<u8> buffer;
const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
+ auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_a) {
buffer.resize(BufferDescriptorA()[buffer_index].Size());
- Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(),
- buffer.size());
+ memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
} else {
buffer.resize(BufferDescriptorX()[buffer_index].Size());
- Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(),
- buffer.size());
+ memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
}
return buffer;
@@ -309,10 +313,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
size = buffer_size; // TODO(bunnei): This needs to be HW tested
}
+ auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_b) {
- Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
+ memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
} else {
- Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
+ memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
}
return size;
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index ccf5e56aa..050ad8fd7 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include <functional>
#include <memory>
#include <optional>
#include <string>
@@ -60,20 +61,20 @@ public:
* associated ServerSession alive for the duration of the connection.
* @param server_session Owning pointer to the ServerSession associated with the connection.
*/
- void ClientConnected(SharedPtr<ServerSession> server_session);
+ void ClientConnected(std::shared_ptr<ServerSession> server_session);
/**
* Signals that a client has just disconnected from this HLE handler and releases the
* associated ServerSession.
* @param server_session ServerSession associated with the connection.
*/
- void ClientDisconnected(const SharedPtr<ServerSession>& server_session);
+ void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session);
protected:
/// List of sessions that are connected to this handler.
/// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
/// for the duration of the connection.
- std::vector<SharedPtr<ServerSession>> connected_sessions;
+ std::vector<std::shared_ptr<ServerSession>> connected_sessions;
};
/**
@@ -97,7 +98,8 @@ protected:
*/
class HLERequestContext {
public:
- explicit HLERequestContext(SharedPtr<ServerSession> session, SharedPtr<Thread> thread);
+ explicit HLERequestContext(std::shared_ptr<ServerSession> session,
+ std::shared_ptr<Thread> thread);
~HLERequestContext();
/// Returns a pointer to the IPC command buffer for this request.
@@ -109,12 +111,12 @@ public:
* Returns the session through which this request was made. This can be used as a map key to
* access per-client data on services.
*/
- const SharedPtr<Kernel::ServerSession>& Session() const {
+ const std::shared_ptr<Kernel::ServerSession>& Session() const {
return server_session;
}
- using WakeupCallback = std::function<void(SharedPtr<Thread> thread, HLERequestContext& context,
- ThreadWakeupReason reason)>;
+ using WakeupCallback = std::function<void(
+ std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
/**
* Puts the specified guest thread to sleep until the returned event is signaled or until the
@@ -129,9 +131,9 @@ public:
* created.
* @returns Event that when signaled will resume the thread and call the callback function.
*/
- SharedPtr<WritableEvent> SleepClientThread(const std::string& reason, u64 timeout,
- WakeupCallback&& callback,
- SharedPtr<WritableEvent> writable_event = nullptr);
+ std::shared_ptr<WritableEvent> SleepClientThread(
+ const std::string& reason, u64 timeout, WakeupCallback&& callback,
+ std::shared_ptr<WritableEvent> writable_event = nullptr);
/// Populates this context with data from the requesting process/thread.
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
@@ -209,20 +211,20 @@ public:
std::size_t GetWriteBufferSize(int buffer_index = 0) const;
template <typename T>
- SharedPtr<T> GetCopyObject(std::size_t index) {
+ std::shared_ptr<T> GetCopyObject(std::size_t index) {
return DynamicObjectCast<T>(copy_objects.at(index));
}
template <typename T>
- SharedPtr<T> GetMoveObject(std::size_t index) {
+ std::shared_ptr<T> GetMoveObject(std::size_t index) {
return DynamicObjectCast<T>(move_objects.at(index));
}
- void AddMoveObject(SharedPtr<Object> object) {
+ void AddMoveObject(std::shared_ptr<Object> object) {
move_objects.emplace_back(std::move(object));
}
- void AddCopyObject(SharedPtr<Object> object) {
+ void AddCopyObject(std::shared_ptr<Object> object) {
copy_objects.emplace_back(std::move(object));
}
@@ -262,15 +264,27 @@ public:
std::string Description() const;
+ Thread& GetThread() {
+ return *thread;
+ }
+
+ const Thread& GetThread() const {
+ return *thread;
+ }
+
+ bool IsThreadWaiting() const {
+ return is_thread_waiting;
+ }
+
private:
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
- SharedPtr<Kernel::ServerSession> server_session;
- SharedPtr<Thread> thread;
+ std::shared_ptr<Kernel::ServerSession> server_session;
+ std::shared_ptr<Thread> thread;
// TODO(yuriks): Check common usage of this and optimize size accordingly
- boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
- boost::container::small_vector<SharedPtr<Object>, 8> copy_objects;
+ boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
+ boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
std::optional<IPC::CommandHeader> command_header;
@@ -288,6 +302,7 @@ private:
u32_le command{};
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
+ bool is_thread_waiting{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f94ac150d..1c90546a4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -40,7 +40,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
// Lock the global kernel mutex when we enter the kernel HLE.
std::lock_guard lock{HLE::g_hle_lock};
- SharedPtr<Thread> thread =
+ std::shared_ptr<Thread> thread =
system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle);
if (thread == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
@@ -53,7 +53,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
// Remove the thread from each of its waiting objects' waitlists
for (const auto& object : thread->GetWaitObjects()) {
- object->RemoveWaitingThread(thread.get());
+ object->RemoveWaitingThread(thread);
}
thread->ClearWaitObjects();
@@ -64,8 +64,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
} else if (thread->GetStatus() == ThreadStatus::WaitMutex ||
thread->GetStatus() == ThreadStatus::WaitCondVar) {
thread->SetMutexWaitAddress(0);
- thread->SetCondVarWaitAddress(0);
thread->SetWaitHandle(0);
+ if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
+ thread->GetOwnerProcess()->RemoveConditionVariableThread(thread);
+ thread->SetCondVarWaitAddress(0);
+ }
auto* const lock_owner = thread->GetLockOwner();
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
@@ -136,12 +139,12 @@ struct KernelCore::Impl {
void InitializeThreads() {
thread_wakeup_event_type =
- system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
+ Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback);
}
void InitializePreemption() {
- preemption_event = system.CoreTiming().RegisterEvent(
- "PreemptionCallback", [this](u64 userdata, s64 cycles_late) {
+ preemption_event =
+ Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) {
global_scheduler.PreemptThreads();
s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10));
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
@@ -151,20 +154,31 @@ struct KernelCore::Impl {
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
}
+ void MakeCurrentProcess(Process* process) {
+ current_process = process;
+
+ if (process == nullptr) {
+ return;
+ }
+
+ system.Memory().SetCurrentPageTable(*process);
+ }
+
std::atomic<u32> next_object_id{0};
std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
std::atomic<u64> next_thread_id{1};
// Lists all processes that exist in the current session.
- std::vector<SharedPtr<Process>> process_list;
+ std::vector<std::shared_ptr<Process>> process_list;
Process* current_process = nullptr;
Kernel::GlobalScheduler global_scheduler;
- SharedPtr<ResourceLimit> system_resource_limit;
+ std::shared_ptr<ResourceLimit> system_resource_limit;
+
+ std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type;
+ std::shared_ptr<Core::Timing::EventType> preemption_event;
- Core::Timing::EventType* thread_wakeup_event_type = nullptr;
- Core::Timing::EventType* preemption_event = nullptr;
// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
// allowing us to simply use a pool index or similar.
Kernel::HandleTable thread_wakeup_callback_handle_table;
@@ -190,26 +204,21 @@ void KernelCore::Shutdown() {
impl->Shutdown();
}
-SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
+std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
return impl->system_resource_limit;
}
-SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
+std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(
+ Handle handle) const {
return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
}
-void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
+void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
impl->process_list.push_back(std::move(process));
}
void KernelCore::MakeCurrentProcess(Process* process) {
- impl->current_process = process;
-
- if (process == nullptr) {
- return;
- }
-
- Memory::SetCurrentPageTable(*process);
+ impl->MakeCurrentProcess(process);
}
Process* KernelCore::CurrentProcess() {
@@ -220,7 +229,7 @@ const Process* KernelCore::CurrentProcess() const {
return impl->current_process;
}
-const std::vector<SharedPtr<Process>>& KernelCore::GetProcessList() const {
+const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const {
return impl->process_list;
}
@@ -232,7 +241,7 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
return impl->global_scheduler;
}
-void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
+void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
impl->named_ports.emplace(std::move(name), std::move(port));
}
@@ -265,7 +274,7 @@ u64 KernelCore::CreateNewUserProcessID() {
return impl->next_user_process_id++;
}
-Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
+const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallbackEventType() const {
return impl->thread_wakeup_event_type;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index c4397fc77..babb531c6 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -6,6 +6,7 @@
#include <string>
#include <unordered_map>
+#include <vector>
#include "core/hle/kernel/object.h"
namespace Core {
@@ -30,7 +31,7 @@ class Thread;
/// Represents a single instance of the kernel.
class KernelCore {
private:
- using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>;
+ using NamedPortTable = std::unordered_map<std::string, std::shared_ptr<ClientPort>>;
public:
/// Constructs an instance of the kernel using the given System
@@ -56,13 +57,13 @@ public:
void Shutdown();
/// Retrieves a shared pointer to the system resource limit instance.
- SharedPtr<ResourceLimit> GetSystemResourceLimit() const;
+ std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
- SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
+ std::shared_ptr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes.
- void AppendNewProcess(SharedPtr<Process> process);
+ void AppendNewProcess(std::shared_ptr<Process> process);
/// Makes the given process the new current process.
void MakeCurrentProcess(Process* process);
@@ -74,7 +75,7 @@ public:
const Process* CurrentProcess() const;
/// Retrieves the list of processes.
- const std::vector<SharedPtr<Process>>& GetProcessList() const;
+ const std::vector<std::shared_ptr<Process>>& GetProcessList() const;
/// Gets the sole instance of the global scheduler
Kernel::GlobalScheduler& GlobalScheduler();
@@ -83,7 +84,7 @@ public:
const Kernel::GlobalScheduler& GlobalScheduler() const;
/// Adds a port to the named port table
- void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
+ void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
/// Finds a port within the named port table with the given name.
NamedPortTable::iterator FindNamedPort(const std::string& name);
@@ -112,7 +113,7 @@ private:
u64 CreateNewThreadID();
/// Retrieves the event type used for thread wakeup callbacks.
- Core::Timing::EventType* ThreadWakeupCallbackEventType() const;
+ const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const;
/// Provides a reference to the thread wakeup callback handle table.
Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 663d0f4b6..061e9bcb0 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -22,10 +22,10 @@ namespace Kernel {
/// Returns the number of threads that are waiting for a mutex, and the highest priority one among
/// those.
-static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
- const SharedPtr<Thread>& current_thread, VAddr mutex_addr) {
+static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
+ const std::shared_ptr<Thread>& current_thread, VAddr mutex_addr) {
- SharedPtr<Thread> highest_priority_thread;
+ std::shared_ptr<Thread> highest_priority_thread;
u32 num_waiters = 0;
for (const auto& thread : current_thread->GetMutexWaitingThreads()) {
@@ -45,14 +45,14 @@ static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
}
/// Update the mutex owner field of all threads waiting on the mutex to point to the new owner.
-static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_thread,
- SharedPtr<Thread> new_owner) {
+static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr<Thread> current_thread,
+ std::shared_ptr<Thread> new_owner) {
const auto threads = current_thread->GetMutexWaitingThreads();
for (const auto& thread : threads) {
if (thread->GetMutexWaitAddress() != mutex_addr)
continue;
- ASSERT(thread->GetLockOwner() == current_thread);
+ ASSERT(thread->GetLockOwner() == current_thread.get());
current_thread->RemoveMutexWaiter(thread);
if (new_owner != thread)
new_owner->AddMutexWaiter(thread);
@@ -70,15 +70,16 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
}
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- Thread* const current_thread = system.CurrentScheduler().GetCurrentThread();
- SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
- SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle);
+ std::shared_ptr<Thread> current_thread =
+ SharedFrom(system.CurrentScheduler().GetCurrentThread());
+ std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
+ std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle);
// TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
// thread.
ASSERT(requesting_thread == current_thread);
- const u32 addr_value = Memory::Read32(address);
+ const u32 addr_value = system.Memory().Read32(address);
// If the mutex isn't being held, just return success.
if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
@@ -110,12 +111,13 @@ ResultCode Mutex::Release(VAddr address) {
return ERR_INVALID_ADDRESS;
}
- auto* const current_thread = system.CurrentScheduler().GetCurrentThread();
+ std::shared_ptr<Thread> current_thread =
+ SharedFrom(system.CurrentScheduler().GetCurrentThread());
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address);
// There are no more threads waiting for the mutex, release it completely.
if (thread == nullptr) {
- Memory::Write32(address, 0);
+ system.Memory().Write32(address, 0);
return RESULT_SUCCESS;
}
@@ -130,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) {
}
// Grant the mutex to the next waiting thread and resume it.
- Memory::Write32(address, mutex_value);
+ system.Memory().Write32(address, mutex_value);
ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
thread->ResumeFromWait();
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index 10431e94c..2c571792b 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -27,6 +27,7 @@ bool Object::IsWaitable() const {
case HandleType::ResourceLimit:
case HandleType::ClientPort:
case HandleType::ClientSession:
+ case HandleType::Session:
return false;
}
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index a6faeb83b..e3391e2af 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -5,10 +5,9 @@
#pragma once
#include <atomic>
+#include <memory>
#include <string>
-#include <boost/smart_ptr/intrusive_ptr.hpp>
-
#include "common/common_types.h"
namespace Kernel {
@@ -30,9 +29,10 @@ enum class HandleType : u32 {
ServerPort,
ClientSession,
ServerSession,
+ Session,
};
-class Object : NonCopyable {
+class Object : NonCopyable, public std::enable_shared_from_this<Object> {
public:
explicit Object(KernelCore& kernel);
virtual ~Object();
@@ -61,35 +61,24 @@ protected:
KernelCore& kernel;
private:
- friend void intrusive_ptr_add_ref(Object*);
- friend void intrusive_ptr_release(Object*);
-
- std::atomic<u32> ref_count{0};
std::atomic<u32> object_id{0};
};
-// Special functions used by boost::instrusive_ptr to do automatic ref-counting
-inline void intrusive_ptr_add_ref(Object* object) {
- object->ref_count.fetch_add(1, std::memory_order_relaxed);
-}
-
-inline void intrusive_ptr_release(Object* object) {
- if (object->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
- delete object;
- }
-}
-
template <typename T>
-using SharedPtr = boost::intrusive_ptr<T>;
+std::shared_ptr<T> SharedFrom(T* raw) {
+ if (raw == nullptr)
+ return nullptr;
+ return std::static_pointer_cast<T>(raw->shared_from_this());
+}
/**
* Attempts to downcast the given Object pointer to a pointer to T.
* @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
*/
template <typename T>
-inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
+inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
- return boost::static_pointer_cast<T>(object);
+ return std::static_pointer_cast<T>(object);
}
return nullptr;
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 12a900bcc..12ea4ebe3 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -38,7 +38,7 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) {
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
owner_process.GetIdealCore(), stack_top, owner_process);
- SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
+ std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
// Register 1 must be a handle to the main thread
const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
@@ -100,10 +100,10 @@ private:
std::bitset<num_slot_entries> is_slot_used;
};
-SharedPtr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) {
+std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) {
auto& kernel = system.Kernel();
- SharedPtr<Process> process(new Process(system));
+ std::shared_ptr<Process> process = std::make_shared<Process>(system);
process->name = std::move(name);
process->resource_limit = kernel.GetSystemResourceLimit();
process->status = ProcessStatus::Created;
@@ -121,7 +121,7 @@ SharedPtr<Process> Process::Create(Core::System& system, std::string name, Proce
return process;
}
-SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
+std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
return resource_limit;
}
@@ -142,6 +142,49 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
}
+void Process::InsertConditionVariableThread(std::shared_ptr<Thread> thread) {
+ VAddr cond_var_addr = thread->GetCondVarWaitAddress();
+ std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr];
+ auto it = thread_list.begin();
+ while (it != thread_list.end()) {
+ const std::shared_ptr<Thread> current_thread = *it;
+ if (current_thread->GetPriority() > thread->GetPriority()) {
+ thread_list.insert(it, thread);
+ return;
+ }
+ ++it;
+ }
+ thread_list.push_back(thread);
+}
+
+void Process::RemoveConditionVariableThread(std::shared_ptr<Thread> thread) {
+ VAddr cond_var_addr = thread->GetCondVarWaitAddress();
+ std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr];
+ auto it = thread_list.begin();
+ while (it != thread_list.end()) {
+ const std::shared_ptr<Thread> current_thread = *it;
+ if (current_thread.get() == thread.get()) {
+ thread_list.erase(it);
+ return;
+ }
+ ++it;
+ }
+ UNREACHABLE();
+}
+
+std::vector<std::shared_ptr<Thread>> Process::GetConditionVariableThreads(
+ const VAddr cond_var_addr) {
+ std::vector<std::shared_ptr<Thread>> result{};
+ std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr];
+ auto it = thread_list.begin();
+ while (it != thread_list.end()) {
+ std::shared_ptr<Thread> current_thread = *it;
+ result.push_back(current_thread);
+ ++it;
+ }
+ return result;
+}
+
void Process::RegisterThread(const Thread* thread) {
thread_list.push_back(thread);
}
@@ -197,12 +240,12 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
void Process::PrepareForTermination() {
ChangeStatus(ProcessStatus::Exiting);
- const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
+ const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) {
for (auto& thread : thread_list) {
if (thread->GetOwnerProcess() != this)
continue;
- if (thread == system.CurrentScheduler().GetCurrentThread())
+ if (thread.get() == system.CurrentScheduler().GetCurrentThread())
continue;
// TODO(Subv): When are the other running/ready threads terminated?
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index c2df451f3..3483fa19d 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -8,6 +8,7 @@
#include <cstddef>
#include <list>
#include <string>
+#include <unordered_map>
#include <vector>
#include "common/common_types.h"
#include "core/hle/kernel/address_arbiter.h"
@@ -61,6 +62,9 @@ enum class ProcessStatus {
class Process final : public WaitObject {
public:
+ explicit Process(Core::System& system);
+ ~Process() override;
+
enum : u64 {
/// Lowest allowed process ID for a kernel initial process.
InitialKIPIDMin = 1,
@@ -81,7 +85,8 @@ public:
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
- static SharedPtr<Process> Create(Core::System& system, std::string name, ProcessType type);
+ static std::shared_ptr<Process> Create(Core::System& system, std::string name,
+ ProcessType type);
std::string GetTypeName() const override {
return "Process";
@@ -156,7 +161,7 @@ public:
}
/// Gets the resource limit descriptor for this process
- SharedPtr<ResourceLimit> GetResourceLimit() const;
+ std::shared_ptr<ResourceLimit> GetResourceLimit() const;
/// Gets the ideal CPU core ID for this process
u8 GetIdealCore() const {
@@ -232,6 +237,15 @@ public:
return thread_list;
}
+ /// Insert a thread into the condition variable wait container
+ void InsertConditionVariableThread(std::shared_ptr<Thread> thread);
+
+ /// Remove a thread from the condition variable wait container
+ void RemoveConditionVariableThread(std::shared_ptr<Thread> thread);
+
+ /// Obtain all condition variable threads waiting for some address
+ std::vector<std::shared_ptr<Thread>> GetConditionVariableThreads(VAddr cond_var_addr);
+
/// Registers a thread as being created under this process,
/// adding it to this process' thread list.
void RegisterThread(const Thread* thread);
@@ -287,9 +301,6 @@ public:
void FreeTLSRegion(VAddr tls_address);
private:
- explicit Process(Core::System& system);
- ~Process() override;
-
/// Checks if the specified thread should wait until this process is available.
bool ShouldWait(const Thread* thread) const override;
@@ -328,7 +339,7 @@ private:
u32 system_resource_size = 0;
/// Resource limit descriptor for this process
- SharedPtr<ResourceLimit> resource_limit;
+ std::shared_ptr<ResourceLimit> resource_limit;
/// The ideal CPU core for this process, threads are scheduled on this core by default.
u8 ideal_core = 0;
@@ -375,6 +386,9 @@ private:
/// List of threads that are running with this process as their owner.
std::list<const Thread*> thread_list;
+ /// List of threads waiting for a condition variable
+ std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads;
+
/// System context
Core::System& system;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 173f69915..b53423462 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -16,8 +16,8 @@ constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
ResourceLimit::~ResourceLimit() = default;
-SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
- return new ResourceLimit(kernel);
+std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
+ return std::make_shared<ResourceLimit>(kernel);
}
s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 2613a6bb5..b5534620d 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -31,8 +31,11 @@ constexpr bool IsValidResourceType(ResourceType type) {
class ResourceLimit final : public Object {
public:
+ explicit ResourceLimit(KernelCore& kernel);
+ ~ResourceLimit() override;
+
/// Creates a resource limit object.
- static SharedPtr<ResourceLimit> Create(KernelCore& kernel);
+ static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel);
std::string GetTypeName() const override {
return "ResourceLimit";
@@ -76,9 +79,6 @@ public:
ResultCode SetLimitValue(ResourceType resource, s64 value);
private:
- explicit ResourceLimit(KernelCore& kernel);
- ~ResourceLimit() override;
-
// TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
// functions
//
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 16e95381b..3f5192087 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -26,11 +26,11 @@ GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {}
GlobalScheduler::~GlobalScheduler() = default;
-void GlobalScheduler::AddThread(SharedPtr<Thread> thread) {
+void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) {
thread_list.push_back(std::move(thread));
}
-void GlobalScheduler::RemoveThread(const Thread* thread) {
+void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
thread_list.end());
}
@@ -42,11 +42,11 @@ void GlobalScheduler::UnloadThread(std::size_t core) {
void GlobalScheduler::SelectThread(std::size_t core) {
const auto update_thread = [](Thread* thread, Scheduler& sched) {
- if (thread != sched.selected_thread) {
+ if (thread != sched.selected_thread.get()) {
if (thread == nullptr) {
++sched.idle_selection_count;
}
- sched.selected_thread = thread;
+ sched.selected_thread = SharedFrom(thread);
}
sched.is_context_switch_pending = sched.selected_thread != sched.current_thread;
std::atomic_thread_fence(std::memory_order_seq_cst);
@@ -446,7 +446,7 @@ void Scheduler::SwitchContext() {
// Cancel any outstanding wakeup events for this thread
new_thread->CancelWakeupTimer();
- current_thread = new_thread;
+ current_thread = SharedFrom(new_thread);
new_thread->SetStatus(ThreadStatus::Running);
new_thread->SetIsRunning(true);
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 311849dfb..3c5c21346 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -28,13 +28,13 @@ public:
~GlobalScheduler();
/// Adds a new thread to the scheduler
- void AddThread(SharedPtr<Thread> thread);
+ void AddThread(std::shared_ptr<Thread> thread);
/// Removes a thread from the scheduler
- void RemoveThread(const Thread* thread);
+ void RemoveThread(std::shared_ptr<Thread> thread);
/// Returns a list of all threads managed by the scheduler
- const std::vector<SharedPtr<Thread>>& GetThreadList() const {
+ const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
return thread_list;
}
@@ -157,7 +157,7 @@ private:
std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
/// Lists all thread ids that aren't deleted/etc.
- std::vector<SharedPtr<Thread>> thread_list;
+ std::vector<std::shared_ptr<Thread>> thread_list;
Core::System& system;
};
@@ -213,8 +213,8 @@ private:
*/
void UpdateLastContextSwitchTime(Thread* thread, Process* process);
- SharedPtr<Thread> current_thread = nullptr;
- SharedPtr<Thread> selected_thread = nullptr;
+ std::shared_ptr<Thread> current_thread = nullptr;
+ std::shared_ptr<Thread> selected_thread = nullptr;
Core::System& system;
Core::ARM_Interface& cpu_core;
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 02e7c60e6..a4ccfa35e 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -16,7 +16,7 @@ namespace Kernel {
ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {}
ServerPort::~ServerPort() = default;
-ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() {
+ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
if (pending_sessions.empty()) {
return ERR_NOT_FOUND;
}
@@ -26,7 +26,7 @@ ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() {
return MakeResult(std::move(session));
}
-void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session) {
+void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) {
pending_sessions.push_back(std::move(pending_session));
}
@@ -41,8 +41,8 @@ void ServerPort::Acquire(Thread* thread) {
ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
std::string name) {
- SharedPtr<ServerPort> server_port(new ServerPort(kernel));
- SharedPtr<ClientPort> client_port(new ClientPort(kernel));
+ std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
+ std::shared_ptr<ClientPort> client_port = std::make_shared<ClientPort>(kernel);
server_port->name = name + "_Server";
client_port->name = name + "_Client";
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index dc88a1ebd..8be8a75ea 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -22,8 +22,11 @@ class SessionRequestHandler;
class ServerPort final : public WaitObject {
public:
+ explicit ServerPort(KernelCore& kernel);
+ ~ServerPort() override;
+
using HLEHandler = std::shared_ptr<SessionRequestHandler>;
- using PortPair = std::pair<SharedPtr<ServerPort>, SharedPtr<ClientPort>>;
+ using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
/**
* Creates a pair of ServerPort and an associated ClientPort.
@@ -52,7 +55,7 @@ public:
* Accepts a pending incoming connection on this port. If there are no pending sessions, will
* return ERR_NO_PENDING_SESSIONS.
*/
- ResultVal<SharedPtr<ServerSession>> Accept();
+ ResultVal<std::shared_ptr<ServerSession>> Accept();
/// Whether or not this server port has an HLE handler available.
bool HasHLEHandler() const {
@@ -74,17 +77,14 @@ public:
/// Appends a ServerSession to the collection of ServerSessions
/// waiting to be accepted by this port.
- void AppendPendingSession(SharedPtr<ServerSession> pending_session);
+ void AppendPendingSession(std::shared_ptr<ServerSession> pending_session);
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
private:
- explicit ServerPort(KernelCore& kernel);
- ~ServerPort() override;
-
/// ServerSessions waiting to be accepted by the port
- std::vector<SharedPtr<ServerSession>> pending_sessions;
+ std::vector<std::shared_ptr<ServerSession>> pending_sessions;
/// This session's HLE request handler template (optional)
/// ServerSessions created from this port inherit a reference to this handler.
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 30b2bfb5a..7825e1ec4 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
@@ -19,35 +20,32 @@
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
+#include "core/memory.h"
namespace Kernel {
ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
-ServerSession::~ServerSession() {
- // This destructor will be called automatically when the last ServerSession handle is closed by
- // the emulated application.
+ServerSession::~ServerSession() = default;
- // Decrease the port's connection count.
- if (parent->port) {
- parent->port->ConnectionClosed();
- }
-
- parent->server = nullptr;
-}
+ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
+ std::shared_ptr<Session> parent,
+ std::string name) {
+ std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
-ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, std::string name) {
- SharedPtr<ServerSession> server_session(new ServerSession(kernel));
+ session->request_event = Core::Timing::CreateEvent(
+ name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); });
+ session->name = std::move(name);
+ session->parent = std::move(parent);
- server_session->name = std::move(name);
- server_session->parent = nullptr;
-
- return MakeResult(std::move(server_session));
+ return MakeResult(std::move(session));
}
bool ServerSession::ShouldWait(const Thread* thread) const {
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
- if (parent->client == nullptr)
+ if (!parent->Client()) {
return false;
+ }
+
// Wait if we have no pending requests, or if we're currently handling a request.
return pending_requesting_threads.empty() || currently_handling != nullptr;
}
@@ -69,7 +67,7 @@ void ServerSession::ClientDisconnected() {
if (handler) {
// Note that after this returns, this server session's hle_handler is
// invalidated (set to null).
- handler->ClientDisconnected(this);
+ handler->ClientDisconnected(SharedFrom(this));
}
// Clean up the list of client threads with pending requests, they are unneeded now that the
@@ -126,13 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
return RESULT_SUCCESS;
}
-ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
- // The ServerSession received a sync request, this means that there's new data available
- // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
- // similar.
- Kernel::HLERequestContext context(this, thread);
- u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
- context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
+ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) {
+ u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
+ std::shared_ptr<Kernel::HLERequestContext> context{
+ std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))};
+
+ context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
+ request_queue.Push(std::move(context));
+
+ return RESULT_SUCCESS;
+}
+
+ResultCode ServerSession::CompleteSyncRequest() {
+ ASSERT(!request_queue.Empty());
+
+ auto& context = *request_queue.Front();
ResultCode result = RESULT_SUCCESS;
// If the session has been converted to a domain, handle the domain request
@@ -144,61 +150,27 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
result = hle_handler->HandleSyncRequest(context);
}
- if (thread->GetStatus() == ThreadStatus::Running) {
- // Put the thread to sleep until the server replies, it will be awoken in
- // svcReplyAndReceive for LLE servers.
- thread->SetStatus(ThreadStatus::WaitIPC);
-
- if (hle_handler != nullptr) {
- // For HLE services, we put the request threads to sleep for a short duration to
- // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for
- // other reasons like an async callback. The IPC overhead is needed to prevent
- // starvation when a thread only does sync requests to HLE services while a
- // lower-priority thread is waiting to run.
-
- // This delay was approximated in a homebrew application by measuring the average time
- // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC
- // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have
- // a high variance and vary between models.
- static constexpr u64 IPCDelayNanoseconds = 39000;
- thread->WakeAfterDelay(IPCDelayNanoseconds);
- } else {
- // Add the thread to the list of threads that have issued a sync request with this
- // server.
- pending_requesting_threads.push_back(std::move(thread));
- }
- }
-
- // If this ServerSession does not have an HLE implementation, just wake up the threads waiting
- // on it.
- WakeupAllWaitingThreads();
-
- // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
- // end of the command such that only commands following this one are handled as domains
if (convert_to_domain) {
ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");
domain_request_handlers = {hle_handler};
convert_to_domain = false;
}
- return result;
-}
-
-ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
- const std::string& name,
- SharedPtr<ClientPort> port) {
- auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap();
- SharedPtr<ClientSession> client_session(new ClientSession(kernel));
- client_session->name = name + "_Client";
+ // Some service requests require the thread to block
+ if (!context.IsThreadWaiting()) {
+ context.GetThread().ResumeFromWait();
+ context.GetThread().SetWaitSynchronizationResult(result);
+ }
- std::shared_ptr<Session> parent(new Session);
- parent->client = client_session.get();
- parent->server = server_session.get();
- parent->port = std::move(port);
+ request_queue.Pop();
- client_session->parent = parent;
- server_session->parent = parent;
+ return result;
+}
- return std::make_pair(std::move(server_session), std::move(client_session));
+ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
+ Memory::Memory& memory) {
+ Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {});
+ return QueueSyncRequest(std::move(thread), memory);
}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 738df30f8..d6e48109e 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -9,17 +9,22 @@
#include <utility>
#include <vector>
-#include "core/hle/kernel/object.h"
+#include "common/threadsafe_queue.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
+namespace Memory {
+class Memory;
+}
+
+namespace Core::Timing {
+struct EventType;
+}
+
namespace Kernel {
-class ClientPort;
-class ClientSession;
class HLERequestContext;
class KernelCore;
-class ServerSession;
class Session;
class SessionRequestHandler;
class Thread;
@@ -38,6 +43,15 @@ class Thread;
*/
class ServerSession final : public WaitObject {
public:
+ explicit ServerSession(KernelCore& kernel);
+ ~ServerSession() override;
+
+ friend class Session;
+
+ static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel,
+ std::shared_ptr<Session> parent,
+ std::string name = "Unknown");
+
std::string GetTypeName() const override {
return "ServerSession";
}
@@ -59,18 +73,6 @@ public:
return parent.get();
}
- using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
-
- /**
- * Creates a pair of ServerSession and an associated ClientSession.
- * @param kernel The kernal instance to create the session pair under.
- * @param name Optional name of the ports.
- * @param client_port Optional The ClientPort that spawned this session.
- * @return The created session tuple
- */
- static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown",
- SharedPtr<ClientPort> client_port = nullptr);
-
/**
* Sets the HLE handler for the session. This handler will be called to service IPC requests
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
@@ -82,10 +84,13 @@ public:
/**
* Handle a sync request from the emulated application.
+ *
* @param thread Thread that initiated the request.
+ * @param memory Memory context to handle the sync request under.
+ *
* @returns ResultCode from the operation.
*/
- ResultCode HandleSyncRequest(SharedPtr<Thread> thread);
+ ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
bool ShouldWait(const Thread* thread) const override;
@@ -118,18 +123,11 @@ public:
}
private:
- explicit ServerSession(KernelCore& kernel);
- ~ServerSession() override;
+ /// Queues a sync request from the emulated application.
+ ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
- /**
- * Creates a server session. The server session can have an optional HLE handler,
- * which will be invoked to handle the IPC requests that this session receives.
- * @param kernel The kernel instance to create this server session under.
- * @param name Optional name of the server session.
- * @return The created server session
- */
- static ResultVal<SharedPtr<ServerSession>> Create(KernelCore& kernel,
- std::string name = "Unknown");
+ /// Completes a sync request from the emulated application.
+ ResultCode CompleteSyncRequest();
/// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
/// object handle.
@@ -147,18 +145,24 @@ private:
/// List of threads that are pending a response after a sync request. This list is processed in
/// a LIFO manner, thus, the last request will be dispatched first.
/// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
- std::vector<SharedPtr<Thread>> pending_requesting_threads;
+ std::vector<std::shared_ptr<Thread>> pending_requesting_threads;
/// Thread whose request is currently being handled. A request is considered "handled" when a
/// response is sent via svcReplyAndReceive.
/// TODO(Subv): Find a better name for this.
- SharedPtr<Thread> currently_handling;
+ std::shared_ptr<Thread> currently_handling;
/// When set to True, converts the session to a domain at the end of the command
bool convert_to_domain{};
/// The name of this session (optional)
std::string name;
+
+ /// Core timing event used to schedule the service request at some point in the future
+ std::shared_ptr<Core::Timing::EventType> request_event;
+
+ /// Queue of scheduled service requests
+ Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index 642914744..dee6e2b72 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -1,12 +1,36 @@
-// Copyright 2015 Citra Emulator Project
+// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/assert.h"
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
-#include "core/hle/kernel/thread.h"
namespace Kernel {
-Session::Session() {}
-Session::~Session() {}
+Session::Session(KernelCore& kernel) : WaitObject{kernel} {}
+Session::~Session() = default;
+
+Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
+ auto session{std::make_shared<Session>(kernel)};
+ auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()};
+ auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()};
+
+ session->name = std::move(name);
+ session->client = client_session;
+ session->server = server_session;
+
+ return std::make_pair(std::move(client_session), std::move(server_session));
+}
+
+bool Session::ShouldWait(const Thread* thread) const {
+ UNIMPLEMENTED();
+ return {};
+}
+
+void Session::Acquire(Thread* thread) {
+ UNIMPLEMENTED();
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 7a551f5e4..5a9d4e9ad 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -1,27 +1,64 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
-#include "core/hle/kernel/object.h"
+#include <memory>
+#include <string>
+
+#include "core/hle/kernel/wait_object.h"
+#include "core/hle/result.h"
namespace Kernel {
class ClientSession;
-class ClientPort;
class ServerSession;
/**
* Parent structure to link the client and server endpoints of a session with their associated
- * client port. The client port need not exist, as is the case for portless sessions like the
- * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its
- * corresponding field in this structure will be set to nullptr.
+ * client port.
*/
-class Session final {
+class Session final : public WaitObject {
public:
- ClientSession* client = nullptr; ///< The client endpoint of the session.
- ServerSession* server = nullptr; ///< The server endpoint of the session.
- SharedPtr<ClientPort> port; ///< The port that this session is associated with (optional).
+ explicit Session(KernelCore& kernel);
+ ~Session() override;
+
+ using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>;
+
+ static SessionPair Create(KernelCore& kernel, std::string name = "Unknown");
+
+ std::string GetName() const override {
+ return name;
+ }
+
+ static constexpr HandleType HANDLE_TYPE = HandleType::Session;
+ HandleType GetHandleType() const override {
+ return HANDLE_TYPE;
+ }
+
+ bool ShouldWait(const Thread* thread) const override;
+
+ void Acquire(Thread* thread) override;
+
+ std::shared_ptr<ClientSession> Client() {
+ if (auto result{client.lock()}) {
+ return result;
+ }
+ return {};
+ }
+
+ std::shared_ptr<ServerSession> Server() {
+ if (auto result{server.lock()}) {
+ return result;
+ }
+ return {};
+ }
+
+private:
+ std::string name;
+ std::weak_ptr<ClientSession> client;
+ std::weak_ptr<ServerSession> server;
};
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index a815c4eea..afb2e3fc2 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -15,11 +15,12 @@ namespace Kernel {
SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {}
SharedMemory::~SharedMemory() = default;
-SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, u64 size,
- MemoryPermission permissions,
- MemoryPermission other_permissions, VAddr address,
- MemoryRegion region, std::string name) {
- SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
+std::shared_ptr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process,
+ u64 size, MemoryPermission permissions,
+ MemoryPermission other_permissions,
+ VAddr address, MemoryRegion region,
+ std::string name) {
+ std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel);
shared_memory->owner_process = owner_process;
shared_memory->name = std::move(name);
@@ -58,10 +59,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_
return shared_memory;
}
-SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
+std::shared_ptr<SharedMemory> SharedMemory::CreateForApplet(
KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset,
u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
- SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
+ std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel);
shared_memory->owner_process = nullptr;
shared_memory->name = std::move(name);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 01ca6dcd2..18400a5ad 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -33,6 +33,9 @@ enum class MemoryPermission : u32 {
class SharedMemory final : public Object {
public:
+ explicit SharedMemory(KernelCore& kernel);
+ ~SharedMemory() override;
+
/**
* Creates a shared memory object.
* @param kernel The kernel instance to create a shared memory instance under.
@@ -46,11 +49,12 @@ public:
* linear heap.
* @param name Optional object name, used for debugging purposes.
*/
- static SharedPtr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, u64 size,
- MemoryPermission permissions,
- MemoryPermission other_permissions, VAddr address = 0,
- MemoryRegion region = MemoryRegion::BASE,
- std::string name = "Unknown");
+ static std::shared_ptr<SharedMemory> Create(KernelCore& kernel, Process* owner_process,
+ u64 size, MemoryPermission permissions,
+ MemoryPermission other_permissions,
+ VAddr address = 0,
+ MemoryRegion region = MemoryRegion::BASE,
+ std::string name = "Unknown");
/**
* Creates a shared memory object from a block of memory managed by an HLE applet.
@@ -63,7 +67,7 @@ public:
* block.
* @param name Optional object name, used for debugging purposes.
*/
- static SharedPtr<SharedMemory> CreateForApplet(
+ static std::shared_ptr<SharedMemory> CreateForApplet(
KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset,
u64 size, MemoryPermission permissions, MemoryPermission other_permissions,
std::string name = "Unknown Applet");
@@ -130,9 +134,6 @@ public:
const u8* GetPointer(std::size_t offset = 0) const;
private:
- explicit SharedMemory(KernelCore& kernel);
- ~SharedMemory() override;
-
/// Backing memory for this shared memory block.
std::shared_ptr<PhysicalMemory> backing_block;
/// Offset into the backing block for this shared memory.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c63a9ba8b..bd25de478 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -17,6 +17,7 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
+#include "core/core_timing_util.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
@@ -331,7 +332,9 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
/// Connect to an OS service given the port name, returns the handle to the port to out
static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
VAddr port_name_address) {
- if (!Memory::IsValidVirtualAddress(port_name_address)) {
+ auto& memory = system.Memory();
+
+ if (!memory.IsValidVirtualAddress(port_name_address)) {
LOG_ERROR(Kernel_SVC,
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
port_name_address);
@@ -340,7 +343,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
static constexpr std::size_t PortNameMaxLength = 11;
// Read 1 char beyond the max allowed port name to detect names that are too long.
- std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
+ const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
if (port_name.size() > PortNameMaxLength) {
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
port_name.size());
@@ -358,7 +361,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
auto client_port = it->second;
- SharedPtr<ClientSession> client_session;
+ std::shared_ptr<ClientSession> client_session;
CASCADE_RESULT(client_session, client_port->Connect());
// Return the client session
@@ -370,7 +373,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
/// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle);
+ std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle);
if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
@@ -378,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
- system.PrepareReschedule();
+ auto thread = system.CurrentScheduler().GetCurrentThread();
+ thread->InvalidateWakeupCallback();
+ thread->SetStatus(ThreadStatus::WaitIPC);
+ system.PrepareReschedule(thread->GetProcessorID());
- // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
- // responds and cause a reschedule.
- return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread());
+ return session->SendSyncRequest(SharedFrom(thread), system.Memory());
}
/// Get the ID for the specified thread.
@@ -390,7 +394,7 @@ static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle threa
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+ const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
return ERR_INVALID_HANDLE;
@@ -405,13 +409,13 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const SharedPtr<Process> process = handle_table.Get<Process>(handle);
+ const std::shared_ptr<Process> process = handle_table.Get<Process>(handle);
if (process) {
*process_id = process->GetProcessID();
return RESULT_SUCCESS;
}
- const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
+ const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
if (thread) {
const Process* const owner_process = thread->GetOwnerProcess();
if (!owner_process) {
@@ -430,8 +434,8 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
}
/// Default thread wakeup callback for WaitSynchronization
-static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
- SharedPtr<WaitObject> object, std::size_t index) {
+static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+ std::shared_ptr<WaitObject> object, std::size_t index) {
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
if (reason == ThreadWakeupReason::Timeout) {
@@ -451,7 +455,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
handles_address, handle_count, nano_seconds);
- if (!Memory::IsValidVirtualAddress(handles_address)) {
+ auto& memory = system.Memory();
+ if (!memory.IsValidVirtualAddress(handles_address)) {
LOG_ERROR(Kernel_SVC,
"Handle address is not a valid virtual address, handle_address=0x{:016X}",
handles_address);
@@ -473,7 +478,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
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));
+ const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
const auto object = handle_table.Get<WaitObject>(handle);
if (object == nullptr) {
@@ -505,8 +510,13 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
return RESULT_TIMEOUT;
}
+ if (thread->IsSyncCancelled()) {
+ thread->SetSyncCancelled(false);
+ return ERR_SYNCHRONIZATION_CANCELED;
+ }
+
for (auto& object : objects) {
- object->AddWaitingThread(thread);
+ object->AddWaitingThread(SharedFrom(thread));
}
thread->SetWaitObjects(std::move(objects));
@@ -526,7 +536,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+ std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
thread_handle);
@@ -610,13 +620,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
return;
}
+ auto& memory = system.Memory();
+
// This typically is an error code so we're going to assume this is the case
if (sz == sizeof(u32)) {
- LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr));
+ LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
} else {
// We don't know what's in here so we'll hexdump it
debug_buffer.resize(sz);
- Memory::ReadBlock(addr, debug_buffer.data(), sz);
+ memory.ReadBlock(addr, debug_buffer.data(), sz);
std::string hexdump;
for (std::size_t i = 0; i < debug_buffer.size(); i++) {
hexdump += fmt::format("{:02X} ", debug_buffer[i]);
@@ -706,7 +718,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre
}
std::string str(len, '\0');
- Memory::ReadBlock(address, str.data(), str.size());
+ system.Memory().ReadBlock(address, str.data(), str.size());
LOG_DEBUG(Debug_Emulated, "{}", str);
}
@@ -935,7 +947,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
const auto& core_timing = system.CoreTiming();
const auto& scheduler = system.CurrentScheduler();
const auto* const current_thread = scheduler.GetCurrentThread();
- const bool same_thread = current_thread == thread;
+ const bool same_thread = current_thread == thread.get();
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
u64 out_ticks = 0;
@@ -1045,7 +1057,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act
}
const auto* current_process = system.Kernel().CurrentProcess();
- const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+ const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
@@ -1061,7 +1073,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act
return ERR_INVALID_HANDLE;
}
- if (thread == system.CurrentScheduler().GetCurrentThread()) {
+ if (thread.get() == system.CurrentScheduler().GetCurrentThread()) {
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
return ERR_BUSY;
}
@@ -1077,7 +1089,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
const auto* current_process = system.Kernel().CurrentProcess();
- const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+ const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
@@ -1093,7 +1105,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
return ERR_INVALID_HANDLE;
}
- if (thread == system.CurrentScheduler().GetCurrentThread()) {
+ if (thread.get() == system.CurrentScheduler().GetCurrentThread()) {
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
return ERR_BUSY;
}
@@ -1109,7 +1121,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
}
- Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
+ system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
return RESULT_SUCCESS;
}
@@ -1118,7 +1130,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle
LOG_TRACE(Kernel_SVC, "called");
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
+ const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
@@ -1142,7 +1154,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
const auto* const current_process = system.Kernel().CurrentProcess();
- SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+ std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
@@ -1262,27 +1274,28 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
VAddr address) {
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
+ std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle);
if (!process) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
return ERR_INVALID_HANDLE;
}
+ auto& memory = system.Memory();
const auto& vm_manager = process->VMManager();
const MemoryInfo memory_info = vm_manager.QueryMemory(address);
- Memory::Write64(memory_info_address, memory_info.base_address);
- Memory::Write64(memory_info_address + 8, memory_info.size);
- Memory::Write32(memory_info_address + 16, memory_info.state);
- Memory::Write32(memory_info_address + 20, memory_info.attributes);
- Memory::Write32(memory_info_address + 24, memory_info.permission);
- Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count);
- Memory::Write32(memory_info_address + 28, memory_info.device_ref_count);
- Memory::Write32(memory_info_address + 36, 0);
+ memory.Write64(memory_info_address, memory_info.base_address);
+ memory.Write64(memory_info_address + 8, memory_info.size);
+ memory.Write32(memory_info_address + 16, memory_info.state);
+ memory.Write32(memory_info_address + 20, memory_info.attributes);
+ memory.Write32(memory_info_address + 24, memory_info.permission);
+ memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count);
+ memory.Write32(memory_info_address + 28, memory_info.device_ref_count);
+ memory.Write32(memory_info_address + 36, 0);
// Page info appears to be currently unused by the kernel and is always set to zero.
- Memory::Write32(page_info_address, 0);
+ memory.Write32(page_info_address, 0);
return RESULT_SUCCESS;
}
@@ -1490,7 +1503,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
}
auto& kernel = system.Kernel();
- CASCADE_RESULT(SharedPtr<Thread> thread,
+ CASCADE_RESULT(std::shared_ptr<Thread> thread,
Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top,
*current_process));
@@ -1516,7 +1529,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+ const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
thread_handle);
@@ -1540,7 +1553,7 @@ static void ExitThread(Core::System& system) {
auto* const current_thread = system.CurrentScheduler().GetCurrentThread();
current_thread->Stop();
- system.GlobalScheduler().RemoveThread(current_thread);
+ system.GlobalScheduler().RemoveThread(SharedFrom(current_thread));
system.PrepareReschedule();
}
@@ -1612,7 +1625,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
auto* const current_process = system.Kernel().CurrentProcess();
const auto& handle_table = current_process->GetHandleTable();
- SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+ std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
ASSERT(thread);
const auto release_result = current_process->GetMutex().Release(mutex_addr);
@@ -1620,12 +1633,13 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
return release_result;
}
- SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread();
+ Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
current_thread->SetCondVarWaitAddress(condition_variable_addr);
current_thread->SetMutexWaitAddress(mutex_addr);
current_thread->SetWaitHandle(thread_handle);
current_thread->SetStatus(ThreadStatus::WaitCondVar);
current_thread->InvalidateWakeupCallback();
+ current_process->InsertConditionVariableThread(SharedFrom(current_thread));
current_thread->WakeAfterDelay(nano_seconds);
@@ -1644,42 +1658,28 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
// Retrieve a list of all threads that are waiting for this condition variable.
- std::vector<SharedPtr<Thread>> waiting_threads;
- const auto& scheduler = system.GlobalScheduler();
- const auto& thread_list = scheduler.GetThreadList();
-
- for (const auto& thread : thread_list) {
- if (thread->GetCondVarWaitAddress() == condition_variable_addr) {
- waiting_threads.push_back(thread);
- }
- }
-
- // Sort them by priority, such that the highest priority ones come first.
- std::sort(waiting_threads.begin(), waiting_threads.end(),
- [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
- return lhs->GetPriority() < rhs->GetPriority();
- });
+ auto* const current_process = system.Kernel().CurrentProcess();
+ std::vector<std::shared_ptr<Thread>> waiting_threads =
+ current_process->GetConditionVariableThreads(condition_variable_addr);
- // Only process up to 'target' threads, unless 'target' is -1, in which case process
+ // Only process up to 'target' threads, unless 'target' is less equal 0, in which case process
// them all.
std::size_t last = waiting_threads.size();
- if (target != -1)
+ if (target > 0)
last = std::min(waiting_threads.size(), static_cast<std::size_t>(target));
- // If there are no threads waiting on this condition variable, just exit
- if (last == 0)
- return RESULT_SUCCESS;
-
for (std::size_t index = 0; index < last; ++index) {
auto& thread = waiting_threads[index];
ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
// liberate Cond Var Thread.
+ current_process->RemoveConditionVariableThread(thread);
thread->SetCondVarWaitAddress(0);
const std::size_t current_core = system.CurrentCoreIndex();
auto& monitor = system.Monitor();
+ auto& memory = system.Memory();
// Atomically read the value of the mutex.
u32 mutex_val = 0;
@@ -1689,7 +1689,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
monitor.SetExclusive(current_core, mutex_address);
// If the mutex is not yet acquired, acquire it.
- mutex_val = Memory::Read32(mutex_address);
+ mutex_val = memory.Read32(mutex_address);
if (mutex_val != 0) {
update_val = mutex_val | Mutex::MutexHasWaitersFlag;
@@ -1786,7 +1786,9 @@ static u64 GetSystemTick(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called");
auto& core_timing = system.CoreTiming();
- const u64 result{core_timing.GetTicks()};
+
+ // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
+ const u64 result{Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks())};
// Advance time to defeat dumb games that busy-wait for the frame to end.
core_timing.AddTicks(400);
@@ -1975,7 +1977,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+ const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
thread_handle);
@@ -2034,7 +2036,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
}
const auto& handle_table = current_process->GetHandleTable();
- const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+ const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
thread_handle);
@@ -2290,12 +2292,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
return ERR_INVALID_ADDRESS_STATE;
}
+ auto& memory = system.Memory();
const auto& process_list = kernel.GetProcessList();
const auto num_processes = process_list.size();
const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
for (std::size_t i = 0; i < copy_amount; ++i) {
- Memory::Write64(out_process_ids, process_list[i]->GetProcessID());
+ memory.Write64(out_process_ids, process_list[i]->GetProcessID());
out_process_ids += sizeof(u64);
}
@@ -2329,13 +2332,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
return ERR_INVALID_ADDRESS_STATE;
}
+ auto& memory = system.Memory();
const auto& thread_list = current_process->GetThreadList();
const auto num_threads = thread_list.size();
const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
auto list_iter = thread_list.cbegin();
for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
- Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID());
+ memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
out_thread_ids += sizeof(u64);
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ee7531f2d..e84e5ce0d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -50,7 +50,7 @@ void Thread::Stop() {
// Clean up any dangling references in objects that this thread was waiting for
for (auto& wait_object : wait_objects) {
- wait_object->RemoveWaitingThread(this);
+ wait_object->RemoveWaitingThread(SharedFrom(this));
}
wait_objects.clear();
@@ -120,8 +120,11 @@ void Thread::ResumeFromWait() {
}
void Thread::CancelWait() {
- ASSERT(GetStatus() == ThreadStatus::WaitSynch);
- ClearWaitObjects();
+ if (GetSchedulingStatus() != ThreadSchedStatus::Paused) {
+ is_sync_cancelled = true;
+ return;
+ }
+ is_sync_cancelled = false;
SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
ResumeFromWait();
}
@@ -144,9 +147,10 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
context.fpcr = 0x03C00000;
}
-ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
- u32 priority, u64 arg, s32 processor_id,
- VAddr stack_top, Process& owner_process) {
+ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::string name,
+ VAddr entry_point, u32 priority, u64 arg,
+ s32 processor_id, VAddr stack_top,
+ Process& owner_process) {
// Check if priority is in ranged. Lowest priority -> highest priority id.
if (priority > THREADPRIO_LOWEST) {
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
@@ -158,14 +162,14 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
return ERR_INVALID_PROCESSOR_ID;
}
- if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
+ auto& system = Core::System::GetInstance();
+ if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) {
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
// TODO (bunnei): Find the correct error code to use here
return RESULT_UNKNOWN;
}
- auto& system = Core::System::GetInstance();
- SharedPtr<Thread> thread(new Thread(kernel));
+ std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel);
thread->thread_id = kernel.CreateNewThreadID();
thread->status = ThreadStatus::Dormant;
@@ -194,7 +198,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
// to initialize the context
ResetThreadContext(thread->context, stack_top, entry_point, arg);
- return MakeResult<SharedPtr<Thread>>(std::move(thread));
+ return MakeResult<std::shared_ptr<Thread>>(std::move(thread));
}
void Thread::SetPriority(u32 priority) {
@@ -212,7 +216,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output;
}
-s32 Thread::GetWaitObjectIndex(const WaitObject* object) const {
+s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const {
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
@@ -252,8 +256,8 @@ void Thread::SetStatus(ThreadStatus new_status) {
status = new_status;
}
-void Thread::AddMutexWaiter(SharedPtr<Thread> thread) {
- if (thread->lock_owner == this) {
+void Thread::AddMutexWaiter(std::shared_ptr<Thread> thread) {
+ if (thread->lock_owner.get() == this) {
// If the thread is already waiting for this thread to release the mutex, ensure that the
// waiters list is consistent and return without doing anything.
const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread);
@@ -273,13 +277,13 @@ void Thread::AddMutexWaiter(SharedPtr<Thread> thread) {
wait_mutex_threads.begin(), wait_mutex_threads.end(),
[&thread](const auto& entry) { return entry->GetPriority() > thread->GetPriority(); });
wait_mutex_threads.insert(insertion_point, thread);
- thread->lock_owner = this;
+ thread->lock_owner = SharedFrom(this);
UpdatePriority();
}
-void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) {
- ASSERT(thread->lock_owner == this);
+void Thread::RemoveMutexWaiter(std::shared_ptr<Thread> thread) {
+ ASSERT(thread->lock_owner.get() == this);
// Ensure that the thread is in the list of mutex waiters
const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread);
@@ -306,16 +310,24 @@ void Thread::UpdatePriority() {
return;
}
+ if (GetStatus() == ThreadStatus::WaitCondVar) {
+ owner_process->RemoveConditionVariableThread(SharedFrom(this));
+ }
+
SetCurrentPriority(new_priority);
+ if (GetStatus() == ThreadStatus::WaitCondVar) {
+ owner_process->InsertConditionVariableThread(SharedFrom(this));
+ }
+
if (!lock_owner) {
return;
}
// Ensure that the thread is within the correct location in the waiting list.
auto old_owner = lock_owner;
- lock_owner->RemoveMutexWaiter(this);
- old_owner->AddMutexWaiter(this);
+ lock_owner->RemoveMutexWaiter(SharedFrom(this));
+ old_owner->AddMutexWaiter(SharedFrom(this));
// Recursively update the priority of the thread that depends on the priority of this one.
lock_owner->UpdatePriority();
@@ -328,11 +340,11 @@ void Thread::ChangeCore(u32 core, u64 mask) {
bool Thread::AllWaitObjectsReady() const {
return std::none_of(
wait_objects.begin(), wait_objects.end(),
- [this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); });
+ [this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); });
}
-bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
- SharedPtr<WaitObject> object, std::size_t index) {
+bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+ std::shared_ptr<WaitObject> object, std::size_t index) {
ASSERT(wakeup_callback);
return wakeup_callback(reason, std::move(thread), std::move(object), index);
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index c9870873d..3bcf9e137 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -97,14 +97,18 @@ enum class ThreadSchedMasks : u32 {
class Thread final : public WaitObject {
public:
- using MutexWaitingThreads = std::vector<SharedPtr<Thread>>;
+ explicit Thread(KernelCore& kernel);
+ ~Thread() override;
+
+ using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>;
using ThreadContext = Core::ARM_Interface::ThreadContext;
- using ThreadWaitObjects = std::vector<SharedPtr<WaitObject>>;
+ using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>;
- using WakeupCallback = std::function<bool(ThreadWakeupReason reason, SharedPtr<Thread> thread,
- SharedPtr<WaitObject> object, std::size_t index)>;
+ using WakeupCallback =
+ std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+ std::shared_ptr<WaitObject> object, std::size_t index)>;
/**
* Creates and returns a new thread. The new thread is immediately scheduled
@@ -118,10 +122,10 @@ public:
* @param owner_process The parent process for the thread
* @return A shared pointer to the newly created thread
*/
- static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name,
- VAddr entry_point, u32 priority, u64 arg,
- s32 processor_id, VAddr stack_top,
- Process& owner_process);
+ static ResultVal<std::shared_ptr<Thread>> Create(KernelCore& kernel, std::string name,
+ VAddr entry_point, u32 priority, u64 arg,
+ s32 processor_id, VAddr stack_top,
+ Process& owner_process);
std::string GetName() const override {
return name;
@@ -166,10 +170,10 @@ public:
void SetPriority(u32 priority);
/// Adds a thread to the list of threads that are waiting for a lock held by this thread.
- void AddMutexWaiter(SharedPtr<Thread> thread);
+ void AddMutexWaiter(std::shared_ptr<Thread> thread);
/// Removes a thread from the list of threads that are waiting for a lock held by this thread.
- void RemoveMutexWaiter(SharedPtr<Thread> thread);
+ void RemoveMutexWaiter(std::shared_ptr<Thread> thread);
/// Recalculates the current priority taking into account priority inheritance.
void UpdatePriority();
@@ -229,7 +233,7 @@ public:
*
* @param object Object to query the index of.
*/
- s32 GetWaitObjectIndex(const WaitObject* object) const;
+ s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const;
/**
* Stops a thread, invalidating it from further use
@@ -320,7 +324,7 @@ public:
void ClearWaitObjects() {
for (const auto& waiting_object : wait_objects) {
- waiting_object->RemoveWaitingThread(this);
+ waiting_object->RemoveWaitingThread(SharedFrom(this));
}
wait_objects.clear();
}
@@ -336,7 +340,7 @@ public:
return lock_owner.get();
}
- void SetLockOwner(SharedPtr<Thread> owner) {
+ void SetLockOwner(std::shared_ptr<Thread> owner) {
lock_owner = std::move(owner);
}
@@ -390,8 +394,8 @@ public:
* @pre A valid wakeup callback has been set. Violating this precondition
* will cause an assertion to trigger.
*/
- bool InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
- SharedPtr<WaitObject> object, std::size_t index);
+ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+ std::shared_ptr<WaitObject> object, std::size_t index);
u32 GetIdealCore() const {
return ideal_core;
@@ -440,10 +444,15 @@ public:
is_running = value;
}
-private:
- explicit Thread(KernelCore& kernel);
- ~Thread() override;
+ bool IsSyncCancelled() const {
+ return is_sync_cancelled;
+ }
+ void SetSyncCancelled(bool value) {
+ is_sync_cancelled = value;
+ }
+
+private:
void SetSchedulingStatus(ThreadSchedStatus new_status);
void SetCurrentPriority(u32 new_priority);
ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask);
@@ -491,7 +500,7 @@ private:
MutexWaitingThreads wait_mutex_threads;
/// Thread that owns the lock that this thread is waiting for.
- SharedPtr<Thread> lock_owner;
+ std::shared_ptr<Thread> lock_owner;
/// If waiting on a ConditionVariable, this is the ConditionVariable address
VAddr condvar_wait_address = 0;
@@ -524,6 +533,7 @@ private:
u32 scheduling_state = 0;
bool is_running = false;
+ bool is_sync_cancelled = false;
std::string name;
};
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp
index 1113c815e..f0e73f57b 100644
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ b/src/core/hle/kernel/transfer_memory.cpp
@@ -14,9 +14,9 @@ namespace Kernel {
TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
TransferMemory::~TransferMemory() = default;
-SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size,
- MemoryPermission permissions) {
- SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)};
+std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
+ u64 size, MemoryPermission permissions) {
+ std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)};
transfer_memory->base_address = base_address;
transfer_memory->memory_size = size;
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
index 6be9dc094..556e6c62b 100644
--- a/src/core/hle/kernel/transfer_memory.h
+++ b/src/core/hle/kernel/transfer_memory.h
@@ -27,10 +27,13 @@ enum class MemoryPermission : u32;
///
class TransferMemory final : public Object {
public:
+ explicit TransferMemory(KernelCore& kernel);
+ ~TransferMemory() override;
+
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
- static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
- MemoryPermission permissions);
+ static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
+ MemoryPermission permissions);
TransferMemory(const TransferMemory&) = delete;
TransferMemory& operator=(const TransferMemory&) = delete;
@@ -79,9 +82,6 @@ public:
ResultCode UnmapMemory(VAddr address, u64 size);
private:
- explicit TransferMemory(KernelCore& kernel);
- ~TransferMemory() override;
-
/// Memory block backing this instance.
std::shared_ptr<PhysicalMemory> backing_block;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index e6eee09d7..a9a20ef76 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -16,7 +16,6 @@
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
-#include "core/memory_setup.h"
namespace Kernel {
namespace {
@@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
}
void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
+ auto& memory = system.Memory();
+
switch (vma.type) {
case VMAType::Free:
- Memory::UnmapRegion(page_table, vma.base, vma.size);
+ memory.UnmapRegion(page_table, vma.base, vma.size);
break;
case VMAType::AllocatedMemoryBlock:
- Memory::MapMemoryRegion(page_table, vma.base, vma.size,
- vma.backing_block->data() + vma.offset);
+ memory.MapMemoryRegion(page_table, vma.base, vma.size,
+ vma.backing_block->data() + vma.offset);
break;
case VMAType::BackingMemory:
- Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
+ memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
break;
case VMAType::MMIO:
- Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
+ memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
break;
}
}
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index c00cef062..745f2c4e8 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -18,13 +18,13 @@ namespace Kernel {
WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {}
WaitObject::~WaitObject() = default;
-void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
+void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
if (itr == waiting_threads.end())
waiting_threads.push_back(std::move(thread));
}
-void WaitObject::RemoveWaitingThread(Thread* thread) {
+void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
// If a thread passed multiple handles to the same object,
// the kernel might attempt to remove the thread from the object's
@@ -33,7 +33,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
waiting_threads.erase(itr);
}
-SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
+std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
Thread* candidate = nullptr;
u32 candidate_priority = THREADPRIO_LOWEST + 1;
@@ -64,10 +64,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
}
}
- return candidate;
+ return SharedFrom(candidate);
}
-void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
+void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
ASSERT(!ShouldWait(thread.get()));
if (!thread) {
@@ -83,7 +83,7 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
Acquire(thread.get());
}
- const std::size_t index = thread->GetWaitObjectIndex(this);
+ const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this));
thread->ClearWaitObjects();
@@ -91,7 +91,8 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
bool resume = true;
if (thread->HasWakeupCallback()) {
- resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index);
+ resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this),
+ index);
}
if (resume) {
thread->ResumeFromWait();
@@ -105,7 +106,7 @@ void WaitObject::WakeupAllWaitingThreads() {
}
}
-const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
+const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const {
return waiting_threads;
}
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index 3271a30a7..f9d596db9 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -33,13 +33,13 @@ public:
* Add a thread to wait on this object
* @param thread Pointer to thread to add
*/
- void AddWaitingThread(SharedPtr<Thread> thread);
+ void AddWaitingThread(std::shared_ptr<Thread> thread);
/**
* Removes a thread from waiting on this object (e.g. if it was resumed already)
* @param thread Pointer to thread to remove
*/
- void RemoveWaitingThread(Thread* thread);
+ void RemoveWaitingThread(std::shared_ptr<Thread> thread);
/**
* Wake up all threads waiting on this object that can be awoken, in priority order,
@@ -51,24 +51,24 @@ public:
* Wakes up a single thread waiting on this object.
* @param thread Thread that is waiting on this object to wakeup.
*/
- void WakeupWaitingThread(SharedPtr<Thread> thread);
+ void WakeupWaitingThread(std::shared_ptr<Thread> thread);
/// Obtains the highest priority thread that is ready to run from this object's waiting list.
- SharedPtr<Thread> GetHighestPriorityReadyThread() const;
+ std::shared_ptr<Thread> GetHighestPriorityReadyThread() const;
/// Get a const reference to the waiting threads list for debug use
- const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
+ const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
private:
/// Threads waiting for this object to become available
- std::vector<SharedPtr<Thread>> waiting_threads;
+ std::vector<std::shared_ptr<Thread>> waiting_threads;
};
// Specialization of DynamicObjectCast for WaitObjects
template <>
-inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
+inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) {
if (object != nullptr && object->IsWaitable()) {
- return boost::static_pointer_cast<WaitObject>(object);
+ return std::static_pointer_cast<WaitObject>(object);
}
return nullptr;
}
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
index c783a34ee..c9332e3e1 100644
--- a/src/core/hle/kernel/writable_event.cpp
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -16,8 +16,8 @@ WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
WritableEvent::~WritableEvent() = default;
EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
- SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
- SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
+ std::shared_ptr<WritableEvent> writable_event(new WritableEvent(kernel));
+ std::shared_ptr<ReadableEvent> readable_event(new ReadableEvent(kernel));
writable_event->name = name + ":Writable";
writable_event->readable = readable_event;
@@ -27,7 +27,7 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
return {std::move(readable_event), std::move(writable_event)};
}
-SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
+std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const {
return readable;
}
diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h
index f46cf1dd8..afe97f3a9 100644
--- a/src/core/hle/kernel/writable_event.h
+++ b/src/core/hle/kernel/writable_event.h
@@ -13,8 +13,8 @@ class ReadableEvent;
class WritableEvent;
struct EventPair {
- SharedPtr<ReadableEvent> readable;
- SharedPtr<WritableEvent> writable;
+ std::shared_ptr<ReadableEvent> readable;
+ std::shared_ptr<WritableEvent> writable;
};
class WritableEvent final : public Object {
@@ -40,7 +40,7 @@ public:
return HANDLE_TYPE;
}
- SharedPtr<ReadableEvent> GetReadableEvent() const;
+ std::shared_ptr<ReadableEvent> GetReadableEvent() const;
void Signal();
void Clear();
@@ -49,7 +49,7 @@ public:
private:
explicit WritableEvent(KernelCore& kernel);
- SharedPtr<ReadableEvent> readable;
+ std::shared_ptr<ReadableEvent> readable;
std::string name; ///< Name of event (optional)
};
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 0d1663657..b941c260b 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -28,6 +28,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
{104, nullptr, "GetProfileUpdateNotifier"},
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
+ {106, nullptr, "GetProfileSyncNotifier"},
{110, nullptr, "StoreSaveDataThumbnail"},
{111, nullptr, "ClearSaveDataThumbnail"},
{112, nullptr, "LoadSaveDataThumbnail"},
@@ -44,6 +45,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
{206, nullptr, "CompleteUserRegistrationForcibly"},
{210, nullptr, "CreateFloatingRegistrationRequest"},
+ {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
+ {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
{230, nullptr, "AuthenticateServiceAsync"},
{250, nullptr, "GetBaasAccountAdministrator"},
{290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index 6520b3968..858e91dde 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -28,6 +28,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{103, nullptr, "GetProfileUpdateNotifier"},
{104, nullptr, "CheckNetworkServiceAvailabilityAsync"},
{105, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
+ {106, nullptr, "GetProfileSyncNotifier"},
{110, nullptr, "StoreSaveDataThumbnail"},
{111, nullptr, "ClearSaveDataThumbnail"},
{112, nullptr, "LoadSaveDataThumbnail"},
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a5702e1ab..95aa5d23d 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -229,7 +229,15 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
{20, nullptr, "InvalidateTransitionLayer"},
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
{40, nullptr, "GetAppletResourceUsageInfo"},
- {41, nullptr, "SetCpuBoostModeForApplet"},
+ {100, nullptr, "SetCpuBoostModeForApplet"},
+ {110, nullptr, "PushToAppletBoundChannelForDebug"},
+ {111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
+ {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
+ {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
+ {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
+ {130, nullptr, "FriendInvitationSetApplicationParameter"},
+ {131, nullptr, "FriendInvitationClearApplicationParameter"},
+ {132, nullptr, "FriendInvitationPushApplicationParameter"},
};
// clang-format on
@@ -278,10 +286,12 @@ ISelfController::ISelfController(Core::System& system,
{69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
{70, nullptr, "ReportMultimediaError"},
{71, nullptr, "GetCurrentIlluminanceEx"},
+ {72, nullptr, "SetInputDetectionPolicy"},
{80, nullptr, "SetWirelessPriorityMode"},
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
{100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
+ {110, nullptr, "SetApplicationAlbumUserData"},
{1000, nullptr, "GetDebugStorageChannel"},
};
// clang-format on
@@ -531,12 +541,11 @@ AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
AppletMessageQueue::~AppletMessageQueue() = default;
-const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
- const {
+const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() const {
return on_new_message.readable;
}
-const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
+const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
const {
return on_operation_mode_changed.readable;
}
@@ -613,6 +622,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system,
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
{200, nullptr, "GetOperationModeSystemInfo"},
+ {300, nullptr, "GetSettingsPlatformRegion"},
};
// clang-format on
@@ -1076,12 +1086,18 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
{101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
- {110, nullptr, "QueryApplicationPlayStatistics"},
+ {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
{120, nullptr, "ExecuteProgram"},
{121, nullptr, "ClearUserChannel"},
{122, nullptr, "UnpopToUserChannel"},
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
+ {140, nullptr, "GetFriendInvitationStorageChannelEvent"},
+ {141, nullptr, "TryPopFromFriendInvitationStorageChannel"},
+ {150, nullptr, "GetNotificationStorageChannelEvent"},
+ {151, nullptr, "TryPopFromNotificationStorageChannel"},
+ {160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
+ {170, nullptr, "SetHdcpAuthenticationActivated"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},
@@ -1336,12 +1352,16 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
}
void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
+ struct Parameters {
+ FileSys::SaveDataType type;
+ u128 user_id;
+ u64 new_normal_size;
+ u64 new_journal_size;
+ };
+ static_assert(sizeof(Parameters) == 40);
+
IPC::RequestParser rp{ctx};
- const auto type{rp.PopRaw<FileSys::SaveDataType>()};
- rp.Skip(1, false);
- const auto user_id{rp.PopRaw<u128>()};
- const auto new_normal_size{rp.PopRaw<u64>()};
- const auto new_journal_size{rp.PopRaw<u64>()};
+ const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AM,
"called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
@@ -1360,10 +1380,14 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
}
void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
+ struct Parameters {
+ FileSys::SaveDataType type;
+ u128 user_id;
+ };
+ static_assert(sizeof(Parameters) == 24);
+
IPC::RequestParser rp{ctx};
- const auto type{rp.PopRaw<FileSys::SaveDataType>()};
- rp.Skip(1, false);
- const auto user_id{rp.PopRaw<u128>()};
+ const auto [type, user_id] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
user_id[1], user_id[0]);
@@ -1377,12 +1401,12 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
rb.Push(size.journal);
}
-void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(gpu_error_detected_event.readable);
+ rb.Push<u32>(0);
}
void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx) {
@@ -1393,6 +1417,14 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
rb.Push<u32>(0);
}
+void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(gpu_error_detected_event.readable);
+}
+
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
@@ -1418,6 +1450,8 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
+ {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
+ {200, nullptr, "LaunchDevMenu"},
};
// clang-format on
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index f64013ea0..448817be9 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -54,8 +54,8 @@ public:
explicit AppletMessageQueue(Kernel::KernelCore& kernel);
~AppletMessageQueue();
- const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
- const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
+ const std::shared_ptr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
+ const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
@@ -255,8 +255,9 @@ private:
void InitializeApplicationCopyrightFrameBuffer(Kernel::HLERequestContext& ctx);
void SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx);
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
- void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
+ void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
+ void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
bool launch_popped_application_specific = false;
bool launch_popped_account_preselect = false;
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 673ad1f7f..92f995f8f 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -108,15 +108,15 @@ void AppletDataBroker::SignalStateChanged() const {
state_changed_event.writable->Signal();
}
-Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
+std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
return pop_out_data_event.readable;
}
-Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
+std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
return pop_interactive_out_data_event.readable;
}
-Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
+std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
return state_changed_event.readable;
}
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 226be88b1..16e61fc6f 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -86,9 +86,9 @@ public:
void SignalStateChanged() const;
- Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
- Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
- Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
+ std::shared_ptr<Kernel::ReadableEvent> GetNormalDataEvent() const;
+ std::shared_ptr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
+ std::shared_ptr<Kernel::ReadableEvent> GetStateChangedEvent() const;
private:
// Queues are named from applet's perspective
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp
index f814fe2c0..d256d57c8 100644
--- a/src/core/hle/service/am/idle.cpp
+++ b/src/core/hle/service/am/idle.cpp
@@ -10,7 +10,7 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAutoPowerDownEvent"},
- {1, nullptr, "Unknown1"},
+ {1, nullptr, "IsAutoPowerDownRequested"},
{2, nullptr, "Unknown2"},
{3, nullptr, "SetHandlingContext"},
{4, nullptr, "LoadAndApplySettings"},
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp
index 6ab3fb906..37389ccda 100644
--- a/src/core/hle/service/am/omm.cpp
+++ b/src/core/hle/service/am/omm.cpp
@@ -35,6 +35,8 @@ OMM::OMM() : ServiceFramework{"omm"} {
{23, nullptr, "GetHdcpState"},
{24, nullptr, "ShowCardUpdateProcessing"},
{25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"},
+ {26, nullptr, "GetOperationModeSystemInfo"},
+ {27, nullptr, "GetAppletFullAwakingSystemEvent"},
};
// clang-format on
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 30076a53e..4227a4adf 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -61,6 +61,7 @@ AOC_U::AOC_U(Core::System& system)
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{100, nullptr, "CreateEcPurchasedEventManager"},
+ {101, nullptr, "CreatePermanentEcPurchasedEventManager"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
index 6a01d4d29..9e08e5346 100644
--- a/src/core/hle/service/audio/audctl.cpp
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -38,6 +38,7 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} {
{24, nullptr, "GetSystemOutputMasterVolume"},
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
{26, nullptr, "UpdateHeadphoneSettings"},
+ {27, nullptr, "SetVolumeMappingTableForDev"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 6a29377e3..4fb2cbc4b 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -43,7 +43,8 @@ public:
IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core,
std::string&& device_name, std::string&& unique_name)
: ServiceFramework("IAudioOut"), audio_core(audio_core),
- device_name(std::move(device_name)), audio_params(audio_params) {
+ device_name(std::move(device_name)),
+ audio_params(audio_params), main_memory{system.Memory()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -137,7 +138,7 @@ private:
const u64 tag{rp.Pop<u64>()};
std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
- Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
+ main_memory.ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -209,6 +210,7 @@ private:
/// This is the event handle used to check if the audio buffer was released
Kernel::EventPair buffer_event;
+ Memory::Memory& main_memory;
};
AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 4ea7ade6e..82a5dbf14 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -49,8 +49,9 @@ public:
system_event =
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
- renderer = std::make_unique<AudioCore::AudioRenderer>(
- system.CoreTiming(), audren_params, system_event.writable, instance_number);
+ renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
+ audren_params, system_event.writable,
+ instance_number);
}
private:
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index dec0849b8..6f5ea095a 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -16,7 +16,7 @@ ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel,
kernel, std::string("ProgressServiceBackend:UpdateEvent:").append(event_name));
}
-Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const {
+std::shared_ptr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const {
return event.readable;
}
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h
index ea4b16ad0..48bbbe66f 100644
--- a/src/core/hle/service/bcat/backend/backend.h
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -98,7 +98,7 @@ public:
private:
explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name);
- Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent() const;
+ std::shared_ptr<Kernel::ReadableEvent> GetEvent() const;
DeliveryCacheProgressImpl& GetImpl();
void SignalUpdate() const;
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 8a7304f86..7ada67130 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -87,7 +87,7 @@ struct DeliveryCacheDirectoryEntry {
class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
public:
- IDeliveryCacheProgressService(Kernel::SharedPtr<Kernel::ReadableEvent> event,
+ IDeliveryCacheProgressService(std::shared_ptr<Kernel::ReadableEvent> event,
const DeliveryCacheProgressImpl& impl)
: ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) {
// clang-format off
@@ -118,7 +118,7 @@ private:
rb.Push(RESULT_SUCCESS);
}
- Kernel::SharedPtr<Kernel::ReadableEvent> event;
+ std::shared_ptr<Kernel::ReadableEvent> event;
const DeliveryCacheProgressImpl& impl;
};
@@ -137,14 +137,20 @@ public:
{10200, nullptr, "CancelSyncDeliveryCacheRequest"},
{20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
{20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
+ {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"},
+ {20301, nullptr, "RequestSuspendDeliveryTask"},
+ {20400, nullptr, "RegisterSystemApplicationDeliveryTask"},
+ {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
{30100, &IBcatService::SetPassphrase, "SetPassphrase"},
{30200, nullptr, "RegisterBackgroundDeliveryTask"},
{30201, nullptr, "UnregisterBackgroundDeliveryTask"},
{30202, nullptr, "BlockDeliveryTask"},
{30203, nullptr, "UnblockDeliveryTask"},
+ {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
{90200, nullptr, "GetDeliveryList"},
{90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"},
+ {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
{90300, nullptr, "GetPushNotificationLog"},
};
// clang-format on
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 4574d9572..40a06c9fd 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -155,6 +155,7 @@ public:
{98, nullptr, "SetLeScanParameter"},
{256, nullptr, "GetIsManufacturingMode"},
{257, nullptr, "EmulateBluetoothCrash"},
+ {258, nullptr, "GetBleChannelMap"},
};
// clang-format on
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index d9b32954e..4ec8c3093 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -24,6 +24,8 @@ public:
{6, nullptr, "SubmitMultipleCategoryContext"},
{7, nullptr, "UpdateApplicationLaunchTime"},
{8, nullptr, "ClearApplicationLaunchTime"},
+ {9, nullptr, "SubmitAttachment"},
+ {10, nullptr, "CreateReportWithAttachments"},
};
// clang-format on
@@ -38,6 +40,7 @@ public:
static const FunctionInfo functions[] = {
{0, nullptr, "OpenReport"},
{1, nullptr, "OpenManager"},
+ {2, nullptr, "OpenAttachment"},
};
// clang-format on
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index f77ddd739..df00ae625 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -52,6 +52,8 @@ public:
{34, nullptr, "GetEncryptedTicketSize"},
{35, nullptr, "GetEncryptedTicketData"},
{36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"},
+ {37, nullptr, "OwnTicket2"},
+ {38, nullptr, "OwnTicket3"},
{503, nullptr, "GetTitleKey"},
};
// clang-format on
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 92162d3e1..55d62fc5e 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -256,8 +256,8 @@ public:
// TODO(DarkLordZach): Verify that this is the correct behavior.
// Build entry index now to save time later.
- BuildEntryIndex(entries, backend->GetFiles(), FileSys::File);
- BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::Directory);
+ BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
+ BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
}
private:
@@ -391,13 +391,10 @@ public:
}
void RenameFile(Kernel::HLERequestContext& ctx) {
- std::vector<u8> buffer;
- buffer.resize(ctx.BufferDescriptorX()[0].Size());
- Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
+ std::vector<u8> buffer = ctx.ReadBuffer(0);
const std::string src_name = Common::StringFromBuffer(buffer);
- buffer.resize(ctx.BufferDescriptorX()[1].Size());
- Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size());
+ buffer = ctx.ReadBuffer(1);
const std::string dst_name = Common::StringFromBuffer(buffer);
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
@@ -680,6 +677,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
{33, nullptr, "DeleteCacheStorage"},
{34, nullptr, "GetCacheStorageSize"},
{35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
+ {36, nullptr, "OpenHostFileSystemWithOption"},
{51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
{52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"},
{53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
@@ -694,11 +692,14 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
{67, nullptr, "FindSaveDataWithFilter"},
{68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
+ {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
+ {70, nullptr, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
{80, nullptr, "OpenSaveDataMetaFile"},
{81, nullptr, "OpenSaveDataTransferManager"},
{82, nullptr, "OpenSaveDataTransferManagerVersion2"},
{83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
{84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
+ {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
{100, nullptr, "OpenImageDirectoryFileSystem"},
{110, nullptr, "OpenContentStorageFileSystem"},
{120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
@@ -756,6 +757,8 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1010, nullptr, "SetDataStorageRedirectTarget"},
{1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},
+ {1012, nullptr, "GetFsStackUsage"},
+ {1013, nullptr, "UnsetSaveDataRootPath"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
{1200, nullptr, "OpenMultiCommitManager"},
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 1a0214f08..219176c31 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -60,6 +60,9 @@ public:
{20801, nullptr, "SyncUserSetting"},
{20900, nullptr, "RequestListSummaryOverlayNotification"},
{21000, nullptr, "GetExternalApplicationCatalog"},
+ {22000, nullptr, "GetReceivedFriendInvitationList"},
+ {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"},
+ {22010, nullptr, "GetReceivedFriendInvitationCountCache"},
{30100, nullptr, "DropFriendNewlyFlags"},
{30101, nullptr, "DeleteFriend"},
{30110, nullptr, "DropFriendNewlyFlag"},
@@ -91,6 +94,8 @@ public:
{30812, nullptr, "ChangePlayLogPermission"},
{30820, nullptr, "IssueFriendCode"},
{30830, nullptr, "ClearPlayLog"},
+ {30900, nullptr, "SendFriendInvitation"},
+ {30910, nullptr, "ReadFriendInvitation"},
{49900, nullptr, "DeleteNetworkServiceAccountCache"},
};
// clang-format on
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 79fff517e..4d952adc0 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -501,8 +501,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
last_processed_vibration = vibrations.back();
}
-Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(
- u32 npad_id) const {
+std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
// TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
// be signalled at least once, and signaled after a new controller is connected?
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 16c4caa1f..931f03430 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -109,7 +109,7 @@ public:
void VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations);
- Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
+ std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ecc130f6c..89bf8b815 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -77,15 +77,14 @@ IAppletResource::IAppletResource(Core::System& system)
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
// Register update callbacks
- auto& core_timing = system.CoreTiming();
pad_update_event =
- core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
+ Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
UpdateControllers(userdata, cycles_late);
});
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
- core_timing.ScheduleEvent(pad_update_ticks, pad_update_event);
+ system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event);
ReloadInputDevices();
}
@@ -215,6 +214,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
{134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
+ {135, nullptr, "SetNpadCaptureButtonAssignment"},
+ {136, nullptr, "ClearNpadCaptureButtonAssignment"},
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
{201, &Hid::SendVibrationValue, "SendVibrationValue"},
{202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
@@ -245,6 +246,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{404, nullptr, "HasLeftRightBattery"},
{405, nullptr, "GetNpadInterfaceType"},
{406, nullptr, "GetNpadLeftRightInterfaceType"},
+ {407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"},
+ {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
{500, nullptr, "GetPalmaConnectionHandle"},
{501, nullptr, "InitializePalma"},
{502, nullptr, "AcquirePalmaOperationCompleteEvent"},
@@ -272,8 +275,13 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{524, nullptr, "PairPalma"},
{525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
{526, nullptr, "CancelWritePalmaWaveEntry"},
+ {527, nullptr, "EnablePalmaBoostMode"},
+ {528, nullptr, "GetPalmaBluetoothAddress"},
+ {529, nullptr, "SetDisallowedPalmaConnection"},
{1000, nullptr, "SetNpadCommunicationMode"},
{1001, nullptr, "GetNpadCommunicationMode"},
+ {1002, nullptr, "SetTouchScreenConfiguration"},
+ {1003, nullptr, "IsFirmwareUpdateNeededForNotification"},
};
// clang-format on
@@ -969,6 +977,9 @@ public:
{310, nullptr, "GetMaskedSupportedNpadStyleSet"},
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
{312, nullptr, "SetSupportedNpadStyleSetAll"},
+ {313, nullptr, "GetNpadCaptureButtonAssignment"},
+ {314, nullptr, "GetAppletFooterUiType"},
+ {315, nullptr, "GetAppletDetailedUiType"},
{321, nullptr, "GetUniquePadsFromNpad"},
{322, nullptr, "GetIrSensorState"},
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
@@ -984,6 +995,8 @@ public:
{513, nullptr, "EndPermitVibrationSession"},
{520, nullptr, "EnableHandheldHids"},
{521, nullptr, "DisableHandheldHids"},
+ {522, nullptr, "SetJoyConRailEnabled"},
+ {523, nullptr, "IsJoyConRailEnabled"},
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
{541, nullptr, "GetPlayReportControllerUsages"},
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@@ -1010,6 +1023,7 @@ public:
{809, nullptr, "GetUniquePadSerialNumber"},
{810, nullptr, "GetUniquePadControllerNumber"},
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
+ {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
{821, nullptr, "StartAnalogStickManualCalibration"},
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
{823, nullptr, "CancelAnalogStickManualCalibration"},
@@ -1020,6 +1034,8 @@ public:
{828, nullptr, "IsAnalogStickInReleasePosition"},
{829, nullptr, "IsAnalogStickInCircumference"},
{830, nullptr, "SetNotificationLedPattern"},
+ {831, nullptr, "SetNotificationLedPatternWithTimeout"},
+ {832, nullptr, "PrepareHidsForNotificationWake"},
{850, nullptr, "IsUsbFullKeyControllerEnabled"},
{851, nullptr, "EnableUsbFullKeyController"},
{852, nullptr, "IsUsbConnected"},
@@ -1049,6 +1065,13 @@ public:
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
{1133, nullptr, "StartUsbFirmwareUpdate"},
{1134, nullptr, "GetUsbFirmwareUpdateState"},
+ {1150, nullptr, "SetTouchScreenMagnification"},
+ {1151, nullptr, "GetTouchScreenFirmwareVersion"},
+ {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
+ {1153, nullptr, "GetTouchScreenDefaultConfiguration"},
+ {1154, nullptr, "IsFirmwareAvailableForNotification"},
+ {1155, nullptr, "SetForceHandheldStyleVibration"},
+ {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
};
// clang-format on
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index f08e036a3..ad20f147c 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -67,9 +67,9 @@ private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(u64 userdata, s64 cycles_late);
- Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
+ std::shared_ptr<Kernel::SharedMemory> shared_mem;
- Core::Timing::EventType* pad_update_event;
+ std::shared_ptr<Core::Timing::EventType> pad_update_event;
Core::System& system;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index eb4e898dd..8918ad6ca 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -37,7 +37,7 @@ private:
void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
- Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
+ std::shared_ptr<Kernel::SharedMemory> shared_mem;
const u32 device_handle{0xABCD};
Core::System& system;
};
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 88f903bfd..157aeec88 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -140,9 +140,10 @@ public:
rb.Push(ERROR_INVALID_SIZE);
return;
}
+
// Read NRR data from memory
std::vector<u8> nrr_data(nrr_size);
- Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size);
+ system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
NRRHeader header;
std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
@@ -291,7 +292,7 @@ public:
// Read NRO data from memory
std::vector<u8> nro_data(nro_size);
- Memory::ReadBlock(nro_address, nro_data.data(), nro_size);
+ system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size);
SHA256Hash hash{};
mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 435f2d286..346c8f899 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -17,7 +17,8 @@ namespace Service::LM {
class ILogger final : public ServiceFramework<ILogger> {
public:
- ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) {
+ explicit ILogger(Manager& manager_, Memory::Memory& memory_)
+ : ServiceFramework("ILogger"), manager{manager_}, memory{memory_} {
static const FunctionInfo functions[] = {
{0, &ILogger::Log, "Log"},
{1, &ILogger::SetDestination, "SetDestination"},
@@ -35,15 +36,15 @@ private:
MessageHeader header{};
VAddr addr{ctx.BufferDescriptorX()[0].Address()};
const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
- Memory::ReadBlock(addr, &header, sizeof(MessageHeader));
+ memory.ReadBlock(addr, &header, sizeof(MessageHeader));
addr += sizeof(MessageHeader);
FieldMap fields;
while (addr < end_addr) {
- const auto field = static_cast<Field>(Memory::Read8(addr++));
- const auto length = Memory::Read8(addr++);
+ const auto field = static_cast<Field>(memory.Read8(addr++));
+ const auto length = memory.Read8(addr++);
- if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
+ if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) {
++addr;
}
@@ -54,7 +55,7 @@ private:
}
std::vector<u8> data(length);
- Memory::ReadBlock(addr, data.data(), length);
+ memory.ReadBlock(addr, data.data(), length);
fields.emplace(field, std::move(data));
}
@@ -74,11 +75,13 @@ private:
}
Manager& manager;
+ Memory::Memory& memory;
};
class LM final : public ServiceFramework<LM> {
public:
- explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) {
+ explicit LM(Manager& manager_, Memory::Memory& memory_)
+ : ServiceFramework{"lm"}, manager{manager_}, memory{memory_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LM::OpenLogger, "OpenLogger"},
@@ -94,14 +97,16 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILogger>(manager);
+ rb.PushIpcInterface<ILogger>(manager, memory);
}
Manager& manager;
+ Memory::Memory& memory;
};
void InstallInterfaces(Core::System& system) {
- std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager());
+ std::make_shared<LM>(system.GetLogManager(), system.Memory())
+ ->InstallAsService(system.ServiceManager());
}
} // namespace Service::LM
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 0ffc5009e..a128edb43 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -50,6 +50,8 @@ public:
{21, &IDatabaseService::GetIndex, "GetIndex"},
{22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
{23, nullptr, "Convert"},
+ {24, nullptr, "ConvertCoreDataToCharInfo"},
+ {25, nullptr, "ConvertCharInfoToCoreData"},
};
// clang-format on
diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp
index b405a4b66..89e283ca5 100644
--- a/src/core/hle/service/ncm/ncm.cpp
+++ b/src/core/hle/service/ncm/ncm.cpp
@@ -61,7 +61,8 @@ public:
{5, nullptr, "RegisterHtmlDocumentPath"},
{6, nullptr, "UnregisterHtmlDocumentPath"},
{7, nullptr, "RedirectHtmlDocumentPath"},
- {8, nullptr, ""},
+ {8, nullptr, "Refresh"},
+ {9, nullptr, "RefreshExcluding"},
};
// clang-format on
@@ -77,6 +78,8 @@ public:
{0, nullptr, "ResolveAddOnContentPath"},
{1, nullptr, "RegisterAddOnContentStorage"},
{2, nullptr, "UnregisterAllAddOnContentPath"},
+ {3, nullptr, "RefreshApplicationAddOnContent"},
+ {4, nullptr, "UnregisterApplicationAddOnContent"},
};
// clang-format on
@@ -118,6 +121,7 @@ public:
{10, nullptr, "InactivateContentStorage"},
{11, nullptr, "ActivateContentMetaDatabase"},
{12, nullptr, "InactivateContentMetaDatabase"},
+ {13, nullptr, "InvalidateRightsIdCache"},
};
// clang-format on
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index ca88bf97f..b7b34ce7e 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -215,6 +215,7 @@ public:
{411, nullptr, "AttachActivateEvent"},
{412, nullptr, "AttachDeactivateEvent"},
{500, nullptr, "SetNfcEnabled"},
+ {510, nullptr, "OutputTestWave"},
{1000, nullptr, "ReadMifare"},
{1001, nullptr, "WriteMifare"},
{1300, nullptr, "SendCommandByPassThrough"},
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 3bf753dee..4b79eb81d 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -189,7 +189,7 @@ private:
LOG_DEBUG(Service_NFP, "called");
auto nfc_event = nfp_interface.GetNFCEvent();
- if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
+ if (!nfc_event->ShouldWait(&ctx.GetThread()) && !has_attached_handle) {
device_state = DeviceState::TagFound;
nfc_event->Clear();
}
@@ -342,7 +342,7 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
return true;
}
-const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
+const std::shared_ptr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
return nfc_tag_load.readable;
}
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 9718ef745..200013795 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -34,7 +34,7 @@ public:
void CreateUserInterface(Kernel::HLERequestContext& ctx);
bool LoadAmiibo(const std::vector<u8>& buffer);
- const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const;
+ const std::shared_ptr<Kernel::ReadableEvent>& GetNFCEvent() const;
const AmiiboFile& GetAmiiboBuffer() const;
private:
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 01d557c7a..2e53b3221 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -208,6 +208,7 @@ private:
IGeneralService::IGeneralService(Core::System& system)
: ServiceFramework("IGeneralService"), system(system) {
+ // clang-format off
static const FunctionInfo functions[] = {
{1, &IGeneralService::GetClientId, "GetClientId"},
{2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
@@ -246,7 +247,14 @@ IGeneralService::IGeneralService(Core::System& system)
{36, nullptr, "GetCurrentAccessPoint"},
{37, nullptr, "Shutdown"},
{38, nullptr, "GetAllowedChannels"},
+ {39, nullptr, "NotifyApplicationSuspended"},
+ {40, nullptr, "SetAcceptableNetworkTypeFlag"},
+ {41, nullptr, "GetAcceptableNetworkTypeFlag"},
+ {42, nullptr, "NotifyConnectionStateChanged"},
+ {43, nullptr, "SetWowlDelayedWakeTime"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 7d6cf2070..e85f123e2 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -116,6 +116,8 @@ public:
{500, nullptr, "RequestSyncTicket"},
{501, nullptr, "RequestDownloadTicket"},
{502, nullptr, "RequestDownloadTicketForPrepurchasedContents"},
+ {503, nullptr, "RequestSyncTicket"},
+ {504, nullptr, "RequestDownloadTicketForPrepurchasedContents2"},
};
// clang-format on
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index 8751522ca..aa171473b 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -44,6 +44,10 @@ public:
{113, nullptr, "DestroyJid"},
{114, nullptr, "AttachJid"},
{115, nullptr, "DetachJid"},
+ {120, nullptr, "CreateNotificationReceiver"},
+ {151, nullptr, "GetStateWithHandover"},
+ {152, nullptr, "GetStateChangeEventWithHandover"},
+ {153, nullptr, "GetDropEventWithHandover"},
{201, nullptr, "RequestChangeStateForceTimed"},
{202, nullptr, "RequestChangeStateForceAsync"},
};
@@ -74,6 +78,9 @@ public:
{104, nullptr, "GetStatistics"},
{111, nullptr, "GetJid"},
{120, nullptr, "CreateNotificationReceiver"},
+ {151, nullptr, "GetStateWithHandover"},
+ {152, nullptr, "GetStateChangeEventWithHandover"},
+ {153, nullptr, "GetDropEventWithHandover"},
};
// clang-format on
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index eeba0aa19..fdab3cf78 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -106,6 +106,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{96, nullptr, "AcquireApplicationLaunchInfo"},
{97, nullptr, "GetMainApplicationProgramIndex2"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
+ {99, nullptr, "LaunchDevMenu"},
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
@@ -130,6 +131,8 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{404, nullptr, "InvalidateApplicationControlCache"},
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
+ {407, nullptr, "ListApplicationTitle"},
+ {408, nullptr, "ListApplicationIcon"},
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
@@ -138,6 +141,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{507, nullptr, "EnsureGameCardAccess"},
{508, nullptr, "GetLastGameCardMountFailureResult"},
{509, nullptr, "ListApplicationIdOnGameCard"},
+ {510, nullptr, "GetGameCardPlatformRegion"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
@@ -168,6 +172,9 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{910, nullptr, "HasApplicationRecord"},
{911, nullptr, "SetPreInstalledApplication"},
{912, nullptr, "ClearPreInstalledApplicationFlag"},
+ {913, nullptr, "ListAllApplicationRecord"},
+ {914, nullptr, "HideApplicationRecord"},
+ {915, nullptr, "ShowApplicationRecord"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
@@ -190,12 +197,14 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
+ {1506, nullptr, "GetSdCardStartupStatus"},
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, nullptr, "GetApplicationView"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
+ {1704, nullptr, "GetApplicationViewWithPromotionInfo"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
@@ -223,6 +232,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2050, nullptr, "GetApplicationRightsOnClient"},
+ {2051, nullptr, "InvalidateRightsIdCache"},
{2100, nullptr, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
@@ -230,6 +240,8 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{2152, nullptr, "ActivateRightsEnvironment"},
{2153, nullptr, "DeactivateRightsEnvironment"},
{2154, nullptr, "ForceActivateRightsContextForExit"},
+ {2155, nullptr, "UpdateRightsEnvironmentStatus"},
+ {2156, nullptr, "CreateRightsEnvironmentForPreomia"},
{2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
{2161, nullptr, "SetUsersToRightsEnvironment"},
{2170, nullptr, "GetRightsEnvironmentStatus"},
@@ -243,6 +255,20 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
{2250, nullptr, "RequestReportActiveELicence"},
{2300, nullptr, "ListEventLog"},
+ {2350, nullptr, "PerformAutoUpdateByApplicationId"},
+ {2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
+ {2352, nullptr, "RequestResolveNoDownloadRightsError"},
+ {2400, nullptr, "GetPromotionInfo"},
+ {2401, nullptr, "CountPromotionInfo"},
+ {2402, nullptr, "ListPromotionInfo"},
+ {2403, nullptr, "ImportPromotionJsonForDebug"},
+ {2404, nullptr, "ClearPromotionInfoForDebug"},
+ {2500, nullptr, "ConfirmAvailableTime"},
+ {2510, nullptr, "CreateApplicationResource"},
+ {2511, nullptr, "GetApplicationResource"},
+ {2513, nullptr, "LaunchPreomia"},
+ {2514, nullptr, "ClearTaskOfAsyncTaskManager"},
+ {2800, nullptr, "GetApplicationIdOfPreomia"},
};
// clang-format on
@@ -463,6 +489,7 @@ IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterfa
{3, nullptr, "RequestSyncRights"},
{4, nullptr, "RequestUnlinkDevice"},
{5, nullptr, "RequestRevokeAllELicense"},
+ {6, nullptr, "RequestSyncRightsBasedOnAssignedELicenses"},
};
// clang-format on
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index db433305f..8da4e52c5 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -141,7 +141,7 @@ struct PL_U::Impl {
}
/// Handle to shared memory region designated for a shared font
- Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
+ std::shared_ptr<Kernel::SharedMemory> shared_font_mem;
/// Backing memory for the shared font data
std::shared_ptr<Kernel::PhysicalMemory> shared_font;
@@ -152,7 +152,7 @@ struct PL_U::Impl {
PL_U::PL_U(Core::System& system)
: ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) {
-
+ // clang-format off
static const FunctionInfo functions[] = {
{0, &PL_U::RequestLoad, "RequestLoad"},
{1, &PL_U::GetLoadState, "GetLoadState"},
@@ -160,7 +160,13 @@ PL_U::PL_U(Core::System& system)
{3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"},
{4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
+ {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"},
+ {100, nullptr, "RequestApplicationFunctionAuthorization"},
+ {101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"},
+ {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
+ {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
};
+ // clang-format on
RegisterHandlers(functions);
auto& fsc = system.GetFileSystemController();
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 9de0ace22..6d8bca8bb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -191,8 +191,8 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
std::memcpy(entries.data(), input2.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
} else {
- Memory::ReadBlock(params.address, entries.data(),
- params.num_entries * sizeof(Tegra::CommandListHeader));
+ system.Memory().ReadBlock(params.address, entries.data(),
+ params.num_entries * sizeof(Tegra::CommandListHeader));
}
UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 68d139cfb..c8ea6c661 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -61,7 +61,7 @@ void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
if (ctrl.must_delay) {
ctrl.fresh_call = false;
ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout,
- [=](Kernel::SharedPtr<Kernel::Thread> thread,
+ [=](std::shared_ptr<Kernel::Thread> thread,
Kernel::HLERequestContext& ctx,
Kernel::ThreadWakeupReason reason) {
IoctlCtrl ctrl2{ctrl};
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index cc9cd3fd1..197c77db0 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -100,11 +100,11 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
}
}
-Kernel::SharedPtr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const {
+std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const {
return events_interface.events[event_id].readable;
}
-Kernel::SharedPtr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const {
+std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const {
return events_interface.events[event_id].writable;
}
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index f8bb28969..d7a1bef91 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -114,9 +114,9 @@ public:
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
- Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(u32 event_id) const;
+ std::shared_ptr<Kernel::ReadableEvent> GetEvent(u32 event_id) const;
- Kernel::SharedPtr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const;
+ std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const;
private:
/// Id to use for the next open file descriptor.
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 1af11e80c..32b6f4b27 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -117,11 +117,11 @@ u32 BufferQueue::Query(QueryType type) {
return 0;
}
-Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
+std::shared_ptr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
return buffer_wait_event.writable;
}
-Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
+std::shared_ptr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
return buffer_wait_event.readable;
}
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8f9b18547..f4bbfd945 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -93,9 +93,9 @@ public:
return id;
}
- Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
+ std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
- Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
+ std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
private:
u32 id;
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index cc9522aad..52623cf89 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -37,8 +37,8 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
displays.emplace_back(4, "Null", system);
// Schedule the screen composition events
- composition_event = system.CoreTiming().RegisterEvent(
- "ScreenComposition", [this](u64 userdata, s64 cycles_late) {
+ composition_event =
+ Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) {
Compose();
const auto ticks =
Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks();
@@ -98,7 +98,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
return layer->GetBufferQueue().GetId();
}
-Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
+std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 5d7e3bfb8..e3cc14bdc 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -62,7 +62,7 @@ public:
/// Gets the vsync event for the specified display.
///
/// If an invalid display ID is provided, then nullptr is returned.
- Kernel::SharedPtr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
+ std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
/// Obtains a buffer queue identified by the ID.
BufferQueue& FindBufferQueue(u32 id);
@@ -103,7 +103,7 @@ private:
u32 swap_interval = 1;
/// Event that handles screen composition.
- Core::Timing::EventType* composition_event;
+ std::shared_ptr<Core::Timing::EventType> composition_event;
Core::System& system;
};
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index fe6b5f798..809eca0ab 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -16,9 +16,9 @@ constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
constexpr u64 NO_PROCESS_FOUND_PID{0};
-std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList(
- const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list,
- std::function<bool(const Kernel::SharedPtr<Kernel::Process>&)> predicate) {
+std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList(
+ const std::vector<std::shared_ptr<Kernel::Process>>& process_list,
+ std::function<bool(const std::shared_ptr<Kernel::Process>&)> predicate) {
const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
if (iter == process_list.end()) {
@@ -29,7 +29,7 @@ std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList(
}
void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
- const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list) {
+ const std::vector<std::shared_ptr<Kernel::Process>>& process_list) {
const auto process = SearchProcessList(process_list, [](const auto& process) {
return process->GetProcessID() == Kernel::Process::ProcessIDMin;
});
@@ -124,7 +124,7 @@ private:
class Info final : public ServiceFramework<Info> {
public:
- explicit Info(const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list)
+ explicit Info(const std::vector<std::shared_ptr<Kernel::Process>>& process_list)
: ServiceFramework{"pm:info"}, process_list(process_list) {
static const FunctionInfo functions[] = {
{0, &Info::GetTitleId, "GetTitleId"},
@@ -154,7 +154,7 @@ private:
rb.Push((*process)->GetTitleID());
}
- const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list;
+ const std::vector<std::shared_ptr<Kernel::Process>>& process_list;
};
class Shell final : public ServiceFramework<Shell> {
@@ -172,7 +172,7 @@ public:
{6, &Shell::GetApplicationPid, "GetApplicationPid"},
{7, nullptr, "BoostSystemMemoryResourceLimit"},
{8, nullptr, "EnableAdditionalSystemThreads"},
- {9, nullptr, "GetUnimplementedEventHandle"},
+ {9, nullptr, "GetBootFinishedEventHandle"},
};
// clang-format on
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 18d895263..5eb26caf8 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -25,6 +25,7 @@ public:
{10103, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::New>, "SaveReportWithUser"},
{10200, nullptr, "RequestImmediateTransmission"},
{10300, nullptr, "GetTransmissionStatus"},
+ {10400, nullptr, "GetSystemSessionId"},
{20100, &PlayReport::SaveSystemReport, "SaveSystemReport"},
{20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
{20200, nullptr, "SetOperationMode"},
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 7c5302017..fa5347af9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -116,7 +116,7 @@ void ServiceFrameworkBase::InstallAsNamedPort() {
port_installed = true;
}
-Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
+std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
ASSERT(!port_installed);
auto& kernel = Core::System::GetInstance().Kernel();
@@ -186,7 +186,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType()));
}
- context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread());
+ context.WriteToOutgoingCommandBuffer(context.GetThread());
return RESULT_SUCCESS;
}
@@ -201,7 +201,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
- SM::ServiceManager::InstallInterfaces(sm);
+ SM::ServiceManager::InstallInterfaces(sm, system.Kernel());
Account::InstallInterfaces(system);
AM::InstallInterfaces(*sm, nv_flinger, system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index aef964861..022d885b6 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -65,7 +65,7 @@ public:
/// Creates a port pair and registers it on the kernel's global port registry.
void InstallAsNamedPort();
/// Creates and returns an unregistered port for the service.
- Kernel::SharedPtr<Kernel::ClientPort> CreatePort();
+ std::shared_ptr<Kernel::ClientPort> CreatePort();
void InvokeRequest(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index b54214421..5bcc0b588 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -124,6 +124,7 @@ SET::SET() : ServiceFramework("set") {
{7, nullptr, "GetKeyCodeMap"},
{8, &SET::GetQuestFlag, "GetQuestFlag"},
{9, nullptr, "GetKeyCodeMap2"},
+ {10, nullptr, "GetFirmwareVersionForDebug"},
};
// clang-format on
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp
index 5981c575c..1398a4a48 100644
--- a/src/core/hle/service/set/set_cal.cpp
+++ b/src/core/hle/service/set/set_cal.cpp
@@ -7,6 +7,7 @@
namespace Service::Set {
SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetBluetoothBdAddress"},
{1, nullptr, "GetConfigurationId1"},
@@ -40,8 +41,18 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
{30, nullptr, "GetAmiiboEcqvBlsCertificate"},
{31, nullptr, "GetAmiiboEcqvBlsRootCertificate"},
{32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"},
+ {33, nullptr, "GetAnalogStickModuleTypeL"},
+ {34, nullptr, "GetAnalogStickModelParameterL"},
+ {35, nullptr, "GetAnalogStickFactoryCalibrationL"},
+ {36, nullptr, "GetAnalogStickModuleTypeR"},
+ {37, nullptr, "GetAnalogStickModelParameterR"},
+ {38, nullptr, "GetAnalogStickFactoryCalibrationR"},
+ {39, nullptr, "GetConsoleSixAxisSensorModuleType"},
+ {40, nullptr, "GetConsoleSixAxisSensorHorizontalOffset"},
{41, nullptr, "GetBatteryVersion"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp
index cac6af86d..565882a31 100644
--- a/src/core/hle/service/set/set_fd.cpp
+++ b/src/core/hle/service/set/set_fd.cpp
@@ -7,6 +7,7 @@
namespace Service::Set {
SET_FD::SET_FD() : ServiceFramework("set:fd") {
+ // clang-format off
static const FunctionInfo functions[] = {
{2, nullptr, "SetSettingsItemValue"},
{3, nullptr, "ResetSettingsItemValue"},
@@ -16,7 +17,10 @@ SET_FD::SET_FD() : ServiceFramework("set:fd") {
{20, nullptr, "SetWebInspectorFlag"},
{21, nullptr, "SetAllowedSslHosts"},
{22, nullptr, "SetHostFsMountPoint"},
+ {23, nullptr, "SetMemoryUsageRateFlag"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 98d0cfdfd..b7c9ea74b 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -273,10 +273,21 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
{171, nullptr, "SetChineseTraditionalInputMethod"},
{172, nullptr, "GetPtmCycleCountReliability"},
{173, nullptr, "SetPtmCycleCountReliability"},
+ {174, nullptr, "GetHomeMenuScheme"},
{175, nullptr, "GetThemeSettings"},
{176, nullptr, "SetThemeSettings"},
{177, nullptr, "GetThemeKey"},
{178, nullptr, "SetThemeKey"},
+ {179, nullptr, "GetZoomFlag"},
+ {180, nullptr, "SetZoomFlag"},
+ {181, nullptr, "GetT"},
+ {182, nullptr, "SetT"},
+ {183, nullptr, "GetPlatformRegion"},
+ {184, nullptr, "SetPlatformRegion"},
+ {185, nullptr, "GetHomeMenuSchemeModel"},
+ {186, nullptr, "GetMemoryUsageRateFlag"},
+ {187, nullptr, "GetTouchScreenMode"},
+ {188, nullptr, "SetTouchScreenMode"},
};
// clang-format on
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index e9ee73710..c45b285f8 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -30,10 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(RESULT_SUCCESS);
- Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client};
- rb.PushMoveObjects(session);
-
- LOG_DEBUG(Service, "session={}", session->GetObjectId());
+ rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
}
void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 142929124..88909504d 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -36,16 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) {
return RESULT_SUCCESS;
}
-void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) {
+void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self,
+ Kernel::KernelCore& kernel) {
ASSERT(self->sm_interface.expired());
- auto sm = std::make_shared<SM>(self);
+ auto sm = std::make_shared<SM>(self, kernel);
sm->InstallAsNamedPort();
self->sm_interface = sm;
self->controller_interface = std::make_unique<Controller>();
}
-ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService(
+ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(
std::string name, unsigned int max_sessions) {
CASCADE_CODE(ValidateServiceName(name));
@@ -72,7 +73,7 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
return RESULT_SUCCESS;
}
-ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
+ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
@@ -84,7 +85,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
return MakeResult(it->second);
}
-ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService(
+ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
const std::string& name) {
CASCADE_RESULT(auto client_port, GetServicePort(name));
@@ -114,8 +115,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
std::string name(name_buf.begin(), end);
- // TODO(yuriks): Permission checks go here
-
auto client_port = service_manager->GetServicePort(name);
if (client_port.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -127,14 +126,22 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
return;
}
- auto session = client_port.Unwrap()->Connect();
- ASSERT(session.Succeeded());
- if (session.Succeeded()) {
- LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId());
- IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
- rb.Push(session.Code());
- rb.PushMoveObjects(std::move(session).Unwrap());
+ auto [client, server] = Kernel::Session::Create(kernel, name);
+
+ const auto& server_port = client_port.Unwrap()->GetServerPort();
+ if (server_port->GetHLEHandler()) {
+ server_port->GetHLEHandler()->ClientConnected(server);
+ } else {
+ server_port->AppendPendingSession(server);
}
+
+ // Wake the threads waiting on the ServerPort
+ server_port->WakeupAllWaitingThreads();
+
+ LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushMoveObjects(std::move(client));
}
void SM::RegisterService(Kernel::HLERequestContext& ctx) {
@@ -178,8 +185,8 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
rb.Push(service_manager->UnregisterService(name));
}
-SM::SM(std::shared_ptr<ServiceManager> service_manager)
- : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
+SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel)
+ : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} {
static const FunctionInfo functions[] = {
{0x00000000, &SM::Initialize, "Initialize"},
{0x00000001, &SM::GetService, "GetService"},
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index b9d6381b4..b06d2f103 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -18,6 +18,7 @@
namespace Kernel {
class ClientPort;
class ClientSession;
+class KernelCore;
class ServerPort;
class SessionRequestHandler;
} // namespace Kernel
@@ -29,7 +30,7 @@ class Controller;
/// Interface to "sm:" service
class SM final : public ServiceFramework<SM> {
public:
- explicit SM(std::shared_ptr<ServiceManager> service_manager);
+ explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel);
~SM() override;
private:
@@ -39,20 +40,21 @@ private:
void UnregisterService(Kernel::HLERequestContext& ctx);
std::shared_ptr<ServiceManager> service_manager;
+ Kernel::KernelCore& kernel;
};
class ServiceManager {
public:
- static void InstallInterfaces(std::shared_ptr<ServiceManager> self);
+ static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel);
ServiceManager();
~ServiceManager();
- ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
- unsigned int max_sessions);
+ ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name,
+ unsigned int max_sessions);
ResultCode UnregisterService(const std::string& name);
- ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
- ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
+ ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
+ ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
template <typename T>
std::shared_ptr<T> GetService(const std::string& service_name) const {
@@ -77,7 +79,7 @@ private:
std::unique_ptr<Controller> controller_interface;
/// Map of registered services, retrieved using GetServicePort or ConnectToService.
- std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services;
+ std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services;
};
} // namespace Service::SM
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index e6d73065e..dc70fd6fe 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -7,6 +7,7 @@
namespace Service::Sockets {
NSD::NSD(const char* name) : ServiceFramework(name) {
+ // clang-format off
static const FunctionInfo functions[] = {
{10, nullptr, "GetSettingName"},
{11, nullptr, "GetEnvironmentIdentifier"},
@@ -22,10 +23,14 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
{42, nullptr, "GetNasApiFqdn"},
{43, nullptr, "GetNasApiFqdnEx"},
{50, nullptr, "GetCurrentSetting"},
+ {51, nullptr, "WriteTestParameter"},
+ {52, nullptr, "ReadTestParameter"},
{60, nullptr, "ReadSaveDataFromFsForTest"},
{61, nullptr, "WriteSaveDataToFsForTest"},
{62, nullptr, "DeleteSaveDataOfFsForTest"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 65040c077..1ba8c19a0 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -13,6 +13,7 @@ namespace Service::SSL {
class ISslConnection final : public ServiceFramework<ISslConnection> {
public:
ISslConnection() : ServiceFramework("ISslConnection") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetSocketDescriptor"},
{1, nullptr, "SetHostName"},
@@ -40,7 +41,11 @@ public:
{23, nullptr, "GetOption"},
{24, nullptr, "GetVerifyCertErrors"},
{25, nullptr, "GetCipherInfo"},
+ {26, nullptr, "SetNextAlpnProto"},
+ {27, nullptr, "GetNextAlpnProto"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
};
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 9565e7de5..bc74f1e1d 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -21,6 +21,7 @@ Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_me
{30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
+ {51, nullptr, "GetStandardSteadyClockRtcValue"},
{100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
{101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 62efe021e..6ee77c5f9 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -74,15 +74,17 @@ public:
ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory,
ClockContextType clock_type)
: ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
{1, nullptr, "SetCurrentTime"},
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
{3, nullptr, "SetSystemClockContext"},
-
+ {4, nullptr, "GetOperationEventReadableHandle"},
};
- RegisterHandlers(functions);
+ // clang-format on
+ RegisterHandlers(functions);
UpdateSharedMemoryContext(system_clock_context);
}
@@ -162,6 +164,7 @@ private:
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
public:
ITimeZoneService() : ServiceFramework("ITimeZoneService") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
{1, nullptr, "SetDeviceLocationName"},
@@ -169,11 +172,17 @@ public:
{3, nullptr, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, nullptr, "GetTimeZoneRuleVersion"},
+ {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
+ {7, nullptr, "SetDeviceLocationNameWithTimeZoneRule"},
+ {8, nullptr, "ParseTimeZoneBinary"},
+ {20, nullptr, "GetDeviceLocationNameOperationEventReadableHandle"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
{202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index bfc81b83c..4035f5072 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -21,7 +21,7 @@ SharedMemory::SharedMemory(Core::System& system) : system(system) {
SharedMemory::~SharedMemory() = default;
-Kernel::SharedPtr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const {
+std::shared_ptr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const {
return shared_memory_holder;
}
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index cb8253541..904a96430 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -15,7 +15,7 @@ public:
~SharedMemory();
// Return the shared memory handle
- Kernel::SharedPtr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
+ std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
// Set memory barriers in shared memory and update them
void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint);
@@ -66,7 +66,7 @@ public:
static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
private:
- Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_holder{};
+ std::shared_ptr<Kernel::SharedMemory> shared_memory_holder{};
Core::System& system;
Format shared_memory_format{};
};
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index 07033fb98..cd18c1610 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -31,7 +31,7 @@ const Layer& Display::GetLayer(std::size_t index) const {
return layers.at(index);
}
-Kernel::SharedPtr<Kernel::ReadableEvent> Display::GetVSyncEvent() const {
+std::shared_ptr<Kernel::ReadableEvent> Display::GetVSyncEvent() const {
return vsync_event.readable;
}
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index f56b5badc..8bb966a85 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -57,7 +57,7 @@ public:
const Layer& GetLayer(std::size_t index) const;
/// Gets the readable vsync event.
- Kernel::SharedPtr<Kernel::ReadableEvent> GetVSyncEvent() const;
+ std::shared_ptr<Kernel::ReadableEvent> GetVSyncEvent() const;
/// Signals the internal vsync event.
void SignalVSyncEvent();
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index abfc3a801..651c89dc0 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -542,7 +542,7 @@ private:
// Wait the current thread until a buffer becomes available
ctx.SleepClientThread(
"IHOSBinderDriver::DequeueBuffer", UINT64_MAX,
- [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
+ [=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available
auto& buffer_queue = nv_flinger->FindBufferQueue(id);
@@ -731,6 +731,7 @@ class IManagerDisplayService final : public ServiceFramework<IManagerDisplayServ
public:
explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
+ // clang-format off
static const FunctionInfo functions[] = {
{200, nullptr, "AllocateProcessHeapBlock"},
{201, nullptr, "FreeProcessHeapBlock"},
@@ -766,8 +767,11 @@ public:
{6008, nullptr, "StartLayerPresentationFenceWait"},
{6009, nullptr, "StopLayerPresentationFenceWait"},
{6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
+ {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"},
+ {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"},
{7000, nullptr, "SetContentVisibility"},
{8000, nullptr, "SetConductorLayer"},
+ {8001, nullptr, "SetTimestampTracking"},
{8100, nullptr, "SetIndirectProducerFlipOffset"},
{8200, nullptr, "CreateSharedBufferStaticStorage"},
{8201, nullptr, "CreateSharedBufferTransferMemory"},
@@ -800,6 +804,8 @@ public:
{8297, nullptr, "GetSharedFrameBufferContentParameter"},
{8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
};
+ // clang-format on
+
RegisterHandlers(functions);
}
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index fa49f3dd0..91bf07a92 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -17,529 +17,699 @@
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
-#include "core/memory_setup.h"
#include "video_core/gpu.h"
namespace Memory {
-static Common::PageTable* current_page_table = nullptr;
+// Implementation class used to keep the specifics of the memory subsystem hidden
+// from outside classes. This also allows modification to the internals of the memory
+// subsystem without needing to rebuild all files that make use of the memory interface.
+struct Memory::Impl {
+ explicit Impl(Core::System& system_) : system{system_} {}
-void SetCurrentPageTable(Kernel::Process& process) {
- current_page_table = &process.VMManager().page_table;
+ void SetCurrentPageTable(Kernel::Process& process) {
+ current_page_table = &process.VMManager().page_table;
- const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth();
+ const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth();
- auto& system = Core::System::GetInstance();
- system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width);
- system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width);
- system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width);
- system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width);
-}
+ system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width);
+ system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width);
+ system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width);
+ system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width);
+ }
-static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
- Common::PageType type) {
- LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
- (base + size) * PAGE_SIZE);
-
- // During boot, current_page_table might not be set yet, in which case we need not flush
- if (Core::System::GetInstance().IsPoweredOn()) {
- auto& gpu = Core::System::GetInstance().GPU();
- for (u64 i = 0; i < size; i++) {
- const auto page = base + i;
- if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) {
- gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE);
- }
- }
+ void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
+ ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
+ ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
+ MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
}
- VAddr end = base + size;
- ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
- base + page_table.pointers.size());
+ void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer mmio_handler) {
+ ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
+ ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
+ MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr,
+ Common::PageType::Special);
+
+ const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
+ const Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice,
+ std::move(mmio_handler)};
+ page_table.special_regions.add(
+ std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
+ }
- std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type);
+ void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
+ ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
+ ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
+ MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr,
+ Common::PageType::Unmapped);
- if (memory == nullptr) {
- std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end, memory);
- } else {
- while (base != end) {
- page_table.pointers[base] = memory;
+ const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
+ page_table.special_regions.erase(interval);
+ }
- base += 1;
- memory += PAGE_SIZE;
- }
+ void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer hook) {
+ const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
+ const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
+ page_table.special_regions.add(
+ std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
}
-}
-void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
- ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
- ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
- MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
-}
+ void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer hook) {
+ const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
+ const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
+ page_table.special_regions.subtract(
+ std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
+ }
-void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
- Common::MemoryHookPointer mmio_handler) {
- ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
- ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
- MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Special);
+ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
+ const auto& page_table = process.VMManager().page_table;
- auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
- Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice, std::move(mmio_handler)};
- page_table.special_regions.add(
- std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
-}
+ const u8* const page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
+ if (page_pointer != nullptr) {
+ return true;
+ }
-void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
- ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
- ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
- MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Unmapped);
+ if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) {
+ return true;
+ }
- auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
- page_table.special_regions.erase(interval);
-}
+ if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) {
+ return false;
+ }
-void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
- Common::MemoryHookPointer hook) {
- auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
- Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
- page_table.special_regions.add(
- std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
-}
+ return false;
+ }
-void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
- Common::MemoryHookPointer hook) {
- auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
- Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
- page_table.special_regions.subtract(
- std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
-}
+ bool IsValidVirtualAddress(VAddr vaddr) const {
+ return IsValidVirtualAddress(*system.CurrentProcess(), vaddr);
+ }
-/**
- * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
- * using a VMA from the current process
- */
-static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
- const auto& vm_manager = process.VMManager();
-
- const auto it = vm_manager.FindVMA(vaddr);
- DEBUG_ASSERT(vm_manager.IsValidHandle(it));
-
- u8* direct_pointer = nullptr;
- const auto& vma = it->second;
- switch (vma.type) {
- case Kernel::VMAType::AllocatedMemoryBlock:
- direct_pointer = vma.backing_block->data() + vma.offset;
- break;
- case Kernel::VMAType::BackingMemory:
- direct_pointer = vma.backing_memory;
- break;
- case Kernel::VMAType::Free:
- return nullptr;
- default:
- UNREACHABLE();
+ /**
+ * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
+ * using a VMA from the current process
+ */
+ u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
+ const auto& vm_manager = process.VMManager();
+
+ const auto it = vm_manager.FindVMA(vaddr);
+ DEBUG_ASSERT(vm_manager.IsValidHandle(it));
+
+ u8* direct_pointer = nullptr;
+ const auto& vma = it->second;
+ switch (vma.type) {
+ case Kernel::VMAType::AllocatedMemoryBlock:
+ direct_pointer = vma.backing_block->data() + vma.offset;
+ break;
+ case Kernel::VMAType::BackingMemory:
+ direct_pointer = vma.backing_memory;
+ break;
+ case Kernel::VMAType::Free:
+ return nullptr;
+ default:
+ UNREACHABLE();
+ }
+
+ return direct_pointer + (vaddr - vma.base);
}
- return direct_pointer + (vaddr - vma.base);
-}
+ /**
+ * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
+ * using a VMA from the current process.
+ */
+ u8* GetPointerFromVMA(VAddr vaddr) {
+ return GetPointerFromVMA(*system.CurrentProcess(), vaddr);
+ }
-/**
- * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
- * using a VMA from the current process.
- */
-static u8* GetPointerFromVMA(VAddr vaddr) {
- return GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr);
-}
+ u8* GetPointer(const VAddr vaddr) {
+ u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer != nullptr) {
+ return page_pointer + (vaddr & PAGE_MASK);
+ }
-template <typename T>
-T Read(const VAddr vaddr) {
- const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
- if (page_pointer) {
- // NOTE: Avoid adding any extra logic to this fast-path block
- T value;
- std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
- return value;
- }
-
- Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
- switch (type) {
- case Common::PageType::Unmapped:
- LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
- return 0;
- case Common::PageType::Memory:
- ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
- break;
- case Common::PageType::RasterizerCachedMemory: {
- auto host_ptr{GetPointerFromVMA(vaddr)};
- Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
- T value;
- std::memcpy(&value, host_ptr, sizeof(T));
- return value;
- }
- default:
- UNREACHABLE();
- }
- return {};
-}
+ if (current_page_table->attributes[vaddr >> PAGE_BITS] ==
+ Common::PageType::RasterizerCachedMemory) {
+ return GetPointerFromVMA(vaddr);
+ }
-template <typename T>
-void Write(const VAddr vaddr, const T data) {
- u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
- if (page_pointer) {
- // NOTE: Avoid adding any extra logic to this fast-path block
- std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
- return;
- }
-
- Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
- switch (type) {
- case Common::PageType::Unmapped:
- LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
- static_cast<u32>(data), vaddr);
- return;
- case Common::PageType::Memory:
- ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
- break;
- case Common::PageType::RasterizerCachedMemory: {
- auto host_ptr{GetPointerFromVMA(vaddr)};
- Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
- std::memcpy(host_ptr, &data, sizeof(T));
- break;
- }
- default:
- UNREACHABLE();
+ LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr);
+ return nullptr;
}
-}
-bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
- const auto& page_table = process.VMManager().page_table;
+ u8 Read8(const VAddr addr) {
+ return Read<u8>(addr);
+ }
- const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
- if (page_pointer)
- return true;
+ u16 Read16(const VAddr addr) {
+ return Read<u16_le>(addr);
+ }
- if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory)
- return true;
+ u32 Read32(const VAddr addr) {
+ return Read<u32_le>(addr);
+ }
- if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special)
- return false;
+ u64 Read64(const VAddr addr) {
+ return Read<u64_le>(addr);
+ }
- return false;
-}
+ void Write8(const VAddr addr, const u8 data) {
+ Write<u8>(addr, data);
+ }
-bool IsValidVirtualAddress(const VAddr vaddr) {
- return IsValidVirtualAddress(*Core::System::GetInstance().CurrentProcess(), vaddr);
-}
+ void Write16(const VAddr addr, const u16 data) {
+ Write<u16_le>(addr, data);
+ }
-bool IsKernelVirtualAddress(const VAddr vaddr) {
- return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
-}
+ void Write32(const VAddr addr, const u32 data) {
+ Write<u32_le>(addr, data);
+ }
-u8* GetPointer(const VAddr vaddr) {
- u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
- if (page_pointer) {
- return page_pointer + (vaddr & PAGE_MASK);
+ void Write64(const VAddr addr, const u64 data) {
+ Write<u64_le>(addr, data);
}
- if (current_page_table->attributes[vaddr >> PAGE_BITS] ==
- Common::PageType::RasterizerCachedMemory) {
- return GetPointerFromVMA(vaddr);
+ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
+ std::string string;
+ string.reserve(max_length);
+ for (std::size_t i = 0; i < max_length; ++i) {
+ const char c = Read8(vaddr);
+ if (c == '\0') {
+ break;
+ }
+ string.push_back(c);
+ ++vaddr;
+ }
+ string.shrink_to_fit();
+ return string;
}
- LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr);
- return nullptr;
-}
+ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
+ const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+
+ std::size_t remaining_size = size;
+ std::size_t page_index = src_addr >> PAGE_BITS;
+ std::size_t page_offset = src_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, src_addr, size);
+ std::memset(dest_buffer, 0, copy_amount);
+ break;
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
-std::string ReadCString(VAddr vaddr, std::size_t max_length) {
- std::string string;
- string.reserve(max_length);
- for (std::size_t i = 0; i < max_length; ++i) {
- char c = Read8(vaddr);
- if (c == '\0')
- break;
- string.push_back(c);
- ++vaddr;
+ const u8* const src_ptr = page_table.pointers[page_index] + page_offset;
+ std::memcpy(dest_buffer, src_ptr, copy_amount);
+ break;
+ }
+ case Common::PageType::RasterizerCachedMemory: {
+ const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
+ system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
+ std::memcpy(dest_buffer, host_ptr, copy_amount);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ page_index++;
+ page_offset = 0;
+ dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
+ remaining_size -= copy_amount;
+ }
}
- string.shrink_to_fit();
- return string;
-}
-void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
- if (vaddr == 0) {
- return;
+ void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
+ ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
}
- // Iterate over a contiguous CPU address space, which corresponds to the specified GPU address
- // space, marking the region as un/cached. The region is marked un/cached at a granularity of
- // CPU pages, hence why we iterate on a CPU page basis (note: GPU page size is different). This
- // assumes the specified GPU address region is contiguous as well.
+ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
+ const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+ std::size_t remaining_size = size;
+ std::size_t page_index = dest_addr >> PAGE_BITS;
+ std::size_t page_offset = dest_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, dest_addr, size);
+ break;
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
+
+ u8* const dest_ptr = page_table.pointers[page_index] + page_offset;
+ std::memcpy(dest_ptr, src_buffer, copy_amount);
+ break;
+ }
+ case Common::PageType::RasterizerCachedMemory: {
+ u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
+ system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
+ std::memcpy(host_ptr, src_buffer, copy_amount);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ page_index++;
+ page_offset = 0;
+ src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
+ remaining_size -= copy_amount;
+ }
+ }
- u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
- for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
- Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
+ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
+ WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size);
+ }
- if (cached) {
- // Switch page type to cached if now cached
- switch (page_type) {
- case Common::PageType::Unmapped:
- // It is not necessary for a process to have this region mapped into its address
- // space, for example, a system module need not have a VRAM mapping.
+ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+ std::size_t remaining_size = size;
+ std::size_t page_index = dest_addr >> PAGE_BITS;
+ std::size_t page_offset = dest_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, dest_addr, size);
break;
- case Common::PageType::Memory:
- page_type = Common::PageType::RasterizerCachedMemory;
- current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
+
+ u8* dest_ptr = page_table.pointers[page_index] + page_offset;
+ std::memset(dest_ptr, 0, copy_amount);
break;
- case Common::PageType::RasterizerCachedMemory:
- // There can be more than one GPU region mapped per CPU region, so it's common that
- // this area is already marked as cached.
+ }
+ case Common::PageType::RasterizerCachedMemory: {
+ u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
+ system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
+ std::memset(host_ptr, 0, copy_amount);
break;
+ }
default:
UNREACHABLE();
}
- } else {
- // Switch page type to uncached if now uncached
- switch (page_type) {
- case Common::PageType::Unmapped:
- // It is not necessary for a process to have this region mapped into its address
- // space, for example, a system module need not have a VRAM mapping.
+
+ page_index++;
+ page_offset = 0;
+ remaining_size -= copy_amount;
+ }
+ }
+
+ void ZeroBlock(const VAddr dest_addr, const std::size_t size) {
+ ZeroBlock(*system.CurrentProcess(), dest_addr, size);
+ }
+
+ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+ const std::size_t size) {
+ const auto& page_table = process.VMManager().page_table;
+ std::size_t remaining_size = size;
+ std::size_t page_index = src_addr >> PAGE_BITS;
+ std::size_t page_offset = src_addr & PAGE_MASK;
+
+ while (remaining_size > 0) {
+ const std::size_t copy_amount =
+ std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
+ const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
+
+ switch (page_table.attributes[page_index]) {
+ case Common::PageType::Unmapped: {
+ LOG_ERROR(HW_Memory,
+ "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
+ current_vaddr, src_addr, size);
+ ZeroBlock(process, dest_addr, copy_amount);
break;
- case Common::PageType::Memory:
- // There can be more than one GPU region mapped per CPU region, so it's common that
- // this area is already unmarked as cached.
+ }
+ case Common::PageType::Memory: {
+ DEBUG_ASSERT(page_table.pointers[page_index]);
+ const u8* src_ptr = page_table.pointers[page_index] + page_offset;
+ WriteBlock(process, dest_addr, src_ptr, copy_amount);
break;
+ }
case Common::PageType::RasterizerCachedMemory: {
- u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
- if (pointer == nullptr) {
- // It's possible that this function has been called while updating the pagetable
- // after unmapping a VMA. In that case the underlying VMA will no longer exist,
- // and we should just leave the pagetable entry blank.
- page_type = Common::PageType::Unmapped;
- } else {
- page_type = Common::PageType::Memory;
- current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
- }
+ const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
+ system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
+ WriteBlock(process, dest_addr, host_ptr, copy_amount);
break;
}
default:
UNREACHABLE();
}
+
+ page_index++;
+ page_offset = 0;
+ dest_addr += static_cast<VAddr>(copy_amount);
+ src_addr += static_cast<VAddr>(copy_amount);
+ remaining_size -= copy_amount;
}
}
-}
-u8 Read8(const VAddr addr) {
- return Read<u8>(addr);
-}
+ void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
+ return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size);
+ }
-u16 Read16(const VAddr addr) {
- return Read<u16_le>(addr);
-}
+ void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
+ if (vaddr == 0) {
+ return;
+ }
-u32 Read32(const VAddr addr) {
- return Read<u32_le>(addr);
-}
+ // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
+ // address space, marking the region as un/cached. The region is marked un/cached at a
+ // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size
+ // is different). This assumes the specified GPU address region is contiguous as well.
+
+ u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
+ for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
+ Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
+
+ if (cached) {
+ // Switch page type to cached if now cached
+ switch (page_type) {
+ case Common::PageType::Unmapped:
+ // It is not necessary for a process to have this region mapped into its address
+ // space, for example, a system module need not have a VRAM mapping.
+ break;
+ case Common::PageType::Memory:
+ page_type = Common::PageType::RasterizerCachedMemory;
+ current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
+ break;
+ case Common::PageType::RasterizerCachedMemory:
+ // There can be more than one GPU region mapped per CPU region, so it's common
+ // that this area is already marked as cached.
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else {
+ // Switch page type to uncached if now uncached
+ switch (page_type) {
+ case Common::PageType::Unmapped:
+ // It is not necessary for a process to have this region mapped into its address
+ // space, for example, a system module need not have a VRAM mapping.
+ break;
+ case Common::PageType::Memory:
+ // There can be more than one GPU region mapped per CPU region, so it's common
+ // that this area is already unmarked as cached.
+ break;
+ case Common::PageType::RasterizerCachedMemory: {
+ u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
+ if (pointer == nullptr) {
+ // It's possible that this function has been called while updating the
+ // pagetable after unmapping a VMA. In that case the underlying VMA will no
+ // longer exist, and we should just leave the pagetable entry blank.
+ page_type = Common::PageType::Unmapped;
+ } else {
+ page_type = Common::PageType::Memory;
+ current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+ }
-u64 Read64(const VAddr addr) {
- return Read<u64_le>(addr);
-}
+ /**
+ * Maps a region of pages as a specific type.
+ *
+ * @param page_table The page table to use to perform the mapping.
+ * @param base The base address to begin mapping at.
+ * @param size The total size of the range in bytes.
+ * @param memory The memory to map.
+ * @param type The page type to map the memory as.
+ */
+ void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
+ Common::PageType type) {
+ LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
+ (base + size) * PAGE_SIZE);
+
+ // During boot, current_page_table might not be set yet, in which case we need not flush
+ if (system.IsPoweredOn()) {
+ auto& gpu = system.GPU();
+ for (u64 i = 0; i < size; i++) {
+ const auto page = base + i;
+ if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) {
+ gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE);
+ }
+ }
+ }
-void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
- const std::size_t size) {
- const auto& page_table = process.VMManager().page_table;
-
- std::size_t remaining_size = size;
- std::size_t page_index = src_addr >> PAGE_BITS;
- std::size_t page_offset = src_addr & PAGE_MASK;
-
- while (remaining_size > 0) {
- const std::size_t copy_amount =
- std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
- const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
-
- switch (page_table.attributes[page_index]) {
- case Common::PageType::Unmapped: {
- LOG_ERROR(HW_Memory,
- "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, src_addr, size);
- std::memset(dest_buffer, 0, copy_amount);
- break;
+ const VAddr end = base + size;
+ ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
+ base + page_table.pointers.size());
+
+ std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type);
+
+ if (memory == nullptr) {
+ std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end,
+ memory);
+ } else {
+ while (base != end) {
+ page_table.pointers[base] = memory;
+
+ base += 1;
+ memory += PAGE_SIZE;
+ }
+ }
+ }
+
+ /**
+ * Reads a particular data type out of memory at the given virtual address.
+ *
+ * @param vaddr The virtual address to read the data type from.
+ *
+ * @tparam T The data type to read out of memory. This type *must* be
+ * trivially copyable, otherwise the behavior of this function
+ * is undefined.
+ *
+ * @returns The instance of T read from the specified virtual address.
+ */
+ template <typename T>
+ T Read(const VAddr vaddr) {
+ const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer != nullptr) {
+ // NOTE: Avoid adding any extra logic to this fast-path block
+ T value;
+ std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
+ return value;
}
- case Common::PageType::Memory: {
- DEBUG_ASSERT(page_table.pointers[page_index]);
- const u8* src_ptr = page_table.pointers[page_index] + page_offset;
- std::memcpy(dest_buffer, src_ptr, copy_amount);
+ const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
+ switch (type) {
+ case Common::PageType::Unmapped:
+ LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
+ return 0;
+ case Common::PageType::Memory:
+ ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
break;
+ case Common::PageType::RasterizerCachedMemory: {
+ const u8* const host_ptr = GetPointerFromVMA(vaddr);
+ system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
+ T value;
+ std::memcpy(&value, host_ptr, sizeof(T));
+ return value;
+ }
+ default:
+ UNREACHABLE();
}
+ return {};
+ }
+
+ /**
+ * Writes a particular data type to memory at the given virtual address.
+ *
+ * @param vaddr The virtual address to write the data type to.
+ *
+ * @tparam T The data type to write to memory. This type *must* be
+ * trivially copyable, otherwise the behavior of this function
+ * is undefined.
+ *
+ * @returns The instance of T write to the specified virtual address.
+ */
+ template <typename T>
+ void Write(const VAddr vaddr, const T data) {
+ u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
+ if (page_pointer != nullptr) {
+ // NOTE: Avoid adding any extra logic to this fast-path block
+ std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
+ return;
+ }
+
+ const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
+ switch (type) {
+ case Common::PageType::Unmapped:
+ LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
+ static_cast<u32>(data), vaddr);
+ return;
+ case Common::PageType::Memory:
+ ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
+ break;
case Common::PageType::RasterizerCachedMemory: {
- const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
- Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
- std::memcpy(dest_buffer, host_ptr, copy_amount);
+ u8* const host_ptr{GetPointerFromVMA(vaddr)};
+ system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
+ std::memcpy(host_ptr, &data, sizeof(T));
break;
}
default:
UNREACHABLE();
}
-
- page_index++;
- page_offset = 0;
- dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
- remaining_size -= copy_amount;
}
+
+ Common::PageTable* current_page_table = nullptr;
+ Core::System& system;
+};
+
+Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
+Memory::~Memory() = default;
+
+void Memory::SetCurrentPageTable(Kernel::Process& process) {
+ impl->SetCurrentPageTable(process);
}
-void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
- ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size);
+void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
+ impl->MapMemoryRegion(page_table, base, size, target);
}
-void Write8(const VAddr addr, const u8 data) {
- Write<u8>(addr, data);
+void Memory::MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer mmio_handler) {
+ impl->MapIoRegion(page_table, base, size, std::move(mmio_handler));
}
-void Write16(const VAddr addr, const u16 data) {
- Write<u16_le>(addr, data);
+void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
+ impl->UnmapRegion(page_table, base, size);
}
-void Write32(const VAddr addr, const u32 data) {
- Write<u32_le>(addr, data);
+void Memory::AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer hook) {
+ impl->AddDebugHook(page_table, base, size, std::move(hook));
}
-void Write64(const VAddr addr, const u64 data) {
- Write<u64_le>(addr, data);
+void Memory::RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer hook) {
+ impl->RemoveDebugHook(page_table, base, size, std::move(hook));
}
-void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
- const std::size_t size) {
- const auto& page_table = process.VMManager().page_table;
- std::size_t remaining_size = size;
- std::size_t page_index = dest_addr >> PAGE_BITS;
- std::size_t page_offset = dest_addr & PAGE_MASK;
-
- while (remaining_size > 0) {
- const std::size_t copy_amount =
- std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
- const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
-
- switch (page_table.attributes[page_index]) {
- case Common::PageType::Unmapped: {
- LOG_ERROR(HW_Memory,
- "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, dest_addr, size);
- break;
- }
- case Common::PageType::Memory: {
- DEBUG_ASSERT(page_table.pointers[page_index]);
+bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
+ return impl->IsValidVirtualAddress(process, vaddr);
+}
- u8* dest_ptr = page_table.pointers[page_index] + page_offset;
- std::memcpy(dest_ptr, src_buffer, copy_amount);
- break;
- }
- case Common::PageType::RasterizerCachedMemory: {
- const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
- Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
- std::memcpy(host_ptr, src_buffer, copy_amount);
- break;
- }
- default:
- UNREACHABLE();
- }
+bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
+ return impl->IsValidVirtualAddress(vaddr);
+}
- page_index++;
- page_offset = 0;
- src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
- remaining_size -= copy_amount;
- }
+u8* Memory::GetPointer(VAddr vaddr) {
+ return impl->GetPointer(vaddr);
}
-void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
- WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size);
+const u8* Memory::GetPointer(VAddr vaddr) const {
+ return impl->GetPointer(vaddr);
}
-void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
- const auto& page_table = process.VMManager().page_table;
- std::size_t remaining_size = size;
- std::size_t page_index = dest_addr >> PAGE_BITS;
- std::size_t page_offset = dest_addr & PAGE_MASK;
-
- while (remaining_size > 0) {
- const std::size_t copy_amount =
- std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
- const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
-
- switch (page_table.attributes[page_index]) {
- case Common::PageType::Unmapped: {
- LOG_ERROR(HW_Memory,
- "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, dest_addr, size);
- break;
- }
- case Common::PageType::Memory: {
- DEBUG_ASSERT(page_table.pointers[page_index]);
+u8 Memory::Read8(const VAddr addr) {
+ return impl->Read8(addr);
+}
- u8* dest_ptr = page_table.pointers[page_index] + page_offset;
- std::memset(dest_ptr, 0, copy_amount);
- break;
- }
- case Common::PageType::RasterizerCachedMemory: {
- const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
- Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
- std::memset(host_ptr, 0, copy_amount);
- break;
- }
- default:
- UNREACHABLE();
- }
+u16 Memory::Read16(const VAddr addr) {
+ return impl->Read16(addr);
+}
- page_index++;
- page_offset = 0;
- remaining_size -= copy_amount;
- }
+u32 Memory::Read32(const VAddr addr) {
+ return impl->Read32(addr);
}
-void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
- const std::size_t size) {
- const auto& page_table = process.VMManager().page_table;
- std::size_t remaining_size = size;
- std::size_t page_index = src_addr >> PAGE_BITS;
- std::size_t page_offset = src_addr & PAGE_MASK;
-
- while (remaining_size > 0) {
- const std::size_t copy_amount =
- std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
- const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
-
- switch (page_table.attributes[page_index]) {
- case Common::PageType::Unmapped: {
- LOG_ERROR(HW_Memory,
- "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, src_addr, size);
- ZeroBlock(process, dest_addr, copy_amount);
- break;
- }
- case Common::PageType::Memory: {
- DEBUG_ASSERT(page_table.pointers[page_index]);
- const u8* src_ptr = page_table.pointers[page_index] + page_offset;
- WriteBlock(process, dest_addr, src_ptr, copy_amount);
- break;
- }
- case Common::PageType::RasterizerCachedMemory: {
- const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
- Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
- WriteBlock(process, dest_addr, host_ptr, copy_amount);
- break;
- }
- default:
- UNREACHABLE();
- }
+u64 Memory::Read64(const VAddr addr) {
+ return impl->Read64(addr);
+}
- page_index++;
- page_offset = 0;
- dest_addr += static_cast<VAddr>(copy_amount);
- src_addr += static_cast<VAddr>(copy_amount);
- remaining_size -= copy_amount;
- }
+void Memory::Write8(VAddr addr, u8 data) {
+ impl->Write8(addr, data);
+}
+
+void Memory::Write16(VAddr addr, u16 data) {
+ impl->Write16(addr, data);
+}
+
+void Memory::Write32(VAddr addr, u32 data) {
+ impl->Write32(addr, data);
+}
+
+void Memory::Write64(VAddr addr, u64 data) {
+ impl->Write64(addr, data);
+}
+
+std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
+ return impl->ReadCString(vaddr, max_length);
+}
+
+void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
+ const std::size_t size) {
+ impl->ReadBlock(process, src_addr, dest_buffer, size);
+}
+
+void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
+ impl->ReadBlock(src_addr, dest_buffer, size);
+}
+
+void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ std::size_t size) {
+ impl->WriteBlock(process, dest_addr, src_buffer, size);
+}
+
+void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
+ impl->WriteBlock(dest_addr, src_buffer, size);
}
-void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
- CopyBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_addr, size);
+void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
+ impl->ZeroBlock(process, dest_addr, size);
+}
+
+void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) {
+ impl->ZeroBlock(dest_addr, size);
+}
+
+void Memory::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+ const std::size_t size) {
+ impl->CopyBlock(process, dest_addr, src_addr, size);
+}
+
+void Memory::CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
+ impl->CopyBlock(dest_addr, src_addr, size);
+}
+
+void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
+ impl->RasterizerMarkRegionCached(vaddr, size, cached);
+}
+
+bool IsKernelVirtualAddress(const VAddr vaddr) {
+ return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
}
} // namespace Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index 09008e1dd..1428a6d60 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -5,8 +5,18 @@
#pragma once
#include <cstddef>
+#include <memory>
#include <string>
#include "common/common_types.h"
+#include "common/memory_hook.h"
+
+namespace Common {
+struct PageTable;
+}
+
+namespace Core {
+class System;
+}
namespace Kernel {
class Process;
@@ -36,41 +46,369 @@ enum : VAddr {
KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
};
-/// Changes the currently active page table to that of
-/// the given process instance.
-void SetCurrentPageTable(Kernel::Process& process);
+/// Central class that handles all memory operations and state.
+class Memory {
+public:
+ explicit Memory(Core::System& system);
+ ~Memory();
-/// Determines if the given VAddr is valid for the specified process.
-bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
-bool IsValidVirtualAddress(VAddr vaddr);
-/// Determines if the given VAddr is a kernel address
-bool IsKernelVirtualAddress(VAddr vaddr);
+ Memory(const Memory&) = delete;
+ Memory& operator=(const Memory&) = delete;
-u8 Read8(VAddr addr);
-u16 Read16(VAddr addr);
-u32 Read32(VAddr addr);
-u64 Read64(VAddr addr);
+ Memory(Memory&&) = default;
+ Memory& operator=(Memory&&) = default;
-void Write8(VAddr addr, u8 data);
-void Write16(VAddr addr, u16 data);
-void Write32(VAddr addr, u32 data);
-void Write64(VAddr addr, u64 data);
+ /**
+ * Changes the currently active page table to that of the given process instance.
+ *
+ * @param process The process to use the page table of.
+ */
+ void SetCurrentPageTable(Kernel::Process& process);
-void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
-void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
-void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
- std::size_t size);
-void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
-void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
-void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
+ /**
+ * Maps an allocated buffer onto a region of the emulated process address space.
+ *
+ * @param page_table The page table of the emulated process.
+ * @param base The address to start mapping at. Must be page-aligned.
+ * @param size The amount of bytes to map. Must be page-aligned.
+ * @param target Buffer with the memory backing the mapping. Must be of length at least
+ * `size`.
+ */
+ void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
-u8* GetPointer(VAddr vaddr);
+ /**
+ * Maps a region of the emulated process address space as a IO region.
+ *
+ * @param page_table The page table of the emulated process.
+ * @param base The address to start mapping at. Must be page-aligned.
+ * @param size The amount of bytes to map. Must be page-aligned.
+ * @param mmio_handler The handler that backs the mapping.
+ */
+ void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer mmio_handler);
-std::string ReadCString(VAddr vaddr, std::size_t max_length);
+ /**
+ * Unmaps a region of the emulated process address space.
+ *
+ * @param page_table The page table of the emulated process.
+ * @param base The address to begin unmapping at.
+ * @param size The amount of bytes to unmap.
+ */
+ void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
-/**
- * Mark each page touching the region as cached.
- */
-void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
+ /**
+ * Adds a memory hook to intercept reads and writes to given region of memory.
+ *
+ * @param page_table The page table of the emulated process
+ * @param base The starting address to apply the hook to.
+ * @param size The size of the memory region to apply the hook to, in bytes.
+ * @param hook The hook to apply to the region of memory.
+ */
+ void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer hook);
+
+ /**
+ * Removes a memory hook from a given range of memory.
+ *
+ * @param page_table The page table of the emulated process.
+ * @param base The starting address to remove the hook from.
+ * @param size The size of the memory region to remove the hook from, in bytes.
+ * @param hook The hook to remove from the specified region of memory.
+ */
+ void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
+ Common::MemoryHookPointer hook);
+
+ /**
+ * Checks whether or not the supplied address is a valid virtual
+ * address for the given process.
+ *
+ * @param process The emulated process to check the address against.
+ * @param vaddr The virtual address to check the validity of.
+ *
+ * @returns True if the given virtual address is valid, false otherwise.
+ */
+ bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const;
+
+ /**
+ * Checks whether or not the supplied address is a valid virtual
+ * address for the current process.
+ *
+ * @param vaddr The virtual address to check the validity of.
+ *
+ * @returns True if the given virtual address is valid, false otherwise.
+ */
+ bool IsValidVirtualAddress(VAddr vaddr) const;
+
+ /**
+ * Gets a pointer to the given address.
+ *
+ * @param vaddr Virtual address to retrieve a pointer to.
+ *
+ * @returns The pointer to the given address, if the address is valid.
+ * If the address is not valid, nullptr will be returned.
+ */
+ u8* GetPointer(VAddr vaddr);
+
+ /**
+ * Gets a pointer to the given address.
+ *
+ * @param vaddr Virtual address to retrieve a pointer to.
+ *
+ * @returns The pointer to the given address, if the address is valid.
+ * If the address is not valid, nullptr will be returned.
+ */
+ const u8* GetPointer(VAddr vaddr) const;
+
+ /**
+ * Reads an 8-bit unsigned value from the current process' address space
+ * at the given virtual address.
+ *
+ * @param addr The virtual address to read the 8-bit value from.
+ *
+ * @returns the read 8-bit unsigned value.
+ */
+ u8 Read8(VAddr addr);
+
+ /**
+ * Reads a 16-bit unsigned value from the current process' address space
+ * at the given virtual address.
+ *
+ * @param addr The virtual address to read the 16-bit value from.
+ *
+ * @returns the read 16-bit unsigned value.
+ */
+ u16 Read16(VAddr addr);
+
+ /**
+ * Reads a 32-bit unsigned value from the current process' address space
+ * at the given virtual address.
+ *
+ * @param addr The virtual address to read the 32-bit value from.
+ *
+ * @returns the read 32-bit unsigned value.
+ */
+ u32 Read32(VAddr addr);
+
+ /**
+ * Reads a 64-bit unsigned value from the current process' address space
+ * at the given virtual address.
+ *
+ * @param addr The virtual address to read the 64-bit value from.
+ *
+ * @returns the read 64-bit value.
+ */
+ u64 Read64(VAddr addr);
+
+ /**
+ * Writes an 8-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 8-bit unsigned integer to.
+ * @param data The 8-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory at the given virtual address contains the specified data value.
+ */
+ void Write8(VAddr addr, u8 data);
+
+ /**
+ * Writes a 16-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 16-bit unsigned integer to.
+ * @param data The 16-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory range [addr, sizeof(data)) contains the given data value.
+ */
+ void Write16(VAddr addr, u16 data);
+
+ /**
+ * Writes a 32-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 32-bit unsigned integer to.
+ * @param data The 32-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory range [addr, sizeof(data)) contains the given data value.
+ */
+ void Write32(VAddr addr, u32 data);
+
+ /**
+ * Writes a 64-bit unsigned integer to the given virtual address in
+ * the current process' address space.
+ *
+ * @param addr The virtual address to write the 64-bit unsigned integer to.
+ * @param data The 64-bit unsigned integer to write to the given virtual address.
+ *
+ * @post The memory range [addr, sizeof(data)) contains the given data value.
+ */
+ void Write64(VAddr addr, u64 data);
+
+ /**
+ * Reads a null-terminated string from the given virtual address.
+ * This function will continually read characters until either:
+ *
+ * - A null character ('\0') is reached.
+ * - max_length characters have been read.
+ *
+ * @note The final null-terminating character (if found) is not included
+ * in the returned string.
+ *
+ * @param vaddr The address to begin reading the string from.
+ * @param max_length The maximum length of the string to read in characters.
+ *
+ * @returns The read string.
+ */
+ std::string ReadCString(VAddr vaddr, std::size_t max_length);
+
+ /**
+ * Reads a contiguous block of bytes from a specified process' address space.
+ *
+ * @param process The process to read the data from.
+ * @param src_addr The virtual address to begin reading from.
+ * @param dest_buffer The buffer to place the read bytes into.
+ * @param size The amount of data to read, in bytes.
+ *
+ * @note If a size of 0 is specified, then this function reads nothing and
+ * no attempts to access memory are made at all.
+ *
+ * @pre dest_buffer must be at least size bytes in length, otherwise a
+ * buffer overrun will occur.
+ *
+ * @post The range [dest_buffer, size) contains the read bytes from the
+ * process' address space.
+ */
+ void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
+ std::size_t size);
+
+ /**
+ * Reads a contiguous block of bytes from the current process' address space.
+ *
+ * @param src_addr The virtual address to begin reading from.
+ * @param dest_buffer The buffer to place the read bytes into.
+ * @param size The amount of data to read, in bytes.
+ *
+ * @note If a size of 0 is specified, then this function reads nothing and
+ * no attempts to access memory are made at all.
+ *
+ * @pre dest_buffer must be at least size bytes in length, otherwise a
+ * buffer overrun will occur.
+ *
+ * @post The range [dest_buffer, size) contains the read bytes from the
+ * current process' address space.
+ */
+ void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
+
+ /**
+ * Writes a range of bytes into a given process' address space at the specified
+ * virtual address.
+ *
+ * @param process The process to write data into the address space of.
+ * @param dest_addr The destination virtual address to begin writing the data at.
+ * @param src_buffer The data to write into the process' address space.
+ * @param size The size of the data to write, in bytes.
+ *
+ * @post The address range [dest_addr, size) in the process' address space
+ * contains the data that was within src_buffer.
+ *
+ * @post If an attempt is made to write into an unmapped region of memory, the writes
+ * will be ignored and an error will be logged.
+ *
+ * @post If a write is performed into a region of memory that is considered cached
+ * rasterizer memory, will cause the currently active rasterizer to be notified
+ * and will mark that region as invalidated to caches that the active
+ * graphics backend may be maintaining over the course of execution.
+ */
+ void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ std::size_t size);
+
+ /**
+ * Writes a range of bytes into the current process' address space at the specified
+ * virtual address.
+ *
+ * @param dest_addr The destination virtual address to begin writing the data at.
+ * @param src_buffer The data to write into the current process' address space.
+ * @param size The size of the data to write, in bytes.
+ *
+ * @post The address range [dest_addr, size) in the current process' address space
+ * contains the data that was within src_buffer.
+ *
+ * @post If an attempt is made to write into an unmapped region of memory, the writes
+ * will be ignored and an error will be logged.
+ *
+ * @post If a write is performed into a region of memory that is considered cached
+ * rasterizer memory, will cause the currently active rasterizer to be notified
+ * and will mark that region as invalidated to caches that the active
+ * graphics backend may be maintaining over the course of execution.
+ */
+ void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
+
+ /**
+ * Fills the specified address range within a process' address space with zeroes.
+ *
+ * @param process The process that will have a portion of its memory zeroed out.
+ * @param dest_addr The starting virtual address of the range to zero out.
+ * @param size The size of the address range to zero out, in bytes.
+ *
+ * @post The range [dest_addr, size) within the process' address space is
+ * filled with zeroes.
+ */
+ void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
+
+ /**
+ * Fills the specified address range within the current process' address space with zeroes.
+ *
+ * @param dest_addr The starting virtual address of the range to zero out.
+ * @param size The size of the address range to zero out, in bytes.
+ *
+ * @post The range [dest_addr, size) within the current process' address space is
+ * filled with zeroes.
+ */
+ void ZeroBlock(VAddr dest_addr, std::size_t size);
+
+ /**
+ * Copies data within a process' address space to another location within the
+ * same address space.
+ *
+ * @param process The process that will have data copied within its address space.
+ * @param dest_addr The destination virtual address to begin copying the data into.
+ * @param src_addr The source virtual address to begin copying the data from.
+ * @param size The size of the data to copy, in bytes.
+ *
+ * @post The range [dest_addr, size) within the process' address space contains the
+ * same data within the range [src_addr, size).
+ */
+ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+ std::size_t size);
+
+ /**
+ * Copies data within the current process' address space to another location within the
+ * same address space.
+ *
+ * @param dest_addr The destination virtual address to begin copying the data into.
+ * @param src_addr The source virtual address to begin copying the data from.
+ * @param size The size of the data to copy, in bytes.
+ *
+ * @post The range [dest_addr, size) within the current process' address space
+ * contains the same data within the range [src_addr, size).
+ */
+ void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
+
+ /**
+ * Marks each page within the specified address range as cached or uncached.
+ *
+ * @param vaddr The virtual address indicating the start of the address range.
+ * @param size The size of the address range in bytes.
+ * @param cached Whether or not any pages within the address range should be
+ * marked as cached or uncached.
+ */
+ void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
+
+private:
+ struct Impl;
+ std::unique_ptr<Impl> impl;
+};
+
+/// Determines if the given VAddr is a kernel address
+bool IsKernelVirtualAddress(VAddr vaddr);
} // namespace Memory
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 10821d452..d1e6bed93 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -20,18 +20,17 @@ namespace Memory {
constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12);
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
-StandardVmCallbacks::StandardVmCallbacks(const Core::System& system,
- const CheatProcessMetadata& metadata)
+StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
: metadata(metadata), system(system) {}
StandardVmCallbacks::~StandardVmCallbacks() = default;
void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
- ReadBlock(SanitizeAddress(address), data, size);
+ system.Memory().ReadBlock(SanitizeAddress(address), data, size);
}
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
- WriteBlock(SanitizeAddress(address), data, size);
+ system.Memory().WriteBlock(SanitizeAddress(address), data, size);
}
u64 StandardVmCallbacks::HidKeysDown() {
@@ -186,7 +185,7 @@ CheatEngine::~CheatEngine() {
}
void CheatEngine::Initialize() {
- event = core_timing.RegisterEvent(
+ event = Core::Timing::CreateEvent(
"CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
[this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index 0f012e9b5..3d6b2298a 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -5,6 +5,7 @@
#pragma once
#include <atomic>
+#include <memory>
#include <vector>
#include "common/common_types.h"
#include "core/memory/dmnt_cheat_types.h"
@@ -23,7 +24,7 @@ namespace Memory {
class StandardVmCallbacks : public DmntCheatVm::Callbacks {
public:
- StandardVmCallbacks(const Core::System& system, const CheatProcessMetadata& metadata);
+ StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata);
~StandardVmCallbacks() override;
void MemoryRead(VAddr address, void* data, u64 size) override;
@@ -36,7 +37,7 @@ private:
VAddr SanitizeAddress(VAddr address) const;
const CheatProcessMetadata& metadata;
- const Core::System& system;
+ Core::System& system;
};
// Intermediary class that parses a text file or other disk format for storing cheats into a
@@ -78,7 +79,7 @@ private:
std::vector<CheatEntry> cheats;
std::atomic_bool is_pending_reload{false};
- Core::Timing::EventType* event{};
+ std::shared_ptr<Core::Timing::EventType> event;
Core::Timing::CoreTiming& core_timing;
Core::System& system;
};
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
deleted file mode 100644
index 5225ee8e2..000000000
--- a/src/core/memory_setup.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-#include "common/memory_hook.h"
-
-namespace Common {
-struct PageTable;
-}
-
-namespace Memory {
-
-/**
- * Maps an allocated buffer onto a region of the emulated process address space.
- *
- * @param page_table The page table of the emulated process.
- * @param base The address to start mapping at. Must be page-aligned.
- * @param size The amount of bytes to map. Must be page-aligned.
- * @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
- */
-void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
-
-/**
- * Maps a region of the emulated process address space as a IO region.
- * @param page_table The page table of the emulated process.
- * @param base The address to start mapping at. Must be page-aligned.
- * @param size The amount of bytes to map. Must be page-aligned.
- * @param mmio_handler The handler that backs the mapping.
- */
-void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
- Common::MemoryHookPointer mmio_handler);
-
-void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
-
-void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
- Common::MemoryHookPointer hook);
-void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
- Common::MemoryHookPointer hook);
-
-} // namespace Memory
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 6f4af77fd..f95eee3b1 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -147,7 +147,7 @@ json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& s
}
template <bool read_value, typename DescriptorType>
-json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
+json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer, Memory::Memory& memory) {
auto buffer_out = json::array();
for (const auto& desc : buffer) {
auto entry = json{
@@ -157,7 +157,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
if constexpr (read_value) {
std::vector<u8> data(desc.Size());
- Memory::ReadBlock(desc.Address(), data.data(), desc.Size());
+ memory.ReadBlock(desc.Address(), data.data(), desc.Size());
entry["data"] = Common::HexToString(data);
}
@@ -167,7 +167,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
return buffer_out;
}
-json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
+json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Memory::Memory& memory) {
json out;
auto cmd_buf = json::array();
@@ -177,10 +177,10 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
out["command_buffer"] = std::move(cmd_buf);
- out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA());
- out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB());
- out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC());
- out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX());
+ out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA(), memory);
+ out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB(), memory);
+ out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC(), memory);
+ out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX(), memory);
return out;
}
@@ -259,7 +259,7 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u
const auto title_id = system.CurrentProcess()->GetTitleID();
auto out = GetFullDataAuto(timestamp, title_id, system);
- auto function_out = GetHLERequestContextData(ctx);
+ auto function_out = GetHLERequestContextData(ctx, system.Memory());
function_out["command_id"] = command_id;
function_out["function_name"] = name;
function_out["service_name"] = service_name;
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 17f050068..55e0dbc49 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -11,40 +11,39 @@
#include "core/tools/freezer.h"
namespace Tools {
-
namespace {
constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
-u64 MemoryReadWidth(u32 width, VAddr addr) {
+u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
switch (width) {
case 1:
- return Memory::Read8(addr);
+ return memory.Read8(addr);
case 2:
- return Memory::Read16(addr);
+ return memory.Read16(addr);
case 4:
- return Memory::Read32(addr);
+ return memory.Read32(addr);
case 8:
- return Memory::Read64(addr);
+ return memory.Read64(addr);
default:
UNREACHABLE();
return 0;
}
}
-void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
+void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
switch (width) {
case 1:
- Memory::Write8(addr, static_cast<u8>(value));
+ memory.Write8(addr, static_cast<u8>(value));
break;
case 2:
- Memory::Write16(addr, static_cast<u16>(value));
+ memory.Write16(addr, static_cast<u16>(value));
break;
case 4:
- Memory::Write32(addr, static_cast<u32>(value));
+ memory.Write32(addr, static_cast<u32>(value));
break;
case 8:
- Memory::Write64(addr, value);
+ memory.Write64(addr, value);
break;
default:
UNREACHABLE();
@@ -53,8 +52,9 @@ void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
} // Anonymous namespace
-Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) {
- event = core_timing.RegisterEvent(
+Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_)
+ : core_timing{core_timing_}, memory{memory_} {
+ event = Core::Timing::CreateEvent(
"MemoryFreezer::FrameCallback",
[this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event);
@@ -89,7 +89,7 @@ void Freezer::Clear() {
u64 Freezer::Freeze(VAddr address, u32 width) {
std::lock_guard lock{entries_mutex};
- const auto current_value = MemoryReadWidth(width, address);
+ const auto current_value = MemoryReadWidth(memory, width, address);
entries.push_back({address, width, current_value});
LOG_DEBUG(Common_Memory,
@@ -169,7 +169,7 @@ void Freezer::FrameCallback(u64 userdata, s64 cycles_late) {
LOG_DEBUG(Common_Memory,
"Enforcing memory freeze at address={:016X}, value={:016X}, width={:02X}",
entry.address, entry.value, entry.width);
- MemoryWriteWidth(entry.width, entry.address, entry.value);
+ MemoryWriteWidth(memory, entry.width, entry.address, entry.value);
}
core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - cycles_late, event);
@@ -181,7 +181,7 @@ void Freezer::FillEntryReads() {
LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values.");
for (auto& entry : entries) {
- entry.value = MemoryReadWidth(entry.width, entry.address);
+ entry.value = MemoryReadWidth(memory, entry.width, entry.address);
}
}
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index b58de5472..916339c6c 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -5,6 +5,7 @@
#pragma once
#include <atomic>
+#include <memory>
#include <mutex>
#include <optional>
#include <vector>
@@ -15,6 +16,10 @@ class CoreTiming;
struct EventType;
} // namespace Core::Timing
+namespace Memory {
+class Memory;
+}
+
namespace Tools {
/**
@@ -33,7 +38,7 @@ public:
u64 value;
};
- explicit Freezer(Core::Timing::CoreTiming& core_timing);
+ explicit Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_);
~Freezer();
// Enables or disables the entire memory freezer.
@@ -75,8 +80,9 @@ private:
mutable std::mutex entries_mutex;
std::vector<Entry> entries;
- Core::Timing::EventType* event;
+ std::shared_ptr<Core::Timing::EventType> event;
Core::Timing::CoreTiming& core_timing;
+ Memory::Memory& memory;
};
} // namespace Tools