Skip to content

Instantly share code, notes, and snippets.

@exjam
Created April 13, 2017 23:09
Show Gist options
  • Save exjam/b96143ffc81caec9cdbc6b22334834f8 to your computer and use it in GitHub Desktop.
Save exjam/b96143ffc81caec9cdbc6b22334834f8 to your computer and use it in GitHub Desktop.
#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