diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b7f21698f..54a848936 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -497,7 +498,21 @@ struct Memory::Impl { return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size); } + struct PageEntry { + u8* const pointer; + const Common::PageType attribute; + }; + + PageEntry SafePageEntry(std::size_t base) const { + std::lock_guard lock{rasterizer_cache_guard}; + return { + .pointer = current_page_table->pointers[base], + .attribute = current_page_table->attributes[base], + }; + } + void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { + std::lock_guard lock{rasterizer_cache_guard}; if (vaddr == 0) { return; } @@ -630,16 +645,22 @@ struct Memory::Impl { */ 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 + // Avoid adding any extra logic to this fast-path block + if (const u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) { T value; - std::memcpy(&value, &page_pointer[vaddr], sizeof(T)); + std::memcpy(&value, &pointer[vaddr], sizeof(T)); return value; } - const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; - switch (type) { + // Otherwise, we need to grab the page with a lock, in case it is currently being modified + const auto entry = SafePageEntry(vaddr >> PAGE_BITS); + if (entry.pointer) { + T value; + std::memcpy(&value, &entry.pointer[vaddr], sizeof(T)); + return value; + } + + switch (entry.attribute) { case Common::PageType::Unmapped: LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); return 0; @@ -670,15 +691,21 @@ struct Memory::Impl { */ 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], &data, sizeof(T)); + // Avoid adding any extra logic to this fast-path block + if (u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) { + std::memcpy(&pointer[vaddr], &data, sizeof(T)); return; } - const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; - switch (type) { + // Otherwise, we need to grab the page with a lock, in case it is currently being modified + const auto entry = SafePageEntry(vaddr >> PAGE_BITS); + if (entry.pointer) { + // Memory was mapped, we are done + std::memcpy(&entry.pointer[vaddr], &data, sizeof(T)); + return; + } + + switch (entry.attribute) { case Common::PageType::Unmapped: LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, static_cast(data), vaddr); @@ -756,6 +783,7 @@ struct Memory::Impl { return true; } + mutable std::mutex rasterizer_cache_guard; Common::PageTable* current_page_table = nullptr; Core::System& system; };