summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2019-11-28 11:43:17 -0500
committerGravatar GitHub2019-11-28 11:43:17 -0500
commite3ee017e91ef4d713f1af8cb60c5157e40d43f18 (patch)
treee0a5b47cac1d548599b8ceba7f71b40746fe6b48 /src
parentMerge pull request #3171 from lioncash/internal-link (diff)
parentcore/memory; Migrate over SetCurrentPageTable() to the Memory class (diff)
downloadyuzu-e3ee017e91ef4d713f1af8cb60c5157e40d43f18.tar.gz
yuzu-e3ee017e91ef4d713f1af8cb60c5157e40d43f18.tar.xz
yuzu-e3ee017e91ef4d713f1af8cb60c5157e40d43f18.zip
Merge pull request #3169 from lioncash/memory
core/memory: Deglobalize memory management code
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp41
-rw-r--r--src/audio_core/audio_renderer.h10
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/arm/arm_interface.cpp27
-rw-r--r--src/core/arm/arm_interface.h8
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp48
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h1
-rw-r--r--src/core/core.cpp16
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/core_cpu.cpp5
-rw-r--r--src/core/core_cpu.h18
-rw-r--r--src/core/cpu_core_manager.cpp2
-rw-r--r--src/core/gdbstub/gdbstub.cpp36
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp34
-rw-r--r--src/core/hle/kernel/client_session.cpp4
-rw-r--r--src/core/hle/kernel/client_session.h6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp21
-rw-r--r--src/core/hle/kernel/kernel.cpp18
-rw-r--r--src/core/hle/kernel/mutex.cpp6
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/server_session.h9
-rw-r--r--src/core/hle/kernel/svc.cpp51
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/kernel/vm_manager.cpp13
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.cpp5
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp7
-rw-r--r--src/core/hle/service/ldr/ldr.cpp5
-rw-r--r--src/core/hle/service/lm/lm.cpp23
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp4
-rw-r--r--src/core/memory.cpp1008
-rw-r--r--src/core/memory.h396
-rw-r--r--src/core/memory/cheat_engine.cpp7
-rw-r--r--src/core/memory/cheat_engine.h4
-rw-r--r--src/core/memory_setup.h43
-rw-r--r--src/core/reporter.cpp16
-rw-r--r--src/core/tools/freezer.cpp30
-rw-r--r--src/core/tools/freezer.h7
-rw-r--r--src/tests/core/arm/arm_test_common.cpp15
-rw-r--r--src/video_core/memory_manager.cpp4
-rw-r--r--src/video_core/rasterizer_accelerated.cpp7
-rw-r--r--src/video_core/rasterizer_accelerated.h9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h7
-rw-r--r--src/yuzu/debugger/wait_tree.cpp7
49 files changed, 1314 insertions, 721 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 6b0167acd..c187d8ac5 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -36,9 +36,9 @@ public:
36 } 36 }
37 37
38 void SetWaveIndex(std::size_t index); 38 void SetWaveIndex(std::size_t index);
39 std::vector<s16> DequeueSamples(std::size_t sample_count); 39 std::vector<s16> DequeueSamples(std::size_t sample_count, Memory::Memory& memory);
40 void UpdateState(); 40 void UpdateState();
41 void RefreshBuffer(); 41 void RefreshBuffer(Memory::Memory& memory);
42 42
43private: 43private:
44 bool is_in_use{}; 44 bool is_in_use{};
@@ -66,17 +66,18 @@ public:
66 return info; 66 return info;
67 } 67 }
68 68
69 void UpdateState(); 69 void UpdateState(Memory::Memory& memory);
70 70
71private: 71private:
72 EffectOutStatus out_status{}; 72 EffectOutStatus out_status{};
73 EffectInStatus info{}; 73 EffectInStatus info{};
74}; 74};
75AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params, 75AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memory& memory_,
76 AudioRendererParameter params,
76 std::shared_ptr<Kernel::WritableEvent> buffer_event, 77 std::shared_ptr<Kernel::WritableEvent> buffer_event,
77 std::size_t instance_number) 78 std::size_t instance_number)
78 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 79 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
79 effects(params.effect_count) { 80 effects(params.effect_count), memory{memory_} {
80 81
81 audio_out = std::make_unique<AudioCore::AudioOut>(); 82 audio_out = std::make_unique<AudioCore::AudioOut>();
82 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, 83 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
@@ -162,7 +163,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
162 } 163 }
163 164
164 for (auto& effect : effects) { 165 for (auto& effect : effects) {
165 effect.UpdateState(); 166 effect.UpdateState(memory);
166 } 167 }
167 168
168 // Release previous buffers and queue next ones for playback 169 // Release previous buffers and queue next ones for playback
@@ -206,13 +207,14 @@ void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
206 is_refresh_pending = true; 207 is_refresh_pending = true;
207} 208}
208 209
209std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count) { 210std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count,
211 Memory::Memory& memory) {
210 if (!IsPlaying()) { 212 if (!IsPlaying()) {
211 return {}; 213 return {};
212 } 214 }
213 215
214 if (is_refresh_pending) { 216 if (is_refresh_pending) {
215 RefreshBuffer(); 217 RefreshBuffer(memory);
216 } 218 }
217 219
218 const std::size_t max_size{samples.size() - offset}; 220 const std::size_t max_size{samples.size() - offset};
@@ -256,10 +258,11 @@ void AudioRenderer::VoiceState::UpdateState() {
256 is_in_use = info.is_in_use; 258 is_in_use = info.is_in_use;
257} 259}
258 260
259void AudioRenderer::VoiceState::RefreshBuffer() { 261void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) {
260 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;
261 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;
262 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);
263 266
264 switch (static_cast<Codec::PcmFormat>(info.sample_format)) { 267 switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
265 case Codec::PcmFormat::Int16: { 268 case Codec::PcmFormat::Int16: {
@@ -269,7 +272,7 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
269 case Codec::PcmFormat::Adpcm: { 272 case Codec::PcmFormat::Adpcm: {
270 // Decode ADPCM to PCM16 273 // Decode ADPCM to PCM16
271 Codec::ADPCM_Coeff coeffs; 274 Codec::ADPCM_Coeff coeffs;
272 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));
273 new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()), 276 new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
274 new_samples.size() * sizeof(s16), coeffs, adpcm_state); 277 new_samples.size() * sizeof(s16), coeffs, adpcm_state);
275 break; 278 break;
@@ -307,18 +310,18 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
307 is_refresh_pending = false; 310 is_refresh_pending = false;
308} 311}
309 312
310void AudioRenderer::EffectState::UpdateState() { 313void AudioRenderer::EffectState::UpdateState(Memory::Memory& memory) {
311 if (info.is_new) { 314 if (info.is_new) {
312 out_status.state = EffectStatus::New; 315 out_status.state = EffectStatus::New;
313 } else { 316 } else {
314 if (info.type == Effect::Aux) { 317 if (info.type == Effect::Aux) {
315 ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0, 318 ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_info) == 0,
316 "Aux buffers tried to update"); 319 "Aux buffers tried to update");
317 ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0, 320 ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_info) == 0,
318 "Aux buffers tried to update"); 321 "Aux buffers tried to update");
319 ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0, 322 ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_base) == 0,
320 "Aux buffers tried to update"); 323 "Aux buffers tried to update");
321 ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0, 324 ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_base) == 0,
322 "Aux buffers tried to update"); 325 "Aux buffers tried to update");
323 } 326 }
324 } 327 }
@@ -340,7 +343,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
340 std::size_t offset{}; 343 std::size_t offset{};
341 s64 samples_remaining{BUFFER_SIZE}; 344 s64 samples_remaining{BUFFER_SIZE};
342 while (samples_remaining > 0) { 345 while (samples_remaining > 0) {
343 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)}; 346 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining, memory)};
344 347
345 if (samples.empty()) { 348 if (samples.empty()) {
346 break; 349 break;
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index abed224bb..be1b019f1 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -22,6 +22,10 @@ namespace Kernel {
22class WritableEvent; 22class WritableEvent;
23} 23}
24 24
25namespace Memory {
26class Memory;
27}
28
25namespace AudioCore { 29namespace AudioCore {
26 30
27class AudioOut; 31class AudioOut;
@@ -217,7 +221,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
217 221
218class AudioRenderer { 222class AudioRenderer {
219public: 223public:
220 AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params, 224 AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memory& memory_,
225 AudioRendererParameter params,
221 std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); 226 std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
222 ~AudioRenderer(); 227 ~AudioRenderer();
223 228
@@ -238,7 +243,8 @@ private:
238 std::vector<VoiceState> voices; 243 std::vector<VoiceState> voices;
239 std::vector<EffectState> effects; 244 std::vector<EffectState> effects;
240 std::unique_ptr<AudioOut> audio_out; 245 std::unique_ptr<AudioOut> audio_out;
241 AudioCore::StreamPtr stream; 246 StreamPtr stream;
247 Memory::Memory& memory;
242}; 248};
243 249
244} // namespace AudioCore 250} // namespace AudioCore
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f2e774a6b..2dfdcb0d7 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -509,7 +509,6 @@ add_library(core STATIC
509 memory/dmnt_cheat_vm.h 509 memory/dmnt_cheat_vm.h
510 memory.cpp 510 memory.cpp
511 memory.h 511 memory.h
512 memory_setup.h
513 perf_stats.cpp 512 perf_stats.cpp
514 perf_stats.h 513 perf_stats.h
515 reporter.cpp 514 reporter.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 372612c9b..7e846ddd5 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -13,7 +13,6 @@
13#include "core/memory.h" 13#include "core/memory.h"
14 14
15namespace Core { 15namespace Core {
16
17namespace { 16namespace {
18 17
19constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; 18constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
@@ -61,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size.");
61 60
62using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; 61using Symbols = std::vector<std::pair<ELFSymbol, std::string>>;
63 62
64Symbols GetSymbols(VAddr text_offset) { 63Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) {
65 const auto mod_offset = text_offset + Memory::Read32(text_offset + 4); 64 const auto mod_offset = text_offset + memory.Read32(text_offset + 4);
66 65
67 if (mod_offset < text_offset || (mod_offset & 0b11) != 0 || 66 if (mod_offset < text_offset || (mod_offset & 0b11) != 0 ||
68 Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { 67 memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
69 return {}; 68 return {};
70 } 69 }
71 70
72 const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset; 71 const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset;
73 72
74 VAddr string_table_offset{}; 73 VAddr string_table_offset{};
75 VAddr symbol_table_offset{}; 74 VAddr symbol_table_offset{};
@@ -77,8 +76,8 @@ Symbols GetSymbols(VAddr text_offset) {
77 76
78 VAddr dynamic_index = dynamic_offset; 77 VAddr dynamic_index = dynamic_offset;
79 while (true) { 78 while (true) {
80 const auto tag = Memory::Read64(dynamic_index); 79 const u64 tag = memory.Read64(dynamic_index);
81 const auto value = Memory::Read64(dynamic_index + 0x8); 80 const u64 value = memory.Read64(dynamic_index + 0x8);
82 dynamic_index += 0x10; 81 dynamic_index += 0x10;
83 82
84 if (tag == ELF_DYNAMIC_TAG_NULL) { 83 if (tag == ELF_DYNAMIC_TAG_NULL) {
@@ -106,11 +105,11 @@ Symbols GetSymbols(VAddr text_offset) {
106 VAddr symbol_index = symbol_table_address; 105 VAddr symbol_index = symbol_table_address;
107 while (symbol_index < string_table_address) { 106 while (symbol_index < string_table_address) {
108 ELFSymbol symbol{}; 107 ELFSymbol symbol{};
109 Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); 108 memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
110 109
111 VAddr string_offset = string_table_address + symbol.name_index; 110 VAddr string_offset = string_table_address + symbol.name_index;
112 std::string name; 111 std::string name;
113 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)) {
114 name += static_cast<char>(c); 113 name += static_cast<char>(c);
115 } 114 }
116 115
@@ -142,28 +141,28 @@ constexpr u64 SEGMENT_BASE = 0x7100000000ull;
142 141
143std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { 142std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
144 std::vector<BacktraceEntry> out; 143 std::vector<BacktraceEntry> out;
144 auto& memory = system.Memory();
145 145
146 auto fp = GetReg(29); 146 auto fp = GetReg(29);
147 auto lr = GetReg(30); 147 auto lr = GetReg(30);
148
149 while (true) { 148 while (true) {
150 out.push_back({"", 0, lr, 0}); 149 out.push_back({"", 0, lr, 0});
151 if (!fp) { 150 if (!fp) {
152 break; 151 break;
153 } 152 }
154 lr = Memory::Read64(fp + 8) - 4; 153 lr = memory.Read64(fp + 8) - 4;
155 fp = Memory::Read64(fp); 154 fp = memory.Read64(fp);
156 } 155 }
157 156
158 std::map<VAddr, std::string> modules; 157 std::map<VAddr, std::string> modules;
159 auto& loader{System::GetInstance().GetAppLoader()}; 158 auto& loader{system.GetAppLoader()};
160 if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { 159 if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) {
161 return {}; 160 return {};
162 } 161 }
163 162
164 std::map<std::string, Symbols> symbols; 163 std::map<std::string, Symbols> symbols;
165 for (const auto& module : modules) { 164 for (const auto& module : modules) {
166 symbols.insert_or_assign(module.second, GetSymbols(module.first)); 165 symbols.insert_or_assign(module.second, GetSymbols(module.first, memory));
167 } 166 }
168 167
169 for (auto& entry : out) { 168 for (auto& entry : out) {
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 45e94e625..47b964eb7 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -17,11 +17,13 @@ enum class VMAPermission : u8;
17} 17}
18 18
19namespace Core { 19namespace Core {
20class System;
20 21
21/// Generic ARMv8 CPU interface 22/// Generic ARMv8 CPU interface
22class ARM_Interface : NonCopyable { 23class ARM_Interface : NonCopyable {
23public: 24public:
24 virtual ~ARM_Interface() {} 25 explicit ARM_Interface(System& system_) : system{system_} {}
26 virtual ~ARM_Interface() = default;
25 27
26 struct ThreadContext { 28 struct ThreadContext {
27 std::array<u64, 31> cpu_registers; 29 std::array<u64, 31> cpu_registers;
@@ -163,6 +165,10 @@ public:
163 /// fp+0 : pointer to previous frame record 165 /// fp+0 : pointer to previous frame record
164 /// fp+8 : value of lr for frame 166 /// fp+8 : value of lr for frame
165 void LogBacktrace() const; 167 void LogBacktrace() const;
168
169protected:
170 /// System context that this ARM interface is running under.
171 System& system;
166}; 172};
167 173
168} // namespace Core 174} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index a0705b2b8..f8c7f0efd 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -28,36 +28,38 @@ public:
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 return Memory::Read8(vaddr); 31 return parent.system.Memory().Read8(vaddr);
32 } 32 }
33 u16 MemoryRead16(u64 vaddr) override { 33 u16 MemoryRead16(u64 vaddr) override {
34 return Memory::Read16(vaddr); 34 return parent.system.Memory().Read16(vaddr);
35 } 35 }
36 u32 MemoryRead32(u64 vaddr) override { 36 u32 MemoryRead32(u64 vaddr) override {
37 return Memory::Read32(vaddr); 37 return parent.system.Memory().Read32(vaddr);
38 } 38 }
39 u64 MemoryRead64(u64 vaddr) override { 39 u64 MemoryRead64(u64 vaddr) override {
40 return Memory::Read64(vaddr); 40 return parent.system.Memory().Read64(vaddr);
41 } 41 }
42 Vector MemoryRead128(u64 vaddr) override { 42 Vector MemoryRead128(u64 vaddr) override {
43 return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)}; 43 auto& memory = parent.system.Memory();
44 return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
44 } 45 }
45 46
46 void MemoryWrite8(u64 vaddr, u8 value) override { 47 void MemoryWrite8(u64 vaddr, u8 value) override {
47 Memory::Write8(vaddr, value); 48 parent.system.Memory().Write8(vaddr, value);
48 } 49 }
49 void MemoryWrite16(u64 vaddr, u16 value) override { 50 void MemoryWrite16(u64 vaddr, u16 value) override {
50 Memory::Write16(vaddr, value); 51 parent.system.Memory().Write16(vaddr, value);
51 } 52 }
52 void MemoryWrite32(u64 vaddr, u32 value) override { 53 void MemoryWrite32(u64 vaddr, u32 value) override {
53 Memory::Write32(vaddr, value); 54 parent.system.Memory().Write32(vaddr, value);
54 } 55 }
55 void MemoryWrite64(u64 vaddr, u64 value) override { 56 void MemoryWrite64(u64 vaddr, u64 value) override {
56 Memory::Write64(vaddr, value); 57 parent.system.Memory().Write64(vaddr, value);
57 } 58 }
58 void MemoryWrite128(u64 vaddr, Vector value) override { 59 void MemoryWrite128(u64 vaddr, Vector value) override {
59 Memory::Write64(vaddr, value[0]); 60 auto& memory = parent.system.Memory();
60 Memory::Write64(vaddr + 8, value[1]); 61 memory.Write64(vaddr, value[0]);
62 memory.Write64(vaddr + 8, value[1]);
61 } 63 }
62 64
63 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 65 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
@@ -171,9 +173,10 @@ void ARM_Dynarmic::Step() {
171 173
172ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, 174ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
173 std::size_t core_index) 175 std::size_t core_index)
174 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, 176 : ARM_Interface{system},
175 core_index{core_index}, system{system}, 177 cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
176 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} 178 core_index{core_index}, exclusive_monitor{
179 dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
177 180
178ARM_Dynarmic::~ARM_Dynarmic() = default; 181ARM_Dynarmic::~ARM_Dynarmic() = default;
179 182
@@ -264,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
264 jit = MakeJit(page_table, new_address_space_size_in_bits); 267 jit = MakeJit(page_table, new_address_space_size_in_bits);
265} 268}
266 269
267DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} 270DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count)
271 : monitor(core_count), memory{memory_} {}
272
268DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; 273DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
269 274
270void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { 275void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
@@ -277,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
277} 282}
278 283
279bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { 284bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
280 return monitor.DoExclusiveOperation(core_index, vaddr, 1, 285 return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); });
281 [&] { Memory::Write8(vaddr, value); });
282} 286}
283 287
284bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { 288bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
285 return monitor.DoExclusiveOperation(core_index, vaddr, 2, 289 return monitor.DoExclusiveOperation(core_index, vaddr, 2,
286 [&] { Memory::Write16(vaddr, value); }); 290 [&] { memory.Write16(vaddr, value); });
287} 291}
288 292
289bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { 293bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
290 return monitor.DoExclusiveOperation(core_index, vaddr, 4, 294 return monitor.DoExclusiveOperation(core_index, vaddr, 4,
291 [&] { Memory::Write32(vaddr, value); }); 295 [&] { memory.Write32(vaddr, value); });
292} 296}
293 297
294bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { 298bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
295 return monitor.DoExclusiveOperation(core_index, vaddr, 8, 299 return monitor.DoExclusiveOperation(core_index, vaddr, 8,
296 [&] { Memory::Write64(vaddr, value); }); 300 [&] { memory.Write64(vaddr, value); });
297} 301}
298 302
299bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { 303bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
300 return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { 304 return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
301 Memory::Write64(vaddr + 0, value[0]); 305 memory.Write64(vaddr + 0, value[0]);
302 Memory::Write64(vaddr + 8, value[1]); 306 memory.Write64(vaddr + 8, value[1]);
303 }); 307 });
304} 308}
305 309
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 504d46c68..9cd475cfb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,6 +12,10 @@
12#include "core/arm/exclusive_monitor.h" 12#include "core/arm/exclusive_monitor.h"
13#include "core/arm/unicorn/arm_unicorn.h" 13#include "core/arm/unicorn/arm_unicorn.h"
14 14
15namespace Memory {
16class Memory;
17}
18
15namespace Core { 19namespace Core {
16 20
17class ARM_Dynarmic_Callbacks; 21class ARM_Dynarmic_Callbacks;
@@ -58,13 +62,12 @@ private:
58 ARM_Unicorn inner_unicorn; 62 ARM_Unicorn inner_unicorn;
59 63
60 std::size_t core_index; 64 std::size_t core_index;
61 System& system;
62 DynarmicExclusiveMonitor& exclusive_monitor; 65 DynarmicExclusiveMonitor& exclusive_monitor;
63}; 66};
64 67
65class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 68class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
66public: 69public:
67 explicit DynarmicExclusiveMonitor(std::size_t core_count); 70 explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count);
68 ~DynarmicExclusiveMonitor() override; 71 ~DynarmicExclusiveMonitor() override;
69 72
70 void SetExclusive(std::size_t core_index, VAddr addr) override; 73 void SetExclusive(std::size_t core_index, VAddr addr) override;
@@ -79,6 +82,7 @@ public:
79private: 82private:
80 friend class ARM_Dynarmic; 83 friend class ARM_Dynarmic;
81 Dynarmic::A64::ExclusiveMonitor monitor; 84 Dynarmic::A64::ExclusiveMonitor monitor;
85 Memory::Memory& memory;
82}; 86};
83 87
84} // namespace Core 88} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 9698172db..48182c99a 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -60,7 +60,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
60 return false; 60 return false;
61} 61}
62 62
63ARM_Unicorn::ARM_Unicorn(System& system) : system{system} { 63ARM_Unicorn::ARM_Unicorn(System& system) : ARM_Interface{system} {
64 CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc)); 64 CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
65 65
66 auto fpv = 3 << 20; 66 auto fpv = 3 << 20;
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index b39426ea0..3c5b155f9 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -45,7 +45,6 @@ private:
45 static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data); 45 static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
46 46
47 uc_engine* uc{}; 47 uc_engine* uc{};
48 System& system;
49 GDBStub::BreakpointAddress last_bkpt{}; 48 GDBStub::BreakpointAddress last_bkpt{};
50 bool last_bkpt_hit = false; 49 bool last_bkpt_hit = false;
51}; 50};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index eba17218a..c45fb960c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -39,6 +39,7 @@
39#include "core/hle/service/service.h" 39#include "core/hle/service/service.h"
40#include "core/hle/service/sm/sm.h" 40#include "core/hle/service/sm/sm.h"
41#include "core/loader/loader.h" 41#include "core/loader/loader.h"
42#include "core/memory.h"
42#include "core/memory/cheat_engine.h" 43#include "core/memory/cheat_engine.h"
43#include "core/perf_stats.h" 44#include "core/perf_stats.h"
44#include "core/reporter.h" 45#include "core/reporter.h"
@@ -112,8 +113,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
112} 113}
113struct System::Impl { 114struct System::Impl {
114 explicit Impl(System& system) 115 explicit Impl(System& system)
115 : kernel{system}, fs_controller{system}, cpu_core_manager{system}, reporter{system}, 116 : kernel{system}, fs_controller{system}, memory{system},
116 applet_manager{system} {} 117 cpu_core_manager{system}, reporter{system}, applet_manager{system} {}
117 118
118 Cpu& CurrentCpuCore() { 119 Cpu& CurrentCpuCore() {
119 return cpu_core_manager.GetCurrentCore(); 120 return cpu_core_manager.GetCurrentCore();
@@ -341,7 +342,8 @@ struct System::Impl {
341 std::unique_ptr<VideoCore::RendererBase> renderer; 342 std::unique_ptr<VideoCore::RendererBase> renderer;
342 std::unique_ptr<Tegra::GPU> gpu_core; 343 std::unique_ptr<Tegra::GPU> gpu_core;
343 std::shared_ptr<Tegra::DebugContext> debug_context; 344 std::shared_ptr<Tegra::DebugContext> debug_context;
344 std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; 345 std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
346 Memory::Memory memory;
345 CpuCoreManager cpu_core_manager; 347 CpuCoreManager cpu_core_manager;
346 bool is_powered_on = false; 348 bool is_powered_on = false;
347 bool exit_lock = false; 349 bool exit_lock = false;
@@ -498,6 +500,14 @@ const ExclusiveMonitor& System::Monitor() const {
498 return impl->cpu_core_manager.GetExclusiveMonitor(); 500 return impl->cpu_core_manager.GetExclusiveMonitor();
499} 501}
500 502
503Memory::Memory& System::Memory() {
504 return impl->memory;
505}
506
507const Memory::Memory& System::Memory() const {
508 return impl->memory;
509}
510
501Tegra::GPU& System::GPU() { 511Tegra::GPU& System::GPU() {
502 return *impl->gpu_core; 512 return *impl->gpu_core;
503} 513}
diff --git a/src/core/core.h b/src/core/core.h
index f9b1a2866..91184e433 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -86,6 +86,10 @@ namespace Core::Hardware {
86class InterruptManager; 86class InterruptManager;
87} 87}
88 88
89namespace Memory {
90class Memory;
91}
92
89namespace Core { 93namespace Core {
90 94
91class ARM_Interface; 95class ARM_Interface;
@@ -225,6 +229,12 @@ public:
225 /// Gets a constant reference to the exclusive monitor 229 /// Gets a constant reference to the exclusive monitor
226 const ExclusiveMonitor& Monitor() const; 230 const ExclusiveMonitor& Monitor() const;
227 231
232 /// Gets a mutable reference to the system memory instance.
233 Memory::Memory& Memory();
234
235 /// Gets a constant reference to the system memory instance.
236 const Memory::Memory& Memory() const;
237
228 /// Gets a mutable reference to the GPU interface 238 /// Gets a mutable reference to the GPU interface
229 Tegra::GPU& GPU(); 239 Tegra::GPU& GPU();
230 240
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 233ea572c..cf3fe0b0b 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -66,9 +66,10 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
66 66
67Cpu::~Cpu() = default; 67Cpu::~Cpu() = default;
68 68
69std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { 69std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
70 [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
70#ifdef ARCHITECTURE_x86_64 71#ifdef ARCHITECTURE_x86_64
71 return std::make_unique<DynarmicExclusiveMonitor>(num_cores); 72 return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
72#else 73#else
73 // TODO(merry): Passthrough exclusive monitor 74 // TODO(merry): Passthrough exclusive monitor
74 return nullptr; 75 return nullptr;
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index cafca8df7..78f5021a2 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -24,6 +24,10 @@ namespace Core::Timing {
24class CoreTiming; 24class CoreTiming;
25} 25}
26 26
27namespace Memory {
28class Memory;
29}
30
27namespace Core { 31namespace Core {
28 32
29class ARM_Interface; 33class ARM_Interface;
@@ -86,7 +90,19 @@ public:
86 90
87 void Shutdown(); 91 void Shutdown();
88 92
89 static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores); 93 /**
94 * Creates an exclusive monitor to handle exclusive reads/writes.
95 *
96 * @param memory The current memory subsystem that the monitor may wish
97 * to keep track of.
98 *
99 * @param num_cores The number of cores to assume about the CPU.
100 *
101 * @returns The constructed exclusive monitor instance, or nullptr if the current
102 * CPU backend is unable to use an exclusive monitor.
103 */
104 static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
105 std::size_t num_cores);
90 106
91private: 107private:
92 void Reschedule(); 108 void Reschedule();
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 8efd410bb..f04a34133 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -25,7 +25,7 @@ CpuCoreManager::~CpuCoreManager() = default;
25 25
26void CpuCoreManager::Initialize() { 26void CpuCoreManager::Initialize() {
27 barrier = std::make_unique<CpuBarrier>(); 27 barrier = std::make_unique<CpuBarrier>();
28 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); 28 exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
29 29
30 for (std::size_t index = 0; index < cores.size(); ++index) { 30 for (std::size_t index = 0; index < cores.size(); ++index) {
31 cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); 31 cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 54ed680db..37cb28848 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -508,8 +508,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
508 bp->second.len, bp->second.addr, static_cast<int>(type)); 508 bp->second.len, bp->second.addr, static_cast<int>(type));
509 509
510 if (type == BreakpointType::Execute) { 510 if (type == BreakpointType::Execute) {
511 Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); 511 auto& system = Core::System::GetInstance();
512 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 512 system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
513 system.InvalidateCpuInstructionCaches();
513 } 514 }
514 p.erase(addr); 515 p.erase(addr);
515} 516}
@@ -969,12 +970,13 @@ static void ReadMemory() {
969 SendReply("E01"); 970 SendReply("E01");
970 } 971 }
971 972
972 if (!Memory::IsValidVirtualAddress(addr)) { 973 auto& memory = Core::System::GetInstance().Memory();
974 if (!memory.IsValidVirtualAddress(addr)) {
973 return SendReply("E00"); 975 return SendReply("E00");
974 } 976 }
975 977
976 std::vector<u8> data(len); 978 std::vector<u8> data(len);
977 Memory::ReadBlock(addr, data.data(), len); 979 memory.ReadBlock(addr, data.data(), len);
978 980
979 MemToGdbHex(reply, data.data(), len); 981 MemToGdbHex(reply, data.data(), len);
980 reply[len * 2] = '\0'; 982 reply[len * 2] = '\0';
@@ -984,22 +986,23 @@ static void ReadMemory() {
984/// Modify location in memory with data received from the gdb client. 986/// Modify location in memory with data received from the gdb client.
985static void WriteMemory() { 987static void WriteMemory() {
986 auto start_offset = command_buffer + 1; 988 auto start_offset = command_buffer + 1;
987 auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); 989 const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
988 VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); 990 const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
989 991
990 start_offset = addr_pos + 1; 992 start_offset = addr_pos + 1;
991 auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); 993 const auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
992 u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset)); 994 const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
993 995
994 if (!Memory::IsValidVirtualAddress(addr)) { 996 auto& system = Core::System::GetInstance();
997 auto& memory = system.Memory();
998 if (!memory.IsValidVirtualAddress(addr)) {
995 return SendReply("E00"); 999 return SendReply("E00");
996 } 1000 }
997 1001
998 std::vector<u8> data(len); 1002 std::vector<u8> data(len);
999
1000 GdbHexToMem(data.data(), len_pos + 1, len); 1003 GdbHexToMem(data.data(), len_pos + 1, len);
1001 Memory::WriteBlock(addr, data.data(), len); 1004 memory.WriteBlock(addr, data.data(), len);
1002 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1005 system.InvalidateCpuInstructionCaches();
1003 SendReply("OK"); 1006 SendReply("OK");
1004} 1007}
1005 1008
@@ -1055,12 +1058,15 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1055 breakpoint.active = true; 1058 breakpoint.active = true;
1056 breakpoint.addr = addr; 1059 breakpoint.addr = addr;
1057 breakpoint.len = len; 1060 breakpoint.len = len;
1058 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 1061
1062 auto& system = Core::System::GetInstance();
1063 auto& memory = system.Memory();
1064 memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1059 1065
1060 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; 1066 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1061 if (type == BreakpointType::Execute) { 1067 if (type == BreakpointType::Execute) {
1062 Memory::WriteBlock(addr, btrap.data(), btrap.size()); 1068 memory.WriteBlock(addr, btrap.data(), btrap.size());
1063 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1069 system.InvalidateCpuInstructionCaches();
1064 } 1070 }
1065 p.insert({addr, breakpoint}); 1071 p.insert({addr, breakpoint});
1066 1072
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 4859954cb..98d07fa5b 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -67,23 +67,27 @@ 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 (!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
79 Memory::Write32(address, static_cast<u32>(value + 1)); 81 memory.Write32(address, static_cast<u32>(value + 1));
80 return SignalToAddressOnly(address, num_to_wake); 82 return SignalToAddressOnly(address, num_to_wake);
81} 83}
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 (!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,11 +113,11 @@ 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
116 Memory::Write32(address, static_cast<u32>(updated_value)); 120 memory.Write32(address, static_cast<u32>(updated_value));
117 WakeThreads(waiting_threads, num_to_wake); 121 WakeThreads(waiting_threads, num_to_wake);
118 return RESULT_SUCCESS; 122 return RESULT_SUCCESS;
119} 123}
@@ -134,18 +138,20 @@ 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 (!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 }
146 152
147 if (should_decrement) { 153 if (should_decrement) {
148 Memory::Write32(address, static_cast<u32>(cur_value - 1)); 154 memory.Write32(address, static_cast<u32>(cur_value - 1));
149 } 155 }
150 156
151 // Short-circuit without rescheduling, if timeout is zero. 157 // Short-circuit without rescheduling, if timeout is zero.
@@ -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 (!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/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 5995a6556..9849dbe91 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -21,10 +21,10 @@ ClientSession::~ClientSession() {
21 } 21 }
22} 22}
23 23
24ResultCode ClientSession::SendSyncRequest(Thread* thread) { 24ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) {
25 // Signal the server session that new data is available 25 // Signal the server session that new data is available
26 if (auto server = parent->server.lock()) { 26 if (auto server = parent->server.lock()) {
27 return server->HandleSyncRequest(SharedFrom(thread)); 27 return server->HandleSyncRequest(SharedFrom(thread), memory);
28 } 28 }
29 29
30 return ERR_SESSION_CLOSED_BY_REMOTE; 30 return ERR_SESSION_CLOSED_BY_REMOTE;
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 5ae41db29..484dd7bc9 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -10,6 +10,10 @@
10 10
11union ResultCode; 11union ResultCode;
12 12
13namespace Memory {
14class Memory;
15}
16
13namespace Kernel { 17namespace Kernel {
14 18
15class KernelCore; 19class KernelCore;
@@ -37,7 +41,7 @@ public:
37 return HANDLE_TYPE; 41 return HANDLE_TYPE;
38 } 42 }
39 43
40 ResultCode SendSyncRequest(Thread* thread); 44 ResultCode SendSyncRequest(Thread* thread, Memory::Memory& memory);
41 45
42private: 46private:
43 /// The parent session, which links to the server endpoint. 47 /// The parent session, which links to the server endpoint.
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index be24cef06..8b01567a8 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.
@@ -273,8 +274,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
273 } 274 }
274 275
275 // Copy the translated command buffer back into the thread's command buffer area. 276 // Copy the translated command buffer back into the thread's command buffer area.
276 Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), 277 memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
277 dst_cmdbuf.size() * sizeof(u32)); 278 dst_cmdbuf.size() * sizeof(u32));
278 279
279 return RESULT_SUCCESS; 280 return RESULT_SUCCESS;
280} 281}
@@ -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;
@@ -311,10 +311,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
311 size = buffer_size; // TODO(bunnei): This needs to be HW tested 311 size = buffer_size; // TODO(bunnei): This needs to be HW tested
312 } 312 }
313 313
314 auto& memory = Core::System::GetInstance().Memory();
314 if (is_buffer_b) { 315 if (is_buffer_b) {
315 Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); 316 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
316 } else { 317 } else {
317 Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); 318 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
318 } 319 }
319 320
320 return size; 321 return size;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index a9851113a..1c90546a4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -154,6 +154,16 @@ struct KernelCore::Impl {
154 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 154 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
155 } 155 }
156 156
157 void MakeCurrentProcess(Process* process) {
158 current_process = process;
159
160 if (process == nullptr) {
161 return;
162 }
163
164 system.Memory().SetCurrentPageTable(*process);
165 }
166
157 std::atomic<u32> next_object_id{0}; 167 std::atomic<u32> next_object_id{0};
158 std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; 168 std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
159 std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; 169 std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
@@ -208,13 +218,7 @@ void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
208} 218}
209 219
210void KernelCore::MakeCurrentProcess(Process* process) { 220void KernelCore::MakeCurrentProcess(Process* process) {
211 impl->current_process = process; 221 impl->MakeCurrentProcess(process);
212
213 if (process == nullptr) {
214 return;
215 }
216
217 Memory::SetCurrentPageTable(*process);
218} 222}
219 223
220Process* KernelCore::CurrentProcess() { 224Process* KernelCore::CurrentProcess() {
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 8493d0f78..061e9bcb0 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)) {
@@ -117,7 +117,7 @@ ResultCode Mutex::Release(VAddr address) {
117 117
118 // There are no more threads waiting for the mutex, release it completely. 118 // There are no more threads waiting for the mutex, release it completely.
119 if (thread == nullptr) { 119 if (thread == nullptr) {
120 Memory::Write32(address, 0); 120 system.Memory().Write32(address, 0);
121 return RESULT_SUCCESS; 121 return RESULT_SUCCESS;
122 } 122 }
123 123
@@ -132,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) {
132 } 132 }
133 133
134 // Grant the mutex to the next waiting thread and resume it. 134 // Grant the mutex to the next waiting thread and resume it.
135 Memory::Write32(address, mutex_value); 135 system.Memory().Write32(address, mutex_value);
136 136
137 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); 137 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
138 thread->ResumeFromWait(); 138 thread->ResumeFromWait();
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index c7db21eb2..1198c7a97 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -19,6 +19,7 @@
19#include "core/hle/kernel/server_session.h" 19#include "core/hle/kernel/server_session.h"
20#include "core/hle/kernel/session.h" 20#include "core/hle/kernel/session.h"
21#include "core/hle/kernel/thread.h" 21#include "core/hle/kernel/thread.h"
22#include "core/memory.h"
22 23
23namespace Kernel { 24namespace Kernel {
24 25
@@ -127,12 +128,13 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
127 return RESULT_SUCCESS; 128 return RESULT_SUCCESS;
128} 129}
129 130
130ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) { 131ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
132 Memory::Memory& memory) {
131 // The ServerSession received a sync request, this means that there's new data available 133 // The ServerSession received a sync request, this means that there's new data available
132 // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or 134 // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
133 // similar. 135 // similar.
134 Kernel::HLERequestContext context(SharedFrom(this), thread); 136 Kernel::HLERequestContext context(SharedFrom(this), thread);
135 u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); 137 u32* cmd_buf = (u32*)memory.GetPointer(thread->GetTLSAddress());
136 context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); 138 context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
137 139
138 ResultCode result = RESULT_SUCCESS; 140 ResultCode result = RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 8a65647b6..641709a45 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -13,6 +13,10 @@
13#include "core/hle/kernel/wait_object.h" 13#include "core/hle/kernel/wait_object.h"
14#include "core/hle/result.h" 14#include "core/hle/result.h"
15 15
16namespace Memory {
17class Memory;
18}
19
16namespace Kernel { 20namespace Kernel {
17 21
18class ClientPort; 22class ClientPort;
@@ -85,10 +89,13 @@ public:
85 89
86 /** 90 /**
87 * Handle a sync request from the emulated application. 91 * Handle a sync request from the emulated application.
92 *
88 * @param thread Thread that initiated the request. 93 * @param thread Thread that initiated the request.
94 * @param memory Memory context to handle the sync request under.
95 *
89 * @returns ResultCode from the operation. 96 * @returns ResultCode from the operation.
90 */ 97 */
91 ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread); 98 ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
92 99
93 bool ShouldWait(const Thread* thread) const override; 100 bool ShouldWait(const Thread* thread) const override;
94 101
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 9928b3a26..db3ae3eb8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -332,7 +332,9 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
332/// Connect to an OS service given the port name, returns the handle to the port to out 332/// Connect to an OS service given the port name, returns the handle to the port to out
333static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, 333static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
334 VAddr port_name_address) { 334 VAddr port_name_address) {
335 if (!Memory::IsValidVirtualAddress(port_name_address)) { 335 auto& memory = system.Memory();
336
337 if (!memory.IsValidVirtualAddress(port_name_address)) {
336 LOG_ERROR(Kernel_SVC, 338 LOG_ERROR(Kernel_SVC,
337 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", 339 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
338 port_name_address); 340 port_name_address);
@@ -341,7 +343,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
341 343
342 static constexpr std::size_t PortNameMaxLength = 11; 344 static constexpr std::size_t PortNameMaxLength = 11;
343 // Read 1 char beyond the max allowed port name to detect names that are too long. 345 // Read 1 char beyond the max allowed port name to detect names that are too long.
344 std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); 346 const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
345 if (port_name.size() > PortNameMaxLength) { 347 if (port_name.size() > PortNameMaxLength) {
346 LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength, 348 LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
347 port_name.size()); 349 port_name.size());
@@ -383,7 +385,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
383 385
384 // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server 386 // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
385 // responds and cause a reschedule. 387 // responds and cause a reschedule.
386 return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread()); 388 return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread(), system.Memory());
387} 389}
388 390
389/// Get the ID for the specified thread. 391/// Get the ID for the specified thread.
@@ -452,7 +454,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
452 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={}",
453 handles_address, handle_count, nano_seconds); 455 handles_address, handle_count, nano_seconds);
454 456
455 if (!Memory::IsValidVirtualAddress(handles_address)) { 457 auto& memory = system.Memory();
458 if (!memory.IsValidVirtualAddress(handles_address)) {
456 LOG_ERROR(Kernel_SVC, 459 LOG_ERROR(Kernel_SVC,
457 "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}",
458 handles_address); 461 handles_address);
@@ -474,7 +477,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
474 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 477 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
475 478
476 for (u64 i = 0; i < handle_count; ++i) { 479 for (u64 i = 0; i < handle_count; ++i) {
477 const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); 480 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
478 const auto object = handle_table.Get<WaitObject>(handle); 481 const auto object = handle_table.Get<WaitObject>(handle);
479 482
480 if (object == nullptr) { 483 if (object == nullptr) {
@@ -616,13 +619,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
616 return; 619 return;
617 } 620 }
618 621
622 auto& memory = system.Memory();
623
619 // 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
620 if (sz == sizeof(u32)) { 625 if (sz == sizeof(u32)) {
621 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));
622 } else { 627 } else {
623 // 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
624 debug_buffer.resize(sz); 629 debug_buffer.resize(sz);
625 Memory::ReadBlock(addr, debug_buffer.data(), sz); 630 memory.ReadBlock(addr, debug_buffer.data(), sz);
626 std::string hexdump; 631 std::string hexdump;
627 for (std::size_t i = 0; i < debug_buffer.size(); i++) { 632 for (std::size_t i = 0; i < debug_buffer.size(); i++) {
628 hexdump += fmt::format("{:02X} ", debug_buffer[i]); 633 hexdump += fmt::format("{:02X} ", debug_buffer[i]);
@@ -712,7 +717,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre
712 } 717 }
713 718
714 std::string str(len, '\0'); 719 std::string str(len, '\0');
715 Memory::ReadBlock(address, str.data(), str.size()); 720 system.Memory().ReadBlock(address, str.data(), str.size());
716 LOG_DEBUG(Debug_Emulated, "{}", str); 721 LOG_DEBUG(Debug_Emulated, "{}", str);
717} 722}
718 723
@@ -1115,7 +1120,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
1115 std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); 1120 std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
1116 } 1121 }
1117 1122
1118 Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); 1123 system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
1119 return RESULT_SUCCESS; 1124 return RESULT_SUCCESS;
1120} 1125}
1121 1126
@@ -1275,20 +1280,21 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
1275 return ERR_INVALID_HANDLE; 1280 return ERR_INVALID_HANDLE;
1276 } 1281 }
1277 1282
1283 auto& memory = system.Memory();
1278 const auto& vm_manager = process->VMManager(); 1284 const auto& vm_manager = process->VMManager();
1279 const MemoryInfo memory_info = vm_manager.QueryMemory(address); 1285 const MemoryInfo memory_info = vm_manager.QueryMemory(address);
1280 1286
1281 Memory::Write64(memory_info_address, memory_info.base_address); 1287 memory.Write64(memory_info_address, memory_info.base_address);
1282 Memory::Write64(memory_info_address + 8, memory_info.size); 1288 memory.Write64(memory_info_address + 8, memory_info.size);
1283 Memory::Write32(memory_info_address + 16, memory_info.state); 1289 memory.Write32(memory_info_address + 16, memory_info.state);
1284 Memory::Write32(memory_info_address + 20, memory_info.attributes); 1290 memory.Write32(memory_info_address + 20, memory_info.attributes);
1285 Memory::Write32(memory_info_address + 24, memory_info.permission); 1291 memory.Write32(memory_info_address + 24, memory_info.permission);
1286 Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count); 1292 memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count);
1287 Memory::Write32(memory_info_address + 28, memory_info.device_ref_count); 1293 memory.Write32(memory_info_address + 28, memory_info.device_ref_count);
1288 Memory::Write32(memory_info_address + 36, 0); 1294 memory.Write32(memory_info_address + 36, 0);
1289 1295
1290 // Page info appears to be currently unused by the kernel and is always set to zero. 1296 // Page info appears to be currently unused by the kernel and is always set to zero.
1291 Memory::Write32(page_info_address, 0); 1297 memory.Write32(page_info_address, 0);
1292 1298
1293 return RESULT_SUCCESS; 1299 return RESULT_SUCCESS;
1294} 1300}
@@ -1672,6 +1678,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1672 1678
1673 const std::size_t current_core = system.CurrentCoreIndex(); 1679 const std::size_t current_core = system.CurrentCoreIndex();
1674 auto& monitor = system.Monitor(); 1680 auto& monitor = system.Monitor();
1681 auto& memory = system.Memory();
1675 1682
1676 // Atomically read the value of the mutex. 1683 // Atomically read the value of the mutex.
1677 u32 mutex_val = 0; 1684 u32 mutex_val = 0;
@@ -1681,7 +1688,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1681 monitor.SetExclusive(current_core, mutex_address); 1688 monitor.SetExclusive(current_core, mutex_address);
1682 1689
1683 // If the mutex is not yet acquired, acquire it. 1690 // If the mutex is not yet acquired, acquire it.
1684 mutex_val = Memory::Read32(mutex_address); 1691 mutex_val = memory.Read32(mutex_address);
1685 1692
1686 if (mutex_val != 0) { 1693 if (mutex_val != 0) {
1687 update_val = mutex_val | Mutex::MutexHasWaitersFlag; 1694 update_val = mutex_val | Mutex::MutexHasWaitersFlag;
@@ -2284,12 +2291,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
2284 return ERR_INVALID_ADDRESS_STATE; 2291 return ERR_INVALID_ADDRESS_STATE;
2285 } 2292 }
2286 2293
2294 auto& memory = system.Memory();
2287 const auto& process_list = kernel.GetProcessList(); 2295 const auto& process_list = kernel.GetProcessList();
2288 const auto num_processes = process_list.size(); 2296 const auto num_processes = process_list.size();
2289 const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); 2297 const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
2290 2298
2291 for (std::size_t i = 0; i < copy_amount; ++i) { 2299 for (std::size_t i = 0; i < copy_amount; ++i) {
2292 Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); 2300 memory.Write64(out_process_ids, process_list[i]->GetProcessID());
2293 out_process_ids += sizeof(u64); 2301 out_process_ids += sizeof(u64);
2294 } 2302 }
2295 2303
@@ -2323,13 +2331,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
2323 return ERR_INVALID_ADDRESS_STATE; 2331 return ERR_INVALID_ADDRESS_STATE;
2324 } 2332 }
2325 2333
2334 auto& memory = system.Memory();
2326 const auto& thread_list = current_process->GetThreadList(); 2335 const auto& thread_list = current_process->GetThreadList();
2327 const auto num_threads = thread_list.size(); 2336 const auto num_threads = thread_list.size();
2328 const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); 2337 const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
2329 2338
2330 auto list_iter = thread_list.cbegin(); 2339 auto list_iter = thread_list.cbegin();
2331 for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { 2340 for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
2332 Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); 2341 memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
2333 out_thread_ids += sizeof(u64); 2342 out_thread_ids += sizeof(u64);
2334 } 2343 }
2335 2344
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 735019d96..e84e5ce0d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -162,13 +162,13 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
162 return ERR_INVALID_PROCESSOR_ID; 162 return ERR_INVALID_PROCESSOR_ID;
163 } 163 }
164 164
165 if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) { 165 auto& system = Core::System::GetInstance();
166 if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) {
166 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); 167 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
167 // TODO (bunnei): Find the correct error code to use here 168 // TODO (bunnei): Find the correct error code to use here
168 return RESULT_UNKNOWN; 169 return RESULT_UNKNOWN;
169 } 170 }
170 171
171 auto& system = Core::System::GetInstance();
172 std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel); 172 std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel);
173 173
174 thread->thread_id = kernel.CreateNewThreadID(); 174 thread->thread_id = kernel.CreateNewThreadID();
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index e6eee09d7..a9a20ef76 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -16,7 +16,6 @@
16#include "core/hle/kernel/resource_limit.h" 16#include "core/hle/kernel/resource_limit.h"
17#include "core/hle/kernel/vm_manager.h" 17#include "core/hle/kernel/vm_manager.h"
18#include "core/memory.h" 18#include "core/memory.h"
19#include "core/memory_setup.h"
20 19
21namespace Kernel { 20namespace Kernel {
22namespace { 21namespace {
@@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
786} 785}
787 786
788void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { 787void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
788 auto& memory = system.Memory();
789
789 switch (vma.type) { 790 switch (vma.type) {
790 case VMAType::Free: 791 case VMAType::Free:
791 Memory::UnmapRegion(page_table, vma.base, vma.size); 792 memory.UnmapRegion(page_table, vma.base, vma.size);
792 break; 793 break;
793 case VMAType::AllocatedMemoryBlock: 794 case VMAType::AllocatedMemoryBlock:
794 Memory::MapMemoryRegion(page_table, vma.base, vma.size, 795 memory.MapMemoryRegion(page_table, vma.base, vma.size,
795 vma.backing_block->data() + vma.offset); 796 vma.backing_block->data() + vma.offset);
796 break; 797 break;
797 case VMAType::BackingMemory: 798 case VMAType::BackingMemory:
798 Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); 799 memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
799 break; 800 break;
800 case VMAType::MMIO: 801 case VMAType::MMIO:
801 Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); 802 memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
802 break; 803 break;
803 } 804 }
804} 805}
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/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 4ea7ade6e..82a5dbf14 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -49,8 +49,9 @@ public:
49 49
50 system_event = 50 system_event =
51 Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); 51 Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
52 renderer = std::make_unique<AudioCore::AudioRenderer>( 52 renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
53 system.CoreTiming(), audren_params, system_event.writable, instance_number); 53 audren_params, system_event.writable,
54 instance_number);
54 } 55 }
55 56
56private: 57private:
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index ea9cc901e..55d62fc5e 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -391,13 +391,10 @@ public:
391 } 391 }
392 392
393 void RenameFile(Kernel::HLERequestContext& ctx) { 393 void RenameFile(Kernel::HLERequestContext& ctx) {
394 std::vector<u8> buffer; 394 std::vector<u8> buffer = ctx.ReadBuffer(0);
395 buffer.resize(ctx.BufferDescriptorX()[0].Size());
396 Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
397 const std::string src_name = Common::StringFromBuffer(buffer); 395 const std::string src_name = Common::StringFromBuffer(buffer);
398 396
399 buffer.resize(ctx.BufferDescriptorX()[1].Size()); 397 buffer = ctx.ReadBuffer(1);
400 Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size());
401 const std::string dst_name = Common::StringFromBuffer(buffer); 398 const std::string dst_name = Common::StringFromBuffer(buffer);
402 399
403 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); 400 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
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 435f2d286..346c8f899 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -17,7 +17,8 @@ namespace Service::LM {
17 17
18class ILogger final : public ServiceFramework<ILogger> { 18class ILogger final : public ServiceFramework<ILogger> {
19public: 19public:
20 ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) { 20 explicit ILogger(Manager& manager_, Memory::Memory& memory_)
21 : ServiceFramework("ILogger"), manager{manager_}, memory{memory_} {
21 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
22 {0, &ILogger::Log, "Log"}, 23 {0, &ILogger::Log, "Log"},
23 {1, &ILogger::SetDestination, "SetDestination"}, 24 {1, &ILogger::SetDestination, "SetDestination"},
@@ -35,15 +36,15 @@ private:
35 MessageHeader header{}; 36 MessageHeader header{};
36 VAddr addr{ctx.BufferDescriptorX()[0].Address()}; 37 VAddr addr{ctx.BufferDescriptorX()[0].Address()};
37 const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; 38 const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
38 Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); 39 memory.ReadBlock(addr, &header, sizeof(MessageHeader));
39 addr += sizeof(MessageHeader); 40 addr += sizeof(MessageHeader);
40 41
41 FieldMap fields; 42 FieldMap fields;
42 while (addr < end_addr) { 43 while (addr < end_addr) {
43 const auto field = static_cast<Field>(Memory::Read8(addr++)); 44 const auto field = static_cast<Field>(memory.Read8(addr++));
44 const auto length = Memory::Read8(addr++); 45 const auto length = memory.Read8(addr++);
45 46
46 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { 47 if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) {
47 ++addr; 48 ++addr;
48 } 49 }
49 50
@@ -54,7 +55,7 @@ private:
54 } 55 }
55 56
56 std::vector<u8> data(length); 57 std::vector<u8> data(length);
57 Memory::ReadBlock(addr, data.data(), length); 58 memory.ReadBlock(addr, data.data(), length);
58 fields.emplace(field, std::move(data)); 59 fields.emplace(field, std::move(data));
59 } 60 }
60 61
@@ -74,11 +75,13 @@ private:
74 } 75 }
75 76
76 Manager& manager; 77 Manager& manager;
78 Memory::Memory& memory;
77}; 79};
78 80
79class LM final : public ServiceFramework<LM> { 81class LM final : public ServiceFramework<LM> {
80public: 82public:
81 explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) { 83 explicit LM(Manager& manager_, Memory::Memory& memory_)
84 : ServiceFramework{"lm"}, manager{manager_}, memory{memory_} {
82 // clang-format off 85 // clang-format off
83 static const FunctionInfo functions[] = { 86 static const FunctionInfo functions[] = {
84 {0, &LM::OpenLogger, "OpenLogger"}, 87 {0, &LM::OpenLogger, "OpenLogger"},
@@ -94,14 +97,16 @@ private:
94 97
95 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 98 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
96 rb.Push(RESULT_SUCCESS); 99 rb.Push(RESULT_SUCCESS);
97 rb.PushIpcInterface<ILogger>(manager); 100 rb.PushIpcInterface<ILogger>(manager, memory);
98 } 101 }
99 102
100 Manager& manager; 103 Manager& manager;
104 Memory::Memory& memory;
101}; 105};
102 106
103void InstallInterfaces(Core::System& system) { 107void InstallInterfaces(Core::System& system) {
104 std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager()); 108 std::make_shared<LM>(system.GetLogManager(), system.Memory())
109 ->InstallAsService(system.ServiceManager());
105} 110}
106 111
107} // namespace Service::LM 112} // namespace Service::LM
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 fa49f3dd0..91bf07a92 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -17,529 +17,699 @@
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19#include "core/memory.h" 19#include "core/memory.h"
20#include "core/memory_setup.h"
21#include "video_core/gpu.h" 20#include "video_core/gpu.h"
22 21
23namespace Memory { 22namespace Memory {
24 23
25static Common::PageTable* current_page_table = nullptr; 24// Implementation class used to keep the specifics of the memory subsystem hidden
25// from outside classes. This also allows modification to the internals of the memory
26// subsystem without needing to rebuild all files that make use of the memory interface.
27struct Memory::Impl {
28 explicit Impl(Core::System& system_) : system{system_} {}
26 29
27void SetCurrentPageTable(Kernel::Process& process) { 30 void SetCurrentPageTable(Kernel::Process& process) {
28 current_page_table = &process.VMManager().page_table; 31 current_page_table = &process.VMManager().page_table;
29 32
30 const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth(); 33 const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth();
31 34
32 auto& system = Core::System::GetInstance(); 35 system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width);
33 system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width); 36 system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width);
34 system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width); 37 system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width);
35 system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width); 38 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width);
36 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); 39 }
37}
38 40
39static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, 41 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
40 Common::PageType type) { 42 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
41 LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, 43 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
42 (base + size) * PAGE_SIZE); 44 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
43
44 // During boot, current_page_table might not be set yet, in which case we need not flush
45 if (Core::System::GetInstance().IsPoweredOn()) {
46 auto& gpu = Core::System::GetInstance().GPU();
47 for (u64 i = 0; i < size; i++) {
48 const auto page = base + i;
49 if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) {
50 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE);
51 }
52 }
53 } 45 }
54 46
55 VAddr end = base + size; 47 void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
56 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", 48 Common::MemoryHookPointer mmio_handler) {
57 base + page_table.pointers.size()); 49 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
50 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
51 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr,
52 Common::PageType::Special);
53
54 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
55 const Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice,
56 std::move(mmio_handler)};
57 page_table.special_regions.add(
58 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
59 }
58 60
59 std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type); 61 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
62 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
63 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
64 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr,
65 Common::PageType::Unmapped);
60 66
61 if (memory == nullptr) { 67 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
62 std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end, memory); 68 page_table.special_regions.erase(interval);
63 } else { 69 }
64 while (base != end) {
65 page_table.pointers[base] = memory;
66 70
67 base += 1; 71 void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
68 memory += PAGE_SIZE; 72 Common::MemoryHookPointer hook) {
69 } 73 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
74 const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
75 page_table.special_regions.add(
76 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
70 } 77 }
71}
72 78
73void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { 79 void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
74 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 80 Common::MemoryHookPointer hook) {
75 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 81 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
76 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); 82 const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
77} 83 page_table.special_regions.subtract(
84 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
85 }
78 86
79void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, 87 bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
80 Common::MemoryHookPointer mmio_handler) { 88 const auto& page_table = process.VMManager().page_table;
81 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
82 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
83 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Special);
84 89
85 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 90 const u8* const page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
86 Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice, std::move(mmio_handler)}; 91 if (page_pointer != nullptr) {
87 page_table.special_regions.add( 92 return true;
88 std::make_pair(interval, std::set<Common::SpecialRegion>{region})); 93 }
89}
90 94
91void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { 95 if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) {
92 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 96 return true;
93 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 97 }
94 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Unmapped);
95 98
96 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 99 if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) {
97 page_table.special_regions.erase(interval); 100 return false;
98} 101 }
99 102
100void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, 103 return false;
101 Common::MemoryHookPointer hook) { 104 }
102 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
103 Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
104 page_table.special_regions.add(
105 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
106}
107 105
108void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, 106 bool IsValidVirtualAddress(VAddr vaddr) const {
109 Common::MemoryHookPointer hook) { 107 return IsValidVirtualAddress(*system.CurrentProcess(), vaddr);
110 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 108 }
111 Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
112 page_table.special_regions.subtract(
113 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
114}
115 109
116/** 110 /**
117 * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) 111 * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
118 * using a VMA from the current process 112 * using a VMA from the current process
119 */ 113 */
120static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { 114 u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
121 const auto& vm_manager = process.VMManager(); 115 const auto& vm_manager = process.VMManager();
122 116
123 const auto it = vm_manager.FindVMA(vaddr); 117 const auto it = vm_manager.FindVMA(vaddr);
124 DEBUG_ASSERT(vm_manager.IsValidHandle(it)); 118 DEBUG_ASSERT(vm_manager.IsValidHandle(it));
125 119
126 u8* direct_pointer = nullptr; 120 u8* direct_pointer = nullptr;
127 const auto& vma = it->second; 121 const auto& vma = it->second;
128 switch (vma.type) { 122 switch (vma.type) {
129 case Kernel::VMAType::AllocatedMemoryBlock: 123 case Kernel::VMAType::AllocatedMemoryBlock:
130 direct_pointer = vma.backing_block->data() + vma.offset; 124 direct_pointer = vma.backing_block->data() + vma.offset;
131 break; 125 break;
132 case Kernel::VMAType::BackingMemory: 126 case Kernel::VMAType::BackingMemory:
133 direct_pointer = vma.backing_memory; 127 direct_pointer = vma.backing_memory;
134 break; 128 break;
135 case Kernel::VMAType::Free: 129 case Kernel::VMAType::Free:
136 return nullptr; 130 return nullptr;
137 default: 131 default:
138 UNREACHABLE(); 132 UNREACHABLE();
133 }
134
135 return direct_pointer + (vaddr - vma.base);
139 } 136 }
140 137
141 return direct_pointer + (vaddr - vma.base); 138 /**
142} 139 * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
140 * using a VMA from the current process.
141 */
142 u8* GetPointerFromVMA(VAddr vaddr) {
143 return GetPointerFromVMA(*system.CurrentProcess(), vaddr);
144 }
143 145
144/** 146 u8* GetPointer(const VAddr vaddr) {
145 * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) 147 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
146 * using a VMA from the current process. 148 if (page_pointer != nullptr) {
147 */ 149 return page_pointer + (vaddr & PAGE_MASK);
148static u8* GetPointerFromVMA(VAddr vaddr) { 150 }
149 return GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr);
150}
151 151
152template <typename T> 152 if (current_page_table->attributes[vaddr >> PAGE_BITS] ==
153T Read(const VAddr vaddr) { 153 Common::PageType::RasterizerCachedMemory) {
154 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 154 return GetPointerFromVMA(vaddr);
155 if (page_pointer) { 155 }
156 // NOTE: Avoid adding any extra logic to this fast-path block
157 T value;
158 std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
159 return value;
160 }
161
162 Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
163 switch (type) {
164 case Common::PageType::Unmapped:
165 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
166 return 0;
167 case Common::PageType::Memory:
168 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
169 break;
170 case Common::PageType::RasterizerCachedMemory: {
171 auto host_ptr{GetPointerFromVMA(vaddr)};
172 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
173 T value;
174 std::memcpy(&value, host_ptr, sizeof(T));
175 return value;
176 }
177 default:
178 UNREACHABLE();
179 }
180 return {};
181}
182 156
183template <typename T> 157 LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr);
184void Write(const VAddr vaddr, const T data) { 158 return nullptr;
185 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
186 if (page_pointer) {
187 // NOTE: Avoid adding any extra logic to this fast-path block
188 std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
189 return;
190 }
191
192 Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
193 switch (type) {
194 case Common::PageType::Unmapped:
195 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
196 static_cast<u32>(data), vaddr);
197 return;
198 case Common::PageType::Memory:
199 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
200 break;
201 case Common::PageType::RasterizerCachedMemory: {
202 auto host_ptr{GetPointerFromVMA(vaddr)};
203 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
204 std::memcpy(host_ptr, &data, sizeof(T));
205 break;
206 }
207 default:
208 UNREACHABLE();
209 } 159 }
210}
211 160
212bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { 161 u8 Read8(const VAddr addr) {
213 const auto& page_table = process.VMManager().page_table; 162 return Read<u8>(addr);
163 }
214 164
215 const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; 165 u16 Read16(const VAddr addr) {
216 if (page_pointer) 166 return Read<u16_le>(addr);
217 return true; 167 }
218 168
219 if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) 169 u32 Read32(const VAddr addr) {
220 return true; 170 return Read<u32_le>(addr);
171 }
221 172
222 if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) 173 u64 Read64(const VAddr addr) {
223 return false; 174 return Read<u64_le>(addr);
175 }
224 176
225 return false; 177 void Write8(const VAddr addr, const u8 data) {
226} 178 Write<u8>(addr, data);
179 }
227 180
228bool IsValidVirtualAddress(const VAddr vaddr) { 181 void Write16(const VAddr addr, const u16 data) {
229 return IsValidVirtualAddress(*Core::System::GetInstance().CurrentProcess(), vaddr); 182 Write<u16_le>(addr, data);
230} 183 }
231 184
232bool IsKernelVirtualAddress(const VAddr vaddr) { 185 void Write32(const VAddr addr, const u32 data) {
233 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 186 Write<u32_le>(addr, data);
234} 187 }
235 188
236u8* GetPointer(const VAddr vaddr) { 189 void Write64(const VAddr addr, const u64 data) {
237 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 190 Write<u64_le>(addr, data);
238 if (page_pointer) {
239 return page_pointer + (vaddr & PAGE_MASK);
240 } 191 }
241 192
242 if (current_page_table->attributes[vaddr >> PAGE_BITS] == 193 std::string ReadCString(VAddr vaddr, std::size_t max_length) {
243 Common::PageType::RasterizerCachedMemory) { 194 std::string string;
244 return GetPointerFromVMA(vaddr); 195 string.reserve(max_length);
196 for (std::size_t i = 0; i < max_length; ++i) {
197 const char c = Read8(vaddr);
198 if (c == '\0') {
199 break;
200 }
201 string.push_back(c);
202 ++vaddr;
203 }
204 string.shrink_to_fit();
205 return string;
245 } 206 }
246 207
247 LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr); 208 void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
248 return nullptr; 209 const std::size_t size) {
249} 210 const auto& page_table = process.VMManager().page_table;
211
212 std::size_t remaining_size = size;
213 std::size_t page_index = src_addr >> PAGE_BITS;
214 std::size_t page_offset = src_addr & PAGE_MASK;
215
216 while (remaining_size > 0) {
217 const std::size_t copy_amount =
218 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
219 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
220
221 switch (page_table.attributes[page_index]) {
222 case Common::PageType::Unmapped: {
223 LOG_ERROR(HW_Memory,
224 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
225 current_vaddr, src_addr, size);
226 std::memset(dest_buffer, 0, copy_amount);
227 break;
228 }
229 case Common::PageType::Memory: {
230 DEBUG_ASSERT(page_table.pointers[page_index]);
250 231
251std::string ReadCString(VAddr vaddr, std::size_t max_length) { 232 const u8* const src_ptr = page_table.pointers[page_index] + page_offset;
252 std::string string; 233 std::memcpy(dest_buffer, src_ptr, copy_amount);
253 string.reserve(max_length); 234 break;
254 for (std::size_t i = 0; i < max_length; ++i) { 235 }
255 char c = Read8(vaddr); 236 case Common::PageType::RasterizerCachedMemory: {
256 if (c == '\0') 237 const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
257 break; 238 system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
258 string.push_back(c); 239 std::memcpy(dest_buffer, host_ptr, copy_amount);
259 ++vaddr; 240 break;
241 }
242 default:
243 UNREACHABLE();
244 }
245
246 page_index++;
247 page_offset = 0;
248 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
249 remaining_size -= copy_amount;
250 }
260 } 251 }
261 string.shrink_to_fit();
262 return string;
263}
264 252
265void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { 253 void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
266 if (vaddr == 0) { 254 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
267 return;
268 } 255 }
269 256
270 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU address 257 void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
271 // space, marking the region as un/cached. The region is marked un/cached at a granularity of 258 const std::size_t size) {
272 // CPU pages, hence why we iterate on a CPU page basis (note: GPU page size is different). This 259 const auto& page_table = process.VMManager().page_table;
273 // assumes the specified GPU address region is contiguous as well. 260 std::size_t remaining_size = size;
261 std::size_t page_index = dest_addr >> PAGE_BITS;
262 std::size_t page_offset = dest_addr & PAGE_MASK;
263
264 while (remaining_size > 0) {
265 const std::size_t copy_amount =
266 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
267 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
268
269 switch (page_table.attributes[page_index]) {
270 case Common::PageType::Unmapped: {
271 LOG_ERROR(HW_Memory,
272 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
273 current_vaddr, dest_addr, size);
274 break;
275 }
276 case Common::PageType::Memory: {
277 DEBUG_ASSERT(page_table.pointers[page_index]);
278
279 u8* const dest_ptr = page_table.pointers[page_index] + page_offset;
280 std::memcpy(dest_ptr, src_buffer, copy_amount);
281 break;
282 }
283 case Common::PageType::RasterizerCachedMemory: {
284 u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
285 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
286 std::memcpy(host_ptr, src_buffer, copy_amount);
287 break;
288 }
289 default:
290 UNREACHABLE();
291 }
292
293 page_index++;
294 page_offset = 0;
295 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
296 remaining_size -= copy_amount;
297 }
298 }
274 299
275 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; 300 void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
276 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { 301 WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size);
277 Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; 302 }
278 303
279 if (cached) { 304 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
280 // Switch page type to cached if now cached 305 const auto& page_table = process.VMManager().page_table;
281 switch (page_type) { 306 std::size_t remaining_size = size;
282 case Common::PageType::Unmapped: 307 std::size_t page_index = dest_addr >> PAGE_BITS;
283 // It is not necessary for a process to have this region mapped into its address 308 std::size_t page_offset = dest_addr & PAGE_MASK;
284 // space, for example, a system module need not have a VRAM mapping. 309
310 while (remaining_size > 0) {
311 const std::size_t copy_amount =
312 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
313 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
314
315 switch (page_table.attributes[page_index]) {
316 case Common::PageType::Unmapped: {
317 LOG_ERROR(HW_Memory,
318 "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
319 current_vaddr, dest_addr, size);
285 break; 320 break;
286 case Common::PageType::Memory: 321 }
287 page_type = Common::PageType::RasterizerCachedMemory; 322 case Common::PageType::Memory: {
288 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; 323 DEBUG_ASSERT(page_table.pointers[page_index]);
324
325 u8* dest_ptr = page_table.pointers[page_index] + page_offset;
326 std::memset(dest_ptr, 0, copy_amount);
289 break; 327 break;
290 case Common::PageType::RasterizerCachedMemory: 328 }
291 // There can be more than one GPU region mapped per CPU region, so it's common that 329 case Common::PageType::RasterizerCachedMemory: {
292 // this area is already marked as cached. 330 u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
331 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
332 std::memset(host_ptr, 0, copy_amount);
293 break; 333 break;
334 }
294 default: 335 default:
295 UNREACHABLE(); 336 UNREACHABLE();
296 } 337 }
297 } else { 338
298 // Switch page type to uncached if now uncached 339 page_index++;
299 switch (page_type) { 340 page_offset = 0;
300 case Common::PageType::Unmapped: 341 remaining_size -= copy_amount;
301 // It is not necessary for a process to have this region mapped into its address 342 }
302 // space, for example, a system module need not have a VRAM mapping. 343 }
344
345 void ZeroBlock(const VAddr dest_addr, const std::size_t size) {
346 ZeroBlock(*system.CurrentProcess(), dest_addr, size);
347 }
348
349 void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
350 const std::size_t size) {
351 const auto& page_table = process.VMManager().page_table;
352 std::size_t remaining_size = size;
353 std::size_t page_index = src_addr >> PAGE_BITS;
354 std::size_t page_offset = src_addr & PAGE_MASK;
355
356 while (remaining_size > 0) {
357 const std::size_t copy_amount =
358 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
359 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
360
361 switch (page_table.attributes[page_index]) {
362 case Common::PageType::Unmapped: {
363 LOG_ERROR(HW_Memory,
364 "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
365 current_vaddr, src_addr, size);
366 ZeroBlock(process, dest_addr, copy_amount);
303 break; 367 break;
304 case Common::PageType::Memory: 368 }
305 // There can be more than one GPU region mapped per CPU region, so it's common that 369 case Common::PageType::Memory: {
306 // this area is already unmarked as cached. 370 DEBUG_ASSERT(page_table.pointers[page_index]);
371 const u8* src_ptr = page_table.pointers[page_index] + page_offset;
372 WriteBlock(process, dest_addr, src_ptr, copy_amount);
307 break; 373 break;
374 }
308 case Common::PageType::RasterizerCachedMemory: { 375 case Common::PageType::RasterizerCachedMemory: {
309 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); 376 const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
310 if (pointer == nullptr) { 377 system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
311 // It's possible that this function has been called while updating the pagetable 378 WriteBlock(process, dest_addr, host_ptr, copy_amount);
312 // after unmapping a VMA. In that case the underlying VMA will no longer exist,
313 // and we should just leave the pagetable entry blank.
314 page_type = Common::PageType::Unmapped;
315 } else {
316 page_type = Common::PageType::Memory;
317 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
318 }
319 break; 379 break;
320 } 380 }
321 default: 381 default:
322 UNREACHABLE(); 382 UNREACHABLE();
323 } 383 }
384
385 page_index++;
386 page_offset = 0;
387 dest_addr += static_cast<VAddr>(copy_amount);
388 src_addr += static_cast<VAddr>(copy_amount);
389 remaining_size -= copy_amount;
324 } 390 }
325 } 391 }
326}
327 392
328u8 Read8(const VAddr addr) { 393 void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
329 return Read<u8>(addr); 394 return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size);
330} 395 }
331 396
332u16 Read16(const VAddr addr) { 397 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
333 return Read<u16_le>(addr); 398 if (vaddr == 0) {
334} 399 return;
400 }
335 401
336u32 Read32(const VAddr addr) { 402 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
337 return Read<u32_le>(addr); 403 // address space, marking the region as un/cached. The region is marked un/cached at a
338} 404 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size
405 // is different). This assumes the specified GPU address region is contiguous as well.
406
407 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
408 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
409 Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
410
411 if (cached) {
412 // Switch page type to cached if now cached
413 switch (page_type) {
414 case Common::PageType::Unmapped:
415 // It is not necessary for a process to have this region mapped into its address
416 // space, for example, a system module need not have a VRAM mapping.
417 break;
418 case Common::PageType::Memory:
419 page_type = Common::PageType::RasterizerCachedMemory;
420 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
421 break;
422 case Common::PageType::RasterizerCachedMemory:
423 // There can be more than one GPU region mapped per CPU region, so it's common
424 // that this area is already marked as cached.
425 break;
426 default:
427 UNREACHABLE();
428 }
429 } else {
430 // Switch page type to uncached if now uncached
431 switch (page_type) {
432 case Common::PageType::Unmapped:
433 // It is not necessary for a process to have this region mapped into its address
434 // space, for example, a system module need not have a VRAM mapping.
435 break;
436 case Common::PageType::Memory:
437 // There can be more than one GPU region mapped per CPU region, so it's common
438 // that this area is already unmarked as cached.
439 break;
440 case Common::PageType::RasterizerCachedMemory: {
441 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
442 if (pointer == nullptr) {
443 // It's possible that this function has been called while updating the
444 // pagetable after unmapping a VMA. In that case the underlying VMA will no
445 // longer exist, and we should just leave the pagetable entry blank.
446 page_type = Common::PageType::Unmapped;
447 } else {
448 page_type = Common::PageType::Memory;
449 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
450 }
451 break;
452 }
453 default:
454 UNREACHABLE();
455 }
456 }
457 }
458 }
339 459
340u64 Read64(const VAddr addr) { 460 /**
341 return Read<u64_le>(addr); 461 * Maps a region of pages as a specific type.
342} 462 *
463 * @param page_table The page table to use to perform the mapping.
464 * @param base The base address to begin mapping at.
465 * @param size The total size of the range in bytes.
466 * @param memory The memory to map.
467 * @param type The page type to map the memory as.
468 */
469 void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
470 Common::PageType type) {
471 LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
472 (base + size) * PAGE_SIZE);
473
474 // During boot, current_page_table might not be set yet, in which case we need not flush
475 if (system.IsPoweredOn()) {
476 auto& gpu = system.GPU();
477 for (u64 i = 0; i < size; i++) {
478 const auto page = base + i;
479 if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) {
480 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE);
481 }
482 }
483 }
343 484
344void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 485 const VAddr end = base + size;
345 const std::size_t size) { 486 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
346 const auto& page_table = process.VMManager().page_table; 487 base + page_table.pointers.size());
347 488
348 std::size_t remaining_size = size; 489 std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type);
349 std::size_t page_index = src_addr >> PAGE_BITS; 490
350 std::size_t page_offset = src_addr & PAGE_MASK; 491 if (memory == nullptr) {
351 492 std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end,
352 while (remaining_size > 0) { 493 memory);
353 const std::size_t copy_amount = 494 } else {
354 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 495 while (base != end) {
355 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 496 page_table.pointers[base] = memory;
356 497
357 switch (page_table.attributes[page_index]) { 498 base += 1;
358 case Common::PageType::Unmapped: { 499 memory += PAGE_SIZE;
359 LOG_ERROR(HW_Memory, 500 }
360 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 501 }
361 current_vaddr, src_addr, size); 502 }
362 std::memset(dest_buffer, 0, copy_amount); 503
363 break; 504 /**
505 * Reads a particular data type out of memory at the given virtual address.
506 *
507 * @param vaddr The virtual address to read the data type from.
508 *
509 * @tparam T The data type to read out of memory. This type *must* be
510 * trivially copyable, otherwise the behavior of this function
511 * is undefined.
512 *
513 * @returns The instance of T read from the specified virtual address.
514 */
515 template <typename T>
516 T Read(const VAddr vaddr) {
517 const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
518 if (page_pointer != nullptr) {
519 // NOTE: Avoid adding any extra logic to this fast-path block
520 T value;
521 std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
522 return value;
364 } 523 }
365 case Common::PageType::Memory: {
366 DEBUG_ASSERT(page_table.pointers[page_index]);
367 524
368 const u8* src_ptr = page_table.pointers[page_index] + page_offset; 525 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
369 std::memcpy(dest_buffer, src_ptr, copy_amount); 526 switch (type) {
527 case Common::PageType::Unmapped:
528 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
529 return 0;
530 case Common::PageType::Memory:
531 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
370 break; 532 break;
533 case Common::PageType::RasterizerCachedMemory: {
534 const u8* const host_ptr = GetPointerFromVMA(vaddr);
535 system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
536 T value;
537 std::memcpy(&value, host_ptr, sizeof(T));
538 return value;
539 }
540 default:
541 UNREACHABLE();
371 } 542 }
543 return {};
544 }
545
546 /**
547 * Writes a particular data type to memory at the given virtual address.
548 *
549 * @param vaddr The virtual address to write the data type to.
550 *
551 * @tparam T The data type to write to memory. This type *must* be
552 * trivially copyable, otherwise the behavior of this function
553 * is undefined.
554 *
555 * @returns The instance of T write to the specified virtual address.
556 */
557 template <typename T>
558 void Write(const VAddr vaddr, const T data) {
559 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
560 if (page_pointer != nullptr) {
561 // NOTE: Avoid adding any extra logic to this fast-path block
562 std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
563 return;
564 }
565
566 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
567 switch (type) {
568 case Common::PageType::Unmapped:
569 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
570 static_cast<u32>(data), vaddr);
571 return;
572 case Common::PageType::Memory:
573 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
574 break;
372 case Common::PageType::RasterizerCachedMemory: { 575 case Common::PageType::RasterizerCachedMemory: {
373 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; 576 u8* const host_ptr{GetPointerFromVMA(vaddr)};
374 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); 577 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
375 std::memcpy(dest_buffer, host_ptr, copy_amount); 578 std::memcpy(host_ptr, &data, sizeof(T));
376 break; 579 break;
377 } 580 }
378 default: 581 default:
379 UNREACHABLE(); 582 UNREACHABLE();
380 } 583 }
381
382 page_index++;
383 page_offset = 0;
384 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
385 remaining_size -= copy_amount;
386 } 584 }
585
586 Common::PageTable* current_page_table = nullptr;
587 Core::System& system;
588};
589
590Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
591Memory::~Memory() = default;
592
593void Memory::SetCurrentPageTable(Kernel::Process& process) {
594 impl->SetCurrentPageTable(process);
387} 595}
388 596
389void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { 597void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
390 ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size); 598 impl->MapMemoryRegion(page_table, base, size, target);
391} 599}
392 600
393void Write8(const VAddr addr, const u8 data) { 601void Memory::MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
394 Write<u8>(addr, data); 602 Common::MemoryHookPointer mmio_handler) {
603 impl->MapIoRegion(page_table, base, size, std::move(mmio_handler));
395} 604}
396 605
397void Write16(const VAddr addr, const u16 data) { 606void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
398 Write<u16_le>(addr, data); 607 impl->UnmapRegion(page_table, base, size);
399} 608}
400 609
401void Write32(const VAddr addr, const u32 data) { 610void Memory::AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
402 Write<u32_le>(addr, data); 611 Common::MemoryHookPointer hook) {
612 impl->AddDebugHook(page_table, base, size, std::move(hook));
403} 613}
404 614
405void Write64(const VAddr addr, const u64 data) { 615void Memory::RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
406 Write<u64_le>(addr, data); 616 Common::MemoryHookPointer hook) {
617 impl->RemoveDebugHook(page_table, base, size, std::move(hook));
407} 618}
408 619
409void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, 620bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
410 const std::size_t size) { 621 return impl->IsValidVirtualAddress(process, vaddr);
411 const auto& page_table = process.VMManager().page_table; 622}
412 std::size_t remaining_size = size;
413 std::size_t page_index = dest_addr >> PAGE_BITS;
414 std::size_t page_offset = dest_addr & PAGE_MASK;
415
416 while (remaining_size > 0) {
417 const std::size_t copy_amount =
418 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
419 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
420
421 switch (page_table.attributes[page_index]) {
422 case Common::PageType::Unmapped: {
423 LOG_ERROR(HW_Memory,
424 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
425 current_vaddr, dest_addr, size);
426 break;
427 }
428 case Common::PageType::Memory: {
429 DEBUG_ASSERT(page_table.pointers[page_index]);
430 623
431 u8* dest_ptr = page_table.pointers[page_index] + page_offset; 624bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
432 std::memcpy(dest_ptr, src_buffer, copy_amount); 625 return impl->IsValidVirtualAddress(vaddr);
433 break; 626}
434 }
435 case Common::PageType::RasterizerCachedMemory: {
436 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
437 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
438 std::memcpy(host_ptr, src_buffer, copy_amount);
439 break;
440 }
441 default:
442 UNREACHABLE();
443 }
444 627
445 page_index++; 628u8* Memory::GetPointer(VAddr vaddr) {
446 page_offset = 0; 629 return impl->GetPointer(vaddr);
447 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
448 remaining_size -= copy_amount;
449 }
450} 630}
451 631
452void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { 632const u8* Memory::GetPointer(VAddr vaddr) const {
453 WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size); 633 return impl->GetPointer(vaddr);
454} 634}
455 635
456void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 636u8 Memory::Read8(const VAddr addr) {
457 const auto& page_table = process.VMManager().page_table; 637 return impl->Read8(addr);
458 std::size_t remaining_size = size; 638}
459 std::size_t page_index = dest_addr >> PAGE_BITS;
460 std::size_t page_offset = dest_addr & PAGE_MASK;
461
462 while (remaining_size > 0) {
463 const std::size_t copy_amount =
464 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
465 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
466
467 switch (page_table.attributes[page_index]) {
468 case Common::PageType::Unmapped: {
469 LOG_ERROR(HW_Memory,
470 "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
471 current_vaddr, dest_addr, size);
472 break;
473 }
474 case Common::PageType::Memory: {
475 DEBUG_ASSERT(page_table.pointers[page_index]);
476 639
477 u8* dest_ptr = page_table.pointers[page_index] + page_offset; 640u16 Memory::Read16(const VAddr addr) {
478 std::memset(dest_ptr, 0, copy_amount); 641 return impl->Read16(addr);
479 break; 642}
480 }
481 case Common::PageType::RasterizerCachedMemory: {
482 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
483 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
484 std::memset(host_ptr, 0, copy_amount);
485 break;
486 }
487 default:
488 UNREACHABLE();
489 }
490 643
491 page_index++; 644u32 Memory::Read32(const VAddr addr) {
492 page_offset = 0; 645 return impl->Read32(addr);
493 remaining_size -= copy_amount;
494 }
495} 646}
496 647
497void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, 648u64 Memory::Read64(const VAddr addr) {
498 const std::size_t size) { 649 return impl->Read64(addr);
499 const auto& page_table = process.VMManager().page_table; 650}
500 std::size_t remaining_size = size;
501 std::size_t page_index = src_addr >> PAGE_BITS;
502 std::size_t page_offset = src_addr & PAGE_MASK;
503
504 while (remaining_size > 0) {
505 const std::size_t copy_amount =
506 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
507 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
508
509 switch (page_table.attributes[page_index]) {
510 case Common::PageType::Unmapped: {
511 LOG_ERROR(HW_Memory,
512 "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
513 current_vaddr, src_addr, size);
514 ZeroBlock(process, dest_addr, copy_amount);
515 break;
516 }
517 case Common::PageType::Memory: {
518 DEBUG_ASSERT(page_table.pointers[page_index]);
519 const u8* src_ptr = page_table.pointers[page_index] + page_offset;
520 WriteBlock(process, dest_addr, src_ptr, copy_amount);
521 break;
522 }
523 case Common::PageType::RasterizerCachedMemory: {
524 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
525 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
526 WriteBlock(process, dest_addr, host_ptr, copy_amount);
527 break;
528 }
529 default:
530 UNREACHABLE();
531 }
532 651
533 page_index++; 652void Memory::Write8(VAddr addr, u8 data) {
534 page_offset = 0; 653 impl->Write8(addr, data);
535 dest_addr += static_cast<VAddr>(copy_amount); 654}
536 src_addr += static_cast<VAddr>(copy_amount); 655
537 remaining_size -= copy_amount; 656void Memory::Write16(VAddr addr, u16 data) {
538 } 657 impl->Write16(addr, data);
658}
659
660void Memory::Write32(VAddr addr, u32 data) {
661 impl->Write32(addr, data);
662}
663
664void Memory::Write64(VAddr addr, u64 data) {
665 impl->Write64(addr, data);
666}
667
668std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
669 return impl->ReadCString(vaddr, max_length);
670}
671
672void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
673 const std::size_t size) {
674 impl->ReadBlock(process, src_addr, dest_buffer, size);
675}
676
677void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
678 impl->ReadBlock(src_addr, dest_buffer, size);
679}
680
681void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
682 std::size_t size) {
683 impl->WriteBlock(process, dest_addr, src_buffer, size);
684}
685
686void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
687 impl->WriteBlock(dest_addr, src_buffer, size);
539} 688}
540 689
541void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { 690void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
542 CopyBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_addr, size); 691 impl->ZeroBlock(process, dest_addr, size);
692}
693
694void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) {
695 impl->ZeroBlock(dest_addr, size);
696}
697
698void Memory::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
699 const std::size_t size) {
700 impl->CopyBlock(process, dest_addr, src_addr, size);
701}
702
703void Memory::CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
704 impl->CopyBlock(dest_addr, src_addr, size);
705}
706
707void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
708 impl->RasterizerMarkRegionCached(vaddr, size, cached);
709}
710
711bool IsKernelVirtualAddress(const VAddr vaddr) {
712 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
543} 713}
544 714
545} // namespace Memory 715} // namespace Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index 09008e1dd..1428a6d60 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -5,8 +5,18 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <memory>
8#include <string> 9#include <string>
9#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/memory_hook.h"
12
13namespace Common {
14struct PageTable;
15}
16
17namespace Core {
18class System;
19}
10 20
11namespace Kernel { 21namespace Kernel {
12class Process; 22class Process;
@@ -36,41 +46,369 @@ enum : VAddr {
36 KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, 46 KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
37}; 47};
38 48
39/// Changes the currently active page table to that of 49/// Central class that handles all memory operations and state.
40/// the given process instance. 50class Memory {
41void SetCurrentPageTable(Kernel::Process& process); 51public:
52 explicit Memory(Core::System& system);
53 ~Memory();
42 54
43/// Determines if the given VAddr is valid for the specified process. 55 Memory(const Memory&) = delete;
44bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); 56 Memory& operator=(const Memory&) = delete;
45bool IsValidVirtualAddress(VAddr vaddr);
46/// Determines if the given VAddr is a kernel address
47bool IsKernelVirtualAddress(VAddr vaddr);
48 57
49u8 Read8(VAddr addr); 58 Memory(Memory&&) = default;
50u16 Read16(VAddr addr); 59 Memory& operator=(Memory&&) = default;
51u32 Read32(VAddr addr);
52u64 Read64(VAddr addr);
53 60
54void Write8(VAddr addr, u8 data); 61 /**
55void Write16(VAddr addr, u16 data); 62 * Changes the currently active page table to that of the given process instance.
56void Write32(VAddr addr, u32 data); 63 *
57void Write64(VAddr addr, u64 data); 64 * @param process The process to use the page table of.
65 */
66 void SetCurrentPageTable(Kernel::Process& process);
58 67
59void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size); 68 /**
60void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); 69 * Maps an allocated buffer onto a region of the emulated process address space.
61void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, 70 *
62 std::size_t size); 71 * @param page_table The page table of the emulated process.
63void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); 72 * @param base The address to start mapping at. Must be page-aligned.
64void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); 73 * @param size The amount of bytes to map. Must be page-aligned.
65void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); 74 * @param target Buffer with the memory backing the mapping. Must be of length at least
75 * `size`.
76 */
77 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
66 78
67u8* GetPointer(VAddr vaddr); 79 /**
80 * Maps a region of the emulated process address space as a IO region.
81 *
82 * @param page_table The page table of the emulated process.
83 * @param base The address to start mapping at. Must be page-aligned.
84 * @param size The amount of bytes to map. Must be page-aligned.
85 * @param mmio_handler The handler that backs the mapping.
86 */
87 void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
88 Common::MemoryHookPointer mmio_handler);
68 89
69std::string ReadCString(VAddr vaddr, std::size_t max_length); 90 /**
91 * Unmaps a region of the emulated process address space.
92 *
93 * @param page_table The page table of the emulated process.
94 * @param base The address to begin unmapping at.
95 * @param size The amount of bytes to unmap.
96 */
97 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
70 98
71/** 99 /**
72 * Mark each page touching the region as cached. 100 * Adds a memory hook to intercept reads and writes to given region of memory.
73 */ 101 *
74void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); 102 * @param page_table The page table of the emulated process
103 * @param base The starting address to apply the hook to.
104 * @param size The size of the memory region to apply the hook to, in bytes.
105 * @param hook The hook to apply to the region of memory.
106 */
107 void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
108 Common::MemoryHookPointer hook);
109
110 /**
111 * Removes a memory hook from a given range of memory.
112 *
113 * @param page_table The page table of the emulated process.
114 * @param base The starting address to remove the hook from.
115 * @param size The size of the memory region to remove the hook from, in bytes.
116 * @param hook The hook to remove from the specified region of memory.
117 */
118 void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
119 Common::MemoryHookPointer hook);
120
121 /**
122 * Checks whether or not the supplied address is a valid virtual
123 * address for the given process.
124 *
125 * @param process The emulated process to check the address against.
126 * @param vaddr The virtual address to check the validity of.
127 *
128 * @returns True if the given virtual address is valid, false otherwise.
129 */
130 bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const;
131
132 /**
133 * Checks whether or not the supplied address is a valid virtual
134 * address for the current process.
135 *
136 * @param vaddr The virtual address to check the validity of.
137 *
138 * @returns True if the given virtual address is valid, false otherwise.
139 */
140 bool IsValidVirtualAddress(VAddr vaddr) const;
141
142 /**
143 * Gets a pointer to the given address.
144 *
145 * @param vaddr Virtual address to retrieve a pointer to.
146 *
147 * @returns The pointer to the given address, if the address is valid.
148 * If the address is not valid, nullptr will be returned.
149 */
150 u8* GetPointer(VAddr vaddr);
151
152 /**
153 * Gets a pointer to the given address.
154 *
155 * @param vaddr Virtual address to retrieve a pointer to.
156 *
157 * @returns The pointer to the given address, if the address is valid.
158 * If the address is not valid, nullptr will be returned.
159 */
160 const u8* GetPointer(VAddr vaddr) const;
161
162 /**
163 * Reads an 8-bit unsigned value from the current process' address space
164 * at the given virtual address.
165 *
166 * @param addr The virtual address to read the 8-bit value from.
167 *
168 * @returns the read 8-bit unsigned value.
169 */
170 u8 Read8(VAddr addr);
171
172 /**
173 * Reads a 16-bit unsigned value from the current process' address space
174 * at the given virtual address.
175 *
176 * @param addr The virtual address to read the 16-bit value from.
177 *
178 * @returns the read 16-bit unsigned value.
179 */
180 u16 Read16(VAddr addr);
181
182 /**
183 * Reads a 32-bit unsigned value from the current process' address space
184 * at the given virtual address.
185 *
186 * @param addr The virtual address to read the 32-bit value from.
187 *
188 * @returns the read 32-bit unsigned value.
189 */
190 u32 Read32(VAddr addr);
191
192 /**
193 * Reads a 64-bit unsigned value from the current process' address space
194 * at the given virtual address.
195 *
196 * @param addr The virtual address to read the 64-bit value from.
197 *
198 * @returns the read 64-bit value.
199 */
200 u64 Read64(VAddr addr);
201
202 /**
203 * Writes an 8-bit unsigned integer to the given virtual address in
204 * the current process' address space.
205 *
206 * @param addr The virtual address to write the 8-bit unsigned integer to.
207 * @param data The 8-bit unsigned integer to write to the given virtual address.
208 *
209 * @post The memory at the given virtual address contains the specified data value.
210 */
211 void Write8(VAddr addr, u8 data);
212
213 /**
214 * Writes a 16-bit unsigned integer to the given virtual address in
215 * the current process' address space.
216 *
217 * @param addr The virtual address to write the 16-bit unsigned integer to.
218 * @param data The 16-bit unsigned integer to write to the given virtual address.
219 *
220 * @post The memory range [addr, sizeof(data)) contains the given data value.
221 */
222 void Write16(VAddr addr, u16 data);
223
224 /**
225 * Writes a 32-bit unsigned integer to the given virtual address in
226 * the current process' address space.
227 *
228 * @param addr The virtual address to write the 32-bit unsigned integer to.
229 * @param data The 32-bit unsigned integer to write to the given virtual address.
230 *
231 * @post The memory range [addr, sizeof(data)) contains the given data value.
232 */
233 void Write32(VAddr addr, u32 data);
234
235 /**
236 * Writes a 64-bit unsigned integer to the given virtual address in
237 * the current process' address space.
238 *
239 * @param addr The virtual address to write the 64-bit unsigned integer to.
240 * @param data The 64-bit unsigned integer to write to the given virtual address.
241 *
242 * @post The memory range [addr, sizeof(data)) contains the given data value.
243 */
244 void Write64(VAddr addr, u64 data);
245
246 /**
247 * Reads a null-terminated string from the given virtual address.
248 * This function will continually read characters until either:
249 *
250 * - A null character ('\0') is reached.
251 * - max_length characters have been read.
252 *
253 * @note The final null-terminating character (if found) is not included
254 * in the returned string.
255 *
256 * @param vaddr The address to begin reading the string from.
257 * @param max_length The maximum length of the string to read in characters.
258 *
259 * @returns The read string.
260 */
261 std::string ReadCString(VAddr vaddr, std::size_t max_length);
262
263 /**
264 * Reads a contiguous block of bytes from a specified process' address space.
265 *
266 * @param process The process to read the data from.
267 * @param src_addr The virtual address to begin reading from.
268 * @param dest_buffer The buffer to place the read bytes into.
269 * @param size The amount of data to read, in bytes.
270 *
271 * @note If a size of 0 is specified, then this function reads nothing and
272 * no attempts to access memory are made at all.
273 *
274 * @pre dest_buffer must be at least size bytes in length, otherwise a
275 * buffer overrun will occur.
276 *
277 * @post The range [dest_buffer, size) contains the read bytes from the
278 * process' address space.
279 */
280 void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
281 std::size_t size);
282
283 /**
284 * Reads a contiguous block of bytes from the current process' address space.
285 *
286 * @param src_addr The virtual address to begin reading from.
287 * @param dest_buffer The buffer to place the read bytes into.
288 * @param size The amount of data to read, in bytes.
289 *
290 * @note If a size of 0 is specified, then this function reads nothing and
291 * no attempts to access memory are made at all.
292 *
293 * @pre dest_buffer must be at least size bytes in length, otherwise a
294 * buffer overrun will occur.
295 *
296 * @post The range [dest_buffer, size) contains the read bytes from the
297 * current process' address space.
298 */
299 void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
300
301 /**
302 * Writes a range of bytes into a given process' address space at the specified
303 * virtual address.
304 *
305 * @param process The process to write data into the address space of.
306 * @param dest_addr The destination virtual address to begin writing the data at.
307 * @param src_buffer The data to write into the process' address space.
308 * @param size The size of the data to write, in bytes.
309 *
310 * @post The address range [dest_addr, size) in the process' address space
311 * contains the data that was within src_buffer.
312 *
313 * @post If an attempt is made to write into an unmapped region of memory, the writes
314 * will be ignored and an error will be logged.
315 *
316 * @post If a write is performed into a region of memory that is considered cached
317 * rasterizer memory, will cause the currently active rasterizer to be notified
318 * and will mark that region as invalidated to caches that the active
319 * graphics backend may be maintaining over the course of execution.
320 */
321 void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
322 std::size_t size);
323
324 /**
325 * Writes a range of bytes into the current process' address space at the specified
326 * virtual address.
327 *
328 * @param dest_addr The destination virtual address to begin writing the data at.
329 * @param src_buffer The data to write into the current process' address space.
330 * @param size The size of the data to write, in bytes.
331 *
332 * @post The address range [dest_addr, size) in the current process' address space
333 * contains the data that was within src_buffer.
334 *
335 * @post If an attempt is made to write into an unmapped region of memory, the writes
336 * will be ignored and an error will be logged.
337 *
338 * @post If a write is performed into a region of memory that is considered cached
339 * rasterizer memory, will cause the currently active rasterizer to be notified
340 * and will mark that region as invalidated to caches that the active
341 * graphics backend may be maintaining over the course of execution.
342 */
343 void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
344
345 /**
346 * Fills the specified address range within a process' address space with zeroes.
347 *
348 * @param process The process that will have a portion of its memory zeroed out.
349 * @param dest_addr The starting virtual address of the range to zero out.
350 * @param size The size of the address range to zero out, in bytes.
351 *
352 * @post The range [dest_addr, size) within the process' address space is
353 * filled with zeroes.
354 */
355 void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
356
357 /**
358 * Fills the specified address range within the current process' address space with zeroes.
359 *
360 * @param dest_addr The starting virtual address of the range to zero out.
361 * @param size The size of the address range to zero out, in bytes.
362 *
363 * @post The range [dest_addr, size) within the current process' address space is
364 * filled with zeroes.
365 */
366 void ZeroBlock(VAddr dest_addr, std::size_t size);
367
368 /**
369 * Copies data within a process' address space to another location within the
370 * same address space.
371 *
372 * @param process The process that will have data copied within its address space.
373 * @param dest_addr The destination virtual address to begin copying the data into.
374 * @param src_addr The source virtual address to begin copying the data from.
375 * @param size The size of the data to copy, in bytes.
376 *
377 * @post The range [dest_addr, size) within the process' address space contains the
378 * same data within the range [src_addr, size).
379 */
380 void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
381 std::size_t size);
382
383 /**
384 * Copies data within the current process' address space to another location within the
385 * same address space.
386 *
387 * @param dest_addr The destination virtual address to begin copying the data into.
388 * @param src_addr The source virtual address to begin copying the data from.
389 * @param size The size of the data to copy, in bytes.
390 *
391 * @post The range [dest_addr, size) within the current process' address space
392 * contains the same data within the range [src_addr, size).
393 */
394 void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
395
396 /**
397 * Marks each page within the specified address range as cached or uncached.
398 *
399 * @param vaddr The virtual address indicating the start of the address range.
400 * @param size The size of the address range in bytes.
401 * @param cached Whether or not any pages within the address range should be
402 * marked as cached or uncached.
403 */
404 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
405
406private:
407 struct Impl;
408 std::unique_ptr<Impl> impl;
409};
410
411/// Determines if the given VAddr is a kernel address
412bool IsKernelVirtualAddress(VAddr vaddr);
75 413
76} // namespace Memory 414} // namespace Memory
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index b73cc9fbd..d1e6bed93 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -20,18 +20,17 @@ 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) {
34 WriteBlock(SanitizeAddress(address), data, size); 33 system.Memory().WriteBlock(SanitizeAddress(address), data, size);
35} 34}
36 35
37u64 StandardVmCallbacks::HidKeysDown() { 36u64 StandardVmCallbacks::HidKeysDown() {
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/memory_setup.h b/src/core/memory_setup.h
deleted file mode 100644
index 5225ee8e2..000000000
--- a/src/core/memory_setup.h
+++ /dev/null
@@ -1,43 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/memory_hook.h"
9
10namespace Common {
11struct PageTable;
12}
13
14namespace Memory {
15
16/**
17 * Maps an allocated buffer onto a region of the emulated process address space.
18 *
19 * @param page_table The page table of the emulated process.
20 * @param base The address to start mapping at. Must be page-aligned.
21 * @param size The amount of bytes to map. Must be page-aligned.
22 * @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
23 */
24void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
25
26/**
27 * Maps a region of the emulated process address space as a IO region.
28 * @param page_table The page table of the emulated process.
29 * @param base The address to start mapping at. Must be page-aligned.
30 * @param size The amount of bytes to map. Must be page-aligned.
31 * @param mmio_handler The handler that backs the mapping.
32 */
33void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
34 Common::MemoryHookPointer mmio_handler);
35
36void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
37
38void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
39 Common::MemoryHookPointer hook);
40void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
41 Common::MemoryHookPointer hook);
42
43} // namespace Memory
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 6f4af77fd..f95eee3b1 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -147,7 +147,7 @@ json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& s
147} 147}
148 148
149template <bool read_value, typename DescriptorType> 149template <bool read_value, typename DescriptorType>
150json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) { 150json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer, Memory::Memory& memory) {
151 auto buffer_out = json::array(); 151 auto buffer_out = json::array();
152 for (const auto& desc : buffer) { 152 for (const auto& desc : buffer) {
153 auto entry = json{ 153 auto entry = json{
@@ -157,7 +157,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
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
@@ -167,7 +167,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) {
167 return buffer_out; 167 return buffer_out;
168} 168}
169 169
170json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { 170json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Memory::Memory& memory) {
171 json out; 171 json out;
172 172
173 auto cmd_buf = json::array(); 173 auto cmd_buf = json::array();
@@ -177,10 +177,10 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
177 177
178 out["command_buffer"] = std::move(cmd_buf); 178 out["command_buffer"] = std::move(cmd_buf);
179 179
180 out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA()); 180 out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA(), memory);
181 out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB()); 181 out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB(), memory);
182 out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC()); 182 out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC(), memory);
183 out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX()); 183 out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX(), memory);
184 184
185 return out; 185 return out;
186} 186}
@@ -259,7 +259,7 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u
259 const auto title_id = system.CurrentProcess()->GetTitleID(); 259 const auto title_id = system.CurrentProcess()->GetTitleID();
260 auto out = GetFullDataAuto(timestamp, title_id, system); 260 auto out = GetFullDataAuto(timestamp, title_id, system);
261 261
262 auto function_out = GetHLERequestContextData(ctx); 262 auto function_out = GetHLERequestContextData(ctx, system.Memory());
263 function_out["command_id"] = command_id; 263 function_out["command_id"] = command_id;
264 function_out["function_name"] = name; 264 function_out["function_name"] = name;
265 function_out["service_name"] = service_name; 265 function_out["service_name"] = service_name;
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 19b531ecb..55e0dbc49 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -11,40 +11,39 @@
11#include "core/tools/freezer.h" 11#include "core/tools/freezer.h"
12 12
13namespace Tools { 13namespace Tools {
14
15namespace { 14namespace {
16 15
17constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); 16constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
18 17
19u64 MemoryReadWidth(u32 width, VAddr addr) { 18u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
20 switch (width) { 19 switch (width) {
21 case 1: 20 case 1:
22 return Memory::Read8(addr); 21 return memory.Read8(addr);
23 case 2: 22 case 2:
24 return Memory::Read16(addr); 23 return memory.Read16(addr);
25 case 4: 24 case 4:
26 return Memory::Read32(addr); 25 return memory.Read32(addr);
27 case 8: 26 case 8:
28 return Memory::Read64(addr); 27 return memory.Read64(addr);
29 default: 28 default:
30 UNREACHABLE(); 29 UNREACHABLE();
31 return 0; 30 return 0;
32 } 31 }
33} 32}
34 33
35void MemoryWriteWidth(u32 width, VAddr addr, u64 value) { 34void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
36 switch (width) { 35 switch (width) {
37 case 1: 36 case 1:
38 Memory::Write8(addr, static_cast<u8>(value)); 37 memory.Write8(addr, static_cast<u8>(value));
39 break; 38 break;
40 case 2: 39 case 2:
41 Memory::Write16(addr, static_cast<u16>(value)); 40 memory.Write16(addr, static_cast<u16>(value));
42 break; 41 break;
43 case 4: 42 case 4:
44 Memory::Write32(addr, static_cast<u32>(value)); 43 memory.Write32(addr, static_cast<u32>(value));
45 break; 44 break;
46 case 8: 45 case 8:
47 Memory::Write64(addr, value); 46 memory.Write64(addr, value);
48 break; 47 break;
49 default: 48 default:
50 UNREACHABLE(); 49 UNREACHABLE();
@@ -53,7 +52,8 @@ void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
53 52
54} // Anonymous namespace 53} // Anonymous namespace
55 54
56Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) { 55Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_)
56 : core_timing{core_timing_}, memory{memory_} {
57 event = Core::Timing::CreateEvent( 57 event = Core::Timing::CreateEvent(
58 "MemoryFreezer::FrameCallback", 58 "MemoryFreezer::FrameCallback",
59 [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); 59 [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
@@ -89,7 +89,7 @@ void Freezer::Clear() {
89u64 Freezer::Freeze(VAddr address, u32 width) { 89u64 Freezer::Freeze(VAddr address, u32 width) {
90 std::lock_guard lock{entries_mutex}; 90 std::lock_guard lock{entries_mutex};
91 91
92 const auto current_value = MemoryReadWidth(width, address); 92 const auto current_value = MemoryReadWidth(memory, width, address);
93 entries.push_back({address, width, current_value}); 93 entries.push_back({address, width, current_value});
94 94
95 LOG_DEBUG(Common_Memory, 95 LOG_DEBUG(Common_Memory,
@@ -169,7 +169,7 @@ void Freezer::FrameCallback(u64 userdata, s64 cycles_late) {
169 LOG_DEBUG(Common_Memory, 169 LOG_DEBUG(Common_Memory,
170 "Enforcing memory freeze at address={:016X}, value={:016X}, width={:02X}", 170 "Enforcing memory freeze at address={:016X}, value={:016X}, width={:02X}",
171 entry.address, entry.value, entry.width); 171 entry.address, entry.value, entry.width);
172 MemoryWriteWidth(entry.width, entry.address, entry.value); 172 MemoryWriteWidth(memory, entry.width, entry.address, entry.value);
173 } 173 }
174 174
175 core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - cycles_late, event); 175 core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - cycles_late, event);
@@ -181,7 +181,7 @@ void Freezer::FillEntryReads() {
181 LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values."); 181 LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values.");
182 182
183 for (auto& entry : entries) { 183 for (auto& entry : entries) {
184 entry.value = MemoryReadWidth(entry.width, entry.address); 184 entry.value = MemoryReadWidth(memory, entry.width, entry.address);
185 } 185 }
186} 186}
187 187
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 90b1a885c..916339c6c 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -16,6 +16,10 @@ class CoreTiming;
16struct EventType; 16struct EventType;
17} // namespace Core::Timing 17} // namespace Core::Timing
18 18
19namespace Memory {
20class Memory;
21}
22
19namespace Tools { 23namespace Tools {
20 24
21/** 25/**
@@ -34,7 +38,7 @@ public:
34 u64 value; 38 u64 value;
35 }; 39 };
36 40
37 explicit Freezer(Core::Timing::CoreTiming& core_timing); 41 explicit Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_);
38 ~Freezer(); 42 ~Freezer();
39 43
40 // Enables or disables the entire memory freezer. 44 // Enables or disables the entire memory freezer.
@@ -78,6 +82,7 @@ private:
78 82
79 std::shared_ptr<Core::Timing::EventType> event; 83 std::shared_ptr<Core::Timing::EventType> event;
80 Core::Timing::CoreTiming& core_timing; 84 Core::Timing::CoreTiming& core_timing;
85 Memory::Memory& memory;
81}; 86};
82 87
83} // namespace Tools 88} // namespace Tools
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index ac7ae3e52..17043346b 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -8,7 +8,6 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "core/memory_setup.h"
12#include "tests/core/arm/arm_test_common.h" 11#include "tests/core/arm/arm_test_common.h"
13 12
14namespace ArmTests { 13namespace ArmTests {
@@ -16,8 +15,9 @@ namespace ArmTests {
16TestEnvironment::TestEnvironment(bool mutable_memory_) 15TestEnvironment::TestEnvironment(bool mutable_memory_)
17 : mutable_memory(mutable_memory_), 16 : mutable_memory(mutable_memory_),
18 test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} { 17 test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
19 auto process = Kernel::Process::Create(Core::System::GetInstance(), "", 18 auto& system = Core::System::GetInstance();
20 Kernel::Process::ProcessType::Userland); 19
20 auto process = Kernel::Process::Create(system, "", Kernel::Process::ProcessType::Userland);
21 page_table = &process->VMManager().page_table; 21 page_table = &process->VMManager().page_table;
22 22
23 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); 23 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
@@ -25,15 +25,16 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
25 std::fill(page_table->attributes.begin(), page_table->attributes.end(), 25 std::fill(page_table->attributes.begin(), page_table->attributes.end(),
26 Common::PageType::Unmapped); 26 Common::PageType::Unmapped);
27 27
28 Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); 28 system.Memory().MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
29 Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); 29 system.Memory().MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
30 30
31 kernel.MakeCurrentProcess(process.get()); 31 kernel.MakeCurrentProcess(process.get());
32} 32}
33 33
34TestEnvironment::~TestEnvironment() { 34TestEnvironment::~TestEnvironment() {
35 Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000); 35 auto& system = Core::System::GetInstance();
36 Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000); 36 system.Memory().UnmapRegion(*page_table, 0x80000000, 0x80000000);
37 system.Memory().UnmapRegion(*page_table, 0x00000000, 0x80000000);
37} 38}
38 39
39void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { 40void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index bffae940c..11848fbce 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -52,7 +52,7 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
52 const u64 aligned_size{Common::AlignUp(size, page_size)}; 52 const u64 aligned_size{Common::AlignUp(size, page_size)};
53 const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)}; 53 const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)};
54 54
55 MapBackingMemory(gpu_addr, Memory::GetPointer(cpu_addr), aligned_size, cpu_addr); 55 MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr);
56 ASSERT(system.CurrentProcess() 56 ASSERT(system.CurrentProcess()
57 ->VMManager() 57 ->VMManager()
58 .SetMemoryAttribute(cpu_addr, size, Kernel::MemoryAttribute::DeviceMapped, 58 .SetMemoryAttribute(cpu_addr, size, Kernel::MemoryAttribute::DeviceMapped,
@@ -67,7 +67,7 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
67 67
68 const u64 aligned_size{Common::AlignUp(size, page_size)}; 68 const u64 aligned_size{Common::AlignUp(size, page_size)};
69 69
70 MapBackingMemory(gpu_addr, Memory::GetPointer(cpu_addr), aligned_size, cpu_addr); 70 MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr);
71 ASSERT(system.CurrentProcess() 71 ASSERT(system.CurrentProcess()
72 ->VMManager() 72 ->VMManager()
73 .SetMemoryAttribute(cpu_addr, size, Kernel::MemoryAttribute::DeviceMapped, 73 .SetMemoryAttribute(cpu_addr, size, Kernel::MemoryAttribute::DeviceMapped,
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index b230dcc18..fc6ecb899 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -22,7 +22,8 @@ constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
22 22
23} // Anonymous namespace 23} // Anonymous namespace
24 24
25RasterizerAccelerated::RasterizerAccelerated() = default; 25RasterizerAccelerated::RasterizerAccelerated(Memory::Memory& cpu_memory_)
26 : cpu_memory{cpu_memory_} {}
26 27
27RasterizerAccelerated::~RasterizerAccelerated() = default; 28RasterizerAccelerated::~RasterizerAccelerated() = default;
28 29
@@ -47,9 +48,9 @@ void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int del
47 const u64 interval_size = interval_end_addr - interval_start_addr; 48 const u64 interval_size = interval_end_addr - interval_start_addr;
48 49
49 if (delta > 0 && count == delta) { 50 if (delta > 0 && count == delta) {
50 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true); 51 cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
51 } else if (delta < 0 && count == -delta) { 52 } else if (delta < 0 && count == -delta) {
52 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false); 53 cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
53 } else { 54 } else {
54 ASSERT(count >= 0); 55 ASSERT(count >= 0);
55 } 56 }
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
index 8f7e3547e..315798e7c 100644
--- a/src/video_core/rasterizer_accelerated.h
+++ b/src/video_core/rasterizer_accelerated.h
@@ -11,12 +11,16 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/rasterizer_interface.h" 12#include "video_core/rasterizer_interface.h"
13 13
14namespace Memory {
15class Memory;
16}
17
14namespace VideoCore { 18namespace VideoCore {
15 19
16/// Implements the shared part in GPU accelerated rasterizers in RasterizerInterface. 20/// Implements the shared part in GPU accelerated rasterizers in RasterizerInterface.
17class RasterizerAccelerated : public RasterizerInterface { 21class RasterizerAccelerated : public RasterizerInterface {
18public: 22public:
19 explicit RasterizerAccelerated(); 23 explicit RasterizerAccelerated(Memory::Memory& cpu_memory_);
20 ~RasterizerAccelerated() override; 24 ~RasterizerAccelerated() override;
21 25
22 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; 26 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
@@ -24,8 +28,9 @@ public:
24private: 28private:
25 using CachedPageMap = boost::icl::interval_map<u64, int>; 29 using CachedPageMap = boost::icl::interval_map<u64, int>;
26 CachedPageMap cached_pages; 30 CachedPageMap cached_pages;
27
28 std::mutex pages_mutex; 31 std::mutex pages_mutex;
32
33 Memory::Memory& cpu_memory;
29}; 34};
30 35
31} // namespace VideoCore 36} // namespace VideoCore
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index f97ec06f0..a568a4343 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -19,6 +19,7 @@
19#include "common/scope_exit.h" 19#include "common/scope_exit.h"
20#include "core/core.h" 20#include "core/core.h"
21#include "core/hle/kernel/process.h" 21#include "core/hle/kernel/process.h"
22#include "core/memory.h"
22#include "core/settings.h" 23#include "core/settings.h"
23#include "video_core/engines/kepler_compute.h" 24#include "video_core/engines/kepler_compute.h"
24#include "video_core/engines/maxwell_3d.h" 25#include "video_core/engines/maxwell_3d.h"
@@ -86,8 +87,9 @@ std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
86 87
87RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 88RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
88 ScreenInfo& info) 89 ScreenInfo& info)
89 : texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device}, 90 : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device},
90 system{system}, screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} { 91 shader_cache{*this, system, emu_window, device}, system{system}, screen_info{info},
92 buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
91 shader_program_manager = std::make_unique<GLShader::ProgramManager>(); 93 shader_program_manager = std::make_unique<GLShader::ProgramManager>();
92 state.draw.shader_program = 0; 94 state.draw.shader_program = 0;
93 state.Apply(); 95 state.Apply();
@@ -837,7 +839,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
837 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 839 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
838 840
839 const auto surface{ 841 const auto surface{
840 texture_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))}; 842 texture_cache.TryFindFramebufferSurface(system.Memory().GetPointer(framebuffer_addr))};
841 if (!surface) { 843 if (!surface) {
842 return {}; 844 return {};
843 } 845 }
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 7646cbb0e..a57a564f7 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -158,7 +158,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
158 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; 158 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
159 const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)}; 159 const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)};
160 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; 160 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
161 const auto host_ptr{Memory::GetPointer(framebuffer_addr)}; 161 u8* const host_ptr{system.Memory().GetPointer(framebuffer_addr)};
162 rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes); 162 rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
163 163
164 // TODO(Rodrigo): Read this from HLE 164 // TODO(Rodrigo): Read this from HLE
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index d2e9f4031..46da81aaa 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -24,9 +24,11 @@ CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, std::size_t size, u64 offse
24 alignment{alignment} {} 24 alignment{alignment} {}
25 25
26VKBufferCache::VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, 26VKBufferCache::VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
27 Memory::Memory& cpu_memory_,
27 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, 28 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
28 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size) 29 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size)
29 : RasterizerCache{rasterizer}, tegra_memory_manager{tegra_memory_manager} { 30 : RasterizerCache{rasterizer}, tegra_memory_manager{tegra_memory_manager}, cpu_memory{
31 cpu_memory_} {
30 const auto usage = vk::BufferUsageFlagBits::eVertexBuffer | 32 const auto usage = vk::BufferUsageFlagBits::eVertexBuffer |
31 vk::BufferUsageFlagBits::eIndexBuffer | 33 vk::BufferUsageFlagBits::eIndexBuffer |
32 vk::BufferUsageFlagBits::eUniformBuffer; 34 vk::BufferUsageFlagBits::eUniformBuffer;
@@ -48,9 +50,9 @@ u64 VKBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, u64 alignme
48 // TODO: Figure out which size is the best for given games. 50 // TODO: Figure out which size is the best for given games.
49 cache &= size >= 2048; 51 cache &= size >= 2048;
50 52
51 const auto& host_ptr{Memory::GetPointer(*cpu_addr)}; 53 u8* const host_ptr{cpu_memory.GetPointer(*cpu_addr)};
52 if (cache) { 54 if (cache) {
53 auto entry = TryGet(host_ptr); 55 const auto entry = TryGet(host_ptr);
54 if (entry) { 56 if (entry) {
55 if (entry->GetSize() >= size && entry->GetAlignment() == alignment) { 57 if (entry->GetSize() >= size && entry->GetAlignment() == alignment) {
56 return entry->GetOffset(); 58 return entry->GetOffset();
@@ -62,7 +64,7 @@ u64 VKBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, u64 alignme
62 AlignBuffer(alignment); 64 AlignBuffer(alignment);
63 const u64 uploaded_offset = buffer_offset; 65 const u64 uploaded_offset = buffer_offset;
64 66
65 if (!host_ptr) { 67 if (host_ptr == nullptr) {
66 return uploaded_offset; 68 return uploaded_offset;
67 } 69 }
68 70
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 49f13bcdc..daa8ccf66 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -13,6 +13,10 @@
13#include "video_core/renderer_vulkan/declarations.h" 13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
15 15
16namespace Memory {
17class Memory;
18}
19
16namespace Tegra { 20namespace Tegra {
17class MemoryManager; 21class MemoryManager;
18} 22}
@@ -58,7 +62,7 @@ private:
58 62
59class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { 63class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
60public: 64public:
61 explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, 65 explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, Memory::Memory& cpu_memory_,
62 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, 66 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
63 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size); 67 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size);
64 ~VKBufferCache(); 68 ~VKBufferCache();
@@ -92,6 +96,7 @@ private:
92 void AlignBuffer(std::size_t alignment); 96 void AlignBuffer(std::size_t alignment);
93 97
94 Tegra::MemoryManager& tegra_memory_manager; 98 Tegra::MemoryManager& tegra_memory_manager;
99 Memory::Memory& cpu_memory;
95 100
96 std::unique_ptr<VKStreamBuffer> stream_buffer; 101 std::unique_ptr<VKStreamBuffer> stream_buffer;
97 vk::Buffer buffer_handle; 102 vk::Buffer buffer_handle;
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;