diff options
| author | 2019-11-28 11:43:17 -0500 | |
|---|---|---|
| committer | 2019-11-28 11:43:17 -0500 | |
| commit | e3ee017e91ef4d713f1af8cb60c5157e40d43f18 (patch) | |
| tree | e0a5b47cac1d548599b8ceba7f71b40746fe6b48 /src | |
| parent | Merge pull request #3171 from lioncash/internal-link (diff) | |
| parent | core/memory; Migrate over SetCurrentPageTable() to the Memory class (diff) | |
| download | yuzu-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')
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 | ||
| 43 | private: | 43 | private: |
| 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 | ||
| 71 | private: | 71 | private: |
| 72 | EffectOutStatus out_status{}; | 72 | EffectOutStatus out_status{}; |
| 73 | EffectInStatus info{}; | 73 | EffectInStatus info{}; |
| 74 | }; | 74 | }; |
| 75 | AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params, | 75 | AudioRenderer::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 | ||
| 209 | std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count) { | 210 | std::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 | ||
| 259 | void AudioRenderer::VoiceState::RefreshBuffer() { | 261 | void 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 | ||
| 310 | void AudioRenderer::EffectState::UpdateState() { | 313 | void 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 { | |||
| 22 | class WritableEvent; | 22 | class WritableEvent; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | namespace Memory { | ||
| 26 | class Memory; | ||
| 27 | } | ||
| 28 | |||
| 25 | namespace AudioCore { | 29 | namespace AudioCore { |
| 26 | 30 | ||
| 27 | class AudioOut; | 31 | class AudioOut; |
| @@ -217,7 +221,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size | |||
| 217 | 221 | ||
| 218 | class AudioRenderer { | 222 | class AudioRenderer { |
| 219 | public: | 223 | public: |
| 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 | ||
| 15 | namespace Core { | 15 | namespace Core { |
| 16 | |||
| 17 | namespace { | 16 | namespace { |
| 18 | 17 | ||
| 19 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; | 18 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; |
| @@ -61,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size."); | |||
| 61 | 60 | ||
| 62 | using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; | 61 | using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; |
| 63 | 62 | ||
| 64 | Symbols GetSymbols(VAddr text_offset) { | 63 | Symbols 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 | ||
| 143 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | 142 | std::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 | ||
| 19 | namespace Core { | 19 | namespace Core { |
| 20 | class System; | ||
| 20 | 21 | ||
| 21 | /// Generic ARMv8 CPU interface | 22 | /// Generic ARMv8 CPU interface |
| 22 | class ARM_Interface : NonCopyable { | 23 | class ARM_Interface : NonCopyable { |
| 23 | public: | 24 | public: |
| 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 | |||
| 169 | protected: | ||
| 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 | ||
| 172 | ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, | 174 | ARM_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 | ||
| 178 | ARM_Dynarmic::~ARM_Dynarmic() = default; | 181 | ARM_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 | ||
| 267 | DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} | 270 | DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count) |
| 271 | : monitor(core_count), memory{memory_} {} | ||
| 272 | |||
| 268 | DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; | 273 | DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; |
| 269 | 274 | ||
| 270 | void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { | 275 | void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { |
| @@ -277,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() { | |||
| 277 | } | 282 | } |
| 278 | 283 | ||
| 279 | bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { | 284 | bool 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 | ||
| 284 | bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { | 288 | bool 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 | ||
| 289 | bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { | 293 | bool 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 | ||
| 294 | bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { | 298 | bool 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 | ||
| 299 | bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { | 303 | bool 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 | ||
| 15 | namespace Memory { | ||
| 16 | class Memory; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace Core { | 19 | namespace Core { |
| 16 | 20 | ||
| 17 | class ARM_Dynarmic_Callbacks; | 21 | class 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 | ||
| 65 | class DynarmicExclusiveMonitor final : public ExclusiveMonitor { | 68 | class DynarmicExclusiveMonitor final : public ExclusiveMonitor { |
| 66 | public: | 69 | public: |
| 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: | |||
| 79 | private: | 82 | private: |
| 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 | ||
| 63 | ARM_Unicorn::ARM_Unicorn(System& system) : system{system} { | 63 | ARM_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 | } |
| 113 | struct System::Impl { | 114 | struct 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 | ||
| 503 | Memory::Memory& System::Memory() { | ||
| 504 | return impl->memory; | ||
| 505 | } | ||
| 506 | |||
| 507 | const Memory::Memory& System::Memory() const { | ||
| 508 | return impl->memory; | ||
| 509 | } | ||
| 510 | |||
| 501 | Tegra::GPU& System::GPU() { | 511 | Tegra::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 { | |||
| 86 | class InterruptManager; | 86 | class InterruptManager; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | namespace Memory { | ||
| 90 | class Memory; | ||
| 91 | } | ||
| 92 | |||
| 89 | namespace Core { | 93 | namespace Core { |
| 90 | 94 | ||
| 91 | class ARM_Interface; | 95 | class 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 | ||
| 67 | Cpu::~Cpu() = default; | 67 | Cpu::~Cpu() = default; |
| 68 | 68 | ||
| 69 | std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { | 69 | std::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 { | |||
| 24 | class CoreTiming; | 24 | class CoreTiming; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | namespace Memory { | ||
| 28 | class Memory; | ||
| 29 | } | ||
| 30 | |||
| 27 | namespace Core { | 31 | namespace Core { |
| 28 | 32 | ||
| 29 | class ARM_Interface; | 33 | class 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 | ||
| 91 | private: | 107 | private: |
| 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 | ||
| 26 | void CpuCoreManager::Initialize() { | 26 | void 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. |
| 985 | static void WriteMemory() { | 987 | static 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 | ||
| 68 | ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, | 68 | ResultCode 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 | ||
| 83 | ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, | 85 | ResultCode 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 | ||
| 135 | ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, | 139 | ResultCode 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 | ||
| 159 | ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { | 165 | ResultCode 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 | ||
| 24 | ResultCode ClientSession::SendSyncRequest(Thread* thread) { | 24 | ResultCode 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 | ||
| 11 | union ResultCode; | 11 | union ResultCode; |
| 12 | 12 | ||
| 13 | namespace Memory { | ||
| 14 | class Memory; | ||
| 15 | } | ||
| 16 | |||
| 13 | namespace Kernel { | 17 | namespace Kernel { |
| 14 | 18 | ||
| 15 | class KernelCore; | 19 | class 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 | ||
| 42 | private: | 46 | private: |
| 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 | |||
| 214 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { | 214 | ResultCode 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) { | |||
| 282 | std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { | 283 | std::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 | ||
| 210 | void KernelCore::MakeCurrentProcess(Process* process) { | 220 | void 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 | ||
| 220 | Process* KernelCore::CurrentProcess() { | 224 | Process* 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 | ||
| 23 | namespace Kernel { | 24 | namespace 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 | ||
| 130 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) { | 131 | ResultCode 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 | ||
| 16 | namespace Memory { | ||
| 17 | class Memory; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace Kernel { | 20 | namespace Kernel { |
| 17 | 21 | ||
| 18 | class ClientPort; | 22 | class 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 |
| 333 | static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, | 333 | static 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 | ||
| 21 | namespace Kernel { | 20 | namespace Kernel { |
| 22 | namespace { | 21 | namespace { |
| @@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre | |||
| 786 | } | 785 | } |
| 787 | 786 | ||
| 788 | void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | 787 | void 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 | ||
| 214 | AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { | 216 | AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 4ea7ade6e..82a5dbf14 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -49,8 +49,9 @@ public: | |||
| 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 | ||
| 56 | private: | 57 | private: |
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 | ||
| 18 | class ILogger final : public ServiceFramework<ILogger> { | 18 | class ILogger final : public ServiceFramework<ILogger> { |
| 19 | public: | 19 | public: |
| 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 | ||
| 79 | class LM final : public ServiceFramework<LM> { | 81 | class LM final : public ServiceFramework<LM> { |
| 80 | public: | 82 | public: |
| 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 | ||
| 103 | void InstallInterfaces(Core::System& system) { | 107 | void 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 | ||
| 23 | namespace Memory { | 22 | namespace Memory { |
| 24 | 23 | ||
| 25 | static 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. | ||
| 27 | struct Memory::Impl { | ||
| 28 | explicit Impl(Core::System& system_) : system{system_} {} | ||
| 26 | 29 | ||
| 27 | void 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 | ||
| 39 | static 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 | ||
| 73 | void 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 | ||
| 79 | void 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 | ||
| 91 | void 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 | ||
| 100 | void 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 | ||
| 108 | void 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 | */ |
| 120 | static 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); |
| 148 | static u8* GetPointerFromVMA(VAddr vaddr) { | 150 | } |
| 149 | return GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); | ||
| 150 | } | ||
| 151 | 151 | ||
| 152 | template <typename T> | 152 | if (current_page_table->attributes[vaddr >> PAGE_BITS] == |
| 153 | T 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 | ||
| 183 | template <typename T> | 157 | LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr); |
| 184 | void 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 | ||
| 212 | bool 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 | ||
| 228 | bool 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 | ||
| 232 | bool 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 | ||
| 236 | u8* 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 | ||
| 251 | std::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 | ||
| 265 | void 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 | ||
| 328 | u8 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 | ||
| 332 | u16 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 | ||
| 336 | u32 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 | ||
| 340 | u64 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 | ||
| 344 | void 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 | |||
| 590 | Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {} | ||
| 591 | Memory::~Memory() = default; | ||
| 592 | |||
| 593 | void Memory::SetCurrentPageTable(Kernel::Process& process) { | ||
| 594 | impl->SetCurrentPageTable(process); | ||
| 387 | } | 595 | } |
| 388 | 596 | ||
| 389 | void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { | 597 | void 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 | ||
| 393 | void Write8(const VAddr addr, const u8 data) { | 601 | void 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 | ||
| 397 | void Write16(const VAddr addr, const u16 data) { | 606 | void 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 | ||
| 401 | void Write32(const VAddr addr, const u32 data) { | 610 | void 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 | ||
| 405 | void Write64(const VAddr addr, const u64 data) { | 615 | void 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 | ||
| 409 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, | 620 | bool 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; | 624 | bool 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++; | 628 | u8* 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 | ||
| 452 | void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { | 632 | const 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 | ||
| 456 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { | 636 | u8 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; | 640 | u16 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++; | 644 | u32 Memory::Read32(const VAddr addr) { |
| 492 | page_offset = 0; | 645 | return impl->Read32(addr); |
| 493 | remaining_size -= copy_amount; | ||
| 494 | } | ||
| 495 | } | 646 | } |
| 496 | 647 | ||
| 497 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | 648 | u64 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++; | 652 | void 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; | 656 | void Memory::Write16(VAddr addr, u16 data) { |
| 538 | } | 657 | impl->Write16(addr, data); |
| 658 | } | ||
| 659 | |||
| 660 | void Memory::Write32(VAddr addr, u32 data) { | ||
| 661 | impl->Write32(addr, data); | ||
| 662 | } | ||
| 663 | |||
| 664 | void Memory::Write64(VAddr addr, u64 data) { | ||
| 665 | impl->Write64(addr, data); | ||
| 666 | } | ||
| 667 | |||
| 668 | std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { | ||
| 669 | return impl->ReadCString(vaddr, max_length); | ||
| 670 | } | ||
| 671 | |||
| 672 | void 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 | |||
| 677 | void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { | ||
| 678 | impl->ReadBlock(src_addr, dest_buffer, size); | ||
| 679 | } | ||
| 680 | |||
| 681 | void 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 | |||
| 686 | void 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 | ||
| 541 | void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { | 690 | void 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 | |||
| 694 | void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) { | ||
| 695 | impl->ZeroBlock(dest_addr, size); | ||
| 696 | } | ||
| 697 | |||
| 698 | void 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 | |||
| 703 | void Memory::CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { | ||
| 704 | impl->CopyBlock(dest_addr, src_addr, size); | ||
| 705 | } | ||
| 706 | |||
| 707 | void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { | ||
| 708 | impl->RasterizerMarkRegionCached(vaddr, size, cached); | ||
| 709 | } | ||
| 710 | |||
| 711 | bool 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 | |||
| 13 | namespace Common { | ||
| 14 | struct PageTable; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 10 | 20 | ||
| 11 | namespace Kernel { | 21 | namespace Kernel { |
| 12 | class Process; | 22 | class 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. | 50 | class Memory { |
| 41 | void SetCurrentPageTable(Kernel::Process& process); | 51 | public: |
| 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; |
| 44 | bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | 56 | Memory& operator=(const Memory&) = delete; |
| 45 | bool IsValidVirtualAddress(VAddr vaddr); | ||
| 46 | /// Determines if the given VAddr is a kernel address | ||
| 47 | bool IsKernelVirtualAddress(VAddr vaddr); | ||
| 48 | 57 | ||
| 49 | u8 Read8(VAddr addr); | 58 | Memory(Memory&&) = default; |
| 50 | u16 Read16(VAddr addr); | 59 | Memory& operator=(Memory&&) = default; |
| 51 | u32 Read32(VAddr addr); | ||
| 52 | u64 Read64(VAddr addr); | ||
| 53 | 60 | ||
| 54 | void Write8(VAddr addr, u8 data); | 61 | /** |
| 55 | void Write16(VAddr addr, u16 data); | 62 | * Changes the currently active page table to that of the given process instance. |
| 56 | void Write32(VAddr addr, u32 data); | 63 | * |
| 57 | void 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 | ||
| 59 | void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size); | 68 | /** |
| 60 | void 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. |
| 61 | void 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. |
| 63 | void 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. |
| 64 | void 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. |
| 65 | void 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 | ||
| 67 | u8* 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 | ||
| 69 | std::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 | * |
| 74 | void 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 | |||
| 406 | private: | ||
| 407 | struct Impl; | ||
| 408 | std::unique_ptr<Impl> impl; | ||
| 409 | }; | ||
| 410 | |||
| 411 | /// Determines if the given VAddr is a kernel address | ||
| 412 | bool 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 { | |||
| 20 | constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12); | 20 | constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12); |
| 21 | constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; | 21 | constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; |
| 22 | 22 | ||
| 23 | StandardVmCallbacks::StandardVmCallbacks(const Core::System& system, | 23 | StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) |
| 24 | const CheatProcessMetadata& metadata) | ||
| 25 | : metadata(metadata), system(system) {} | 24 | : metadata(metadata), system(system) {} |
| 26 | 25 | ||
| 27 | StandardVmCallbacks::~StandardVmCallbacks() = default; | 26 | StandardVmCallbacks::~StandardVmCallbacks() = default; |
| 28 | 27 | ||
| 29 | void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { | 28 | void 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 | ||
| 33 | void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { | 32 | void 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 | ||
| 37 | u64 StandardVmCallbacks::HidKeysDown() { | 36 | u64 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 | ||
| 25 | class StandardVmCallbacks : public DmntCheatVm::Callbacks { | 25 | class StandardVmCallbacks : public DmntCheatVm::Callbacks { |
| 26 | public: | 26 | public: |
| 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 | |||
| 10 | namespace Common { | ||
| 11 | struct PageTable; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace 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 | */ | ||
| 24 | void 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 | */ | ||
| 33 | void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 34 | Common::MemoryHookPointer mmio_handler); | ||
| 35 | |||
| 36 | void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); | ||
| 37 | |||
| 38 | void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 39 | Common::MemoryHookPointer hook); | ||
| 40 | void 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 | ||
| 149 | template <bool read_value, typename DescriptorType> | 149 | template <bool read_value, typename DescriptorType> |
| 150 | json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) { | 150 | json 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 | ||
| 170 | json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { | 170 | json 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 | ||
| 13 | namespace Tools { | 13 | namespace Tools { |
| 14 | |||
| 15 | namespace { | 14 | namespace { |
| 16 | 15 | ||
| 17 | constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); | 16 | constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); |
| 18 | 17 | ||
| 19 | u64 MemoryReadWidth(u32 width, VAddr addr) { | 18 | u64 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 | ||
| 35 | void MemoryWriteWidth(u32 width, VAddr addr, u64 value) { | 34 | void 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 | ||
| 56 | Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) { | 55 | Freezer::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() { | |||
| 89 | u64 Freezer::Freeze(VAddr address, u32 width) { | 89 | u64 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; | |||
| 16 | struct EventType; | 16 | struct EventType; |
| 17 | } // namespace Core::Timing | 17 | } // namespace Core::Timing |
| 18 | 18 | ||
| 19 | namespace Memory { | ||
| 20 | class Memory; | ||
| 21 | } | ||
| 22 | |||
| 19 | namespace Tools { | 23 | namespace 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 | ||
| 14 | namespace ArmTests { | 13 | namespace ArmTests { |
| @@ -16,8 +15,9 @@ namespace ArmTests { | |||
| 16 | TestEnvironment::TestEnvironment(bool mutable_memory_) | 15 | TestEnvironment::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 | ||
| 34 | TestEnvironment::~TestEnvironment() { | 34 | TestEnvironment::~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 | ||
| 39 | void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { | 40 | void 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 | ||
| 25 | RasterizerAccelerated::RasterizerAccelerated() = default; | 25 | RasterizerAccelerated::RasterizerAccelerated(Memory::Memory& cpu_memory_) |
| 26 | : cpu_memory{cpu_memory_} {} | ||
| 26 | 27 | ||
| 27 | RasterizerAccelerated::~RasterizerAccelerated() = default; | 28 | RasterizerAccelerated::~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 | ||
| 14 | namespace Memory { | ||
| 15 | class Memory; | ||
| 16 | } | ||
| 17 | |||
| 14 | namespace VideoCore { | 18 | namespace 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. |
| 17 | class RasterizerAccelerated : public RasterizerInterface { | 21 | class RasterizerAccelerated : public RasterizerInterface { |
| 18 | public: | 22 | public: |
| 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: | |||
| 24 | private: | 28 | private: |
| 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 | ||
| 87 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | 88 | RasterizerOpenGL::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 | ||
| 26 | VKBufferCache::VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, | 26 | VKBufferCache::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 | ||
| 16 | namespace Memory { | ||
| 17 | class Memory; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace Tegra { | 20 | namespace Tegra { |
| 17 | class MemoryManager; | 21 | class MemoryManager; |
| 18 | } | 22 | } |
| @@ -58,7 +62,7 @@ private: | |||
| 58 | 62 | ||
| 59 | class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { | 63 | class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { |
| 60 | public: | 64 | public: |
| 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 | ||
| 81 | WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table) | 81 | WaitTreeMutexInfo::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; |