diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 12e2b79019..c187d8ac5d 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -259,9 +259,10 @@ void AudioRenderer::VoiceState::UpdateState() { } void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) { - std::vector new_samples(info.wave_buffer[wave_index].buffer_sz / sizeof(s16)); - Memory::ReadBlock(info.wave_buffer[wave_index].buffer_addr, new_samples.data(), - info.wave_buffer[wave_index].buffer_sz); + const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; + const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; + std::vector new_samples(wave_buffer_size / sizeof(s16)); + memory.ReadBlock(wave_buffer_address, new_samples.data(), wave_buffer_size); switch (static_cast(info.sample_format)) { case Codec::PcmFormat::Int16: { @@ -271,7 +272,7 @@ void AudioRenderer::VoiceState::RefreshBuffer(Memory::Memory& memory) { case Codec::PcmFormat::Adpcm: { // Decode ADPCM to PCM16 Codec::ADPCM_Coeff coeffs; - Memory::ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff)); + memory.ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff)); new_samples = Codec::DecodeADPCM(reinterpret_cast(new_samples.data()), new_samples.size() * sizeof(s16), coeffs, adpcm_state); break; @@ -314,13 +315,13 @@ void AudioRenderer::EffectState::UpdateState(Memory::Memory& memory) { out_status.state = EffectStatus::New; } else { if (info.type == Effect::Aux) { - ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0, + ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_info) == 0, "Aux buffers tried to update"); - ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0, + ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_info) == 0, "Aux buffers tried to update"); - ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0, + ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_base) == 0, "Aux buffers tried to update"); - ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0, + ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_base) == 0, "Aux buffers tried to update"); } } diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index dea192869f..7e846ddd5c 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -60,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size."); using Symbols = std::vector>; -Symbols GetSymbols(VAddr text_offset) { - const auto mod_offset = text_offset + Memory::Read32(text_offset + 4); +Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) { + const auto mod_offset = text_offset + memory.Read32(text_offset + 4); if (mod_offset < text_offset || (mod_offset & 0b11) != 0 || - Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { + memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { return {}; } - const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset; + const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset; VAddr string_table_offset{}; VAddr symbol_table_offset{}; @@ -76,8 +76,8 @@ Symbols GetSymbols(VAddr text_offset) { VAddr dynamic_index = dynamic_offset; while (true) { - const auto tag = Memory::Read64(dynamic_index); - const auto value = Memory::Read64(dynamic_index + 0x8); + const u64 tag = memory.Read64(dynamic_index); + const u64 value = memory.Read64(dynamic_index + 0x8); dynamic_index += 0x10; if (tag == ELF_DYNAMIC_TAG_NULL) { @@ -105,11 +105,11 @@ Symbols GetSymbols(VAddr text_offset) { VAddr symbol_index = symbol_table_address; while (symbol_index < string_table_address) { ELFSymbol symbol{}; - Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); + memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); VAddr string_offset = string_table_address + symbol.name_index; std::string name; - for (u8 c = Memory::Read8(string_offset); c != 0; c = Memory::Read8(++string_offset)) { + for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) { name += static_cast(c); } @@ -141,17 +141,17 @@ constexpr u64 SEGMENT_BASE = 0x7100000000ull; std::vector ARM_Interface::GetBacktrace() const { std::vector out; + auto& memory = system.Memory(); auto fp = GetReg(29); auto lr = GetReg(30); - while (true) { out.push_back({"", 0, lr, 0}); if (!fp) { break; } - lr = Memory::Read64(fp + 8) - 4; - fp = Memory::Read64(fp); + lr = memory.Read64(fp + 8) - 4; + fp = memory.Read64(fp); } std::map modules; @@ -162,7 +162,7 @@ std::vector ARM_Interface::GetBacktrace() const { std::map symbols; for (const auto& module : modules) { - symbols.insert_or_assign(module.second, GetSymbols(module.first)); + symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); } for (auto& entry : out) { diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 2b396f1d67..585fb55a90 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -28,20 +28,20 @@ public: explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} u8 MemoryRead8(u64 vaddr) override { - auto& s = parent.system; - return Memory::Read8(vaddr); + return parent.system.Memory().Read8(vaddr); } u16 MemoryRead16(u64 vaddr) override { - return Memory::Read16(vaddr); + return parent.system.Memory().Read16(vaddr); } u32 MemoryRead32(u64 vaddr) override { - return Memory::Read32(vaddr); + return parent.system.Memory().Read32(vaddr); } u64 MemoryRead64(u64 vaddr) override { - return Memory::Read64(vaddr); + return parent.system.Memory().Read64(vaddr); } Vector MemoryRead128(u64 vaddr) override { - return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)}; + auto& memory = parent.system.Memory(); + return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; } void MemoryWrite8(u64 vaddr, u8 value) override { diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 78e44f3bdb..1c74a44d82 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -969,13 +969,13 @@ static void ReadMemory() { SendReply("E01"); } - const auto& memory = Core::System::GetInstance().Memory(); + auto& memory = Core::System::GetInstance().Memory(); if (!memory.IsValidVirtualAddress(addr)) { return SendReply("E00"); } std::vector data(len); - Memory::ReadBlock(addr, data.data(), len); + memory.ReadBlock(addr, data.data(), len); MemToGdbHex(reply, data.data(), len); reply[len * 2] = '\0'; @@ -1057,7 +1057,9 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { breakpoint.active = true; breakpoint.addr = addr; breakpoint.len = len; - Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); + + auto& memory = Core::System::GetInstance().Memory(); + memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); static constexpr std::array btrap{0x00, 0x7d, 0x20, 0xd4}; if (type == BreakpointType::Execute) { diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 7f9a559d2f..07f0dac67a 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -67,12 +67,14 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + auto& memory = system.Memory(); + // Ensure that we can write to the address. - if (!system.Memory().IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } - if (static_cast(Memory::Read32(address)) != value) { + if (static_cast(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } @@ -82,8 +84,10 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + auto& memory = system.Memory(); + // Ensure that we can write to the address. - if (!system.Memory().IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } @@ -109,7 +113,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a } } - if (static_cast(Memory::Read32(address)) != value) { + if (static_cast(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } @@ -134,12 +138,14 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { + auto& memory = system.Memory(); + // Ensure that we can read the address. - if (!system.Memory().IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } - const s32 cur_value = static_cast(Memory::Read32(address)); + const s32 cur_value = static_cast(memory.Read32(address)); if (cur_value >= value) { return ERR_INVALID_STATE; } @@ -157,15 +163,19 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 } ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { + auto& memory = system.Memory(); + // Ensure that we can read the address. - if (!system.Memory().IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } + // Only wait for the address if equal. - if (static_cast(Memory::Read32(address)) != value) { + if (static_cast(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - // Short-circuit without rescheduling, if timeout is zero. + + // Short-circuit without rescheduling if timeout is zero. if (timeout == 0) { return RESULT_TIMEOUT; } diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index be24cef065..03745c4491 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 ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { auto& owner_process = *thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); + auto& memory = Core::System::GetInstance().Memory(); std::array dst_cmdbuf; - Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); // The header was already built in the internal command buffer. Attempt to parse it to verify // the integrity and then copy it over to the target command buffer. @@ -282,15 +283,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { std::vector HLERequestContext::ReadBuffer(int buffer_index) const { std::vector buffer; const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; + auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_a) { buffer.resize(BufferDescriptorA()[buffer_index].Size()); - Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), - buffer.size()); + memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); } else { buffer.resize(BufferDescriptorX()[buffer_index].Size()); - Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), - buffer.size()); + memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); } return buffer; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 8493d0f785..88eede4368 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, // thread. ASSERT(requesting_thread == current_thread); - const u32 addr_value = Memory::Read32(address); + const u32 addr_value = system.Memory().Read32(address); // If the mutex isn't being held, just return success. if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 738db528d6..a6c377cfcc 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -454,7 +454,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", handles_address, handle_count, nano_seconds); - if (!system.Memory().IsValidVirtualAddress(handles_address)) { + auto& memory = system.Memory(); + if (!memory.IsValidVirtualAddress(handles_address)) { LOG_ERROR(Kernel_SVC, "Handle address is not a valid virtual address, handle_address=0x{:016X}", handles_address); @@ -476,7 +477,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); for (u64 i = 0; i < handle_count; ++i) { - const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); + const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); const auto object = handle_table.Get(handle); if (object == nullptr) { @@ -618,13 +619,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { return; } + auto& memory = system.Memory(); + // This typically is an error code so we're going to assume this is the case if (sz == sizeof(u32)) { - LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr)); + LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr)); } else { // We don't know what's in here so we'll hexdump it debug_buffer.resize(sz); - Memory::ReadBlock(addr, debug_buffer.data(), sz); + memory.ReadBlock(addr, debug_buffer.data(), sz); std::string hexdump; for (std::size_t i = 0; i < debug_buffer.size(); i++) { hexdump += fmt::format("{:02X} ", debug_buffer[i]); @@ -714,7 +717,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre } std::string str(len, '\0'); - Memory::ReadBlock(address, str.data(), str.size()); + system.Memory().ReadBlock(address, str.data(), str.size()); LOG_DEBUG(Debug_Emulated, "{}", str); } @@ -1674,6 +1677,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); + auto& memory = system.Memory(); // Atomically read the value of the mutex. u32 mutex_val = 0; @@ -1683,7 +1687,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var monitor.SetExclusive(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. - mutex_val = Memory::Read32(mutex_address); + mutex_val = memory.Read32(mutex_address); if (mutex_val != 0) { update_val = mutex_val | Mutex::MutexHasWaitersFlag; diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 6a29377e31..4fb2cbc4b0 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -43,7 +43,8 @@ public: IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, std::string&& unique_name) : ServiceFramework("IAudioOut"), audio_core(audio_core), - device_name(std::move(device_name)), audio_params(audio_params) { + device_name(std::move(device_name)), + audio_params(audio_params), main_memory{system.Memory()} { // clang-format off static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, @@ -137,7 +138,7 @@ private: const u64 tag{rp.Pop()}; std::vector samples(audio_buffer.buffer_size / sizeof(s16)); - Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size); + main_memory.ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size); if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) { IPC::ResponseBuilder rb{ctx, 2}; @@ -209,6 +210,7 @@ private: /// This is the event handle used to check if the audio buffer was released Kernel::EventPair buffer_event; + Memory::Memory& main_memory; }; AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 88f903bfd8..157aeec88e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -140,9 +140,10 @@ public: rb.Push(ERROR_INVALID_SIZE); return; } + // Read NRR data from memory std::vector nrr_data(nrr_size); - Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size); + system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size); NRRHeader header; std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); @@ -291,7 +292,7 @@ public: // Read NRO data from memory std::vector nro_data(nro_size); - Memory::ReadBlock(nro_address, nro_data.data(), nro_size); + system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size); SHA256Hash hash{}; 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 74ecaef1b7..346c8f8992 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -36,15 +36,15 @@ private: MessageHeader header{}; VAddr addr{ctx.BufferDescriptorX()[0].Address()}; const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; - Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); + memory.ReadBlock(addr, &header, sizeof(MessageHeader)); addr += sizeof(MessageHeader); FieldMap fields; while (addr < end_addr) { - const auto field = static_cast(Memory::Read8(addr++)); - const auto length = Memory::Read8(addr++); + const auto field = static_cast(memory.Read8(addr++)); + const auto length = memory.Read8(addr++); - if (static_cast(Memory::Read8(addr)) == Field::Skip) { + if (static_cast(memory.Read8(addr)) == Field::Skip) { ++addr; } @@ -55,7 +55,7 @@ private: } std::vector data(length); - Memory::ReadBlock(addr, data.data(), length); + memory.ReadBlock(addr, data.data(), length); fields.emplace(field, std::move(data)); } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 9de0ace224..6d8bca8bba 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& input, std::vector& output, std::memcpy(entries.data(), input2.data(), params.num_entries * sizeof(Tegra::CommandListHeader)); } else { - Memory::ReadBlock(params.address, entries.data(), - params.num_entries * sizeof(Tegra::CommandListHeader)); + system.Memory().ReadBlock(params.address, entries.data(), + params.num_entries * sizeof(Tegra::CommandListHeader)); } UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index c939e980d2..699c481071 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -59,37 +59,6 @@ u8* GetPointerFromVMA(VAddr vaddr) { return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); } -template -T Read(const VAddr vaddr) { - const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; - if (page_pointer != nullptr) { - // NOTE: Avoid adding any extra logic to this fast-path block - T value; - std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); - return value; - } - - const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; - switch (type) { - case Common::PageType::Unmapped: - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); - return 0; - case Common::PageType::Memory: - ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); - break; - case Common::PageType::RasterizerCachedMemory: { - const u8* const host_ptr{GetPointerFromVMA(vaddr)}; - Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T)); - T value; - std::memcpy(&value, host_ptr, sizeof(T)); - return value; - } - default: - UNREACHABLE(); - } - return {}; -} - template void Write(const VAddr vaddr, const T data) { u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; @@ -210,6 +179,22 @@ struct Memory::Impl { return nullptr; } + u8 Read8(const VAddr addr) { + return Read(addr); + } + + u16 Read16(const VAddr addr) { + return Read(addr); + } + + u32 Read32(const VAddr addr) { + return Read(addr); + } + + u64 Read64(const VAddr addr) { + return Read(addr); + } + std::string ReadCString(VAddr vaddr, std::size_t max_length) { std::string string; string.reserve(max_length); @@ -225,6 +210,55 @@ struct Memory::Impl { return string; } + void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); + std::memset(dest_buffer, 0, copy_amount); + break; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + + const u8* const src_ptr = page_table.pointers[page_index] + page_offset; + std::memcpy(dest_buffer, src_ptr, copy_amount); + break; + } + case Common::PageType::RasterizerCachedMemory: { + const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); + system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); + std::memcpy(dest_buffer, host_ptr, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + dest_buffer = static_cast(dest_buffer) + copy_amount; + remaining_size -= copy_amount; + } + } + + void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { + ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); + } + void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { const auto& page_table = process.VMManager().page_table; std::size_t remaining_size = size; @@ -425,6 +459,48 @@ struct Memory::Impl { } } + /** + * Reads a particular data type out of memory at the given virtual address. + * + * @param vaddr The virtual address to read the data type from. + * + * @tparam T The data type to read out of memory. This type *must* be + * trivially copyable, otherwise the behavior of this function + * is undefined. + * + * @returns The instance of T read from the specified virtual address. + */ + template + T Read(const VAddr vaddr) { + const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + // NOTE: Avoid adding any extra logic to this fast-path block + T value; + std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); + return value; + } + + const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case Common::PageType::Unmapped: + LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); + return 0; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); + break; + case Common::PageType::RasterizerCachedMemory: { + const u8* const host_ptr = GetPointerFromVMA(vaddr); + system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T)); + T value; + std::memcpy(&value, host_ptr, sizeof(T)); + return value; + } + default: + UNREACHABLE(); + } + return {}; + } + Core::System& system; }; @@ -470,10 +546,35 @@ const u8* Memory::GetPointer(VAddr vaddr) const { return impl->GetPointer(vaddr); } +u8 Memory::Read8(const VAddr addr) { + return impl->Read8(addr); +} + +u16 Memory::Read16(const VAddr addr) { + return impl->Read16(addr); +} + +u32 Memory::Read32(const VAddr addr) { + return impl->Read32(addr); +} + +u64 Memory::Read64(const VAddr addr) { + return impl->Read64(addr); +} + std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { return impl->ReadCString(vaddr, max_length); } +void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + const std::size_t size) { + impl->ReadBlock(process, src_addr, dest_buffer, size); +} + +void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { + impl->ReadBlock(src_addr, dest_buffer, size); +} + void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { impl->ZeroBlock(process, dest_addr, size); } @@ -511,71 +612,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) { return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; } -u8 Read8(const VAddr addr) { - return Read(addr); -} - -u16 Read16(const VAddr addr) { - return Read(addr); -} - -u32 Read32(const VAddr addr) { - return Read(addr); -} - -u64 Read64(const VAddr addr) { - return Read(addr); -} - -void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, - const std::size_t size) { - const auto& page_table = process.VMManager().page_table; - - std::size_t remaining_size = size; - std::size_t page_index = src_addr >> PAGE_BITS; - std::size_t page_offset = src_addr & PAGE_MASK; - - while (remaining_size > 0) { - const std::size_t copy_amount = - std::min(static_cast(PAGE_SIZE) - page_offset, remaining_size); - const VAddr current_vaddr = static_cast((page_index << PAGE_BITS) + page_offset); - - switch (page_table.attributes[page_index]) { - case Common::PageType::Unmapped: { - LOG_ERROR(HW_Memory, - "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", - current_vaddr, src_addr, size); - std::memset(dest_buffer, 0, copy_amount); - break; - } - case Common::PageType::Memory: { - DEBUG_ASSERT(page_table.pointers[page_index]); - - const u8* src_ptr = page_table.pointers[page_index] + page_offset; - std::memcpy(dest_buffer, src_ptr, copy_amount); - break; - } - case Common::PageType::RasterizerCachedMemory: { - const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; - Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); - std::memcpy(dest_buffer, host_ptr, copy_amount); - break; - } - default: - UNREACHABLE(); - } - - page_index++; - page_offset = 0; - dest_buffer = static_cast(dest_buffer) + copy_amount; - remaining_size -= copy_amount; - } -} - -void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { - ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size); -} - void Write8(const VAddr addr, const u8 data) { Write(addr, data); } diff --git a/src/core/memory.h b/src/core/memory.h index fc0013a965..cc6ab920ea 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -152,6 +152,46 @@ public: */ const u8* GetPointer(VAddr vaddr) const; + /** + * Reads an 8-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 8-bit value from. + * + * @returns the read 8-bit unsigned value. + */ + u8 Read8(VAddr addr); + + /** + * Reads a 16-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 16-bit value from. + * + * @returns the read 16-bit unsigned value. + */ + u16 Read16(VAddr addr); + + /** + * Reads a 32-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 32-bit value from. + * + * @returns the read 32-bit unsigned value. + */ + u32 Read32(VAddr addr); + + /** + * Reads a 64-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 64-bit value from. + * + * @returns the read 64-bit value. + */ + u64 Read64(VAddr addr); + /** * Reads a null-terminated string from the given virtual address. * This function will continually read characters until either: @@ -169,6 +209,44 @@ public: */ std::string ReadCString(VAddr vaddr, std::size_t max_length); + /** + * Reads a contiguous block of bytes from a specified process' address space. + * + * @param process The process to read the data from. + * @param src_addr The virtual address to begin reading from. + * @param dest_buffer The buffer to place the read bytes into. + * @param size The amount of data to read, in bytes. + * + * @note If a size of 0 is specified, then this function reads nothing and + * no attempts to access memory are made at all. + * + * @pre dest_buffer must be at least size bytes in length, otherwise a + * buffer overrun will occur. + * + * @post The range [dest_buffer, size) contains the read bytes from the + * process' address space. + */ + void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, + std::size_t size); + + /** + * Reads a contiguous block of bytes from the current process' address space. + * + * @param src_addr The virtual address to begin reading from. + * @param dest_buffer The buffer to place the read bytes into. + * @param size The amount of data to read, in bytes. + * + * @note If a size of 0 is specified, then this function reads nothing and + * no attempts to access memory are made at all. + * + * @pre dest_buffer must be at least size bytes in length, otherwise a + * buffer overrun will occur. + * + * @post The range [dest_buffer, size) contains the read bytes from the + * current process' address space. + */ + void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); + /** * Fills the specified address range within a process' address space with zeroes. * @@ -242,18 +320,11 @@ void SetCurrentPageTable(Kernel::Process& process); /// Determines if the given VAddr is a kernel address bool IsKernelVirtualAddress(VAddr vaddr); -u8 Read8(VAddr addr); -u16 Read16(VAddr addr); -u32 Read32(VAddr addr); -u64 Read64(VAddr addr); - void Write8(VAddr addr, u8 data); void Write16(VAddr addr, u16 data); void Write32(VAddr addr, u32 data); void Write64(VAddr addr, u64 data); -void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size); -void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, std::size_t size); void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index b73cc9fbd9..d6745af8bb 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -20,14 +20,13 @@ namespace Memory { constexpr s64 CHEAT_ENGINE_TICKS = static_cast(Core::Timing::BASE_CLOCK_RATE / 12); constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; -StandardVmCallbacks::StandardVmCallbacks(const Core::System& system, - const CheatProcessMetadata& metadata) +StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) : metadata(metadata), system(system) {} StandardVmCallbacks::~StandardVmCallbacks() = default; void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { - ReadBlock(SanitizeAddress(address), data, size); + system.Memory().ReadBlock(SanitizeAddress(address), data, size); } void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index e3db90dacc..3d6b2298ad 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h @@ -24,7 +24,7 @@ namespace Memory { class StandardVmCallbacks : public DmntCheatVm::Callbacks { public: - StandardVmCallbacks(const Core::System& system, const CheatProcessMetadata& metadata); + StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata); ~StandardVmCallbacks() override; void MemoryRead(VAddr address, void* data, u64 size) override; @@ -37,7 +37,7 @@ private: VAddr SanitizeAddress(VAddr address) const; const CheatProcessMetadata& metadata; - const Core::System& system; + Core::System& system; }; // Intermediary class that parses a text file or other disk format for storing cheats into a diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index af0988d623..f95eee3b1f 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -157,7 +157,7 @@ json GetHLEBufferDescriptorData(const std::vector& buffer, Memor if constexpr (read_value) { std::vector data(desc.Size()); - Memory::ReadBlock(desc.Address(), data.data(), desc.Size()); + memory.ReadBlock(desc.Address(), data.data(), desc.Size()); entry["data"] = Common::HexToString(data); } diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index c7f42388f1..ab66f35f99 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -18,13 +18,13 @@ constexpr s64 MEMORY_FREEZER_TICKS = static_cast(Core::Timing::BASE_CLOCK_R u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) { switch (width) { case 1: - return Memory::Read8(addr); + return memory.Read8(addr); case 2: - return Memory::Read16(addr); + return memory.Read16(addr); case 4: - return Memory::Read32(addr); + return memory.Read32(addr); case 8: - return Memory::Read64(addr); + return memory.Read64(addr); default: UNREACHABLE(); return 0; diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 535b3ce903..727bd8a943 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -80,7 +80,7 @@ QString WaitTreeText::GetText() const { WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table) : mutex_address(mutex_address) { - mutex_value = Memory::Read32(mutex_address); + mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); owner_handle = static_cast(mutex_value & Kernel::Mutex::MutexOwnerMask); owner = handle_table.Get(owner_handle); } @@ -115,10 +115,11 @@ std::vector> WaitTreeCallstack::GetChildren() cons std::vector> list; constexpr std::size_t BaseRegister = 29; + auto& memory = Core::System::GetInstance().Memory(); u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister]; while (base_pointer != 0) { - const u64 lr = Memory::Read64(base_pointer + sizeof(u64)); + const u64 lr = memory.Read64(base_pointer + sizeof(u64)); if (lr == 0) { break; } @@ -126,7 +127,7 @@ std::vector> WaitTreeCallstack::GetChildren() cons list.push_back(std::make_unique( tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'}))); - base_pointer = Memory::Read64(base_pointer); + base_pointer = memory.Read64(base_pointer); } return list;