Created
April 13, 2017 23:09
-
-
Save exjam/b96143ffc81caec9cdbc6b22334834f8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <algorithm> | |
#include <cstdint> | |
#include <vector> | |
class MemoryMap | |
{ | |
enum PhysicalMemoryType | |
{ | |
Invalid, | |
MEM1, | |
MEM2, | |
}; | |
static constexpr uint32_t MEM1BaseAddress = 0; | |
static constexpr uint32_t MEM1EndAddress = 0x01FFFFFF; | |
static constexpr uint32_t MEM2BaseAddress = 0x10000000; | |
static constexpr uint32_t MEM2EndAddress = 0x8FFFFFFF; | |
struct MemoryRange | |
{ | |
uint32_t start; | |
uint64_t size; | |
}; | |
struct VirtualMemoryMap | |
{ | |
PhysicalMemoryType type; | |
uint32_t vAddr; | |
uint32_t pAddr; | |
uint32_t size; | |
}; | |
public: | |
MemoryMap() | |
{ | |
} | |
void reserve() | |
{ | |
// Reserve 32mb MEM1 and 2gb MEM2 physical memory | |
mMem1 = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, SEC_RESERVE | PAGE_READWRITE, 0, 1024 * 1024 * 32, NULL); | |
mMem2 = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, SEC_RESERVE | PAGE_READWRITE, 0, 1024 * 1024 * 1024 * 2, NULL); | |
// Reserve 4gb virtual address space | |
mVirtualBase = 0; | |
for (auto n = 32; n < 64; n++) { | |
auto baseAddress = reinterpret_cast<uint8_t *>(1ull << n); | |
auto addr = VirtualAlloc(baseAddress, 0x100000000, MEM_RESERVE, PAGE_NOACCESS); | |
if (addr) { | |
mVirtualBase = reinterpret_cast<uintptr_t>(addr); | |
break; | |
} | |
} | |
mReservedMemory.push_back({ 0, 0x100000000 }); | |
} | |
PhysicalMemoryType getPhysicalMemoryType(uint32_t physicalAddress) | |
{ | |
if (physicalAddress >= MEM1BaseAddress && physicalAddress <= MEM1EndAddress) { | |
return PhysicalMemoryType::MEM1; | |
} else if (physicalAddress >= MEM2BaseAddress && physicalAddress <= MEM2EndAddress) { | |
return PhysicalMemoryType::MEM2; | |
} | |
return PhysicalMemoryType::Invalid; | |
} | |
bool mapMemory(uint32_t virtualAddress, uint32_t physicalAddress, uint32_t size) | |
{ | |
// First we have to break a hole in our reserved address space! | |
auto foundHole = false; | |
auto physicalMemoryType = getPhysicalMemoryType(physicalAddress); | |
if (physicalMemoryType == PhysicalMemoryType::Invalid) { | |
// Invalid physical memory address | |
return false; | |
} | |
for (auto itr = mReservedMemory.begin(); itr != mReservedMemory.end(); ++itr) { | |
auto &reservation = *itr; | |
if (virtualAddress >= reservation.start && size <= reservation.size) { | |
VirtualFree(reinterpret_cast<LPVOID>(mVirtualBase + reservation.start), reservation.size, MEM_RELEASE); | |
if (size == reservation.size) { | |
// Consumed whole reservation | |
mReservedMemory.erase(itr); | |
} else if (virtualAddress == reservation.start) { | |
// Consumed from start of reservation | |
reservation.start = virtualAddress + size; | |
reservation.size -= size; | |
VirtualAlloc(reinterpret_cast<LPVOID>(mVirtualBase + reservation.start), reservation.size, MEM_RESERVE, PAGE_NOACCESS); | |
} else if (virtualAddress + size == reservation.start + reservation.size) { | |
// Consumed from end of reservation | |
reservation.size -= size; | |
VirtualAlloc(reinterpret_cast<LPVOID>(mVirtualBase + reservation.start), reservation.size, MEM_RESERVE, PAGE_NOACCESS); | |
} else { | |
// Consumed in middle of reservation | |
auto newReservation = MemoryRange {}; | |
newReservation.start = virtualAddress + size; | |
newReservation.size = (reservation.start + reservation.size) - newReservation.start; | |
VirtualAlloc(reinterpret_cast<LPVOID>(mVirtualBase + newReservation.start), newReservation.size, MEM_RESERVE, PAGE_NOACCESS); | |
reservation.size = virtualAddress - reservation.start; | |
VirtualAlloc(reinterpret_cast<LPVOID>(mVirtualBase + reservation.start), reservation.size, MEM_RESERVE, PAGE_NOACCESS); | |
mReservedMemory.insert(itr + 1, newReservation); | |
} | |
foundHole = true; | |
break; | |
} | |
} | |
if (!foundHole) { | |
// Virtual address space not free! | |
return false; | |
} | |
// Now map physical to virtual! | |
auto virtualMemoryMap = VirtualMemoryMap { }; | |
virtualMemoryMap.type = physicalMemoryType; | |
virtualMemoryMap.vAddr = virtualAddress; | |
virtualMemoryMap.pAddr = physicalAddress; | |
virtualMemoryMap.size = size; | |
void *view = nullptr; | |
if (physicalMemoryType == PhysicalMemoryType::MEM1) { | |
view = MapViewOfFileEx(mMem1, FILE_MAP_ALL_ACCESS, 0, | |
physicalAddress - MEM1BaseAddress, | |
size, | |
reinterpret_cast<LPVOID>(mVirtualBase + virtualAddress)); | |
} else { | |
view = MapViewOfFileEx(mMem2, FILE_MAP_ALL_ACCESS, 0, | |
physicalAddress - MEM2BaseAddress, | |
size, | |
reinterpret_cast<LPVOID>(mVirtualBase + virtualAddress)); | |
} | |
mMappedMemory.insert(std::upper_bound(mMappedMemory.begin(), | |
mMappedMemory.end(), | |
virtualMemoryMap, | |
[](const auto &m1, const auto &m1) {return m1.vAddr < m2.vAddr; }), | |
virtualMemoryMap); | |
return true; | |
} | |
private: | |
HANDLE mMem1; | |
HANDLE mMem2; | |
uintptr_t mVirtualBase; | |
std::vector<MemoryRange> mReservedMemory; | |
std::vector<VirtualMemoryMap> mMappedMemory; | |
}; | |
int main(int, char**) | |
{ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment