alcedo/kernel/arch/i386/gdt.nim

77 lines
2.2 KiB
Nim

import serial
type
GDTEntry{.packed.} = object
limit_low: uint16
base_low: uint16
base_middle: uint8
access: uint8
flags_and_limit_mid: uint8
base_high: uint8
GDTPointer{.packed.} = object
limit: uint16 # Size of GDT
base: uint32 # GDT memory location
AccessByte = uint8
Flags = uint8
GDT{.packed.} = object
descriptor: GDTPointer
entries: array[0..2, GDTEntry]
const
gdtAddress: uint32 = 0x00000800
gdt = cast[ptr GDT](gdtAddress)
{.push stackTrace:off.}
proc gdtFlush(){.inline,asmNoStackFrame.} =
asm """
cli
lgdtl [`0x00000800`]
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
ljmp $0x08, $next
next:
"""
{.pop.}
proc gdtSetGate(num: int, base: uint16, limit: uint32, access: AccessByte, flags: Flags) =
# Setup the descriptor base address
gdt.entries[num].base_low = uint16(base and 0xFFFF)
gdt.entries[num].base_middle = uint8((base shr 16) and 0xFF)
gdt.entries[num].base_high = uint8((base shr 24) and 0xFF)
# Setup the descriptor limits
gdt.entries[num].limit_low = uint16(limit and 0xFFFF)
gdt.entries[num].flags_and_limit_mid = uint8(((limit shr 16) and 0x0F) or flags)
gdt.entries[num].access = access
proc createAccessByte(priv: range[0..3], directionConform: bool, readWrite: bool): AccessByte =
result = 0b10011000'u8 # Present and executable bit
result = result or (uint8(priv) shl 5)
if directionConform:
result = result or 0b00000100'u8
if readWrite:
result = result or 0b00000010'u8
proc createFlags(granularity: bool, size: bool): Flags =
if granularity:
result = result or 0b10000000'u8
if size:
result = result or 0b01000000'u8
proc gdtInstall*() =
gdt.descriptor.limit = uint16(sizeof(GDTEntry) * gdt.entries.len) - 1;
gdt.descriptor.base = cast[uint32](gdt.entries.addr)
# NULL descriptor
gdtSetGate(0, 0, 0, 0, 0);
# The second entry is our Code Segment
gdtSetGate(1, 0'u16, 0xFFFFFFFF'u32, createAccessByte(0, false, true), createFlags(true, true));
# The third entry is our Data Segment
gdtSetGate(2, 0'u16, 0xFFFFFFFF'u32, createAccessByte(0, false, true), createFlags(true, true));
serial.write("Flushing GDT.\L")
gdtFlush()