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:
parent
6184b8c0cb
commit
32020df8c0
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue