Fix memory manager crashing upon second reboot

This commit is contained in:
ergo720 2019-10-10 16:49:39 +02:00 committed by RadWolfie
parent f1255cb89b
commit 446b7efc29
2 changed files with 32 additions and 25 deletions

View File

@ -397,6 +397,8 @@ void VMManager::RestorePersistentMemory()
void VMManager::SavePersistentMemory() void VMManager::SavePersistentMemory()
{ {
PersistedMemory* persisted_mem; PersistedMemory* persisted_mem;
size_t num_persisted_ptes;
std::vector<PMMPTE> cached_persisted_ptes;
HANDLE handle; HANDLE handle;
LPVOID addr; LPVOID addr;
PMMPTE PointerPte; PMMPTE PointerPte;
@ -405,31 +407,7 @@ void VMManager::SavePersistentMemory()
Lock(); Lock();
handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, m_NumPersistentPtes * PAGE_SIZE + m_NumPersistentPtes * 4 * 2 + sizeof(PersistedMemory), "PersistentMemory"); num_persisted_ptes = 0;
if (handle == NULL) {
CxbxKrnlCleanup("Couldn't persist memory! CreateFileMapping failed with error 0x%08X", GetLastError());
return;
}
addr = MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (addr == nullptr) {
CxbxKrnlCleanup("Couldn't persist memory! MapViewOfFile failed with error 0x%08X", GetLastError());
return;
}
persisted_mem = (PersistedMemory*)addr;
persisted_mem->NumOfPtes = m_NumPersistentPtes;
if (xboxkrnl::LaunchDataPage != xbnullptr) {
persisted_mem->LaunchFrameAddresses[0] = (VAddr)xboxkrnl::LaunchDataPage;
EmuLog(LOG_LEVEL::INFO, "Persisted LaunchDataPage\n");
}
if (xboxkrnl::AvSavedDataAddress != xbnullptr) {
persisted_mem->LaunchFrameAddresses[1] = (VAddr)xboxkrnl::AvSavedDataAddress;
EmuLog(LOG_LEVEL::INFO, "Persisted Framebuffer\n");
}
i = 0;
PointerPte = GetPteAddress(CONTIGUOUS_MEMORY_BASE); PointerPte = GetPteAddress(CONTIGUOUS_MEMORY_BASE);
if (m_MmLayoutRetail) { if (m_MmLayoutRetail) {
@ -442,15 +420,46 @@ void VMManager::SavePersistentMemory()
while (PointerPte <= EndingPte) while (PointerPte <= EndingPte)
{ {
if (PointerPte->Hardware.Valid != 0 && PointerPte->Hardware.Persist != 0) { if (PointerPte->Hardware.Valid != 0 && PointerPte->Hardware.Persist != 0) {
persisted_mem->Data[i] = GetVAddrMappedByPte(PointerPte); cached_persisted_ptes.push_back(PointerPte);
persisted_mem->Data[m_NumPersistentPtes + i] = PointerPte->Default; num_persisted_ptes++;
memcpy(&persisted_mem->Data[m_NumPersistentPtes * 2 + i * ONE_KB], (void*)(persisted_mem->Data[i]), PAGE_SIZE);
i++;
} }
PointerPte++; PointerPte++;
} }
assert(i == m_NumPersistentPtes); handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, num_persisted_ptes * PAGE_SIZE + num_persisted_ptes * 4 * 2 + sizeof(PersistedMemory), "PersistentMemory");
if (handle == NULL) {
CxbxKrnlCleanup("Couldn't persist memory! CreateFileMapping failed with error 0x%08X", GetLastError());
return;
}
addr = MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (addr == nullptr) {
CxbxKrnlCleanup("Couldn't persist memory! MapViewOfFile failed with error 0x%08X", GetLastError());
return;
}
persisted_mem = (PersistedMemory*)addr;
persisted_mem->NumOfPtes = num_persisted_ptes;
if (xboxkrnl::LaunchDataPage != xbnullptr) {
persisted_mem->LaunchFrameAddresses[0] = (VAddr)xboxkrnl::LaunchDataPage;
EmuLog(LOG_LEVEL::INFO, "Persisted LaunchDataPage\n");
}
if (xboxkrnl::AvSavedDataAddress != xbnullptr) {
persisted_mem->LaunchFrameAddresses[1] = (VAddr)xboxkrnl::AvSavedDataAddress;
EmuLog(LOG_LEVEL::INFO, "Persisted Framebuffer\n");
}
i = 0;
for (const auto &pte : cached_persisted_ptes) {
persisted_mem->Data[i] = GetVAddrMappedByPte(pte);
persisted_mem->Data[num_persisted_ptes + i] = pte->Default;
memcpy(&persisted_mem->Data[num_persisted_ptes * 2 + i * ONE_KB], (void *)(persisted_mem->Data[i]), PAGE_SIZE);
i++;
}
assert(i == num_persisted_ptes);
ipc_send_gui_update(IPC_UPDATE_GUI::VM_PERSIST_MEM, 1); ipc_send_gui_update(IPC_UPDATE_GUI::VM_PERSIST_MEM, 1);
@ -617,7 +626,6 @@ void VMManager::PersistMemory(VAddr addr, size_t Size, bool bPersist)
while (PointerPte <= EndingPte) while (PointerPte <= EndingPte)
{ {
PointerPte->Hardware.Persist = 1; PointerPte->Hardware.Persist = 1;
m_NumPersistentPtes++;
PointerPte++; PointerPte++;
} }
} }
@ -625,7 +633,6 @@ void VMManager::PersistMemory(VAddr addr, size_t Size, bool bPersist)
while (PointerPte <= EndingPte) while (PointerPte <= EndingPte)
{ {
PointerPte->Hardware.Persist = 0; PointerPte->Hardware.Persist = 0;
m_NumPersistentPtes--;
PointerPte++; PointerPte++;
} }
} }

