Browse Source

misc. changes

remotes/1785929830864685280/tmp_refs/heads/variable-page-size
Exverge 1 week ago
parent
commit
9f78e10db5
No known key found for this signature in database GPG Key ID: DAD399BCC5FB77E4
  1. 3
      src/common/host_memory.cpp
  2. 59
      src/core/hle/kernel/k_memory_manager.cpp
  3. 8
      src/core/hle/kernel/kernel.cpp
  4. 50
      src/core/memory.cpp
  5. 8
      src/dynarmic/src/dynarmic/interface/code_page.h

3
src/common/host_memory.cpp

@ -176,7 +176,8 @@ public:
// Check if we failed to allocate for direct-mapping, otherwise map normally // Check if we failed to allocate for direct-mapping, otherwise map normally
if (!virtual_base) { 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<u8*>(pfn_VirtualAlloc2 virtual_base = static_cast<u8*>(pfn_VirtualAlloc2
(process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0)); (process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0));
} }

59
src/core/hle/kernel/k_memory_manager.cpp

@ -8,6 +8,7 @@
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/settings.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "core/core.h" #include "core/core.h"
#include "core/device_memory.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, Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool,
Direction dir, bool unoptimized, bool random, KProcessAddress expected_vaddr) { 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 // Choose a heap based on our page size request
s32 heap_index = KPageHeap::GetAlignedBlockIndex(num_pages, Common::GuestHostAlignment); s32 heap_index = KPageHeap::GetAlignedBlockIndex(num_pages, Common::GuestHostAlignment);
R_UNLESS(0 <= heap_index, ResultOutOfMemory); 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; s32 min_index = 0;
for (s32 i = 0; i < static_cast<s32>(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<s32>(KPageHeap::NumMemoryBlockPageShifts); ++i) {
if (KPageHeap::GetBlockNumPages(i) >= Common::GuestHostAlignment) {
min_index = i;
break;
}
} }
} }
R_UNLESS(0 <= min_index, ResultOutOfMemory);
if (heap_index < min_index) { if (heap_index < min_index) {
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); const size_t pages_per_alloc = KPageHeap::GetBlockNumPages(index);
for (Impl* cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr; for (Impl* cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr;
cur_manager = this->GetNextManager(cur_manager, dir)) { 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. // Allocate a block.
KPhysicalAddress allocated_block = cur_manager->AllocateBlock(index, random); KPhysicalAddress allocated_block = cur_manager->AllocateBlock(index, random);
if (allocated_block == 0) { if (allocated_block == 0) {
break; 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); GetInteger(expected_vaddr) % Common::HostPageSize);
}
// Ensure we don't leak the block if we fail. // Ensure we don't leak the block if we fail.
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {

8
src/core/hle/kernel/kernel.cpp

@ -457,12 +457,12 @@ struct KernelCore::Impl {
GetInteger(kernel_region_start), kernel_region_size, KMemoryRegionType_Kernel)); GetInteger(kernel_region_start), kernel_region_size, KMemoryRegionType_Kernel));
// Setup the code region. // 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); 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); 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( ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
GetInteger(code_region_start), code_region_size, KMemoryRegionType_KernelCode)); GetInteger(code_region_start), code_region_size, KMemoryRegionType_KernelCode));

50
src/core/memory.cpp

@ -567,32 +567,34 @@ struct Memory::Impl {
return {false, false}; return {false, false};
} else { } else {
std::pair out = {false, false}; 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;
}
} }
} }
} }

8
src/dynarmic/src/dynarmic/interface/code_page.h

@ -9,16 +9,12 @@
namespace Dynarmic { namespace Dynarmic {
/// @brief Smallest valid page /// @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; constexpr inline uint64_t CODE_PAGE_SIZE = 0x1000;
#endif
struct CodePage { struct CodePage {
alignas(CODE_PAGE_SIZE) uint32_t inst[CODE_PAGE_SIZE / sizeof(uint32_t)]; alignas(CODE_PAGE_SIZE) uint32_t inst[CODE_PAGE_SIZE / sizeof(uint32_t)];
}; };
static_assert(sizeof(CodePage) == CODE_PAGE_SIZE);
} }
Loading…
Cancel
Save