helos1/memory/paging_init.c

213 lines
9.1 KiB
C
Raw Normal View History

2021-10-10 14:11:45 +08:00
#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
}