vm: workaround bigger native page size for 4k pages

Always allocate full memory block if native page size > 4k
This commit is contained in:
Nekotekina 2022-05-31 21:03:36 +03:00 committed by Ivan
parent b0ccd2a8a0
commit 422246825b
1 changed files with 23 additions and 10 deletions

View File

@ -609,7 +609,7 @@ namespace vm
thread_ctrl::emergency_exit("vm::reservation_escape"); thread_ctrl::emergency_exit("vm::reservation_escape");
} }
static void _page_map(u32 addr, u8 flags, u32 size, utils::shm* shm, std::pair<const u32, std::pair<u32, std::shared_ptr<utils::shm>>>* (*search_shm)(vm::block_t* block, utils::shm* shm)) static void _page_map(u32 addr, u8 flags, u32 size, utils::shm* shm, u64 bflags, std::pair<const u32, std::pair<u32, std::shared_ptr<utils::shm>>>* (*search_shm)(vm::block_t* block, utils::shm* shm))
{ {
perf_meter<"PAGE_MAP"_u64> perf0; perf_meter<"PAGE_MAP"_u64> perf0;
@ -626,6 +626,9 @@ namespace vm
} }
} }
// If native page size exceeds 4096, don't map native pages (expected to be always mapped in this case)
const bool is_noop = bflags & page_size_4k && utils::c_page_size > 4096;
// Lock range being mapped // Lock range being mapped
_lock_main_range_lock(range_allocation, addr, size); _lock_main_range_lock(range_allocation, addr, size);
@ -694,7 +697,10 @@ namespace vm
if (~flags & page_readable) if (~flags & page_readable)
prot = utils::protection::no; prot = utils::protection::no;
if (!shm) if (is_noop)
{
}
else if (!shm)
{ {
utils::memory_protect(g_base_addr + addr, size, prot); utils::memory_protect(g_base_addr + addr, size, prot);
} }
@ -703,7 +709,7 @@ namespace vm
fmt::throw_exception("Memory mapping failed - blame Windows (addr=0x%x, size=0x%x, flags=0x%x)", addr, size, flags); fmt::throw_exception("Memory mapping failed - blame Windows (addr=0x%x, size=0x%x, flags=0x%x)", addr, size, flags);
} }
if (flags & page_executable) if (flags & page_executable && !is_noop)
{ {
// TODO (dead code) // TODO (dead code)
utils::memory_commit(g_exec_addr + addr * 2, size * 2); utils::memory_commit(g_exec_addr + addr * 2, size * 2);
@ -800,7 +806,7 @@ namespace vm
return true; return true;
} }
static u32 _page_unmap(u32 addr, u32 max_size, utils::shm* shm) static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm)
{ {
perf_meter<"PAGE_UNm"_u64> perf0; perf_meter<"PAGE_UNm"_u64> perf0;
@ -809,6 +815,9 @@ namespace vm
fmt::throw_exception("Invalid arguments (addr=0x%x, max_size=0x%x)", addr, max_size); fmt::throw_exception("Invalid arguments (addr=0x%x, max_size=0x%x)", addr, max_size);
} }
// If native page size exceeds 4096, don't unmap native pages (always mapped)
const bool is_noop = bflags & page_size_4k && utils::c_page_size > 4096;
// Determine deallocation size // Determine deallocation size
u32 size = 0; u32 size = 0;
bool is_exec = false; bool is_exec = false;
@ -868,7 +877,11 @@ namespace vm
ppu_remove_hle_instructions(addr, size); ppu_remove_hle_instructions(addr, size);
// Actually unmap memory // Actually unmap memory
if (!shm) if (is_noop)
{
std::memset(g_sudo_addr + addr, 0, size);
}
else if (!shm)
{ {
utils::memory_protect(g_base_addr + addr, size, utils::protection::no); utils::memory_protect(g_base_addr + addr, size, utils::protection::no);
std::memset(g_sudo_addr + addr, 0, size); std::memset(g_sudo_addr + addr, 0, size);
@ -881,7 +894,7 @@ namespace vm
#endif #endif
} }
if (is_exec) if (is_exec && !is_noop)
{ {
utils::memory_decommit(g_exec_addr + addr * 2, size * 2); utils::memory_decommit(g_exec_addr + addr * 2, size * 2);
@ -1045,7 +1058,7 @@ namespace vm
} }
// Map "real" memory pages; provide a function to search for mirrors with private member access // Map "real" memory pages; provide a function to search for mirrors with private member access
_page_map(page_addr, flags, page_size, shm.get(), [](vm::block_t* _this, utils::shm* shm) _page_map(page_addr, flags, page_size, shm.get(), this->flags, [](vm::block_t* _this, utils::shm* shm)
{ {
auto& map = (_this->m.*block_map)(); auto& map = (_this->m.*block_map)();
@ -1127,7 +1140,7 @@ namespace vm
{ {
// Special path for whole-allocated areas allowing 4k granularity // Special path for whole-allocated areas allowing 4k granularity
m_common = std::make_shared<utils::shm>(size); m_common = std::make_shared<utils::shm>(size);
m_common->map_critical(vm::base(addr), utils::protection::no); m_common->map_critical(vm::base(addr), this->flags & page_size_4k && utils::c_page_size > 4096 ? utils::protection::rw : utils::protection::no);
m_common->map_critical(vm::get_super_ptr(addr)); m_common->map_critical(vm::get_super_ptr(addr));
} }
} }
@ -1143,7 +1156,7 @@ namespace vm
{ {
const auto next = std::next(it); const auto next = std::next(it);
const auto size = it->second.first; const auto size = it->second.first;
_page_unmap(it->first, size, it->second.second.get()); _page_unmap(it->first, size, this->flags, it->second.second.get());
it = next; it = next;
} }
@ -1328,7 +1341,7 @@ namespace vm
} }
// Unmap "real" memory pages // Unmap "real" memory pages
ensure(size == _page_unmap(addr, size, found->second.second.get())); ensure(size == _page_unmap(addr, size, this->flags, found->second.second.get()));
// Clear stack guards // Clear stack guards
if (flags & stack_guarded) if (flags & stack_guarded)