alcedo/kernel/arch/i386/paging.nim

75 lines
2.9 KiB
Nim

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)