From 619cd0aa38faf0914ade4b8762ecf450e0f8aaf0 Mon Sep 17 00:00:00 2001 From: "Jared M. White" Date: Fri, 5 Jul 2024 16:14:40 -0500 Subject: [PATCH] Lock tracking logic behind a flag, check if faulted address is in emulated memory, check for page dirtiness before fastmem fault, pass whole page size to set page dirty bit --- Source/Core/Core/HW/HW.cpp | 4 +- Source/Core/Core/HW/HW.h | 2 +- Source/Core/Core/HW/Memmap.cpp | 110 ++++++++++++++++++++++----------- Source/Core/Core/HW/Memmap.h | 3 +- Source/Core/Core/MemTools.cpp | 18 +++--- Source/Core/Core/State.cpp | 16 ++--- 6 files changed, 96 insertions(+), 57 deletions(-) diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 524feab884..4bb05345c9 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -82,9 +82,9 @@ void Shutdown(Core::System& system) system.GetCoreTiming().Shutdown(); } -void DoState(Core::System& system, PointerWrap& p) +void DoState(Core::System& system, PointerWrap& p, bool delta) { - system.GetMemory().DoState(p); + system.GetMemory().DoState(p, delta); p.DoMarker("Memory"); system.GetMemoryInterface().DoState(p); p.DoMarker("MemoryInterface"); diff --git a/Source/Core/Core/HW/HW.h b/Source/Core/Core/HW/HW.h index d70ad72fa6..a3dabfa339 100644 --- a/Source/Core/Core/HW/HW.h +++ b/Source/Core/Core/HW/HW.h @@ -14,5 +14,5 @@ namespace HW { void Init(Core::System& system, const Sram* override_sram); void Shutdown(Core::System& system); -void DoState(Core::System& system, PointerWrap& p); +void DoState(Core::System& system, PointerWrap& p, bool delta); } // namespace HW diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index ffd025ad50..64f8de8cdc 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -205,6 +205,27 @@ bool MemoryManager::IsAddressInFastmemArea(const u8* address) const return address >= m_fastmem_arena && address < m_fastmem_arena + m_fastmem_arena_size; } +bool MemoryManager::IsAddressInEmulatedMemory(const u8* address) const +{ + if (m_ram && address > m_ram && address <= m_ram + GetRamSize()) + { + return true; + } + else if (m_exram && address > m_exram && address <= m_exram + GetExRamSize()) + { + return true; + } + else if (m_l1_cache && address > m_l1_cache && address <= m_l1_cache + GetL1CacheSize()) + { + return true; + } + else if (m_fake_vmem && address > m_fake_vmem && address <= m_fake_vmem + GetFakeVMemSize()) + { + return true; + } + return false; +} + bool MemoryManager::InitFastmemArena() { // Here we set up memory mappings for fastmem. The basic idea of fastmem is that we reserve 4 GiB @@ -331,7 +352,7 @@ void MemoryManager::UpdateLogicalMemory(const PowerPC::BatTable& dbat_table) } } -void MemoryManager::DoState(PointerWrap& p) +void MemoryManager::DoState(PointerWrap& p, bool delta) { const u32 current_ram_size = GetRamSize(); const u32 current_l1_cache_size = GetL1CacheSize(); @@ -368,53 +389,68 @@ void MemoryManager::DoState(PointerWrap& p) p.SetVerifyMode(); return; } - u32 page_count = static_cast(Common::PageSize()); - p.Do(m_dirty_pages); - for (size_t i = 0; i < current_ram_size; i++) + if (delta) { - if (IsPageDirty(reinterpret_cast(&m_ram[i]))) + u32 page_size = static_cast(Common::PageSize()); + p.Do(m_dirty_pages); + for (size_t i = 0; i < current_ram_size; i++) { - p.DoArray(m_ram + i, page_count); - i += page_count; - } - } - for (size_t i = 0; i < current_l1_cache_size; i++) - { - if (IsPageDirty(reinterpret_cast(&m_l1_cache[i]))) - { - p.DoArray(m_l1_cache + i, page_count); - i += page_count; - } - } - p.DoMarker("Memory RAM"); - if (current_have_fake_vmem) - { - for (size_t i = 0; i < current_fake_vmem_size; i++) - { - if (IsPageDirty(reinterpret_cast(&m_fake_vmem[i]))) + if (IsPageDirty(reinterpret_cast(&m_ram[i]))) { - p.DoArray(m_fake_vmem + i, page_count); - i += page_count; + p.DoArray(m_ram + i, page_size); + i += page_size; } } - } - p.DoMarker("Memory FakeVMEM"); - if (current_have_exram) - { - for (size_t i = 0; i < current_exram_size; i++) + for (size_t i = 0; i < current_l1_cache_size; i++) { - if (IsPageDirty(reinterpret_cast(&m_exram[i]))) + if (IsPageDirty(reinterpret_cast(&m_l1_cache[i]))) { - p.DoArray(m_exram + i, page_count); - i += page_count; + p.DoArray(m_l1_cache + i, page_size); + i += page_size; } } - } - p.DoMarker("Memory EXRAM"); + p.DoMarker("Memory RAM"); + if (current_have_fake_vmem) + { + for (size_t i = 0; i < current_fake_vmem_size; i++) + { + if (IsPageDirty(reinterpret_cast(&m_fake_vmem[i]))) + { + p.DoArray(m_fake_vmem + i, page_size); + i += page_size; + } + } + } + p.DoMarker("Memory FakeVMEM"); + if (current_have_exram) + { + for (size_t i = 0; i < current_exram_size; i++) + { + if (IsPageDirty(reinterpret_cast(&m_exram[i]))) + { + p.DoArray(m_exram + i, page_size); + i += page_size; + } + } + } + p.DoMarker("Memory EXRAM"); - if (p.IsWriteMode()) + if (p.IsWriteMode()) + { + ResetDirtyPages(); + } + } + else { - ResetDirtyPages(); + p.DoArray(m_ram, current_ram_size); + p.DoArray(m_l1_cache, current_l1_cache_size); + p.DoMarker("Memory RAM"); + if (current_have_fake_vmem) + p.DoArray(m_fake_vmem, current_fake_vmem_size); + p.DoMarker("Memory FakeVMEM"); + if (current_have_exram) + p.DoArray(m_exram, current_exram_size); + p.DoMarker("Memory EXRAM"); } } diff --git a/Source/Core/Core/HW/Memmap.h b/Source/Core/Core/HW/Memmap.h index dbcdd5bf68..8b263376dd 100644 --- a/Source/Core/Core/HW/Memmap.h +++ b/Source/Core/Core/HW/Memmap.h @@ -79,6 +79,7 @@ public: u32 GetExRamMask() const { return m_exram_mask; } bool IsAddressInFastmemArea(const u8* address) const; + bool IsAddressInEmulatedMemory(const u8* address) const; u8* GetPhysicalBase() const { return m_physical_base; } u8* GetLogicalBase() const { return m_logical_base; } u8* GetPhysicalPageMappingsBase() const { return m_physical_page_mappings_base; } @@ -99,7 +100,7 @@ public: void Shutdown(); bool InitFastmemArena(); void ShutdownFastmemArena(); - void DoState(PointerWrap& p); + void DoState(PointerWrap& p, bool delta); void UpdateLogicalMemory(const PowerPC::BatTable& dbat_table); diff --git a/Source/Core/Core/MemTools.cpp b/Source/Core/Core/MemTools.cpp index 1539a0d685..8b472a6388 100644 --- a/Source/Core/Core/MemTools.cpp +++ b/Source/Core/Core/MemTools.cpp @@ -64,19 +64,17 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) SContext* ctx = pPtrs->ContextRecord; Core::System& system = Core::System::GetInstance(); Memory::MemoryManager& memory = system.GetMemory(); - if (system.GetJitInterface().HandleFault(fault_address, ctx)) + if (!memory.IsPageDirty(fault_address)) { - return EXCEPTION_CONTINUE_EXECUTION; - } - else if (!memory.IsPageDirty(fault_address)) - { - memory.SetPageDirtyBit(fault_address, 1, true); - size_t page_size = Common::PageSize(); + + memory.SetPageDirtyBit(fault_address, page_size, true); + size_t page_mask = page_size - 1; u64 page_index = fault_address & page_mask; + bool change_protection = memory.VirtualProtectMemory(reinterpret_cast(fault_address), - page_size - page_index, PAGE_READWRITE); + page_size - page_index, PAGE_READWRITE); if (!change_protection) { return EXCEPTION_CONTINUE_SEARCH; @@ -84,6 +82,10 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) return EXCEPTION_CONTINUE_EXECUTION; } + else if (system.GetJitInterface().HandleFault(fault_address, ctx)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } else { // Let's not prevent debugging. diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 11c8e9660e..088b8967f5 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -138,7 +138,7 @@ void EnableCompression(bool compression) s_use_compression = compression; } -static void DoState(Core::System& system, PointerWrap& p) +static void DoState(Core::System& system, PointerWrap& p, bool delta) { bool is_wii = system.IsWii() || system.IsMIOS(); const bool is_wii_currently = is_wii; @@ -187,7 +187,7 @@ static void DoState(Core::System& system, PointerWrap& p) p.DoMarker("CoreTiming"); // HW needs to be restored before PowerPC because the data cache might need to be flushed. - HW::DoState(system, p); + HW::DoState(system, p, delta); p.DoMarker("HW"); system.GetPowerPC().DoState(p); @@ -223,7 +223,7 @@ void LoadFromBuffer(Core::System& system, std::vector& buffer) [&] { u8* ptr = buffer.data(); PointerWrap p(&ptr, buffer.size(), PointerWrap::Mode::Read); - DoState(system, p); + DoState(system, p, false); }, true); } @@ -236,13 +236,13 @@ void SaveToBuffer(Core::System& system, std::vector& buffer) u8* ptr = nullptr; PointerWrap p_measure(&ptr, 0, PointerWrap::Mode::Measure); - DoState(system, p_measure); + DoState(system, p_measure, false); const size_t buffer_size = reinterpret_cast(ptr); buffer.resize(buffer_size); ptr = buffer.data(); PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write); - DoState(system, p); + DoState(system, p, false); }, true); } @@ -487,7 +487,7 @@ void SaveAs(Core::System& system, const std::string& filename, bool wait) // Measure the size of the buffer. u8* ptr = nullptr; PointerWrap p_measure(&ptr, 0, PointerWrap::Mode::Measure); - DoState(system, p_measure); + DoState(system, p_measure, false); const size_t buffer_size = reinterpret_cast(ptr); // Then actually do the write. @@ -495,7 +495,7 @@ void SaveAs(Core::System& system, const std::string& filename, bool wait) current_buffer.resize(buffer_size); ptr = current_buffer.data(); PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write); - DoState(system, p); + DoState(system, p, false); if (p.IsWriteMode()) { @@ -901,7 +901,7 @@ void LoadAs(Core::System& system, const std::string& filename) { u8* ptr = buffer.data(); PointerWrap p(&ptr, buffer.size(), PointerWrap::Mode::Read); - DoState(system, p); + DoState(system, p, false); loaded = true; loadedSuccessfully = p.IsReadMode(); }