From 9f78e10db50a063f7016d1ce700384c206dddaec Mon Sep 17 00:00:00 2001 From: Exverge Date: Tue, 4 Aug 2026 10:36:35 -0400 Subject: [PATCH] misc. changes --- src/common/host_memory.cpp | 3 +- src/core/hle/kernel/k_memory_manager.cpp | 59 +++++++++++-------- src/core/hle/kernel/kernel.cpp | 8 +-- src/core/memory.cpp | 50 ++++++++-------- .../src/dynarmic/interface/code_page.h | 8 +-- 5 files changed, 69 insertions(+), 59 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 7853be9ce3..59942ee391 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -176,7 +176,8 @@ public: // Check if we failed to allocate for direct-mapping, otherwise map normally if (!virtual_base) { - LOG_WARNING(HW_Memory, "Failed to allocate within 39-bit address space, direct mapping is not supported"); + // TODO: force disable NCE + LOG_ERROR(HW_Memory, "Failed to allocate within 39-bit address space, direct mapping is not supported"); virtual_base = static_cast(pfn_VirtualAlloc2 (process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0)); } diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index e614b26bff..bf22e0257d 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -8,6 +8,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/settings.h" #include "common/scope_exit.h" #include "core/core.h" #include "core/device_memory.h" @@ -248,20 +249,25 @@ KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, siz Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, KProcessAddress expected_vaddr) { + // Should we align all virtual page offsets to their backing page offsets? + // Necessary for fastmem on non-4KiB page size systems + const bool fix_addr = expected_vaddr != 0 && Settings::IsFastmemEnabled(); + // Choose a heap based on our page size request s32 heap_index = KPageHeap::GetAlignedBlockIndex(num_pages, Common::GuestHostAlignment); R_UNLESS(0 <= heap_index, ResultOutOfMemory); - // Every block we use has to have the same or greater alignment than the host page size, - // so we have to determine the smallest heap index we can use and use that. s32 min_index = 0; - for (s32 i = 0; i < static_cast(KPageHeap::NumMemoryBlockPageShifts); ++i) { - if (KPageHeap::GetBlockNumPages(i) >= Common::GuestHostAlignment) { - min_index = i; - break; + if (fix_addr) { + // Every block we use has to have the same or greater alignment than the host page size, + // so we have to determine the smallest heap index we can use and use that. + for (s32 i = 0; i < static_cast(KPageHeap::NumMemoryBlockPageShifts); ++i) { + if (KPageHeap::GetBlockNumPages(i) >= Common::GuestHostAlignment) { + min_index = i; + break; + } } } - R_UNLESS(0 <= min_index, ResultOutOfMemory); if (heap_index < min_index) { heap_index = min_index; @@ -283,34 +289,39 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, const size_t pages_per_alloc = KPageHeap::GetBlockNumPages(index); for (Impl* cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr; cur_manager = this->GetNextManager(cur_manager, dir)) { - while (num_pages > 0 && (num_pages >= pages_per_alloc || index == min_index)) { + while (num_pages >= pages_per_alloc) { // Allocate a block. KPhysicalAddress allocated_block = cur_manager->AllocateBlock(index, random); if (allocated_block == 0) { break; } - const size_t host_page_off = GetInteger(expected_vaddr) % Common::HostPageSize; + KPhysicalAddress start = allocated_block; + size_t used_pages = pages_per_alloc; + if (fix_addr) { + const size_t host_page_off = GetInteger(expected_vaddr) % Common::HostPageSize; - // Cut off the start of the page to match expected_vaddr. - const size_t cut_pages = host_page_off >> PageBits; - const size_t remainder = pages_per_alloc - cut_pages; - const size_t used_pages = std::min(num_pages, remainder); - // Cut off end of block if needed - const size_t tail_pages = remainder - used_pages; + // Cut off the start of the page to match expected_vaddr. + const size_t cut_pages = host_page_off >> PageBits; + const size_t remainder = pages_per_alloc - cut_pages; - const KPhysicalAddress start = allocated_block + (cut_pages << PageBits); + // Cut off end of block if needed + used_pages = std::min(num_pages, remainder); + const size_t tail_pages = remainder - used_pages; - // Free the unused blocks. - if (cut_pages > 0) { - cur_manager->Free(allocated_block, cut_pages); - } - if (tail_pages > 0) { - cur_manager->Free(start + (used_pages << PageBits), tail_pages); - } + start = allocated_block + (cut_pages << PageBits); + + // Free the unused blocks. + if (cut_pages > 0) { + cur_manager->Free(allocated_block, cut_pages); + } + if (tail_pages > 0) { + cur_manager->Free(start + (used_pages << PageBits), tail_pages); + } - ASSERT(GetInteger(start) % Common::HostPageSize == + ASSERT(GetInteger(start) % Common::HostPageSize == GetInteger(expected_vaddr) % Common::HostPageSize); + } // Ensure we don't leak the block if we fail. ON_RESULT_FAILURE_2 { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b1d6518e5a..d25ac37df4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -457,12 +457,12 @@ struct KernelCore::Impl { GetInteger(kernel_region_start), kernel_region_size, KMemoryRegionType_Kernel)); // Setup the code region. - const size_t CodeRegionAlign = PageSize; - const KVirtualAddress code_region_start = + constexpr size_t CodeRegionAlign = PageSize; + constexpr KVirtualAddress code_region_start = Common::AlignDown(GetInteger(code_start_virt_addr), CodeRegionAlign); - const KVirtualAddress code_region_end = + constexpr KVirtualAddress code_region_end = Common::AlignUp(GetInteger(code_end_virt_addr), CodeRegionAlign); - const size_t code_region_size = code_region_end - code_region_start; + constexpr size_t code_region_size = code_region_end - code_region_start; ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert( GetInteger(code_region_start), code_region_size, KMemoryRegionType_KernelCode)); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index acb122f003..7f453a11ca 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -567,32 +567,34 @@ struct Memory::Impl { return {false, false}; } else { std::pair out = {false, false}; - // keep track of mappings that are unaligned to host page size - if (auto off = base % Common::GuestHostAlignment; off != 0) { - // using `block` here for storage vs. keeping it in another set is a hack to save memory; - // it'll never gets used as a direct value, just as a marker by GetSpan, - // and the value we input here should never be the same so we don't have to worry about GetSpan - // returning the wrong value - auto e = base - off; - - for (u64 i = 0; i < off; ++i, ++e) { - if (page_table.entries[e].addr == 0 && page_table.entries[e].block == 0) { - page_table.entries[e].block = (GetInteger(target) >> YUZU_PAGEBITS) - off + i; - } else { - // Either an irregular mapping or unaligned one; either way we'll just skip this anyway - out.first = true; + if (Settings::IsFastmemEnabled()) { + // keep track of mappings that are unaligned to host page size + if (auto off = base & (Common::GuestHostAlignment - 1); off != 0) { + // using `block` here for storage vs. keeping it in a set is a hack to save memory; + // it'll never gets used as a direct value, just as a marker by GetSpan, + // and the value we input here should never be the same so we don't have to worry about GetSpan + // returning the wrong value + auto e = base - off; + + for (u64 i = 0; i < off; ++i, ++e) { + if (page_table.entries[e].addr == 0 && page_table.entries[e].block == 0) { + page_table.entries[e].block = (GetInteger(target) >> YUZU_PAGEBITS) - off + i; + } else { + // Either an irregular mapping or unaligned one; either way we'll just skip this anyway + out.first = true; + } } } - } - if (auto off = end & (Common::GuestHostAlignment - 1); off != 0) { - auto remaining = Common::GuestHostAlignment - off; - auto e = end; - - for (u64 i = 0; i < remaining; ++i, ++e) { - if (page_table.entries[e].addr == 0 && page_table.entries[e].block == 0) { - page_table.entries[e].block = (GetInteger(target) >> YUZU_PAGEBITS) + size + i; - } else { - out.second = true; + if (auto off = end & (Common::GuestHostAlignment - 1); off != 0) { + auto remaining = Common::GuestHostAlignment - off; + auto e = end; + + for (u64 i = 0; i < remaining; ++i, ++e) { + if (page_table.entries[e].addr == 0 && page_table.entries[e].block == 0) { + page_table.entries[e].block = (GetInteger(target) >> YUZU_PAGEBITS) + size + i; + } else { + out.second = true; + } } } } diff --git a/src/dynarmic/src/dynarmic/interface/code_page.h b/src/dynarmic/src/dynarmic/interface/code_page.h index e6e0fe8e28..b215cb603f 100644 --- a/src/dynarmic/src/dynarmic/interface/code_page.h +++ b/src/dynarmic/src/dynarmic/interface/code_page.h @@ -9,16 +9,12 @@ namespace Dynarmic { /// @brief Smallest valid page -/// -// TODO: can we base this off the system page size without using the heap? -#if defined(__APPLE__) && defined(ARCHITECTURE_arm64) -constexpr inline uint64_t CODE_PAGE_SIZE = 0x4000; -#else constexpr inline uint64_t CODE_PAGE_SIZE = 0x1000; -#endif struct CodePage { alignas(CODE_PAGE_SIZE) uint32_t inst[CODE_PAGE_SIZE / sizeof(uint32_t)]; }; +static_assert(sizeof(CodePage) == CODE_PAGE_SIZE); + }