From e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 26 Nov 2019 17:39:57 -0500 Subject: [PATCH] core/memory: Migrate over Write{8, 16, 32, 64, Block} to the Memory class The Write functions are used slightly less than the Read functions, which make these a bit nicer to move over. The only adjustments we really need to make here are to Dynarmic's exclusive monitor instance. We need to keep a reference to the currently active memory instance to perform exclusive read/write operations. --- src/core/arm/dynarmic/arm_dynarmic.cpp | 30 ++-- src/core/arm/dynarmic/arm_dynarmic.h | 7 +- src/core/core_cpu.cpp | 5 +- src/core/core_cpu.h | 18 +- src/core/cpu_core_manager.cpp | 2 +- src/core/gdbstub/gdbstub.cpp | 16 +- src/core/hle/kernel/address_arbiter.cpp | 6 +- src/core/hle/kernel/hle_ipc.cpp | 9 +- src/core/hle/kernel/mutex.cpp | 4 +- src/core/hle/kernel/svc.cpp | 27 +-- src/core/memory.cpp | 220 ++++++++++++++---------- src/core/memory.h | 97 ++++++++++- src/core/memory/cheat_engine.cpp | 2 +- src/core/tools/freezer.cpp | 8 +- 14 files changed, 298 insertions(+), 153 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 585fb55a90..f8c7f0efd6 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -45,20 +45,21 @@ public: } void MemoryWrite8(u64 vaddr, u8 value) override { - Memory::Write8(vaddr, value); + parent.system.Memory().Write8(vaddr, value); } void MemoryWrite16(u64 vaddr, u16 value) override { - Memory::Write16(vaddr, value); + parent.system.Memory().Write16(vaddr, value); } void MemoryWrite32(u64 vaddr, u32 value) override { - Memory::Write32(vaddr, value); + parent.system.Memory().Write32(vaddr, value); } void MemoryWrite64(u64 vaddr, u64 value) override { - Memory::Write64(vaddr, value); + parent.system.Memory().Write64(vaddr, value); } void MemoryWrite128(u64 vaddr, Vector value) override { - Memory::Write64(vaddr, value[0]); - Memory::Write64(vaddr + 8, value[1]); + auto& memory = parent.system.Memory(); + memory.Write64(vaddr, value[0]); + memory.Write64(vaddr + 8, value[1]); } void InterpreterFallback(u64 pc, std::size_t num_instructions) override { @@ -266,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table, jit = MakeJit(page_table, new_address_space_size_in_bits); } -DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} +DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count) + : monitor(core_count), memory{memory_} {} + DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { @@ -279,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() { } bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 1, - [&] { Memory::Write8(vaddr, value); }); + return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 2, - [&] { Memory::Write16(vaddr, value); }); + [&] { memory.Write16(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 4, - [&] { Memory::Write32(vaddr, value); }); + [&] { memory.Write32(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 8, - [&] { Memory::Write64(vaddr, value); }); + [&] { memory.Write64(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { - Memory::Write64(vaddr + 0, value[0]); - Memory::Write64(vaddr + 8, value[1]); + memory.Write64(vaddr + 0, value[0]); + memory.Write64(vaddr + 8, value[1]); }); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index d08de475f2..9cd475cfb6 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -12,6 +12,10 @@ #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" +namespace Memory { +class Memory; +} + namespace Core { class ARM_Dynarmic_Callbacks; @@ -63,7 +67,7 @@ private: class DynarmicExclusiveMonitor final : public ExclusiveMonitor { public: - explicit DynarmicExclusiveMonitor(std::size_t core_count); + explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count); ~DynarmicExclusiveMonitor() override; void SetExclusive(std::size_t core_index, VAddr addr) override; @@ -78,6 +82,7 @@ public: private: friend class ARM_Dynarmic; Dynarmic::A64::ExclusiveMonitor monitor; + Memory::Memory& memory; }; } // namespace Core diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 233ea572ca..cf3fe0b0b0 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 Cpu::~Cpu() = default; -std::unique_ptr Cpu::MakeExclusiveMonitor(std::size_t num_cores) { +std::unique_ptr Cpu::MakeExclusiveMonitor( + [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) { #ifdef ARCHITECTURE_x86_64 - return std::make_unique(num_cores); + return std::make_unique(memory, num_cores); #else // TODO(merry): Passthrough exclusive monitor return nullptr; diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index cafca8df7f..78f5021a22 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -24,6 +24,10 @@ namespace Core::Timing { class CoreTiming; } +namespace Memory { +class Memory; +} + namespace Core { class ARM_Interface; @@ -86,7 +90,19 @@ public: void Shutdown(); - static std::unique_ptr MakeExclusiveMonitor(std::size_t num_cores); + /** + * Creates an exclusive monitor to handle exclusive reads/writes. + * + * @param memory The current memory subsystem that the monitor may wish + * to keep track of. + * + * @param num_cores The number of cores to assume about the CPU. + * + * @returns The constructed exclusive monitor instance, or nullptr if the current + * CPU backend is unable to use an exclusive monitor. + */ + static std::unique_ptr MakeExclusiveMonitor(Memory::Memory& memory, + std::size_t num_cores); private: void Reschedule(); diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp index 8efd410bba..f04a341336 100644 --- a/src/core/cpu_core_manager.cpp +++ b/src/core/cpu_core_manager.cpp @@ -25,7 +25,7 @@ CpuCoreManager::~CpuCoreManager() = default; void CpuCoreManager::Initialize() { barrier = std::make_unique(); - exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); + exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size()); for (std::size_t index = 0; index < cores.size(); ++index) { cores[index] = std::make_unique(system, *exclusive_monitor, *barrier, index); diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 1c74a44d82..37cb288483 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -508,8 +508,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) { bp->second.len, bp->second.addr, static_cast(type)); if (type == BreakpointType::Execute) { - Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + auto& system = Core::System::GetInstance(); + system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); + system.InvalidateCpuInstructionCaches(); } p.erase(addr); } @@ -993,14 +994,14 @@ static void WriteMemory() { const u64 len = HexToLong(start_offset, static_cast(len_pos - start_offset)); auto& system = Core::System::GetInstance(); - const auto& memory = system.Memory(); + auto& memory = system.Memory(); if (!memory.IsValidVirtualAddress(addr)) { return SendReply("E00"); } std::vector data(len); GdbHexToMem(data.data(), len_pos + 1, len); - Memory::WriteBlock(addr, data.data(), len); + memory.WriteBlock(addr, data.data(), len); system.InvalidateCpuInstructionCaches(); SendReply("OK"); } @@ -1058,13 +1059,14 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { breakpoint.addr = addr; breakpoint.len = len; - auto& memory = Core::System::GetInstance().Memory(); + auto& system = Core::System::GetInstance(); + auto& memory = system.Memory(); memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); static constexpr std::array btrap{0x00, 0x7d, 0x20, 0xd4}; if (type == BreakpointType::Execute) { - Memory::WriteBlock(addr, btrap.data(), btrap.size()); - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + memory.WriteBlock(addr, btrap.data(), btrap.size()); + system.InvalidateCpuInstructionCaches(); } p.insert({addr, breakpoint}); diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 07f0dac67a..98d07fa5b1 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -78,7 +78,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 return ERR_INVALID_STATE; } - Memory::Write32(address, static_cast(value + 1)); + memory.Write32(address, static_cast(value + 1)); return SignalToAddressOnly(address, num_to_wake); } @@ -117,7 +117,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a return ERR_INVALID_STATE; } - Memory::Write32(address, static_cast(updated_value)); + memory.Write32(address, static_cast(updated_value)); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } @@ -151,7 +151,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 } if (should_decrement) { - Memory::Write32(address, static_cast(cur_value - 1)); + memory.Write32(address, static_cast(cur_value - 1)); } // Short-circuit without rescheduling, if timeout is zero. diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 03745c4491..8b01567a84 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -274,8 +274,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { } // Copy the translated command buffer back into the thread's command buffer area. - Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); return RESULT_SUCCESS; } @@ -311,10 +311,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, size = buffer_size; // TODO(bunnei): This needs to be HW tested } + auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_b) { - Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); + memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { - Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); + memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } return size; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 88eede4368..061e9bcb02 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -117,7 +117,7 @@ ResultCode Mutex::Release(VAddr address) { // There are no more threads waiting for the mutex, release it completely. if (thread == nullptr) { - Memory::Write32(address, 0); + system.Memory().Write32(address, 0); return RESULT_SUCCESS; } @@ -132,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) { } // Grant the mutex to the next waiting thread and resume it. - Memory::Write32(address, mutex_value); + system.Memory().Write32(address, mutex_value); ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); thread->ResumeFromWait(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a6c377cfcc..db3ae3eb88 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1120,7 +1120,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); } - Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); + system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx)); return RESULT_SUCCESS; } @@ -1280,20 +1280,21 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add return ERR_INVALID_HANDLE; } + auto& memory = system.Memory(); const auto& vm_manager = process->VMManager(); const MemoryInfo memory_info = vm_manager.QueryMemory(address); - Memory::Write64(memory_info_address, memory_info.base_address); - Memory::Write64(memory_info_address + 8, memory_info.size); - Memory::Write32(memory_info_address + 16, memory_info.state); - Memory::Write32(memory_info_address + 20, memory_info.attributes); - Memory::Write32(memory_info_address + 24, memory_info.permission); - Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count); - Memory::Write32(memory_info_address + 28, memory_info.device_ref_count); - Memory::Write32(memory_info_address + 36, 0); + memory.Write64(memory_info_address, memory_info.base_address); + memory.Write64(memory_info_address + 8, memory_info.size); + memory.Write32(memory_info_address + 16, memory_info.state); + memory.Write32(memory_info_address + 20, memory_info.attributes); + memory.Write32(memory_info_address + 24, memory_info.permission); + memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count); + memory.Write32(memory_info_address + 28, memory_info.device_ref_count); + memory.Write32(memory_info_address + 36, 0); // Page info appears to be currently unused by the kernel and is always set to zero. - Memory::Write32(page_info_address, 0); + memory.Write32(page_info_address, 0); return RESULT_SUCCESS; } @@ -2290,12 +2291,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes, return ERR_INVALID_ADDRESS_STATE; } + auto& memory = system.Memory(); const auto& process_list = kernel.GetProcessList(); const auto num_processes = process_list.size(); const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); for (std::size_t i = 0; i < copy_amount; ++i) { - Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); + memory.Write64(out_process_ids, process_list[i]->GetProcessID()); out_process_ids += sizeof(u64); } @@ -2329,13 +2331,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd return ERR_INVALID_ADDRESS_STATE; } + auto& memory = system.Memory(); const auto& thread_list = current_process->GetThreadList(); const auto num_threads = thread_list.size(); const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); auto list_iter = thread_list.cbegin(); for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { - Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); + memory.Write64(out_thread_ids, (*list_iter)->GetThreadID()); out_thread_ids += sizeof(u64); } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 699c481071..5c940a82e8 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -58,35 +58,6 @@ u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { u8* GetPointerFromVMA(VAddr vaddr) { return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); } - -template -void Write(const VAddr vaddr, const T data) { - 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 - std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); - return; - } - - Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; - switch (type) { - case Common::PageType::Unmapped: - LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, - static_cast(data), vaddr); - return; - case Common::PageType::Memory: - ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); - break; - case Common::PageType::RasterizerCachedMemory: { - u8* const host_ptr{GetPointerFromVMA(vaddr)}; - Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); - std::memcpy(host_ptr, &data, sizeof(T)); - break; - } - default: - UNREACHABLE(); - } -} } // Anonymous namespace // Implementation class used to keep the specifics of the memory subsystem hidden @@ -195,6 +166,22 @@ struct Memory::Impl { return Read(addr); } + void Write8(const VAddr addr, const u8 data) { + Write(addr, data); + } + + void Write16(const VAddr addr, const u16 data) { + Write(addr, data); + } + + void Write32(const VAddr addr, const u32 data) { + Write(addr, data); + } + + void Write64(const VAddr addr, const u64 data) { + Write(addr, data); + } + std::string ReadCString(VAddr vaddr, std::size_t max_length) { std::string string; string.reserve(max_length); @@ -259,6 +246,53 @@ struct Memory::Impl { ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); } + void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_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 = dest_addr >> PAGE_BITS; + std::size_t page_offset = dest_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 WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); + break; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + + u8* const dest_ptr = page_table.pointers[page_index] + page_offset; + std::memcpy(dest_ptr, src_buffer, copy_amount); + break; + } + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); + std::memcpy(host_ptr, src_buffer, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + src_buffer = static_cast(src_buffer) + copy_amount; + remaining_size -= copy_amount; + } + } + + void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { + WriteBlock(*system.CurrentProcess(), dest_addr, src_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; @@ -501,6 +535,46 @@ struct Memory::Impl { return {}; } + /** + * Writes a particular data type to memory at the given virtual address. + * + * @param vaddr The virtual address to write the data type to. + * + * @tparam T The data type to write to memory. This type *must* be + * trivially copyable, otherwise the behavior of this function + * is undefined. + * + * @returns The instance of T write to the specified virtual address. + */ + template + void Write(const VAddr vaddr, const T data) { + 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 + std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); + return; + } + + const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case Common::PageType::Unmapped: + LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, + static_cast(data), vaddr); + return; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); + break; + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr{GetPointerFromVMA(vaddr)}; + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); + std::memcpy(host_ptr, &data, sizeof(T)); + break; + } + default: + UNREACHABLE(); + } + } + Core::System& system; }; @@ -562,6 +636,22 @@ u64 Memory::Read64(const VAddr addr) { return impl->Read64(addr); } +void Memory::Write8(VAddr addr, u8 data) { + impl->Write8(addr, data); +} + +void Memory::Write16(VAddr addr, u16 data) { + impl->Write16(addr, data); +} + +void Memory::Write32(VAddr addr, u32 data) { + impl->Write32(addr, data); +} + +void Memory::Write64(VAddr addr, u64 data) { + impl->Write64(addr, data); +} + std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { return impl->ReadCString(vaddr, max_length); } @@ -575,6 +665,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_ impl->ReadBlock(src_addr, dest_buffer, size); } +void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + std::size_t size) { + impl->WriteBlock(process, dest_addr, src_buffer, size); +} + +void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { + impl->WriteBlock(dest_addr, src_buffer, size); +} + void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { impl->ZeroBlock(process, dest_addr, size); } @@ -612,67 +711,4 @@ bool IsKernelVirtualAddress(const VAddr vaddr) { return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; } -void Write8(const VAddr addr, const u8 data) { - Write(addr, data); -} - -void Write16(const VAddr addr, const u16 data) { - Write(addr, data); -} - -void Write32(const VAddr addr, const u32 data) { - Write(addr, data); -} - -void Write64(const VAddr addr, const u64 data) { - Write(addr, data); -} - -void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_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 = dest_addr >> PAGE_BITS; - std::size_t page_offset = dest_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 WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", - current_vaddr, dest_addr, size); - break; - } - case Common::PageType::Memory: { - DEBUG_ASSERT(page_table.pointers[page_index]); - - u8* dest_ptr = page_table.pointers[page_index] + page_offset; - std::memcpy(dest_ptr, src_buffer, copy_amount); - break; - } - case Common::PageType::RasterizerCachedMemory: { - const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; - Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); - std::memcpy(host_ptr, src_buffer, copy_amount); - break; - } - default: - UNREACHABLE(); - } - - page_index++; - page_offset = 0; - src_buffer = static_cast(src_buffer) + copy_amount; - remaining_size -= copy_amount; - } -} - -void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size); -} - } // namespace Memory diff --git a/src/core/memory.h b/src/core/memory.h index cc6ab920ea..7878f3fb18 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -192,6 +192,50 @@ public: */ u64 Read64(VAddr addr); + /** + * Writes an 8-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 8-bit unsigned integer to. + * @param data The 8-bit unsigned integer to write to the given virtual address. + * + * @post The memory at the given virtual address contains the specified data value. + */ + void Write8(VAddr addr, u8 data); + + /** + * Writes a 16-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 16-bit unsigned integer to. + * @param data The 16-bit unsigned integer to write to the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + void Write16(VAddr addr, u16 data); + + /** + * Writes a 32-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 32-bit unsigned integer to. + * @param data The 32-bit unsigned integer to write to the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + void Write32(VAddr addr, u32 data); + + /** + * Writes a 64-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 64-bit unsigned integer to. + * @param data The 64-bit unsigned integer to write to the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + void Write64(VAddr addr, u64 data); + /** * Reads a null-terminated string from the given virtual address. * This function will continually read characters until either: @@ -247,6 +291,50 @@ public: */ void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); + /** + * Writes a range of bytes into a given process' address space at the specified + * virtual address. + * + * @param process The process to write data into the address space of. + * @param dest_addr The destination virtual address to begin writing the data at. + * @param src_buffer The data to write into the process' address space. + * @param size The size of the data to write, in bytes. + * + * @post The address range [dest_addr, size) in the process' address space + * contains the data that was within src_buffer. + * + * @post If an attempt is made to write into an unmapped region of memory, the writes + * will be ignored and an error will be logged. + * + * @post If a write is performed into a region of memory that is considered cached + * rasterizer memory, will cause the currently active rasterizer to be notified + * and will mark that region as invalidated to caches that the active + * graphics backend may be maintaining over the course of execution. + */ + void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + std::size_t size); + + /** + * Writes a range of bytes into the current process' address space at the specified + * virtual address. + * + * @param dest_addr The destination virtual address to begin writing the data at. + * @param src_buffer The data to write into the current process' address space. + * @param size The size of the data to write, in bytes. + * + * @post The address range [dest_addr, size) in the current process' address space + * contains the data that was within src_buffer. + * + * @post If an attempt is made to write into an unmapped region of memory, the writes + * will be ignored and an error will be logged. + * + * @post If a write is performed into a region of memory that is considered cached + * rasterizer memory, will cause the currently active rasterizer to be notified + * and will mark that region as invalidated to caches that the active + * graphics backend may be maintaining over the course of execution. + */ + void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); + /** * Fills the specified address range within a process' address space with zeroes. * @@ -320,13 +408,4 @@ void SetCurrentPageTable(Kernel::Process& process); /// Determines if the given VAddr is a kernel address bool IsKernelVirtualAddress(VAddr vaddr); -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 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); - } // namespace Memory diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index d6745af8bb..d1e6bed93f 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -30,7 +30,7 @@ void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { } void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { - WriteBlock(SanitizeAddress(address), data, size); + system.Memory().WriteBlock(SanitizeAddress(address), data, size); } u64 StandardVmCallbacks::HidKeysDown() { diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index ab66f35f99..55e0dbc49b 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -34,16 +34,16 @@ u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) { void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) { switch (width) { case 1: - Memory::Write8(addr, static_cast(value)); + memory.Write8(addr, static_cast(value)); break; case 2: - Memory::Write16(addr, static_cast(value)); + memory.Write16(addr, static_cast(value)); break; case 4: - Memory::Write32(addr, static_cast(value)); + memory.Write32(addr, static_cast(value)); break; case 8: - Memory::Write64(addr, value); + memory.Write64(addr, value); break; default: UNREACHABLE();