213 lines
9.1 KiB
C
213 lines
9.1 KiB
C
|
|
#include "../main.h"
|
|
#include "memory.h"
|
|
#include "../runtime/panic_assert.h"
|
|
#include "../runtime/stdio.h"
|
|
#include "../graphics/graphics.h"
|
|
#include "../kernel/kmain.h"
|
|
#include "../interrupt/interrupt.h"
|
|
#include "../execformat/pe/reloc.h"
|
|
void execformat_pe_ReadSystemHeader(execformat_pe_PortableExecutable *pe);
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "paging_internal.h"
|
|
|
|
|
|
EFI_MEMORY_DESCRIPTOR *efiMemoryMap;
|
|
UINTN efiMemoryMapSize;
|
|
UINTN efiMemoryMapKey;
|
|
UINTN efiDescriptorSize;
|
|
UINT32 efiDescriptorVertion;
|
|
|
|
uint64_t paging_TotalBytes, paging_UsableBytes;
|
|
bool paging_SupportExecuteDisable;
|
|
uint64_t paging_EndPhysicalAddress; // past-the-end marker (and length) for physical memory
|
|
int paging_EndPhysicalPage; // past-the-end for physical pages (EndPhysicalAddress/SYSTEM_PAGE_SIZE)
|
|
uint64_t paging_PML4Table[512] ALIGNED(4096); // Kernel-mode virtual memory paging directory pointer table (Level 4 paging)
|
|
uint64_t paging_LoaderCodeAddress, paging_LoaderCodeSize; // physical address for loader code section
|
|
int paging_LoaderCodePageCount; // page count for loader code section
|
|
|
|
void runtime_InitPaging() {
|
|
// TODO Obtain Execute Disable support status instead of assumpting its existence
|
|
paging_SupportExecuteDisable = true;
|
|
|
|
// obtain the UEFI memory mapping
|
|
EFI_STATUS status;
|
|
|
|
efiMemoryMapSize = 0;
|
|
efiMemoryMap = NULL;
|
|
status = efiBootServices->GetMemoryMap(
|
|
&efiMemoryMapSize,
|
|
efiMemoryMap,
|
|
&efiMemoryMapKey,
|
|
&efiDescriptorSize,
|
|
&efiDescriptorVertion);
|
|
assert(status == EFI_BUFFER_TOO_SMALL && "What? An empty buffer is not too small?");
|
|
|
|
efiMemoryMapSize += 2 * sizeof(EFI_MEMORY_DESCRIPTOR);
|
|
efiMemoryMap = (EFI_MEMORY_DESCRIPTOR *)efiMalloc(efiMemoryMapSize);
|
|
assert(efiMemoryMap && "efiMemoryMap allocate failed");
|
|
status = efiBootServices->GetMemoryMap(
|
|
&efiMemoryMapSize,
|
|
efiMemoryMap,
|
|
&efiMemoryMapKey,
|
|
&efiDescriptorSize,
|
|
&efiDescriptorVertion);
|
|
assert(!EFI_ERROR(status) && "GetMemoryMap() with buffer allocated failed");
|
|
|
|
io_Printf(" .text: [%08x-%08x] len=%d (%d pages)\n", link_TextStart, link_TextEnd, link_TextEnd - link_TextStart, roundUpToPageCount(link_TextEnd - link_TextStart));
|
|
io_Printf(" .data: [%08x-%08x] len=%d (%d pages)\n", link_DataStart, link_DataEnd, link_DataEnd - link_DataStart, roundUpToPageCount(link_DataEnd - link_DataStart));
|
|
io_Printf(".rodata: [%08x-%08x] len=%d (%d pages)\n", link_RodataStart, link_RodataEnd, link_RodataEnd - link_RodataStart, roundUpToPageCount(link_RodataEnd - link_RodataStart));
|
|
io_Printf(" .bss: [%08x-%08x] len=%d (%d pages)\n\n", link_BssStart, link_BssEnd, link_BssEnd - link_BssStart, roundUpToPageCount(link_BssEnd - link_BssStart));
|
|
|
|
// iterate the listing, accumlate counters and print info
|
|
paging_LoaderCodeAddress = paging_TotalBytes = paging_UsableBytes = 0;
|
|
memset(paging_physical_Bitmap, 0xff, sizeof(paging_physical_Bitmap));
|
|
io_WriteConsoleASCII("EFI Memory mapping:\n");
|
|
for (EFI_MEMORY_DESCRIPTOR *entry = efiMemoryMap;
|
|
(char *)entry < (char *)efiMemoryMap + efiMemoryMapSize;
|
|
entry = NEXT_MEMORY_DESCRITOR(entry, efiDescriptorSize) {
|
|
io_Printf(
|
|
" [%08x-%08x] -> [%08x] %s (%d)\n",
|
|
entry->PhysicalStart,
|
|
entry->PhysicalStart + entry->NumberOfPages * SYSTEM_PAGE_SIZE,
|
|
entry->VirtualStart,
|
|
memoryTypeName(entry->Type),
|
|
entry->Type);
|
|
paging_TotalBytes += SYSTEM_PAGE_SIZE * entry->NumberOfPages;
|
|
if (entry->Type == EfiConventionalMemory) {
|
|
// TODO include EfiBootServicesCode/Data as usable
|
|
paging_physical_BitmapWriteZero(
|
|
entry->PhysicalStart / SYSTEM_PAGE_SIZE,
|
|
entry->PhysicalStart / SYSTEM_PAGE_SIZE + entry->NumberOfPages);
|
|
paging_UsableBytes += SYSTEM_PAGE_SIZE * entry->NumberOfPages;
|
|
} else // page unusable
|
|
/*paging_physical_BitmapWriteOne(
|
|
entry->PhysicalStart / SYSTEM_PAGE_SIZE,
|
|
entry->PhysicalStart / SYSTEM_PAGE_SIZE + entry->NumberOfPages);*/
|
|
;
|
|
if (entry->Type == EfiLoaderCode) {
|
|
assert(!paging_LoaderCodeAddress && "Two EfiLoaderCode mappings at the same time");
|
|
paging_LoaderCodeAddress = entry->PhysicalStart;
|
|
paging_LoaderCodeSize = entry->NumberOfPages * SYSTEM_PAGE_SIZE;
|
|
paging_LoaderCodePageCount = entry->NumberOfPages;
|
|
}
|
|
if (paging_EndPhysicalAddress < entry->PhysicalStart + entry->NumberOfPages * SYSTEM_PAGE_SIZE)
|
|
paging_EndPhysicalAddress = entry->PhysicalStart + entry->NumberOfPages * SYSTEM_PAGE_SIZE;
|
|
}
|
|
paging_EndPhysicalPage = paging_EndPhysicalAddress / SYSTEM_PAGE_SIZE;
|
|
|
|
io_Printf(
|
|
" Total memory: %llu (%.2lf MB, %.2lf GB), EndPhyAddr %08llx\n",
|
|
paging_TotalBytes,
|
|
paging_TotalBytes / 1024.0 / 1024.0,
|
|
paging_TotalBytes / 1024.0 / 1024.0 / 1024.0,
|
|
paging_EndPhysicalAddress);
|
|
io_Printf(
|
|
"Usable memory: %llu (%.2lf MB, %.2lf GB)\n",
|
|
paging_UsableBytes,
|
|
paging_UsableBytes / 1024.0 / 1024.0,
|
|
paging_UsableBytes / 1024.0 / 1024.0 / 1024.0);
|
|
|
|
io_PauseForKeystroke();
|
|
|
|
assert(paging_LoaderCodeAddress && "EfiLoaderCode mapping not found");
|
|
|
|
io_WriteConsoleASCII("Mapping kernel memory:\n");
|
|
// map kernel code
|
|
io_Printf(" .Text... %d 4K pages\n",roundUpToPageCount(link_TextEnd-link_TextStart));
|
|
paging_map_Page( // map .text
|
|
(uint64_t)link_TextStart,
|
|
KERNEL_CODE_VIRTUAL + ((uint64_t)link_TextStart - paging_LoaderCodeAddress),
|
|
roundUpToPageCount(link_TextEnd - link_TextStart),
|
|
MAP_PROT_READ | MAP_PROT_EXEC);
|
|
io_Printf(" .Data... %d 4K pages\n",roundUpToPageCount(link_DataEnd-link_DataStart));
|
|
paging_map_Page( // map .data
|
|
(uint64_t)link_DataStart,
|
|
KERNEL_CODE_VIRTUAL + ((uint64_t)link_DataStart - paging_LoaderCodeAddress),
|
|
roundUpToPageCount(link_DataEnd - link_DataStart),
|
|
MAP_PROT_READ | MAP_PROT_WRITE);
|
|
io_Printf(" .Rodata... %d 4K pages\n",roundUpToPageCount(link_RodataEnd-link_RodataStart));
|
|
paging_map_Page( // map .rodata
|
|
(uint64_t)link_RodataStart,
|
|
KERNEL_CODE_VIRTUAL + ((uint64_t)link_RodataStart - paging_LoaderCodeAddress),
|
|
roundUpToPageCount(link_RodataEnd - link_RodataStart),
|
|
MAP_PROT_READ);
|
|
io_Printf(" .Bss... %d 4K pages\n",roundUpToPageCount(link_BssEnd-link_BssStart));
|
|
paging_map_Page( // map .bss
|
|
(uint64_t)link_BssStart,
|
|
KERNEL_CODE_VIRTUAL + ((uint64_t)link_BssStart - paging_LoaderCodeAddress),
|
|
roundUpToPageCount(link_BssEnd - link_BssStart),
|
|
MAP_PROT_READ | MAP_PROT_WRITE);
|
|
//paging_map_Page(paging_LoaderCodeAddress,KERNEL_CODE_VIRTUAL,paging_LoaderCodePageCount,MAP_PROT_READ|MAP_PROT_WRITE|MAP_PROT_EXEC);
|
|
|
|
// map other VM data
|
|
io_Printf(" Framebuffer... %d 2M pages\n",roundUpToPageCount2M(graphics_FramebufferSize));
|
|
paging_map_Page2M( // map the framebuffer output
|
|
(uint64_t)graphics_DeviceFramebuffer,
|
|
KERNEL_FRAMEBUFFER_MAPPING,
|
|
roundUpToPageCount2M(graphics_FramebufferSize),
|
|
MAP_PROT_READ | MAP_PROT_WRITE);
|
|
io_Printf(" Physical... %d 2M pages\n",roundUpToPageCount2M(paging_EndPhysicalAddress));
|
|
paging_map_Page2M( // map the physical memory
|
|
0,
|
|
0,
|
|
roundUpToPageCount2M(paging_EndPhysicalAddress),
|
|
MAP_PROT_READ | MAP_PROT_WRITE | MAP_PROT_EXEC);
|
|
io_Printf(" Stack\n");
|
|
paging_map_Page(paging_physical_AllocateOneFrame(),KERNEL_STACK_END_VIRTUAL-SYSTEM_PAGE_SIZE,1,MAP_PROT_READ|MAP_PROT_WRITE);
|
|
/*paging_map_Page2M( // stack, allocate a fresh new 2M
|
|
paging_physical_AllocateOneFrame2M(),
|
|
KERNEL_STACK_END_VIRTUAL - KERNEL_STACK_INITIAL_SIZE,
|
|
KERNEL_STACK_INITIAL_SIZE / SYSTEM_PAGE_2M_SIZE,
|
|
MAP_PROT_READ | MAP_PROT_WRITE);*/
|
|
kMain_StackPosition = KERNEL_STACK_END_VIRTUAL;
|
|
/*paging_map_PageAllocated(
|
|
KERNEL_MISC_MAPPING,
|
|
roundUpToPageCount(KERNEL_MISC_SIZE),
|
|
MAP_PROT_READ|MAP_PROT_WRITE);*/
|
|
io_Printf(" Misc... %d 2M pages\n",roundUpToPageCount2M(KERNEL_MISC_SIZE));
|
|
paging_map_PageAllocated2M( // misc data
|
|
KERNEL_MISC_MAPPING,
|
|
roundUpToPageCount2M(KERNEL_MISC_SIZE),
|
|
MAP_PROT_READ|MAP_PROT_WRITE);
|
|
//paging_map_PageAllocated(KERNEL_HEAP_VIRTUAL,512,MAP_PROT_READ|MAP_PROT_WRITE);
|
|
|
|
io_WriteConsoleASCII("Mapping completed\n");
|
|
|
|
|
|
|
|
// woohoo byebye!
|
|
efiBootServices->ExitBootServices(efiImageHandle, efiMemoryMapKey);
|
|
io_WriteConsoleASCII("Goodbye BootServices!\n");
|
|
|
|
// so now we're in unmanaged mode, we need to set up heap and stack, and jump to the new entry point kMain_Init.
|
|
// disable interrupts asap
|
|
asm volatile("cli":::"memory");
|
|
interrupt_Enabled=false;
|
|
|
|
// set the new virtual memory mapping
|
|
if (paging_SupportExecuteDisable)
|
|
paging_modeswitch_4LevelPagingNX(paging_PML4Table, 0);
|
|
else
|
|
paging_modeswitch_4LevelPaging(paging_PML4Table, 0);
|
|
graphics_DeviceFramebuffer = (void *)KERNEL_FRAMEBUFFER_MAPPING;
|
|
io_WriteConsoleASCII("Virtual Memory mapping switched\n");
|
|
|
|
// relocate the hardcoded symbols
|
|
execformat_pe_PortableExecutable pe;
|
|
execformat_pe_ReadSystemHeader(&pe);
|
|
execformat_pe_BaseRelocate(&pe, (void *)link_RelocStart, (void *)link_RelocEnd, paging_LoaderCodeAddress, KERNEL_CODE_VIRTUAL);
|
|
|
|
io_WriteConsoleASCII("Relocation OK\n");
|
|
|
|
// find the symbol kMain_Init
|
|
//uint64_t target_kmain = KERNEL_CODE_VIRTUAL + ((uint64_t)kMain_Init - paging_LoaderCodeAddress);
|
|
// call it, once and for all
|
|
//((kMainType)target_kmain)();
|
|
kMain_Init();
|
|
__builtin_unreachable(); // execution cannot reach here
|
|
}
|