core: memory: Ensure thread safe access when pages are rasterizer cached (#5206)

* core: memory: Ensure thread safe access when pages are rasterizer cached.
This commit is contained in:
bunnei 2020-12-24 21:51:49 -08:00 committed by GitHub
parent 5836530a87
commit c8a4967c9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -4,6 +4,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <mutex>
#include <optional> #include <optional>
#include <utility> #include <utility>
@ -497,7 +498,21 @@ struct Memory::Impl {
return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size); 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) { void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
std::lock_guard lock{rasterizer_cache_guard};
if (vaddr == 0) { if (vaddr == 0) {
return; return;
} }
@ -630,16 +645,22 @@ struct Memory::Impl {
*/ */
template <typename T> template <typename T>
T Read(const VAddr vaddr) { T Read(const VAddr vaddr) {
const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; // Avoid adding any extra logic to this fast-path block
if (page_pointer != nullptr) { if (const u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) {
// NOTE: Avoid adding any extra logic to this fast-path block
T value; T value;
std::memcpy(&value, &page_pointer[vaddr], sizeof(T)); std::memcpy(&value, &pointer[vaddr], sizeof(T));
return value; return value;
} }
const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; // Otherwise, we need to grab the page with a lock, in case it is currently being modified
switch (type) { 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: case Common::PageType::Unmapped:
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
return 0; return 0;
@ -670,15 +691,21 @@ struct Memory::Impl {
*/ */
template <typename T> template <typename T>
void Write(const VAddr vaddr, const T data) { void Write(const VAddr vaddr, const T data) {
u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; // Avoid adding any extra logic to this fast-path block
if (page_pointer != nullptr) { if (u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) {
// NOTE: Avoid adding any extra logic to this fast-path block std::memcpy(&pointer[vaddr], &data, sizeof(T));
std::memcpy(&page_pointer[vaddr], &data, sizeof(T));
return; return;
} }
const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; // Otherwise, we need to grab the page with a lock, in case it is currently being modified
switch (type) { 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: case Common::PageType::Unmapped:
LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
static_cast<u32>(data), vaddr); static_cast<u32>(data), vaddr);
@ -756,6 +783,7 @@ struct Memory::Impl {
return true; return true;
} }
mutable std::mutex rasterizer_cache_guard;
Common::PageTable* current_page_table = nullptr; Common::PageTable* current_page_table = nullptr;
Core::System& system; Core::System& system;
}; };