Cleanup some arena functionality, fix some odd boot behavior, change array to pagemap-like structure for tracking dirty bits due to possible noncontinguous pages

This commit is contained in:
Jared M. White 2024-07-03 00:42:29 -05:00
parent 6184b8c0cb
commit 32020df8c0
5 changed files with 38 additions and 56 deletions

View File

@ -22,7 +22,7 @@ struct WindowsMemoryFunctions
void* m_address_UnmapViewOfFileEx = nullptr;
void* m_address_VirtualAlloc2 = nullptr;
void* m_address_MapViewOfFile3 = nullptr;
void* m_address_VirtualProtectEx = nullptr;
void* m_address_VirtualProtect = nullptr;
};
#endif
@ -118,7 +118,7 @@ public:
/// @param data Pointer to data to protect.
/// @param size Size of the protection.
///
bool WriteProtectMemoryRegion(void* data, size_t size);
bool WriteProtectMemoryRegion(u8* data, size_t size);
private:
#ifdef _WIN32

View File

@ -34,7 +34,7 @@ using PMapViewOfFile3 = PVOID(WINAPI*)(HANDLE FileMapping, HANDLE Process, PVOID
using PUnmapViewOfFileEx = BOOL(WINAPI*)(PVOID BaseAddress, ULONG UnmapFlags);
using PVirtualProtectEx = BOOL(WINAPI*)(HANDLE Process, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD* lpflOldProtect);
using PVirtualProtect = BOOL(WINAPI*)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
using PIsApiSetImplemented = BOOL(APIENTRY*)(PCSTR Contract);
@ -81,14 +81,14 @@ static bool InitWindowsMemoryFunctions(WindowsMemoryFunctions* functions)
functions->m_api_ms_win_core_memory_l1_1_6_handle.GetSymbolAddress("MapViewOfFile3FromApp");
void* const address_UnmapViewOfFileEx =
functions->m_kernel32_handle.GetSymbolAddress("UnmapViewOfFileEx");
void* const address_VirtualProtectEx =
functions->m_kernel32_handle.GetSymbolAddress("VirtualProtectEx");
void* const address_VirtualProtect =
functions->m_kernel32_handle.GetSymbolAddress("VirtualProtect");
if (address_VirtualAlloc2 && address_MapViewOfFile3 && address_UnmapViewOfFileEx)
{
functions->m_address_VirtualAlloc2 = address_VirtualAlloc2;
functions->m_address_MapViewOfFile3 = address_MapViewOfFile3;
functions->m_address_UnmapViewOfFileEx = address_UnmapViewOfFileEx;
functions->m_address_VirtualProtectEx = address_VirtualProtectEx;
functions->m_address_VirtualProtect = address_VirtualProtect;
return true;
}
@ -215,11 +215,10 @@ void MemArena::ReleaseMemoryRegion()
}
}
bool MemArena::WriteProtectMemoryRegion(void* data, size_t size)
bool MemArena::WriteProtectMemoryRegion(u8* data, size_t size)
{
PDWORD lpflOldProtect = 0;
return static_cast<PVirtualProtectEx>(m_memory_functions.m_address_VirtualProtectEx)(
nullptr, data, size, FILE_MAP_READ, &lpflOldProtect);
DWORD lpflOldProtect = 0;
return static_cast<PVirtualProtect>(m_memory_functions.m_address_VirtualProtect)(data, size, PAGE_READONLY, &lpflOldProtect);
}
WindowsMemoryRegion* MemArena::EnsureSplitRegionForMapping(void* start_address, size_t size)

View File

