struct PACKED PageDirectoryEntry
{
bool Present : 1;
bool ReadWrite : 1;
bool UserSuper : 1;
bool WriteThrough : 1;
bool CacheDisabled : 1;
bool Accessed : 1;
bool ignore0 : 1;
bool LargerPages : 1;
bool ingore1 : 1;
uint8_t Available : 3;
uint64_t Address : 52;
};
struct PageTable
{
PageDirectoryEntry entries [512];
} ALIGNED(0x1000);
void map_memory(PageTable* PML4, void* virtual_address, void* physical_address)
{
uint64_t vaddr = (uint64_t)virtual_address;
vaddr >>= 12;
auto P_i = vaddr & 0x1ff;
vaddr >>= 9;
auto PT_i = vaddr & 0x1ff;
vaddr >>= 9;
auto PD_i = vaddr & 0x1ff;
vaddr >>= 9;
auto PDP_i = vaddr & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
PDP = (PageTable*)EFIMemory::allocate(0x1000);
memset(PDP, 0, 0x1000);
PDE.Address = (uint64_t)PDP >> 12;
PDE.Present = true;
PDE.ReadWrite = true;
PML4->entries[PDP_i] = PDE;
}
else
{
PDP = (PageTable*)((uint64_t)PDE.Address << 12);
}
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
PD = (PageTable*)EFIMemory::allocate(0x1000);
memset(PD, 0, 0x1000);
PDE.Address = (uint64_t)PD >> 12;
PDE.Present = true;
PDE.ReadWrite = true;
PDP->entries[PD_i] = PDE;
}
else
{
PD = (PageTable*)((uint64_t)PDE.Address << 12);
}
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
PT = (PageTable*)EFIMemory::allocate(0x1000);
memset(PT, 0, 0x1000);
PDE.Address = (uint64_t)PT >> 12;
PDE.Present = true;
PDE.ReadWrite = true;
PD->entries[PT_i] = PDE;
}
else
{
PT = (PageTable*)((uint64_t)PDE.Address << 12);
}
PDE = PT->entries[P_i];
PDE.Address = (uint64_t)physical_address >> 12;
PDE.Present = true;
PDE.ReadWrite = true;
PT->entries[P_i] = PDE;
}
EFI_STATUS EFIAPI efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE* system_table)
{
PageTable* pml4 = nullptr;
system_table->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, (EFI_PHYSICAL_ADDRESS*)&pml4);
if(pml4 == nullptr)
return EFI_SUCCESS;
EFI_Memory& memory = efi_data.memory;
UINTN map_key = 0;
UINT32 descriptor_version = 0;
system_table->BootServices->GetMemoryMap(
&memory.map_size,
memory.map,
&map_key,
&memory.descriptor_size,
&descriptor_version
);
system_table->BootServices->AllocatePool(EfiLoaderData, memory.map_size, reinterpret_cast<void**>(&memory.map));
system_table->BootServices->GetMemoryMap(
&memory.map_size,
memory.map,
&map_key,
&memory.descriptor_size,
&descriptor_version
);
size_t num_of_map_entries = memory.map_size / memory.descriptor_size;
for (size_t entry = 0; entry < num_of_map_entries; entry++)
{
EFI_MEMORY_DESCRIPTOR* mem_desc = (EFI_MEMORY_DESCRIPTOR*)((uint64_t)memory.map + (entry * memory.descriptor_size));
for (size_t p = 0; p < mem_desc->NumberOfPages; p++)
{
void* addr = (void*)((uint64_t)mem_desc->PhysicalStart + (p * 0x1000));
map_memory(pml4, addr, addr);
}
}
system_table->BootServices->GetMemoryMap(
&memory.map_size,
memory.map,
&map_key,
&memory.descriptor_size,
&descriptor_version
);
system_table->BootServices->AllocatePool(EfiLoaderData, memory.map_size, reinterpret_cast<void**>(&memory.map));
system_table->BootServices->GetMemoryMap(
&memory.map_size,
memory.map,
&map_key,
&memory.descriptor_size,
&descriptor_version
);
system_table->BootServices->ExitBootServices(image_handle, map_key);
asm ("mov %0, %%cr3" : : "r" (pml4));