summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Lioncash2019-11-26 17:39:57 -0500
committerGravatar Lioncash2019-11-26 21:55:39 -0500
commite4c381b8850db96f162cfcf2cbe28b0e7c1f76f1 (patch)
tree14b95ea207543f3884558ebdf8673a511bf64dc3 /src
parentcore/memory: Migrate over Read{8, 16, 32, 64, Block} to the Memory class (diff)
downloadyuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.gz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.xz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.zip
core/memory: Migrate over Write{8, 16, 32, 64, Block} to the Memory class
The Write functions are used slightly less than the Read functions, which make these a bit nicer to move over. The only adjustments we really need to make here are to Dynarmic's exclusive monitor instance. We need to keep a reference to the currently active memory instance to perform exclusive read/write operations.
Diffstat (limited to 'src')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp30
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h7
-rw-r--r--src/core/core_cpu.cpp5
-rw-r--r--src/core/core_cpu.h18
-rw-r--r--src/core/cpu_core_manager.cpp2
-rw-r--r--src/core/gdbstub/gdbstub.cpp16
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp9
-rw-r--r--src/core/hle/kernel/mutex.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp27
-rw-r--r--src/core/memory.cpp220
-rw-r--r--src/core/memory.h97
-rw-r--r--src/core/memory/cheat_engine.cpp2
-rw-r--r--src/core/tools/freezer.cpp8
14 files changed, 298 insertions, 153 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 585fb55a9..f8c7f0efd 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -45,20 +45,21 @@ public:
45 } 45 }
46 46
47 void MemoryWrite8(u64 vaddr, u8 value) override { 47 void MemoryWrite8(u64 vaddr, u8 value) override {
48 Memory::Write8(vaddr, value); 48 parent.system.Memory().Write8(vaddr, value);
49 } 49 }
50 void MemoryWrite16(u64 vaddr, u16 value) override { 50 void MemoryWrite16(u64 vaddr, u16 value) override {
51 Memory::Write16(vaddr, value); 51 parent.system.Memory().Write16(vaddr, value);
52 } 52 }
53 void MemoryWrite32(u64 vaddr, u32 value) override { 53 void MemoryWrite32(u64 vaddr, u32 value) override {
54 Memory::Write32(vaddr, value); 54 parent.system.Memory().Write32(vaddr, value);
55 } 55 }
56 void MemoryWrite64(u64 vaddr, u64 value) override { 56 void MemoryWrite64(u64 vaddr, u64 value) override {
57 Memory::Write64(vaddr, value); 57 parent.system.Memory().Write64(vaddr, value);
58 } 58 }
59 void MemoryWrite128(u64 vaddr, Vector value) override { 59 void MemoryWrite128(u64 vaddr, Vector value) override {
60 Memory::Write64(vaddr, value[0]); 60 auto& memory = parent.system.Memory();
61 Memory::Write64(vaddr + 8, value[1]); 61 memory.Write64(vaddr, value[0]);
62 memory.Write64(vaddr + 8, value[1]);
62 } 63 }
63 64
64 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 65 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
@@ -266,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
266 jit = MakeJit(page_table, new_address_space_size_in_bits); 267 jit = MakeJit(page_table, new_address_space_size_in_bits);
267} 268}
268 269
269DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} 270DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count)
271 : monitor(core_count), memory{memory_} {}
272
270DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; 273DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
271 274
272void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { 275void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
@@ -279,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
279} 282}
280 283
281bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { 284bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
282 return monitor.DoExclusiveOperation(core_index, vaddr, 1, 285 return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); });
283 [&] { Memory::Write8(vaddr, value); });
284} 286}
285 287
286bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { 288bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
287 return monitor.DoExclusiveOperation(core_index, vaddr, 2, 289 return monitor.DoExclusiveOperation(core_index, vaddr, 2,
288 [&] { Memory::Write16(vaddr, value); }); 290 [&] { memory.Write16(vaddr, value); });
289} 291}
290 292
291bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { 293bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
292 return monitor.DoExclusiveOperation(core_index, vaddr, 4, 294 return monitor.DoExclusiveOperation(core_index, vaddr, 4,
293 [&] { Memory::Write32(vaddr, value); }); 295 [&] { memory.Write32(vaddr, value); });
294} 296}
295 297
296bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { 298bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
297 return monitor.DoExclusiveOperation(core_index, vaddr, 8, 299 return monitor.DoExclusiveOperation(core_index, vaddr, 8,
298 [&] { Memory::Write64(vaddr, value); }); 300 [&] { memory.Write64(vaddr, value); });
299} 301}
300 302
301bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { 303bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
302 return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { 304 return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
303 Memory::Write64(vaddr + 0, value[0]); 305 memory.Write64(vaddr + 0, value[0]);
304 Memory::Write64(vaddr + 8, value[1]); 306 memory.Write64(vaddr + 8, value[1]);
305 }); 307 });
306} 308}
307 309
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index d08de475f..9cd475cfb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,6 +12,10 @@
12#include "core/arm/exclusive_monitor.h" 12#include "core/arm/exclusive_monitor.h"
13#include "core/arm/unicorn/arm_unicorn.h" 13#include "core/arm/unicorn/arm_unicorn.h"
14 14
15namespace Memory {
16class Memory;
17}
18
15namespace Core { 19namespace Core {
16 20
17class ARM_Dynarmic_Callbacks; 21class ARM_Dynarmic_Callbacks;
@@ -63,7 +67,7 @@ private:
63 67
64class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 68class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
65public: 69public:
66 explicit DynarmicExclusiveMonitor(std::size_t core_count); 70 explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count);
67 ~DynarmicExclusiveMonitor() override; 71 ~DynarmicExclusiveMonitor() override;
68 72
69 void SetExclusive(std::size_t core_index, VAddr addr) override; 73 void SetExclusive(std::size_t core_index, VAddr addr) override;
@@ -78,6 +82,7 @@ public:
78private: 82private:
79 friend class ARM_Dynarmic; 83 friend class ARM_Dynarmic;
80 Dynarmic::A64::ExclusiveMonitor monitor; 84 Dynarmic::A64::ExclusiveMonitor monitor;
85 Memory::Memory& memory;
81}; 86};
82 87
83} // namespace Core 88} // namespace Core
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
66 66
67Cpu::~Cpu() = default; 67Cpu::~Cpu() = default;
68 68
69std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { 69std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
70 [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
70#ifdef ARCHITECTURE_x86_64 71#ifdef ARCHITECTURE_x86_64
71 return std::make_unique<DynarmicExclusiveMonitor>(num_cores); 72 return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
72#else 73#else
73 // TODO(merry): Passthrough exclusive monitor 74 // TODO(merry): Passthrough exclusive monitor
74 return nullptr; 75 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 {
24class CoreTiming; 24class CoreTiming;
25} 25}
26 26
27namespace Memory {
28class Memory;
29}
30
27namespace Core { 31namespace Core {
28 32
29class ARM_Interface; 33class ARM_Interface;
@@ -86,7 +90,19 @@ public:
86 90
87 void Shutdown(); 91 void Shutdown();
88 92
89 static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores); 93 /**
94 * Creates an exclusive monitor to handle exclusive reads/writes.
95 *
96 * @param memory The current memory subsystem that the monitor may wish
97 * to keep track of.
98 *
99 * @param num_cores The number of cores to assume about the CPU.
100 *
101 * @returns The constructed exclusive monitor instance, or nullptr if the current
102 * CPU backend is unable to use an exclusive monitor.
103 */
104 static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
105 std::size_t num_cores);
90 106
91private: 107private:
92 void Reschedule(); 108 void Reschedule();
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;
25 25
26void CpuCoreManager::Initialize() { 26void CpuCoreManager::Initialize() {
27 barrier = std::make_unique<CpuBarrier>(); 27 barrier = std::make_unique<CpuBarrier>();
28 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); 28 exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
29 29
30 for (std::size_t index = 0; index < cores.size(); ++index) { 30 for (std::size_t index = 0; index < cores.size(); ++index) {
31 cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); 31 cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 1c74a44d8..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) {
508 bp->second.len, bp->second.addr, static_cast<int>(type)); 508 bp->second.len, bp->second.addr, static_cast<int>(type));
509 509
510 if (type == BreakpointType::Execute) { 510 if (type == BreakpointType::Execute) {
511 Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); 511 auto& system = Core::System::GetInstance();
512 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 512 system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
513 system.InvalidateCpuInstructionCaches();
513 } 514 }
514 p.erase(addr); 515 p.erase(addr);
515} 516}
@@ -993,14 +994,14 @@ static void WriteMemory() {
993 const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset)); 994 const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
994 995
995 auto& system = Core::System::GetInstance(); 996 auto& system = Core::System::GetInstance();
996 const auto& memory = system.Memory(); 997 auto& memory = system.Memory();
997 if (!memory.IsValidVirtualAddress(addr)) { 998 if (!memory.IsValidVirtualAddress(addr)) {
998 return SendReply("E00"); 999 return SendReply("E00");
999 } 1000 }
1000 1001
1001 std::vector<u8> data(len); 1002 std::vector<u8> data(len);
1002 GdbHexToMem(data.data(), len_pos + 1, len); 1003 GdbHexToMem(data.data(), len_pos + 1, len);
1003 Memory::WriteBlock(addr, data.data(), len); 1004 memory.WriteBlock(addr, data.data(), len);
1004 system.InvalidateCpuInstructionCaches(); 1005 system.InvalidateCpuInstructionCaches();
1005 SendReply("OK"); 1006 SendReply("OK");
1006} 1007}
@@ -1058,13 +1059,14 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1058 breakpoint.addr = addr; 1059 breakpoint.addr = addr;
1059 breakpoint.len = len; 1060 breakpoint.len = len;
1060 1061
1061 auto& memory = Core::System::GetInstance().Memory(); 1062 auto& system = Core::System::GetInstance();
1063 auto& memory = system.Memory();
1062 memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 1064 memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1063 1065
1064 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; 1066 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1065 if (type == BreakpointType::Execute) { 1067 if (type == BreakpointType::Execute) {
1066 Memory::WriteBlock(addr, btrap.data(), btrap.size()); 1068 memory.WriteBlock(addr, btrap.data(), btrap.size());
1067 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1069 system.InvalidateCpuInstructionCaches();
1068 } 1070 }
1069 p.insert({addr, breakpoint}); 1071 p.insert({addr, breakpoint});
1070 1072
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 07f0dac67..98d07fa5b 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -78,7 +78,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
78 return ERR_INVALID_STATE; 78 return ERR_INVALID_STATE;
79 } 79 }
80 80
81 Memory::Write32(address, static_cast<u32>(value + 1)); 81 memory.Write32(address, static_cast<u32>(value + 1));
82 return SignalToAddressOnly(address, num_to_wake); 82 return SignalToAddressOnly(address, num_to_wake);
83} 83}
84 84
@@ -117,7 +117,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
117 return ERR_INVALID_STATE; 117 return ERR_INVALID_STATE;
118 } 118 }
119 119
120 Memory::Write32(address, static_cast<u32>(updated_value)); 120 memory.Write32(address, static_cast<u32>(updated_value));
121 WakeThreads(waiting_threads, num_to_wake); 121 WakeThreads(waiting_threads, num_to_wake);
122 return RESULT_SUCCESS; 122 return RESULT_SUCCESS;
123} 123}
@@ -151,7 +151,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
151 } 151 }
152 152
153 if (should_decrement) { 153 if (should_decrement) {
154 Memory::Write32(address, static_cast<u32>(cur_value - 1)); 154 memory.Write32(address, static_cast<u32>(cur_value - 1));
155 } 155 }
156 156
157 // Short-circuit without rescheduling, if timeout is zero. 157 // Short-circuit without rescheduling, if timeout is zero.
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 03745c449..8b01567a8 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -274,8 +274,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
274 } 274 }
275 275
276 // Copy the translated command buffer back into the thread's command buffer area. 276 // Copy the translated command buffer back into the thread's command buffer area.
277 Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), 277 memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
278 dst_cmdbuf.size() * sizeof(u32)); 278 dst_cmdbuf.size() * sizeof(u32));
279 279
280 return RESULT_SUCCESS; 280 return RESULT_SUCCESS;
281} 281}
@@ -311,10 +311,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
311 size = buffer_size; // TODO(bunnei): This needs to be HW tested 311 size = buffer_size; // TODO(bunnei): This needs to be HW tested
312 } 312 }
313 313
314 auto& memory = Core::System::GetInstance().Memory();
314 if (is_buffer_b) { 315 if (is_buffer_b) {
315 Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); 316 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
316 } else { 317 } else {
317 Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); 318 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
318 } 319 }
319 320
320 return size; 321 return size;
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 88eede436..061e9bcb0 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -117,7 +117,7 @@ ResultCode Mutex::Release(VAddr address) {
117 117
118 // There are no more threads waiting for the mutex, release it completely. 118 // There are no more threads waiting for the mutex, release it completely.
119 if (thread == nullptr) { 119 if (thread == nullptr) {
120 Memory::Write32(address, 0); 120 system.Memory().Write32(address, 0);
121 return RESULT_SUCCESS; 121 return RESULT_SUCCESS;
122 } 122 }
123 123
@@ -132,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) {
132 } 132 }
133 133
134 // Grant the mutex to the next waiting thread and resume it. 134 // Grant the mutex to the next waiting thread and resume it.
135 Memory::Write32(address, mutex_value); 135 system.Memory().Write32(address, mutex_value);
136 136
137 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); 137 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
138 thread->ResumeFromWait(); 138 thread->ResumeFromWait();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index a6c377cfc..db3ae3eb8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1120,7 +1120,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
1120 std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); 1120 std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
1121 } 1121 }
1122 1122
1123 Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); 1123 system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
1124 return RESULT_SUCCESS; 1124 return RESULT_SUCCESS;
1125} 1125}
1126 1126
@@ -1280,20 +1280,21 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
1280 return ERR_INVALID_HANDLE; 1280 return ERR_INVALID_HANDLE;
1281 } 1281 }
1282 1282
1283 auto& memory = system.Memory();
1283 const auto& vm_manager = process->VMManager(); 1284 const auto& vm_manager = process->VMManager();
1284 const MemoryInfo memory_info = vm_manager.QueryMemory(address); 1285 const MemoryInfo memory_info = vm_manager.QueryMemory(address);
1285 1286
1286 Memory::Write64(memory_info_address, memory_info.base_address); 1287 memory.Write64(memory_info_address, memory_info.base_address);
1287 Memory::Write64(memory_info_address + 8, memory_info.size); 1288 memory.Write64(memory_info_address + 8, memory_info.size);
1288 Memory::Write32(memory_info_address + 16, memory_info.state); 1289 memory.Write32(memory_info_address + 16, memory_info.state);
1289 Memory::Write32(memory_info_address + 20, memory_info.attributes); 1290 memory.Write32(memory_info_address + 20, memory_info.attributes);
1290 Memory::Write32(memory_info_address + 24, memory_info.permission); 1291 memory.Write32(memory_info_address + 24, memory_info.permission);
1291 Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count); 1292 memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count);
1292 Memory::Write32(memory_info_address + 28, memory_info.device_ref_count); 1293 memory.Write32(memory_info_address + 28, memory_info.device_ref_count);
1293 Memory::Write32(memory_info_address + 36, 0); 1294 memory.Write32(memory_info_address + 36, 0);
1294 1295
1295 // Page info appears to be currently unused by the kernel and is always set to zero. 1296 // Page info appears to be currently unused by the kernel and is always set to zero.
1296 Memory::Write32(page_info_address, 0); 1297 memory.Write32(page_info_address, 0);
1297 1298
1298 return RESULT_SUCCESS; 1299 return RESULT_SUCCESS;
1299} 1300}
@@ -2290,12 +2291,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
2290 return ERR_INVALID_ADDRESS_STATE; 2291 return ERR_INVALID_ADDRESS_STATE;
2291 } 2292 }
2292 2293
2294 auto& memory = system.Memory();
2293 const auto& process_list = kernel.GetProcessList(); 2295 const auto& process_list = kernel.GetProcessList();
2294 const auto num_processes = process_list.size(); 2296 const auto num_processes = process_list.size();
2295 const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); 2297 const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
2296 2298
2297 for (std::size_t i = 0; i < copy_amount; ++i) { 2299 for (std::size_t i = 0; i < copy_amount; ++i) {
2298 Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); 2300 memory.Write64(out_process_ids, process_list[i]->GetProcessID());
2299 out_process_ids += sizeof(u64); 2301 out_process_ids += sizeof(u64);
2300 } 2302 }
2301 2303
@@ -2329,13 +2331,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
2329 return ERR_INVALID_ADDRESS_STATE; 2331 return ERR_INVALID_ADDRESS_STATE;
2330 } 2332 }
2331 2333
2334 auto& memory = system.Memory();
2332 const auto& thread_list = current_process->GetThreadList(); 2335 const auto& thread_list = current_process->GetThreadList();
2333 const auto num_threads = thread_list.size(); 2336 const auto num_threads = thread_list.size();
2334 const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); 2337 const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
2335 2338
2336 auto list_iter = thread_list.cbegin(); 2339 auto list_iter = thread_list.cbegin();
2337 for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { 2340 for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
2338 Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); 2341 memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
2339 out_thread_ids += sizeof(u64); 2342 out_thread_ids += sizeof(u64);
2340 } 2343 }
2341 2344
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 699c48107..5c940a82e 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -58,35 +58,6 @@ u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
58u8* GetPointerFromVMA(VAddr vaddr) { 58u8* GetPointerFromVMA(VAddr vaddr) {
59 return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); 59 return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr);
60} 60}
61
62template <typename T>
63void Write(const VAddr vaddr, const T data) {
64 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
65 if (page_pointer != nullptr) {
66 // NOTE: Avoid adding any extra logic to this fast-path block
67 std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
68 return;
69 }
70
71 Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
72 switch (type) {
73 case Common::PageType::Unmapped:
74 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
75 static_cast<u32>(data), vaddr);
76 return;
77 case Common::PageType::Memory:
78 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
79 break;
80 case Common::PageType::RasterizerCachedMemory: {
81 u8* const host_ptr{GetPointerFromVMA(vaddr)};
82 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
83 std::memcpy(host_ptr, &data, sizeof(T));
84 break;
85 }
86 default:
87 UNREACHABLE();
88 }
89}
90} // Anonymous namespace 61} // Anonymous namespace
91 62
92// Implementation class used to keep the specifics of the memory subsystem hidden 63// Implementation class used to keep the specifics of the memory subsystem hidden
@@ -195,6 +166,22 @@ struct Memory::Impl {
195 return Read<u64_le>(addr); 166 return Read<u64_le>(addr);
196 } 167 }
197 168
169 void Write8(const VAddr addr, const u8 data) {
170 Write<u8>(addr, data);
171 }
172
173 void Write16(const VAddr addr, const u16 data) {
174 Write<u16_le>(addr, data);
175 }
176
177 void Write32(const VAddr addr, const u32 data) {
178 Write<u32_le>(addr, data);
179 }
180
181 void Write64(const VAddr addr, const u64 data) {
182 Write<u64_le>(addr, data);
183 }
184
198 std::string ReadCString(VAddr vaddr, std::size_t max_length) { 185 std::string ReadCString(VAddr vaddr, std::size_t max_length) {
199 std::string string; 186 std::string string;
200 string.reserve(max_length); 187 string.reserve(max_length);
@@ -259,6 +246,53 @@ struct Memory::Impl {
259 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); 246 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
260 } 247 }
261 248
249 void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
250 const std::size_t size) {
251 const auto& page_table = process.VMManager().page_table;
252 std::size_t remaining_size = size;
253 std::size_t page_index = dest_addr >> PAGE_BITS;
254 std::size_t page_offset = dest_addr & PAGE_MASK;
255
256 while (remaining_size > 0) {
257 const std::size_t copy_amount =
258 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
259 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
260
261 switch (page_table.attributes[page_index]) {
262 case Common::PageType::Unmapped: {
263 LOG_ERROR(HW_Memory,
264 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
265 current_vaddr, dest_addr, size);
266 break;
267 }
268 case Common::PageType::Memory: {
269 DEBUG_ASSERT(page_table.pointers[page_index]);
270
271 u8* const dest_ptr = page_table.pointers[page_index] + page_offset;
272 std::memcpy(dest_ptr, src_buffer, copy_amount);
273 break;
274 }
275 case Common::PageType::RasterizerCachedMemory: {
276 u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
277 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
278 std::memcpy(host_ptr, src_buffer, copy_amount);
279 break;
280 }
281 default:
282 UNREACHABLE();
283 }
284
285 page_index++;
286 page_offset = 0;
287 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
288 remaining_size -= copy_amount;
289 }
290 }
291
292 void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
293 WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size);
294 }
295
262 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 296 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
263 const auto& page_table = process.VMManager().page_table; 297 const auto& page_table = process.VMManager().page_table;
264 std::size_t remaining_size = size; 298 std::size_t remaining_size = size;
@@ -501,6 +535,46 @@ struct Memory::Impl {
501 return {}; 535 return {};
502 } 536 }
503 537
538 /**
539 * Writes a particular data type to memory at the given virtual address.
540 *
541 * @param vaddr The virtual address to write the data type to.
542 *
543 * @tparam T The data type to write to memory. This type *must* be
544 * trivially copyable, otherwise the behavior of this function
545 * is undefined.
546 *
547 * @returns The instance of T write to the specified virtual address.
548 */
549 template <typename T>
550 void Write(const VAddr vaddr, const T data) {
551 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
552 if (page_pointer != nullptr) {
553 // NOTE: Avoid adding any extra logic to this fast-path block
554 std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
555 return;
556 }
557
558 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
559 switch (type) {
560 case Common::PageType::Unmapped:
561 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
562 static_cast<u32>(data), vaddr);
563 return;
564 case Common::PageType::Memory:
565 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
566 break;
567 case Common::PageType::RasterizerCachedMemory: {
568 u8* const host_ptr{GetPointerFromVMA(vaddr)};
569 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
570 std::memcpy(host_ptr, &data, sizeof(T));
571 break;
572 }
573 default:
574 UNREACHABLE();
575 }
576 }
577
504 Core::System& system; 578 Core::System& system;
505}; 579};
506 580
@@ -562,6 +636,22 @@ u64 Memory::Read64(const VAddr addr) {
562 return impl->Read64(addr); 636 return impl->Read64(addr);
563} 637}
564 638
639void Memory::Write8(VAddr addr, u8 data) {
640 impl->Write8(addr, data);
641}
642
643void Memory::Write16(VAddr addr, u16 data) {
644 impl->Write16(addr, data);
645}
646
647void Memory::Write32(VAddr addr, u32 data) {
648 impl->Write32(addr, data);
649}
650
651void Memory::Write64(VAddr addr, u64 data) {
652 impl->Write64(addr, data);
653}
654
565std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { 655std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
566 return impl->ReadCString(vaddr, max_length); 656 return impl->ReadCString(vaddr, max_length);
567} 657}
@@ -575,6 +665,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_
575 impl->ReadBlock(src_addr, dest_buffer, size); 665 impl->ReadBlock(src_addr, dest_buffer, size);
576} 666}
577 667
668void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
669 std::size_t size) {
670 impl->WriteBlock(process, dest_addr, src_buffer, size);
671}
672
673void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
674 impl->WriteBlock(dest_addr, src_buffer, size);
675}
676
578void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { 677void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
579 impl->ZeroBlock(process, dest_addr, size); 678 impl->ZeroBlock(process, dest_addr, size);
580} 679}
@@ -612,67 +711,4 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
612 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 711 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
613} 712}
614 713
615void Write8(const VAddr addr, const u8 data) {
616 Write<u8>(addr, data);
617}
618
619void Write16(const VAddr addr, const u16 data) {
620 Write<u16_le>(addr, data);
621}
622
623void Write32(const VAddr addr, const u32 data) {
624 Write<u32_le>(addr, data);
625}
626
627void Write64(const VAddr addr, const u64 data) {
628 Write<u64_le>(addr, data);
629}
630
631void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
632 const std::size_t size) {
633 const auto& page_table = process.VMManager().page_table;
634 std::size_t remaining_size = size;
635 std::size_t page_index = dest_addr >> PAGE_BITS;
636 std::size_t page_offset = dest_addr & PAGE_MASK;
637
638 while (remaining_size > 0) {
639 const std::size_t copy_amount =
640 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
641 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
642
643 switch (page_table.attributes[page_index]) {
644 case Common::PageType::Unmapped: {
645 LOG_ERROR(HW_Memory,
646 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
647 current_vaddr, dest_addr, size);
648 break;
649 }
650 case Common::PageType::Memory: {
651 DEBUG_ASSERT(page_table.pointers[page_index]);
652
653 u8* dest_ptr = page_table.pointers[page_index] + page_offset;
654 std::memcpy(dest_ptr, src_buffer, copy_amount);
655 break;
656 }
657 case Common::PageType::RasterizerCachedMemory: {
658 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
659 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
660 std::memcpy(host_ptr, src_buffer, copy_amount);
661 break;
662 }
663 default:
664 UNREACHABLE();
665 }
666
667 page_index++;
668 page_offset = 0;
669 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
670 remaining_size -= copy_amount;
671 }
672}
673
674void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
675 WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size);
676}
677
678} // namespace Memory 714} // namespace Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index cc6ab920e..7878f3fb1 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -193,6 +193,50 @@ public:
193 u64 Read64(VAddr addr); 193 u64 Read64(VAddr addr);
194 194
195 /** 195 /**
196 * Writes an 8-bit unsigned integer to the given virtual address in
197 * the current process' address space.
198 *
199 * @param addr The virtual address to write the 8-bit unsigned integer to.
200 * @param data The 8-bit unsigned integer to write to the given virtual address.
201 *
202 * @post The memory at the given virtual address contains the specified data value.
203 */
204 void Write8(VAddr addr, u8 data);
205
206 /**
207 * Writes a 16-bit unsigned integer to the given virtual address in
208 * the current process' address space.
209 *
210 * @param addr The virtual address to write the 16-bit unsigned integer to.
211 * @param data The 16-bit unsigned integer to write to the given virtual address.
212 *
213 * @post The memory range [addr, sizeof(data)) contains the given data value.
214 */
215 void Write16(VAddr addr, u16 data);
216
217 /**
218 * Writes a 32-bit unsigned integer to the given virtual address in
219 * the current process' address space.
220 *
221 * @param addr The virtual address to write the 32-bit unsigned integer to.
222 * @param data The 32-bit unsigned integer to write to the given virtual address.
223 *
224 * @post The memory range [addr, sizeof(data)) contains the given data value.
225 */
226 void Write32(VAddr addr, u32 data);
227
228 /**
229 * Writes a 64-bit unsigned integer to the given virtual address in
230 * the current process' address space.
231 *
232 * @param addr The virtual address to write the 64-bit unsigned integer to.
233 * @param data The 64-bit unsigned integer to write to the given virtual address.
234 *
235 * @post The memory range [addr, sizeof(data)) contains the given data value.
236 */
237 void Write64(VAddr addr, u64 data);
238
239 /**
196 * Reads a null-terminated string from the given virtual address. 240 * Reads a null-terminated string from the given virtual address.
197 * This function will continually read characters until either: 241 * This function will continually read characters until either:
198 * 242 *
@@ -248,6 +292,50 @@ public:
248 void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); 292 void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
249 293
250 /** 294 /**
295 * Writes a range of bytes into a given process' address space at the specified
296 * virtual address.
297 *
298 * @param process The process to write data into the address space of.
299 * @param dest_addr The destination virtual address to begin writing the data at.
300 * @param src_buffer The data to write into the process' address space.
301 * @param size The size of the data to write, in bytes.
302 *
303 * @post The address range [dest_addr, size) in the process' address space
304 * contains the data that was within src_buffer.
305 *
306 * @post If an attempt is made to write into an unmapped region of memory, the writes
307 * will be ignored and an error will be logged.
308 *
309 * @post If a write is performed into a region of memory that is considered cached
310 * rasterizer memory, will cause the currently active rasterizer to be notified
311 * and will mark that region as invalidated to caches that the active
312 * graphics backend may be maintaining over the course of execution.
313 */
314 void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
315 std::size_t size);
316
317 /**
318 * Writes a range of bytes into the current process' address space at the specified
319 * virtual address.
320 *
321 * @param dest_addr The destination virtual address to begin writing the data at.
322 * @param src_buffer The data to write into the current process' address space.
323 * @param size The size of the data to write, in bytes.
324 *
325 * @post The address range [dest_addr, size) in the current process' address space
326 * contains the data that was within src_buffer.
327 *
328 * @post If an attempt is made to write into an unmapped region of memory, the writes
329 * will be ignored and an error will be logged.
330 *
331 * @post If a write is performed into a region of memory that is considered cached
332 * rasterizer memory, will cause the currently active rasterizer to be notified
333 * and will mark that region as invalidated to caches that the active
334 * graphics backend may be maintaining over the course of execution.
335 */
336 void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
337
338 /**
251 * Fills the specified address range within a process' address space with zeroes. 339 * Fills the specified address range within a process' address space with zeroes.
252 * 340 *
253 * @param process The process that will have a portion of its memory zeroed out. 341 * @param process The process that will have a portion of its memory zeroed out.
@@ -320,13 +408,4 @@ void SetCurrentPageTable(Kernel::Process& process);
320/// Determines if the given VAddr is a kernel address 408/// Determines if the given VAddr is a kernel address
321bool IsKernelVirtualAddress(VAddr vaddr); 409bool IsKernelVirtualAddress(VAddr vaddr);
322 410
323void Write8(VAddr addr, u8 data);
324void Write16(VAddr addr, u16 data);
325void Write32(VAddr addr, u32 data);
326void Write64(VAddr addr, u64 data);
327
328void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
329 std::size_t size);
330void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
331
332} // namespace Memory 411} // namespace Memory
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index d6745af8b..d1e6bed93 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -30,7 +30,7 @@ void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
30} 30}
31 31
32void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { 32void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
33 WriteBlock(SanitizeAddress(address), data, size); 33 system.Memory().WriteBlock(SanitizeAddress(address), data, size);
34} 34}
35 35
36u64 StandardVmCallbacks::HidKeysDown() { 36u64 StandardVmCallbacks::HidKeysDown() {
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index ab66f35f9..55e0dbc49 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -34,16 +34,16 @@ u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
34void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) { 34void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
35 switch (width) { 35 switch (width) {
36 case 1: 36 case 1:
37 Memory::Write8(addr, static_cast<u8>(value)); 37 memory.Write8(addr, static_cast<u8>(value));
38 break; 38 break;
39 case 2: 39 case 2:
40 Memory::Write16(addr, static_cast<u16>(value)); 40 memory.Write16(addr, static_cast<u16>(value));
41 break; 41 break;
42 case 4: 42 case 4:
43 Memory::Write32(addr, static_cast<u32>(value)); 43 memory.Write32(addr, static_cast<u32>(value));
44 break; 44 break;
45 case 8: 45 case 8:
46 Memory::Write64(addr, value); 46 memory.Write64(addr, value);
47 break; 47 break;
48 default: 48 default:
49 UNREACHABLE(); 49 UNREACHABLE();