summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;