diff --git a/kernel/arch/i386/gdt.nim b/kernel/arch/i386/gdt.nim new file mode 100644 index 0000000..1940792 --- /dev/null +++ b/kernel/arch/i386/gdt.nim @@ -0,0 +1,60 @@ +type + GDTEntry{.packed.} = object + limit_low: uint16 + base_low: uint16 + base_middle: uint8 + access: uint8 + granularity: uint8 + base_high: uint8 + GDTPointer{.packed.} = ptr object + limit: uint16 # Size of GDT + base: uint32 # GDT memory location + GDTEntries = ptr array[0..2, GDTEntry] + +var + gdt: GDTEntries + gp: GDTPointer + +let gpAddr = cast[uint32](addr(gp)) + +{.push stackTrace:off.} +proc gdtFlush(){.asmNoStackFrame, inline.} = + asm """ + lgdt [`gpAddr`] + mov %ax, 0x10 + mov %ds, %ax + mov %es, %ax + mov %fs, %ax + mov %gs, %ax + mov %ss, %ax + """ +{.pop.} + +proc gdtSetGate(num: int, base: uint16, limit: uint32, access: uint8, granularity: uint8) = + # Setup the descriptor base address + gdt[num].base_low = (base and 0xFFFF) + gdt[num].base_middle = (base shr 16) and 0xFF + gdt[num].base_high = (base shr 24) and 0xFF + + # Setup the descriptor limits + gdt[num].limit_low = (limit and 0xFFFF) + gdt[num].granularity = ((limit shr 16) and 0x0F) + + # Finally, set up the granularity and access flags + gdt[num].granularity = gdt[num].granularity or (granularity and 0xF0) + gdt[num].access = access + +proc gdtInstall*() = + gp.limit = uint16(sizeof(GDTEntry) * 3) - 1; + gp.base = cast[uint32](addr(gdt)); + + # NULL descriptor + gdtSetGate(0, 0, 0, 0, 0); + + # The second entry is our Code Segment + gdtSetGate(1, 0'u16, 0xFFFFFFFF'u32, 0x9A'u8, 0xCF'u8); + + # The third entry is our Data Segment + gdtSetGate(2, 0'u16, 0xFFFFFFFF'u32, 0x92'u8, 0xCF'u8); + + gdtFlush(); diff --git a/kernel/kernel.nim b/kernel/kernel.nim index 1f54d52..09a00fb 100644 --- a/kernel/kernel.nim +++ b/kernel/kernel.nim @@ -1,6 +1,7 @@ -import tty +import tty, gdt proc kernelMain() {.exportc: "kernel_main"}= + gdt.gdtInstall() terminalInitialize() terminalWrite("Hello World!\L") terminalWrite("MAX_INT:")