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();