diff --git a/kernel/arch/i386/gdt.nim b/kernel/arch/i386/gdt.nim index 1940792..f72df60 100644 --- a/kernel/arch/i386/gdt.nim +++ b/kernel/arch/i386/gdt.nim @@ -1,25 +1,33 @@ +import serial + type GDTEntry{.packed.} = object limit_low: uint16 base_low: uint16 base_middle: uint8 access: uint8 - granularity: uint8 + flags_and_limit_mid: uint8 base_high: uint8 - GDTPointer{.packed.} = ptr object + GDTPointer{.packed.} = object limit: uint16 # Size of GDT base: uint32 # GDT memory location - GDTEntries = ptr array[0..2, GDTEntry] + GDTEntries = array[0..2, GDTEntry] + AccessByte = uint8 + Flags = uint8 var gdt: GDTEntries gp: GDTPointer - -let gpAddr = cast[uint32](addr(gp)) + gpAddr: uint32 {.push stackTrace:off.} -proc gdtFlush(){.asmNoStackFrame, inline.} = +proc gdtFlush(){.inline.} = + gpAddr = cast[uint32](gp.addr) + serial.write("GDPointer Address: ") + serial.write(gpAddr) + serial.newLine() asm """ + cli lgdt [`gpAddr`] mov %ax, 0x10 mov %ds, %ax @@ -30,7 +38,7 @@ proc gdtFlush(){.asmNoStackFrame, inline.} = """ {.pop.} -proc gdtSetGate(num: int, base: uint16, limit: uint32, access: uint8, granularity: uint8) = +proc gdtSetGate(num: int, base: uint16, limit: uint32, access: AccessByte, flags: Flags) = # Setup the descriptor base address gdt[num].base_low = (base and 0xFFFF) gdt[num].base_middle = (base shr 16) and 0xFF @@ -38,23 +46,36 @@ proc gdtSetGate(num: int, base: uint16, limit: uint32, access: uint8, granularit # 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].flags_and_limit_mid = ((limit shr 16) and 0x0F) or flags gdt[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*() = - gp.limit = uint16(sizeof(GDTEntry) * 3) - 1; - gp.base = cast[uint32](addr(gdt)); + gp.limit = uint16(sizeof(GDTEntry) * gdt.len) - 1; + gp.base = cast[uint32](gdt.addr) + serial.write("GDT Address: ") + serial.write(gp.base) + serial.newLine() + # NULL descriptor + gdtSetGate(0, 0, 0, 0, 0); - # 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 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(); + # 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();