summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Lioncash2019-11-26 16:29:34 -0500
committerGravatar Lioncash2019-11-26 21:55:39 -0500
commitb05bfc603689419dc515a656b9fc711d79994f13 (patch)
treebc0937d11bbe31458785a69478edbf11a720b0ae /src
parentcore/memory: Migrate over ZeroBlock() and CopyBlock() to the Memory class (diff)
downloadyuzu-b05bfc603689419dc515a656b9fc711d79994f13.tar.gz
yuzu-b05bfc603689419dc515a656b9fc711d79994f13.tar.xz
yuzu-b05bfc603689419dc515a656b9fc711d79994f13.zip
core/memory: Migrate over Read{8, 16, 32, 64, Block} to the Memory class
With all of the trivial parts of the memory interface moved over, we can get right into moving over the bits that are used. Note that this does require the use of GetInstance from the global system instance to be used within hle_ipc.cpp and the gdbstub. This is fine for the time being, as they both already rely on the global system instance in other functions. These will be removed in a change directed at both of these respectively. For now, it's sufficient, as it still accomplishes the goal of de-globalizing the memory code.
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp17
-rw-r--r--src/core/arm/arm_interface.cpp24
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp12
-rw-r--r--src/core/gdbstub/gdbstub.cpp8
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp28
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp12
-rw-r--r--src/core/hle/kernel/mutex.cpp2
-rw-r--r--src/core/hle/kernel/svc.cpp16
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/ldr/ldr.cpp5
-rw-r--r--src/core/hle/service/lm/lm.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp4
-rw-r--r--src/core/memory.cpp228
-rw-r--r--src/core/memory.h85
-rw-r--r--src/core/memory/cheat_engine.cpp5
-rw-r--r--src/core/memory/cheat_engine.h4
-rw-r--r--src/core/reporter.cpp2
-rw-r--r--src/core/tools/freezer.cpp8
-rw-r--r--src/yuzu/debugger/wait_tree.cpp7
19 files changed, 305 insertions, 178 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 12e2b7901..c187d8ac5 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -259,9 +259,10 @@ void AudioRenderer::VoiceState::UpdateState() {
259} 259}
260 260
261void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) { 261void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) {
262 std::vector<s16> new_samples(info.wave_buffer[wave_index].buffer_sz / sizeof(s16)); 262 const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr;
263 Memory::ReadBlock(info.wave_buffer[wave_index].buffer_addr, new_samples.data(), 263 const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz;
264 info.wave_buffer[wave_index].buffer_sz); 264 std::vector<s16> new_samples(wave_buffer_size / sizeof(s16));
265 memory.ReadBlock(wave_buffer_address, new_samples.data(), wave_buffer_size);
265 266
266 switch (static_cast<Codec::PcmFormat>(info.sample_format)) { 267 switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
267 case Codec::PcmFormat::Int16: { 268 case Codec::PcmFormat::Int16: {
@@ -271,7 +272,7 @@ void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) {
271 case Codec::PcmFormat::Adpcm: { 272 case Codec::PcmFormat::Adpcm: {
272 // Decode ADPCM to PCM16 273 // Decode ADPCM to PCM16
273 Codec::ADPCM_Coeff coeffs; 274 Codec::ADPCM_Coeff coeffs;
274 Memory::ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff)); 275 memory.ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
275 new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()), 276 new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
276 new_samples.size() * sizeof(s16), coeffs, adpcm_state); 277 new_samples.size() * sizeof(s16), coeffs, adpcm_state);
277 break; 278 break;
@@ -314,13 +315,13 @@ void AudioRenderer::EffectState::UpdateState(Memory::Memory& memory) {
314 out_status.state = EffectStatus::New; 315 out_status.state = EffectStatus::New;
315 } else { 316 } else {
316 if (info.type == Effect::Aux) { 317 if (info.type == Effect::Aux) {
317 ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0, 318 ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_info) == 0,
318 "Aux buffers tried to update"); 319 "Aux buffers tried to update");
319 ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0, 320 ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_info) == 0,
320 "Aux buffers tried to update"); 321 "Aux buffers tried to update");
321 ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0, 322 ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_base) == 0,
322 "Aux buffers tried to update"); 323 "Aux buffers tried to update");
323 ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0, 324 ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_base) == 0,
324 "Aux buffers tried to update"); 325 "Aux buffers tried to update");
325 } 326 }
326 } 327 }
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index dea192869..7e846ddd5 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -60,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size.");
60 60
61using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; 61using Symbols = std::vector<std::pair<ELFSymbol, std::string>>;
62 62
63Symbols GetSymbols(VAddr text_offset) { 63Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) {
64 const auto mod_offset = text_offset + Memory::Read32(text_offset + 4); 64 const auto mod_offset = text_offset + memory.Read32(text_offset + 4);
65 65
66 if (mod_offset < text_offset || (mod_offset & 0b11) != 0 || 66 if (mod_offset < text_offset || (mod_offset & 0b11) != 0 ||
67 Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { 67 memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
68 return {}; 68 return {};
69 } 69 }
70 70
71 const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset; 71 const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset;
72 72
73 VAddr string_table_offset{}; 73 VAddr string_table_offset{};
74 VAddr symbol_table_offset{}; 74 VAddr symbol_table_offset{};
@@ -76,8 +76,8 @@ Symbols GetSymbols(VAddr text_offset) {
76 76
77 VAddr dynamic_index = dynamic_offset; 77 VAddr dynamic_index = dynamic_offset;
78 while (true) { 78 while (true) {
79 const auto tag = Memory::Read64(dynamic_index); 79 const u64 tag = memory.Read64(dynamic_index);
80 const auto value = Memory::Read64(dynamic_index + 0x8); 80 const u64 value = memory.Read64(dynamic_index + 0x8);
81 dynamic_index += 0x10; 81 dynamic_index += 0x10;
82 82
83 if (tag == ELF_DYNAMIC_TAG_NULL) { 83 if (tag == ELF_DYNAMIC_TAG_NULL) {
@@ -105,11 +105,11 @@ Symbols GetSymbols(VAddr text_offset) {
105 VAddr symbol_index = symbol_table_address; 105 VAddr symbol_index = symbol_table_address;
106 while (symbol_index < string_table_address) { 106 while (symbol_index < string_table_address) {
107 ELFSymbol symbol{}; 107 ELFSymbol symbol{};
108 Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); 108 memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
109 109
110 VAddr string_offset = string_table_address + symbol.name_index; 110 VAddr string_offset = string_table_address + symbol.name_index;
111 std::string name; 111 std::string name;
112 for (u8 c = Memory::Read8(string_offset); c != 0; c = Memory::Read8(++string_offset)) { 112 for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) {
113 name += static_cast<char>(c); 113 name += static_cast<char>(c);
114 } 114 }
115 115
@@ -141,17 +141,17 @@ constexpr u64 SEGMENT_BASE = 0x7100000000ull;
141 141
142std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { 142std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
143 std::vector<BacktraceEntry> out; 143 std::vector<BacktraceEntry> out;
144 auto& memory = system.Memory();
144 145
145 auto fp = GetReg(29); 146 auto fp = GetReg(29);
146 auto lr = GetReg(30); 147 auto lr = GetReg(30);
147
148 while (true) { 148 while (true) {
149 out.push_back({"", 0, lr, 0}); 149 out.push_back({"", 0, lr, 0});
150 if (!fp) { 150 if (!fp) {
151 break; 151 break;
152 } 152 }
153 lr = Memory::Read64(fp + 8) - 4; 153 lr = memory.Read64(fp + 8) - 4;
154 fp = Memory::Read64(fp); 154 fp = memory.Read64(fp);
155 } 155 }
156 156
157 std::map<VAddr, std::string> modules; 157 std::map<VAddr, std::string> modules;
@@ -162,7 +162,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
162 162
163 std::map<std::string, Symbols> symbols; 163 std::map<std::string, Symbols> symbols;
164 for (const auto& module : modules) { 164 for (const auto& module : modules) {
165 symbols.insert_or_assign(module.second, GetSymbols(module.first)); 165 symbols.insert_or_assign(module.second, GetSymbols(module.first, memory));
166 } 166 }
167 167
168 for (auto& entry : out) { 168 for (auto& entry : out) {
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 2b396f1d6..585fb55a9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -28,20 +28,20 @@ public:
28 explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} 28 explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
29 29
30 u8 MemoryRead8(u64 vaddr) override { 30 u8 MemoryRead8(u64 vaddr) override {
31 auto& s = parent.system; 31 return parent.system.Memory().Read8(vaddr);
32 return Memory::Read8(vaddr);
33 } 32 }
34 u16 MemoryRead16(u64 vaddr) override { 33 u16 MemoryRead16(u64 vaddr) override {
35 return Memory::Read16(vaddr); 34 return parent.system.Memory().Read16(vaddr);
36 } 35 }
37 u32 MemoryRead32(u64 vaddr) override { 36 u32 MemoryRead32(u64 vaddr) override {
38 return Memory::Read32(vaddr); 37 return parent.system.Memory().Read32(vaddr);
39 } 38 }
40 u64 MemoryRead64(u64 vaddr) override { 39 u64 MemoryRead64(u64 vaddr) override {
41 return Memory::Read64(vaddr); 40 return parent.system.Memory().Read64(vaddr);
42 } 41 }
43 Vector MemoryRead128(u64 vaddr) override { 42 Vector MemoryRead128(u64 vaddr) override {
44 return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)}; 43 auto& memory = parent.system.Memory();
44 return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
45 } 45 }
46 46
47 void MemoryWrite8(u64 vaddr, u8 value) override { 47 void MemoryWrite8(u64 vaddr, u8 value) override {
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 78e44f3bd..1c74a44d8 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -969,13 +969,13 @@ static void ReadMemory() {
969 SendReply("E01"); 969 SendReply("E01");
970 } 970 }
971 971
972 const auto& memory = Core::System::GetInstance().Memory(); 972 auto& memory = Core::System::GetInstance().Memory();
973 if (!memory.IsValidVirtualAddress(addr)) { 973 if (!memory.IsValidVirtualAddress(addr)) {
974 return SendReply("E00"); 974 return SendReply("E00");
975 } 975 }
976 976
977 std::vector<u8> data(len); 977 std::vector<u8> data(len);
978 Memory::ReadBlock(addr, data.data(), len); 978 memory.ReadBlock(addr, data.data(), len);
979 979
980 MemToGdbHex(reply, data.data(), len); 980 MemToGdbHex(reply, data.data(), len);
981 reply[len * 2] = '\0'; 981 reply[len * 2] = '\0';
@@ -1057,7 +1057,9 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1057 breakpoint.active = true; 1057 breakpoint.active = true;
1058 breakpoint.addr = addr; 1058 breakpoint.addr = addr;
1059 breakpoint.len = len; 1059 breakpoint.len = len;
1060 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 1060
1061 auto& memory = Core::System::GetInstance().Memory();
1062 memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1061 1063
1062 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; 1064 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1063 if (type == BreakpointType::Execute) { 1065 if (type == BreakpointType::Execute) {
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 7f9a559d2..07f0dac67 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -67,12 +67,14 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
67 67
68ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, 68ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
69 s32 num_to_wake) { 69 s32 num_to_wake) {
70 auto& memory = system.Memory();
71
70 // Ensure that we can write to the address. 72 // Ensure that we can write to the address.
71 if (!system.Memory().IsValidVirtualAddress(address)) { 73 if (!memory.IsValidVirtualAddress(address)) {
72 return ERR_INVALID_ADDRESS_STATE; 74 return ERR_INVALID_ADDRESS_STATE;
73 } 75 }
74 76
75 if (static_cast<s32>(Memory::Read32(address)) != value) { 77 if (static_cast<s32>(memory.Read32(address)) != value) {
76 return ERR_INVALID_STATE; 78 return ERR_INVALID_STATE;
77 } 79 }
78 80
@@ -82,8 +84,10 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
82 84
83ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, 85ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
84 s32 num_to_wake) { 86 s32 num_to_wake) {
87 auto& memory = system.Memory();
88
85 // Ensure that we can write to the address. 89 // Ensure that we can write to the address.
86 if (!system.Memory().IsValidVirtualAddress(address)) { 90 if (!memory.IsValidVirtualAddress(address)) {
87 return ERR_INVALID_ADDRESS_STATE; 91 return ERR_INVALID_ADDRESS_STATE;
88 } 92 }
89 93
@@ -109,7 +113,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
109 } 113 }
110 } 114 }
111 115
112 if (static_cast<s32>(Memory::Read32(address)) != value) { 116 if (static_cast<s32>(memory.Read32(address)) != value) {
113 return ERR_INVALID_STATE; 117 return ERR_INVALID_STATE;
114 } 118 }
115 119
@@ -134,12 +138,14 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s
134 138
135ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, 139ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
136 bool should_decrement) { 140 bool should_decrement) {
141 auto& memory = system.Memory();
142
137 // Ensure that we can read the address. 143 // Ensure that we can read the address.
138 if (!system.Memory().IsValidVirtualAddress(address)) { 144 if (!memory.IsValidVirtualAddress(address)) {
139 return ERR_INVALID_ADDRESS_STATE; 145 return ERR_INVALID_ADDRESS_STATE;
140 } 146 }
141 147
142 const s32 cur_value = static_cast<s32>(Memory::Read32(address)); 148 const s32 cur_value = static_cast<s32>(memory.Read32(address));
143 if (cur_value >= value) { 149 if (cur_value >= value) {
144 return ERR_INVALID_STATE; 150 return ERR_INVALID_STATE;
145 } 151 }
@@ -157,15 +163,19 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
157} 163}
158 164
159ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { 165ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
166 auto& memory = system.Memory();
167
160 // Ensure that we can read the address. 168 // Ensure that we can read the address.
161 if (!system.Memory().IsValidVirtualAddress(address)) { 169 if (!memory.IsValidVirtualAddress(address)) {
162 return ERR_INVALID_ADDRESS_STATE; 170 return ERR_INVALID_ADDRESS_STATE;
163 } 171 }
172
164 // Only wait for the address if equal. 173 // Only wait for the address if equal.
165 if (static_cast<s32>(Memory::Read32(address)) != value) { 174 if (static_cast<s32>(memory.Read32(address)) != value) {
166 return ERR_INVALID_STATE; 175 return ERR_INVALID_STATE;
167 } 176 }
168 // Short-circuit without rescheduling, if timeout is zero. 177
178 // Short-circuit without rescheduling if timeout is zero.
169 if (timeout == 0) { 179 if (timeout == 0) {
170 return RESULT_TIMEOUT; 180 return RESULT_TIMEOUT;
171 } 181 }
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index be24cef06..03745c449 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -214,10 +214,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl
214ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { 214ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
215 auto& owner_process = *thread.GetOwnerProcess(); 215 auto& owner_process = *thread.GetOwnerProcess();
216 auto& handle_table = owner_process.GetHandleTable(); 216 auto& handle_table = owner_process.GetHandleTable();
217 auto& memory = Core::System::GetInstance().Memory();
217 218
218 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; 219 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
219 Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), 220 memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
220 dst_cmdbuf.size() * sizeof(u32)); 221 dst_cmdbuf.size() * sizeof(u32));
221 222
222 // The header was already built in the internal command buffer. Attempt to parse it to verify 223 // The header was already built in the internal command buffer. Attempt to parse it to verify
223 // the integrity and then copy it over to the target command buffer. 224 // the integrity and then copy it over to the target command buffer.
@@ -282,15 +283,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
282std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { 283std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
283 std::vector<u8> buffer; 284 std::vector<u8> buffer;
284 const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; 285 const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
286 auto& memory = Core::System::GetInstance().Memory();
285 287
286 if (is_buffer_a) { 288 if (is_buffer_a) {
287 buffer.resize(BufferDescriptorA()[buffer_index].Size()); 289 buffer.resize(BufferDescriptorA()[buffer_index].Size());
288 Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), 290 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
289 buffer.size());
290 } else { 291 } else {
291 buffer.resize(BufferDescriptorX()[buffer_index].Size()); 292 buffer.resize(BufferDescriptorX()[buffer_index].Size());
292 Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), 293 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
293 buffer.size());
294 } 294 }
295 295
296 return buffer; 296 return buffer;
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 8493d0f78..88eede436 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -79,7 +79,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
79 // thread. 79 // thread.
80 ASSERT(requesting_thread == current_thread); 80 ASSERT(requesting_thread == current_thread);
81 81
82 const u32 addr_value = Memory::Read32(address); 82 const u32 addr_value = system.Memory().Read32(address);
83 83
84 // If the mutex isn't being held, just return success. 84 // If the mutex isn't being held, just return success.
85 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { 85 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 738db528d..a6c377cfc 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -454,7 +454,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
454 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", 454 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
455 handles_address, handle_count, nano_seconds); 455 handles_address, handle_count, nano_seconds);
456 456
457 if (!system.Memory().IsValidVirtualAddress(handles_address)) { 457 auto& memory = system.Memory();
458 if (!memory.IsValidVirtualAddress(handles_address)) {
458 LOG_ERROR(Kernel_SVC, 459 LOG_ERROR(Kernel_SVC,
459 "Handle address is not a valid virtual address, handle_address=0x{:016X}", 460 "Handle address is not a valid virtual address, handle_address=0x{:016X}",
460 handles_address); 461 handles_address);
@@ -476,7 +477,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
476 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 477 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
477 478
478 for (u64 i = 0; i < handle_count; ++i) { 479 for (u64 i = 0; i < handle_count; ++i) {
479 const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); 480 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
480 const auto object = handle_table.Get<WaitObject>(handle); 481 const auto object = handle_table.Get<WaitObject>(handle);
481 482
482 if (object == nullptr) { 483 if (object == nullptr) {
@@ -618,13 +619,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
618 return; 619 return;
619 } 620 }
620 621
622 auto& memory = system.Memory();
623
621 // This typically is an error code so we're going to assume this is the case 624 // This typically is an error code so we're going to assume this is the case
622 if (sz == sizeof(u32)) { 625 if (sz == sizeof(u32)) {
623 LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr)); 626 LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
624 } else { 627 } else {
625 // We don't know what's in here so we'll hexdump it 628 // We don't know what's in here so we'll hexdump it
626 debug_buffer.resize(sz); 629 debug_buffer.resize(sz);
627 Memory::ReadBlock(addr, debug_buffer.data(), sz); 630 memory.ReadBlock(addr, debug_buffer.data(), sz);
628 std::string hexdump; 631 std::string hexdump;
629 for (std::size_t i = 0; i < debug_buffer.size(); i++) { 632 for (std::size_t i = 0; i < debug_buffer.size(); i++) {
630 hexdump += fmt::format("{:02X} ", debug_buffer[i]); 633 hexdump += fmt::format("{:02X} ", debug_buffer[i]);
@@ -714,7 +717,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre
714 } 717 }
715 718
716 std::string str(len, '\0'); 719 std::string str(len, '\0');
717 Memory::ReadBlock(address, str.data(), str.size()); 720 system.Memory().ReadBlock(address, str.data(), str.size());
718 LOG_DEBUG(Debug_Emulated, "{}", str); 721 LOG_DEBUG(Debug_Emulated, "{}", str);
719} 722}
720 723
@@ -1674,6 +1677,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1674 1677
1675 const std::size_t current_core = system.CurrentCoreIndex(); 1678 const std::size_t current_core = system.CurrentCoreIndex();
1676 auto& monitor = system.Monitor(); 1679 auto& monitor = system.Monitor();
1680 auto& memory = system.Memory();
1677 1681
1678 // Atomically read the value of the mutex. 1682 // Atomically read the value of the mutex.
1679 u32 mutex_val = 0; 1683 u32 mutex_val = 0;
@@ -1683,7 +1687,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1683 monitor.SetExclusive(current_core, mutex_address); 1687 monitor.SetExclusive(current_core, mutex_address);
1684 1688
1685 // If the mutex is not yet acquired, acquire it. 1689 // If the mutex is not yet acquired, acquire it.
1686 mutex_val = Memory::Read32(mutex_address); 1690 mutex_val = memory.Read32(mutex_address);
1687 1691
1688 if (mutex_val != 0) { 1692 if (mutex_val != 0) {
1689 update_val = mutex_val | Mutex::MutexHasWaitersFlag; 1693 update_val = mutex_val | Mutex::MutexHasWaitersFlag;
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:
43 IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, 43 IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core,
44 std::string&& device_name, std::string&& unique_name) 44 std::string&& device_name, std::string&& unique_name)
45 : ServiceFramework("IAudioOut"), audio_core(audio_core), 45 : ServiceFramework("IAudioOut"), audio_core(audio_core),
46 device_name(std::move(device_name)), audio_params(audio_params) { 46 device_name(std::move(device_name)),
47 audio_params(audio_params), main_memory{system.Memory()} {
47 // clang-format off 48 // clang-format off
48 static const FunctionInfo functions[] = { 49 static const FunctionInfo functions[] = {
49 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 50 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -137,7 +138,7 @@ private:
137 const u64 tag{rp.Pop<u64>()}; 138 const u64 tag{rp.Pop<u64>()};
138 139
139 std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16)); 140 std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
140 Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size); 141 main_memory.ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
141 142
142 if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) { 143 if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
143 IPC::ResponseBuilder rb{ctx, 2}; 144 IPC::ResponseBuilder rb{ctx, 2};
@@ -209,6 +210,7 @@ private:
209 210
210 /// This is the event handle used to check if the audio buffer was released 211 /// This is the event handle used to check if the audio buffer was released
211 Kernel::EventPair buffer_event; 212 Kernel::EventPair buffer_event;
213 Memory::Memory& main_memory;
212}; 214};
213 215
214AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { 216AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), 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:
140 rb.Push(ERROR_INVALID_SIZE); 140 rb.Push(ERROR_INVALID_SIZE);
141 return; 141 return;
142 } 142 }
143
143 // Read NRR data from memory 144 // Read NRR data from memory
144 std::vector<u8> nrr_data(nrr_size); 145 std::vector<u8> nrr_data(nrr_size);
145 Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size); 146 system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
146 NRRHeader header; 147 NRRHeader header;
147 std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); 148 std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
148 149
@@ -291,7 +292,7 @@ public:
291 292
292 // Read NRO data from memory 293 // Read NRO data from memory
293 std::vector<u8> nro_data(nro_size); 294 std::vector<u8> nro_data(nro_size);
294 Memory::ReadBlock(nro_address, nro_data.data(), nro_size); 295 system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size);
295 296
296 SHA256Hash hash{}; 297 SHA256Hash hash{};
297 mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0); 298 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 74ecaef1b..346c8f899 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -36,15 +36,15 @@ private:
36 MessageHeader header{}; 36 MessageHeader header{};
37 VAddr addr{ctx.BufferDescriptorX()[0].Address()}; 37 VAddr addr{ctx.BufferDescriptorX()[0].Address()};
38 const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; 38 const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
39 Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); 39 memory.ReadBlock(addr, &header, sizeof(MessageHeader));
40 addr += sizeof(MessageHeader); 40 addr += sizeof(MessageHeader);
41 41
42 FieldMap fields; 42 FieldMap fields;
43 while (addr < end_addr) { 43 while (addr < end_addr) {
44 const auto field = static_cast<Field>(Memory::Read8(addr++)); 44 const auto field = static_cast<Field>(memory.Read8(addr++));
45 const auto length = Memory::Read8(addr++); 45 const auto length = memory.Read8(addr++);
46 46
47 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { 47 if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) {
48 ++addr; 48 ++addr;
49 } 49 }
50 50
@@ -55,7 +55,7 @@ private:
55 } 55 }
56 56
57 std::vector<u8> data(length); 57 std::vector<u8> data(length);
58 Memory::ReadBlock(addr, data.data(), length); 58 memory.ReadBlock(addr, data.data(), length);
59 fields.emplace(field, std::move(data)); 59 fields.emplace(field, std::move(data));
60 } 60 }
61 61
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,
191 std::memcpy(entries.data(), input2.data(), 191 std::memcpy(entries.data(), input2.data(),
192 params.num_entries * sizeof(Tegra::CommandListHeader)); 192 params.num_entries * sizeof(Tegra::CommandListHeader));
193 } else { 193 } else {
194 Memory::ReadBlock(params.address, entries.data(), 194 system.Memory().ReadBlock(params.address, entries.data(),
195 params.num_entries * sizeof(Tegra::CommandListHeader)); 195 params.num_entries * sizeof(Tegra::CommandListHeader));
196 } 196 }
197 UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); 197 UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
198 UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); 198 UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index c939e980d..699c48107 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -60,37 +60,6 @@ u8* GetPointerFromVMA(VAddr vaddr) {
60} 60}
61 61
62template <typename T> 62template <typename T>
63T Read(const VAddr vaddr) {
64 const 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 T value;
68 std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
69 return value;
70 }
71
72 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
73 switch (type) {
74 case Common::PageType::Unmapped:
75 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
76 return 0;
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 const u8* const host_ptr{GetPointerFromVMA(vaddr)};
82 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
83 T value;
84 std::memcpy(&value, host_ptr, sizeof(T));
85 return value;
86 }
87 default:
88 UNREACHABLE();
89 }
90 return {};
91}
92
93template <typename T>
94void Write(const VAddr vaddr, const T data) { 63void Write(const VAddr vaddr, const T data) {
95 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 64 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
96 if (page_pointer != nullptr) { 65 if (page_pointer != nullptr) {
@@ -210,6 +179,22 @@ struct Memory::Impl {
210 return nullptr; 179 return nullptr;
211 } 180 }
212 181
182 u8 Read8(const VAddr addr) {
183 return Read<u8>(addr);
184 }
185
186 u16 Read16(const VAddr addr) {
187 return Read<u16_le>(addr);
188 }
189
190 u32 Read32(const VAddr addr) {
191 return Read<u32_le>(addr);
192 }
193
194 u64 Read64(const VAddr addr) {
195 return Read<u64_le>(addr);
196 }
197
213 std::string ReadCString(VAddr vaddr, std::size_t max_length) { 198 std::string ReadCString(VAddr vaddr, std::size_t max_length) {
214 std::string string; 199 std::string string;
215 string.reserve(max_length); 200 string.reserve(max_length);
@@ -225,6 +210,55 @@ struct Memory::Impl {
225 return string; 210 return string;
226 } 211 }
227 212
213 void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
214 const std::size_t size) {
215 const auto& page_table = process.VMManager().page_table;
216
217 std::size_t remaining_size = size;
218 std::size_t page_index = src_addr >> PAGE_BITS;
219 std::size_t page_offset = src_addr & PAGE_MASK;
220
221 while (remaining_size > 0) {
222 const std::size_t copy_amount =
223 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
224 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
225
226 switch (page_table.attributes[page_index]) {
227 case Common::PageType::Unmapped: {
228 LOG_ERROR(HW_Memory,
229 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
230 current_vaddr, src_addr, size);
231 std::memset(dest_buffer, 0, copy_amount);
232 break;
233 }
234 case Common::PageType::Memory: {
235 DEBUG_ASSERT(page_table.pointers[page_index]);
236
237 const u8* const src_ptr = page_table.pointers[page_index] + page_offset;
238 std::memcpy(dest_buffer, src_ptr, copy_amount);
239 break;
240 }
241 case Common::PageType::RasterizerCachedMemory: {
242 const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
243 system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
244 std::memcpy(dest_buffer, host_ptr, copy_amount);
245 break;
246 }
247 default:
248 UNREACHABLE();
249 }
250
251 page_index++;
252 page_offset = 0;
253 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
254 remaining_size -= copy_amount;
255 }
256 }
257
258 void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
259 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
260 }
261
228 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 262 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
229 const auto& page_table = process.VMManager().page_table; 263 const auto& page_table = process.VMManager().page_table;
230 std::size_t remaining_size = size; 264 std::size_t remaining_size = size;
@@ -425,6 +459,48 @@ struct Memory::Impl {
425 } 459 }
426 } 460 }
427 461
462 /**
463 * Reads a particular data type out of memory at the given virtual address.
464 *
465 * @param vaddr The virtual address to read the data type from.
466 *
467 * @tparam T The data type to read out of memory. This type *must* be
468 * trivially copyable, otherwise the behavior of this function
469 * is undefined.
470 *
471 * @returns The instance of T read from the specified virtual address.
472 */
473 template <typename T>
474 T Read(const VAddr vaddr) {
475 const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
476 if (page_pointer != nullptr) {
477 // NOTE: Avoid adding any extra logic to this fast-path block
478 T value;
479 std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
480 return value;
481 }
482
483 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
484 switch (type) {
485 case Common::PageType::Unmapped:
486 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
487 return 0;
488 case Common::PageType::Memory:
489 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
490 break;
491 case Common::PageType::RasterizerCachedMemory: {
492 const u8* const host_ptr = GetPointerFromVMA(vaddr);
493 system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
494 T value;
495 std::memcpy(&value, host_ptr, sizeof(T));
496 return value;
497 }
498 default:
499 UNREACHABLE();
500 }
501 return {};
502 }
503
428 Core::System& system; 504 Core::System& system;
429}; 505};
430 506
@@ -470,10 +546,35 @@ const u8* Memory::GetPointer(VAddr vaddr) const {
470 return impl->GetPointer(vaddr); 546 return impl->GetPointer(vaddr);
471} 547}
472 548
549u8 Memory::Read8(const VAddr addr) {
550 return impl->Read8(addr);
551}
552
553u16 Memory::Read16(const VAddr addr) {
554 return impl->Read16(addr);
555}
556
557u32 Memory::Read32(const VAddr addr) {
558 return impl->Read32(addr);
559}
560
561u64 Memory::Read64(const VAddr addr) {
562 return impl->Read64(addr);
563}
564
473std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { 565std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
474 return impl->ReadCString(vaddr, max_length); 566 return impl->ReadCString(vaddr, max_length);
475} 567}
476 568
569void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
570 const std::size_t size) {
571 impl->ReadBlock(process, src_addr, dest_buffer, size);
572}
573
574void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
575 impl->ReadBlock(src_addr, dest_buffer, size);
576}
577
477void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { 578void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
478 impl->ZeroBlock(process, dest_addr, size); 579 impl->ZeroBlock(process, dest_addr, size);
479} 580}
@@ -511,71 +612,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
511 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 612 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
512} 613}
513 614
514u8 Read8(const VAddr addr) {
515 return Read<u8>(addr);
516}
517
518u16 Read16(const VAddr addr) {
519 return Read<u16_le>(addr);
520}
521
522u32 Read32(const VAddr addr) {
523 return Read<u32_le>(addr);
524}
525
526u64 Read64(const VAddr addr) {
527 return Read<u64_le>(addr);
528}
529
530void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
531 const std::size_t size) {
532 const auto& page_table = process.VMManager().page_table;
533
534 std::size_t remaining_size = size;
535 std::size_t page_index = src_addr >> PAGE_BITS;
536 std::size_t page_offset = src_addr & PAGE_MASK;
537
538 while (remaining_size > 0) {
539 const std::size_t copy_amount =
540 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
541 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
542
543 switch (page_table.attributes[page_index]) {
544 case Common::PageType::Unmapped: {
545 LOG_ERROR(HW_Memory,
546 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
547 current_vaddr, src_addr, size);
548 std::memset(dest_buffer, 0, copy_amount);
549 break;
550 }
551 case Common::PageType::Memory: {
552 DEBUG_ASSERT(page_table.pointers[page_index]);
553
554 const u8* src_ptr = page_table.pointers[page_index] + page_offset;
555 std::memcpy(dest_buffer, src_ptr, copy_amount);
556 break;
557 }
558 case Common::PageType::RasterizerCachedMemory: {
559 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
560 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
561 std::memcpy(dest_buffer, host_ptr, copy_amount);
562 break;
563 }
564 default:
565 UNREACHABLE();
566 }
567
568 page_index++;
569 page_offset = 0;
570 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
571 remaining_size -= copy_amount;
572 }
573}
574
575void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
576 ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size);
577}
578
579void Write8(const VAddr addr, const u8 data) { 615void Write8(const VAddr addr, const u8 data) {
580 Write<u8>(addr, data); 616 Write<u8>(addr, data);
581} 617}
diff --git a/src/core/memory.h b/src/core/memory.h
index fc0013a96..cc6ab920e 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -153,6 +153,46 @@ public:
153 const u8* GetPointer(VAddr vaddr) const; 153 const u8* GetPointer(VAddr vaddr) const;
154 154
155 /** 155 /**
156 * Reads an 8-bit unsigned value from the current process' address space
157 * at the given virtual address.
158 *
159 * @param addr The virtual address to read the 8-bit value from.
160 *
161 * @returns the read 8-bit unsigned value.
162 */
163 u8 Read8(VAddr addr);
164
165 /**
166 * Reads a 16-bit unsigned value from the current process' address space
167 * at the given virtual address.
168 *
169 * @param addr The virtual address to read the 16-bit value from.
170 *
171 * @returns the read 16-bit unsigned value.
172 */
173 u16 Read16(VAddr addr);
174
175 /**
176 * Reads a 32-bit unsigned value from the current process' address space
177 * at the given virtual address.
178 *
179 * @param addr The virtual address to read the 32-bit value from.
180 *
181 * @returns the read 32-bit unsigned value.
182 */
183 u32 Read32(VAddr addr);
184
185 /**
186 * Reads a 64-bit unsigned value from the current process' address space
187 * at the given virtual address.
188 *
189 * @param addr The virtual address to read the 64-bit value from.
190 *
191 * @returns the read 64-bit value.
192 */
193 u64 Read64(VAddr addr);
194
195 /**
156 * Reads a null-terminated string from the given virtual address. 196 * Reads a null-terminated string from the given virtual address.
157 * This function will continually read characters until either: 197 * This function will continually read characters until either:
158 * 198 *
@@ -170,6 +210,44 @@ public:
170 std::string ReadCString(VAddr vaddr, std::size_t max_length); 210 std::string ReadCString(VAddr vaddr, std::size_t max_length);
171 211
172 /** 212 /**
213 * Reads a contiguous block of bytes from a specified process' address space.
214 *
215 * @param process The process to read the data from.
216 * @param src_addr The virtual address to begin reading from.
217 * @param dest_buffer The buffer to place the read bytes into.
218 * @param size The amount of data to read, in bytes.
219 *
220 * @note If a size of 0 is specified, then this function reads nothing and
221 * no attempts to access memory are made at all.
222 *
223 * @pre dest_buffer must be at least size bytes in length, otherwise a
224 * buffer overrun will occur.
225 *
226 * @post The range [dest_buffer, size) contains the read bytes from the
227 * process' address space.
228 */
229 void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
230 std::size_t size);
231
232 /**
233 * Reads a contiguous block of bytes from the current process' address space.
234 *
235 * @param src_addr The virtual address to begin reading from.
236 * @param dest_buffer The buffer to place the read bytes into.
237 * @param size The amount of data to read, in bytes.
238 *
239 * @note If a size of 0 is specified, then this function reads nothing and
240 * no attempts to access memory are made at all.
241 *
242 * @pre dest_buffer must be at least size bytes in length, otherwise a
243 * buffer overrun will occur.
244 *
245 * @post The range [dest_buffer, size) contains the read bytes from the
246 * current process' address space.
247 */
248 void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
249
250 /**
173 * Fills the specified address range within a process' address space with zeroes. 251 * Fills the specified address range within a process' address space with zeroes.
174 * 252 *
175 * @param process The process that will have a portion of its memory zeroed out. 253 * @param process The process that will have a portion of its memory zeroed out.
@@ -242,18 +320,11 @@ void SetCurrentPageTable(Kernel::Process& process);
242/// Determines if the given VAddr is a kernel address 320/// Determines if the given VAddr is a kernel address
243bool IsKernelVirtualAddress(VAddr vaddr); 321bool IsKernelVirtualAddress(VAddr vaddr);
244 322
245u8 Read8(VAddr addr);
246u16 Read16(VAddr addr);
247u32 Read32(VAddr addr);
248u64 Read64(VAddr addr);
249
250void Write8(VAddr addr, u8 data); 323void Write8(VAddr addr, u8 data);
251void Write16(VAddr addr, u16 data); 324void Write16(VAddr addr, u16 data);
252void Write32(VAddr addr, u32 data); 325void Write32(VAddr addr, u32 data);
253void Write64(VAddr addr, u64 data); 326void Write64(VAddr addr, u64 data);
254 327
255void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
256void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
257void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, 328void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
258 std::size_t size); 329 std::size_t size);
259void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); 330void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index b73cc9fbd..d6745af8b 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -20,14 +20,13 @@ namespace Memory {
20constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12); 20constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12);
21constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; 21constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
22 22
23StandardVmCallbacks::StandardVmCallbacks(const Core::System& system, 23StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
24 const CheatProcessMetadata& metadata)
25 : metadata(metadata), system(system) {} 24 : metadata(metadata), system(system) {}
26 25
27StandardVmCallbacks::~StandardVmCallbacks() = default; 26StandardVmCallbacks::~StandardVmCallbacks() = default;
28 27
29void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { 28void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
30 ReadBlock(SanitizeAddress(address), data, size); 29 system.Memory().ReadBlock(SanitizeAddress(address), data, size);
31} 30}
32 31
33void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { 32void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index e3db90dac..3d6b2298a 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -24,7 +24,7 @@ namespace Memory {
24 24
25class StandardVmCallbacks : public DmntCheatVm::Callbacks { 25class StandardVmCallbacks : public DmntCheatVm::Callbacks {
26public: 26public:
27 StandardVmCallbacks(const Core::System& system, const CheatProcessMetadata& metadata); 27 StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata);
28 ~StandardVmCallbacks() override; 28 ~StandardVmCallbacks() override;
29 29
30 void MemoryRead(VAddr address, void* data, u64 size) override; 30 void MemoryRead(VAddr address, void* data, u64 size) override;
@@ -37,7 +37,7 @@ private:
37 VAddr SanitizeAddress(VAddr address) const; 37 VAddr SanitizeAddress(VAddr address) const;
38 38
39 const CheatProcessMetadata& metadata; 39 const CheatProcessMetadata& metadata;
40 const Core::System& system; 40 Core::System& system;
41}; 41};
42 42
43// Intermediary class that parses a text file or other disk format for storing cheats into a 43// Intermediary class that parses a text file or other disk format for storing cheats into a
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index af0988d62..f95eee3b1 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -157,7 +157,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer, Memor
157 157
158 if constexpr (read_value) { 158 if constexpr (read_value) {
159 std::vector<u8> data(desc.Size()); 159 std::vector<u8> data(desc.Size());
160 Memory::ReadBlock(desc.Address(), data.data(), desc.Size()); 160 memory.ReadBlock(desc.Address(), data.data(), desc.Size());
161 entry["data"] = Common::HexToString(data); 161 entry["data"] = Common::HexToString(data);
162 } 162 }
163 163
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index c7f42388f..ab66f35f9 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -18,13 +18,13 @@ constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_R
18u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) { 18u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
19 switch (width) { 19 switch (width) {
20 case 1: 20 case 1:
21 return Memory::Read8(addr); 21 return memory.Read8(addr);
22 case 2: 22 case 2:
23 return Memory::Read16(addr); 23 return memory.Read16(addr);
24 case 4: 24 case 4:
25 return Memory::Read32(addr); 25 return memory.Read32(addr);
26 case 8: 26 case 8:
27 return Memory::Read64(addr); 27 return memory.Read64(addr);
28 default: 28 default:
29 UNREACHABLE(); 29 UNREACHABLE();
30 return 0; 30 return 0;
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 535b3ce90..727bd8a94 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -80,7 +80,7 @@ QString WaitTreeText::GetText() const {
80 80
81WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table) 81WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table)
82 : mutex_address(mutex_address) { 82 : mutex_address(mutex_address) {
83 mutex_value = Memory::Read32(mutex_address); 83 mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
84 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask); 84 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
85 owner = handle_table.Get<Kernel::Thread>(owner_handle); 85 owner = handle_table.Get<Kernel::Thread>(owner_handle);
86} 86}
@@ -115,10 +115,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
115 std::vector<std::unique_ptr<WaitTreeItem>> list; 115 std::vector<std::unique_ptr<WaitTreeItem>> list;
116 116
117 constexpr std::size_t BaseRegister = 29; 117 constexpr std::size_t BaseRegister = 29;
118 auto& memory = Core::System::GetInstance().Memory();
118 u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister]; 119 u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister];
119 120
120 while (base_pointer != 0) { 121 while (base_pointer != 0) {
121 const u64 lr = Memory::Read64(base_pointer + sizeof(u64)); 122 const u64 lr = memory.Read64(base_pointer + sizeof(u64));
122 if (lr == 0) { 123 if (lr == 0) {
123 break; 124 break;
124 } 125 }
@@ -126,7 +127,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
126 list.push_back(std::make_unique<WaitTreeText>( 127 list.push_back(std::make_unique<WaitTreeText>(
127 tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'}))); 128 tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'})));
128 129
129 base_pointer = Memory::Read64(base_pointer); 130 base_pointer = memory.Read64(base_pointer);
130 } 131 }
131 132
132 return list; 133 return list;