@ -51,31 +51,32 @@ std::optional<size_t> MemoryManager::GetDirtyPageIndexFromAddress(u64 address)
{
size_t page_size = Common::PageSize();
size_t page_mask = page_size - 1;
u64 page_base = address & ~page_mask;
size_t index = 0;
bool foundPageBase = false;
return (address & ~page_mask) >> 12;
}
void MemoryManager::WriteProtectMemory()
{
for (const PhysicalMemoryRegion& region : m_physical_regions)
{
if (!region.active)
continue;
uintptr_t region_address = reinterpret_cast<uintptr_t>(*region.out_pointer);
if (page_base >= region_address && page_base <= region_address + region.size)
size_t page_size = Common::PageSize();
for (size_t i = 0; i < region.size; i += page_size)
{
foundPageBase = true;
index += std::floorl((page_base - region_address) / page_size);
break;
bool change_protection = m_arena.WriteProtectMemoryRegion(
(*region.out_pointer) + i, page_size);
if (!change_protection)
{
PanicAlertFmt(
"Memory::Init(): Failed to write protect for this block of memory at 0x{:08X}.",
reinterpret_cast<u64>(*region.out_pointer));
}
std::optional<size_t> index =
GetDirtyPageIndexFromAddress(reinterpret_cast<u64>(*region.out_pointer + i));
if (index.has_value())
m_dirty_pages[index.value()] = false;
}
index += (region.size / page_size);
}
if (!foundPageBase)
{
PanicAlertFmt("Unknown PTE in Dirty Bit Lookup: {:#010x}", page_base);
return std::nullopt;
}
return index;
}
void MemoryManager::InitMMIO(bool is_wii)
@ -104,25 +105,7 @@ void MemoryManager::InitMMIO(bool is_wii)
void MemoryManager::InitDirtyPages()
{
for (const PhysicalMemoryRegion& region : m_physical_regions)
{
if (!region.active)
continue;
size_t page_size = Common::PageSize();
for (size_t i = 0; i < region.size; i += page_size)
{
DWORD lpflOldProtect = 0;
bool change_protection =
VirtualProtect((*region.out_pointer) + i, page_size, PAGE_READONLY, &lpflOldProtect);
if (!change_protection)
{
PanicAlertFmt(
"Memory::Init(): Failed to write protect for this block of memory at 0x{:08X}.",
reinterpret_cast<u64>(*region.out_pointer));
}
m_dirty_pages.push_back(false);
}
}
WriteProtectMemory();
}
void MemoryManager::Init()
@ -388,7 +371,7 @@ void MemoryManager::DoState(PointerWrap& p)
if (IsPageDirty(reinterpret_cast<uintptr_t>(&m_ram[i])))
{
p.DoArray(m_ram + i, page_count);
i += page_count + 1;
i += page_count;
}
}
for (size_t i = 0; i < current_l1_cache_size; i++)
@ -396,7 +379,7 @@ void MemoryManager::DoState(PointerWrap& p)
if (IsPageDirty(reinterpret_cast<uintptr_t>(&m_l1_cache[i])))
{
p.DoArray(m_l1_cache + i, page_count);
i += page_count + 1;
i += page_count;
}
}
p.DoMarker("Memory RAM");
@ -407,7 +390,7 @@ void MemoryManager::DoState(PointerWrap& p)
if (IsPageDirty(reinterpret_cast<uintptr_t>(&m_fake_vmem[i])))
{
p.DoArray(m_fake_vmem + i, page_count);
i += page_count + 1;
i += page_count;
}
}
}
@ -419,7 +402,7 @@ void MemoryManager::DoState(PointerWrap& p)
if (IsPageDirty(reinterpret_cast<uintptr_t>(&m_exram[i])))
{
p.DoArray(m_exram + i, page_count);
i += page_count + 1;
i += page_count;
}
}
}
@ -692,8 +675,7 @@ void MemoryManager::SetPageDirtyBit(uintptr_t address, size_t size, bool dirty)
void MemoryManager::ResetDirtyPages()
{
for (int i = 0; i < m_dirty_pages.size(); i++)
m_dirty_pages[i] = false;
WriteProtectMemory();
}
} // namespace Memory

View File

@ -135,7 +135,7 @@ public:
void SetPageDirtyBit(uintptr_t address, size_t size, bool dirty);
void ResetDirtyPages();
std::vector<u8>& GetDirtyPages() { return m_dirty_pages; }
std::map<u64, u8>& GetDirtyPages() { return m_dirty_pages; }
// Templated functions for byteswapped copies.
template <typename T>
@ -261,9 +261,10 @@ private:
Core::System& m_system;
std::vector<u8> m_dirty_pages;
std::map<u64, u8> m_dirty_pages;
std::optional<size_t> GetDirtyPageIndexFromAddress(u64 address);
void WriteProtectMemory();
void InitMMIO(bool is_wii);
};
} // namespace Memory

View File

@ -72,9 +72,9 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
size_t page_size = Common::PageSize();
size_t page_mask = page_size - 1;
u64 page_base = fault_address & ~page_mask;
u64 page_index = fault_address & page_mask;
DWORD lpflOldProtect = 0;
bool change_protection = VirtualProtect(reinterpret_cast<u8*>(page_base), page_size, PAGE_READONLY, &lpflOldProtect);
bool change_protection = VirtualProtect(reinterpret_cast<u8*>(fault_address), page_size - page_index, PAGE_READWRITE, &lpflOldProtect);
if (!change_protection)
{
return EXCEPTION_CONTINUE_SEARCH;