diff options
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 79 |
1 files changed, 41 insertions, 38 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a5e6b8592c..837016de1d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -101,8 +101,10 @@ struct Memory::Impl { } u64 protect_bytes = 0, protect_begin = 0; + + current_page_table->entries.CommitRegion(vaddr >> YUZU_PAGEBITS, (vaddr + size) >> YUZU_PAGEBITS); for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) { - const Common::PageType page_type = current_page_table->entries[addr >> YUZU_PAGEBITS].ptr.Type(); + const Common::PageType page_type = current_page_table->entries.GetUnchecked(addr >> YUZU_PAGEBITS).Type(); switch (page_type) { case Common::PageType::RasterizerCachedMemory: if (protect_bytes > 0) { @@ -123,16 +125,14 @@ struct Memory::Impl { } [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const { - Common::PhysicalAddress const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr; - if (paddr) - return system.DeviceMemory().GetPointer<u8>(paddr + vaddr); + if (u64 paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].Pointer(true); paddr) + return reinterpret_cast<u8*>(paddr) + vaddr; return {}; } [[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const { - const Common::PhysicalAddress paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr; - if (paddr != 0) - return system.DeviceMemory().GetPointer<u8>(paddr + vaddr); + if (u64 paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].Pointer(true); paddr) + return reinterpret_cast<u8*>(paddr) + vaddr; return {}; } @@ -243,10 +243,12 @@ struct Memory::Impl { std::size_t page_index = addr >> YUZU_PAGEBITS; std::size_t page_offset = addr & YUZU_PAGEMASK; bool user_accessible = true; + + current_page_table->entries.CommitRegion(page_index, page_index + (size >> YUZU_PAGEBITS) + 1); while (remaining_size != 0) { const std::size_t copy_amount = (std::min)(std::size_t(YUZU_PAGESIZE) - page_offset, remaining_size); const auto current_vaddr = u64((page_index << YUZU_PAGEBITS) + page_offset); - const auto [pointer, type] = current_page_table->entries[page_index].ptr.PointerType(); + const auto [pointer, type, _] = current_page_table->entries.GetUnchecked(page_index).PointerTypeBlock(); switch (type) { case Common::PageType::Unmapped: { user_accessible = false; @@ -297,10 +299,10 @@ struct Memory::Impl { } [[nodiscard]] inline const u8* GetSpan(const VAddr addr, const std::size_t size) const noexcept { - return (current_page_table->entries[addr >> YUZU_PAGEBITS].block == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].block) ? GetPointerSilent(addr) : nullptr; + return (current_page_table->entries[addr >> YUZU_PAGEBITS].Block() == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].Block()) ? GetPointerSilent(addr) : nullptr; } [[nodiscard]] inline u8* GetSpan(const VAddr addr, const std::size_t size) noexcept { - return (current_page_table->entries[addr >> YUZU_PAGEBITS].block == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].block) ? GetPointerSilent(addr) : nullptr; + return (current_page_table->entries[addr >> YUZU_PAGEBITS].Block() == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].Block()) ? GetPointerSilent(addr) : nullptr; } bool WriteBlockImpl(const Common::ProcessAddress addr, const void* buffer, const std::size_t size, bool unsafe) { @@ -404,11 +406,14 @@ struct Memory::Impl { // The region is at a granularity of CPU pages. const u64 num_pages = ((vaddr + size - 1) >> YUZU_PAGEBITS) - (vaddr >> YUZU_PAGEBITS) + 1; + + current_page_table->entries.CommitRegion(vaddr >> YUZU_PAGEBITS, (vaddr >> YUZU_PAGEBITS) + num_pages); for (u64 i = 0; i < num_pages; ++i, vaddr += YUZU_PAGESIZE) { - const Common::PageType page_type = current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Type(); + auto& entry = current_page_table->entries.GetUnchecked(vaddr >> YUZU_PAGEBITS); + const auto [pointer, type, block] = entry.PointerTypeBlock(true); if (debug) { // Switch page type to debug if now debug - switch (page_type) { + switch (type) { case Common::PageType::Unmapped: ASSERT(false && "Attempted to mark unmapped pages as debug"); break; @@ -417,14 +422,14 @@ struct Memory::Impl { // Page is already marked. break; case Common::PageType::Memory: - current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(0, Common::PageType::DebugMemory); + entry.MarkDebug(pointer, block); break; default: UNREACHABLE(); } } else { // Switch page type to non-debug if now non-debug - switch (page_type) { + switch (type) { case Common::PageType::Unmapped: ASSERT(false && "Attempted to mark unmapped pages as non-debug"); break; @@ -433,8 +438,7 @@ struct Memory::Impl { // Don't mess with already non-debug or rasterizer memory. break; case Common::PageType::DebugMemory: { - u8* const pointer = GetPointerFromDebugMemory(vaddr & ~YUZU_PAGEMASK); - current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(uintptr_t(pointer) - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory); + entry.Store(false, Common::PageType::Memory, block, pointer); break; } default: @@ -466,8 +470,10 @@ struct Memory::Impl { // is different). This assumes the specified GPU address region is contiguous as well. const u64 num_pages = ((vaddr + size - 1) >> YUZU_PAGEBITS) - (vaddr >> YUZU_PAGEBITS) + 1; + current_page_table->entries.CommitRegion(vaddr >> YUZU_PAGEBITS, (vaddr >> YUZU_PAGEBITS) + num_pages); for (u64 i = 0; i < num_pages; ++i, vaddr += YUZU_PAGESIZE) { - const Common::PageType page_type= current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Type(); + auto& entry = current_page_table->entries.GetUnchecked(vaddr >> YUZU_PAGEBITS); + const Common::PageType page_type = entry.Type(); if (cached) { // Switch page type to cached if now cached switch (page_type) { @@ -477,7 +483,7 @@ struct Memory::Impl { break; case Common::PageType::DebugMemory: case Common::PageType::Memory: - current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(0, Common::PageType::RasterizerCachedMemory); + entry.MarkRasterizerCached(); break; case Common::PageType::RasterizerCachedMemory: // There can be more than one GPU region mapped per CPU region, so it's common @@ -499,13 +505,13 @@ struct Memory::Impl { // that this area is already unmarked as cached. break; case Common::PageType::RasterizerCachedMemory: { - if (u8* const pointer = GetPointerFromRasterizerCachedMemory(vaddr & ~YUZU_PAGEMASK); pointer == nullptr) { + if (auto [ptr, _, block] = entry.PointerTypeBlock(true); ptr == 0) { // It's possible that this function has been called while updating the // pagetable after unmapping a VMA. In that case the underlying VMA will no // longer exist, and we should just leave the pagetable entry blank. - current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(0, Common::PageType::Unmapped); + entry.Store(false, Common::PageType::Unmapped, block, 0); } else { - current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(uintptr_t(pointer) - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory); + entry.Store(false, Common::PageType::Memory, block, ptr); } break; } @@ -539,22 +545,18 @@ struct Memory::Impl { ASSERT_MSG(type != Common::PageType::Memory, "Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE); - while (base != end) { - page_table.entries[base].ptr.Store(0, type); - page_table.entries[base].addr = 0; - page_table.entries[base].block = 0; - base += 1; - } + page_table.entries.ZeroRegion(base, end); } else { - auto orig_base = base; + auto current_block = block_count.fetch_add(1, std::memory_order_relaxed); + ASSERT(current_block != 65535); + + page_table.entries.CommitRegion(base, end); while (base != end) { - auto host_ptr = uintptr_t(system.DeviceMemory().GetPointer<u8>(target)) - (base << YUZU_PAGEBITS); - auto backing = GetInteger(target) - (base << YUZU_PAGEBITS); - page_table.entries[base].ptr.Store(host_ptr, type); - page_table.entries[base].addr = backing; - page_table.entries[base].block = orig_base << YUZU_PAGEBITS; + auto host_ptr = reinterpret_cast<u64>(system.DeviceMemory().GetPointer<u8>(target)) - (base << YUZU_PAGEBITS);; + auto& entry = page_table.entries.GetUnchecked(base); - ASSERT_MSG(page_table.entries[base].ptr.Pointer(), + entry.Store(false, type, current_block, host_ptr); + ASSERT_MSG(page_table.entries[base].Pointer(), "memory mapping base yield a nullptr within the table"); base += 1; @@ -569,11 +571,11 @@ struct Memory::Impl { vaddr &= 0xffffffffffffULL; if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] { // Avoid adding any extra logic to this fast-path block - const uintptr_t raw_pointer = current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Raw(); - if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) [[likely]] { + const auto raw = current_page_table->entries[vaddr >> YUZU_PAGEBITS].Raw(); + if (auto pointer = Common::PageTable::PageEntryData::ExtractPointer(raw); pointer) [[likely]] { return reinterpret_cast<u8*>(pointer + vaddr); } else { - switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { + switch (static_cast<Common::PageType>(raw.type)) { case Common::PageType::Memory: ASSERT_MSG(false, "Mapped memory page without a pointer @ {:#016x}", vaddr); return nullptr; @@ -773,6 +775,7 @@ struct Memory::Impl { #else Common::HostMemory* host_buffer{}; #endif + std::atomic<u16> block_count = 0; }; Memory::Memory(Core::System& system_) : system{system_} { @@ -811,7 +814,7 @@ bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { if (page >= page_table.entries.size()) { return false; } - const auto [pointer, type] = page_table.entries[page].ptr.PointerType(); + const auto [pointer, type, _] = page_table.entries[page].PointerTypeBlock(); return pointer != 0 || type == Common::PageType::RasterizerCachedMemory || type == Common::PageType::DebugMemory; } |
