project64/Source/Common/MemoryManagement.cpp

133 lines
3.5 KiB
C++
Raw Normal View History

2021-04-12 09:41:28 +00:00
#include "MemoryManagement.h"
#ifdef _WIN32
2016-01-13 09:39:23 +00:00
#include <windows.h>
#else
#include <sys/mman.h>
#endif
2016-01-13 09:39:23 +00:00
#include "MemoryManagement.h"
2016-01-17 05:54:08 +00:00
static bool TranslateFromMemProtect(MEM_PROTECTION memProtection, int & OsMemProtection)
2016-01-13 09:39:23 +00:00
{
#ifdef _WIN32
2016-01-17 05:54:08 +00:00
switch (memProtection)
{
case MEM_NOACCESS: OsMemProtection = PAGE_NOACCESS; break;
case MEM_READONLY: OsMemProtection = PAGE_READONLY; break;
case MEM_READWRITE: OsMemProtection = PAGE_READWRITE; break;
case MEM_EXECUTE_READWRITE: OsMemProtection = PAGE_EXECUTE_READWRITE; break;
default:
return false;
}
#else
switch (memProtection)
{
case MEM_NOACCESS: OsMemProtection = PROT_NONE; break;
case MEM_READONLY: OsMemProtection = PROT_READ; break;
case MEM_READWRITE: OsMemProtection = PROT_READ | PROT_WRITE; break;
case MEM_EXECUTE_READWRITE: OsMemProtection = PROT_READ | PROT_WRITE | PROT_EXEC; break;
default:
return false;
}
#endif
2016-01-17 05:54:08 +00:00
return true;
2016-01-13 09:39:23 +00:00
}
#ifdef _WIN32
static bool TranslateToMemProtect(int OsMemProtection, MEM_PROTECTION & memProtection)
{
switch (OsMemProtection)
{
case PAGE_NOACCESS: memProtection = MEM_NOACCESS; break;
case PAGE_READONLY: memProtection = MEM_READONLY; break;
case PAGE_READWRITE: memProtection = MEM_READWRITE; break;
case PAGE_EXECUTE_READWRITE: memProtection = MEM_EXECUTE_READWRITE; break;
default:
return false;
}
return true;
}
#endif
2022-10-03 08:04:42 +00:00
void * AllocateAddressSpace(size_t size, void * base_address)
2016-01-13 09:39:23 +00:00
{
#ifdef _WIN32
return VirtualAlloc(base_address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS);
#else
2022-10-03 08:04:42 +00:00
void * ptr = mmap((void *)0, size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
{
2021-04-12 11:35:39 +00:00
return nullptr;
}
msync(ptr, size, MS_SYNC | MS_INVALIDATE);
return ptr;
#endif
2016-01-13 09:39:23 +00:00
}
2022-10-03 08:04:42 +00:00
bool FreeAddressSpace(void * addr, size_t size)
2016-01-13 09:39:23 +00:00
{
#ifdef _WIN32
size = 0; // Unused
2016-01-17 05:54:08 +00:00
return VirtualFree(addr, 0, MEM_RELEASE) != 0;
#else
msync(addr, size, MS_SYNC);
munmap(addr, size);
2016-11-27 20:23:12 +00:00
return true;
#endif
2016-01-13 09:39:23 +00:00
}
2022-10-03 08:04:42 +00:00
void * CommitMemory(void * addr, size_t size, MEM_PROTECTION memProtection)
2016-01-13 09:39:23 +00:00
{
2016-01-17 05:54:08 +00:00
int OsMemProtection;
if (!TranslateFromMemProtect(memProtection, OsMemProtection))
{
2021-04-12 11:35:39 +00:00
return nullptr;
2016-01-17 05:54:08 +00:00
}
#ifdef _WIN32
2016-01-17 05:54:08 +00:00
return VirtualAlloc(addr, size, MEM_COMMIT, OsMemProtection);
#else
void * ptr = mmap(addr, size, OsMemProtection, MAP_FIXED | MAP_SHARED | MAP_ANON, -1, 0);
msync(addr, size, MS_SYNC | MS_INVALIDATE);
return ptr;
#endif
2016-01-13 09:39:23 +00:00
}
2022-10-03 08:04:42 +00:00
bool DecommitMemory(void * addr, size_t size)
2016-01-13 09:39:23 +00:00
{
#ifdef _WIN32
2022-10-03 08:04:42 +00:00
return VirtualFree((void *)addr, size, MEM_DECOMMIT) != 0;
#else
// Instead of unmapping the address, we're just gonna trick
// the TLB to mark this as a new mapped area which, due to
// demand paging, will not be committed until used.
mmap(addr, size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
msync(addr, size, MS_SYNC | MS_INVALIDATE);
return true;
#endif
2016-01-13 09:39:23 +00:00
}
2022-10-03 08:04:42 +00:00
bool ProtectMemory(void * addr, size_t size, MEM_PROTECTION memProtection, MEM_PROTECTION * OldProtect)
2016-01-13 09:39:23 +00:00
{
2016-01-17 05:54:08 +00:00
int OsMemProtection;
if (!TranslateFromMemProtect(memProtection, OsMemProtection))
{
return false;
2016-01-17 05:54:08 +00:00
}
2016-01-13 09:39:23 +00:00
#ifdef _WIN32
2016-01-17 05:54:08 +00:00
DWORD OldOsProtect;
2016-01-13 09:39:23 +00:00
BOOL res = VirtualProtect(addr, size, OsMemProtection, &OldOsProtect);
2021-04-12 11:35:39 +00:00
if (OldProtect != nullptr)
2016-01-17 05:54:08 +00:00
{
if (!TranslateToMemProtect(OldOsProtect, *OldProtect))
{
2021-04-12 11:35:39 +00:00
return nullptr;
}
2016-01-17 05:54:08 +00:00
}
return res != 0;
#else
return mprotect(addr, size, OsMemProtection) == 0;
#endif
}