import serial type PageDirectoryEntry = uint32 PageTableEntry = uint32 PageDirectory = array[1024, PageDirectoryEntry] PageTable = array[1024, PageTableEntry] const blankPageDirectory: PageDirectoryEntry = 0x00000002 var kernelMemoryStart{.importc: "_kernel_start"}: uint32 kernelMemoryEnd{.importc: "_kernel_end"}: uint32 proc kernelMemoryStartAddress(): uint32 = cast[uint32](kernelMemoryStart.addr) proc kernelMemoryEndAddress(): uint32 = cast[uint32](kernelMemoryEnd.addr) var pageDirectory: ptr PageDirectory pageTable0{.exportc, codegenDecl: "$# $# __attribute__((aligned(0x1000)))".}: PageTable proc createEntry(address: uint32, present: bool = false, readWrite: bool = false, userAccessible: bool = false, writeThrough: bool = false, disableCache: bool = false): uint32 = result = address and 0xFFFFF000'u32 # Set attributes section to zero if present: result = result or 0b1 if readWrite: result = result or 0b10 if userAccessible: result = result or 0b100 if writeThrough: result = result or 0b1000 if disableCache: result = result or 0b10000 proc createDirectory(address: uint32, present: bool = false, readWrite: bool = false, userAccessible: bool = false, writeThrough: bool = false, disableCache: bool = false, pageSize: bool = false): uint32 = var checkAddress = address if pageSize: checkAddress = checkAddress and 0xFFFF0000'u32 result = createEntry(address, present, readWrite, userAccessible, writeThrough, disableCache) if pageSize: result = result or 0b10000000 proc loadPageDirectory(address: uint32){.inline.} = serial.writeLine("Loading paging data") asm """ mov %%cr3, %%eax ::"a"(`address`) """ # Converts a physical to a virtual address for the kernel proc toVirtual(address: uint32): uint32 = result = address + 0xC0000000'u32 # Converts a physical to a virtual address for the kernel proc toPhysical(address: uint32): uint32 = result = address - 0xC0000000'u32 # Each page starts from a multiple of 0x400000 769 proc init*() = serial.writeLine("Initialising paging tables and directories.") var pagingAddress: uint32 = 0 # Find the bootstrapped page directory asm """ mov %%cr3, %%eax :"=a"(`pagingAddress`) """ pageDirectory = cast[ptr PageDirectory](toVirtual(pagingAddress)) for i in 0..767: pageDirectory[][i] = blankPageDirectory var pages: uint = uint(int(kernelMemoryEndAddress() - 0xC0000000'u32) / 0x1000) serial.write("Pages:") serial.writeLine(pages) # Assign VGA memory area to 0xC0000000 pageTable0[0] = createEntry(address = 0xB8000, readWrite = true, present = true) # Assign kernel memory pages to 0xC0100000+ for i in 256..pages: pageTable0[i] = createEntry(address = uint32(i) * 0x1000, readWrite = true, present = true) pageDirectory[][768] = createDirectory(address = toPhysical(cast[uint32](pageTable0.addr)), readWrite = true, present = true) for i in 769..1023: pageDirectory[][i] = blankPageDirectory loadPageDirectory(pagingAddress)