View File

@ -84,7 +84,8 @@ typedef enum _MemoryRegionType
COUNTRegion, COUNTRegion,
}MemoryRegionType; }MemoryRegionType;
#pragma warning(push)
#pragma warning(disable: 4200)
/* struct used to save the persistent memory between reboots */ /* struct used to save the persistent memory between reboots */
typedef struct _PersistedMemory typedef struct _PersistedMemory
{ {
@ -92,6 +93,7 @@ typedef struct _PersistedMemory
VAddr LaunchFrameAddresses[2]; VAddr LaunchFrameAddresses[2];
uint32_t Data[]; uint32_t Data[];
}PersistedMemory; }PersistedMemory;
#pragma warning(pop)
/* VMManager class */ /* VMManager class */
@ -171,8 +173,6 @@ class VMManager : public PhysicalMemory
DWORD m_AllocationGranularity = 0; DWORD m_AllocationGranularity = 0;
// number of bytes reserved with XBOX_MEM_RESERVE by XbAllocateVirtualMemory // number of bytes reserved with XBOX_MEM_RESERVE by XbAllocateVirtualMemory
size_t m_VirtualMemoryBytesReserved = 0; size_t m_VirtualMemoryBytesReserved = 0;
// number of persisted ptes between quick reboots
size_t m_NumPersistentPtes = 0;
// same as AllocateContiguousMemory, but it allows to allocate beyond m_MaxContiguousPfn // same as AllocateContiguousMemory, but it allows to allocate beyond m_MaxContiguousPfn
VAddr AllocateContiguousMemoryInternal(PFN_COUNT NumberOfPages, PFN LowestPfn, PFN HighestPfn, PFN PfnAlignment, DWORD Perms); VAddr AllocateContiguousMemoryInternal(PFN_COUNT NumberOfPages, PFN LowestPfn, PFN HighestPfn, PFN PfnAlignment, DWORD Perms);