Ok, So I've just wasted a day trawling through examples of setting up a Global Descriptor Table, now the structure of the table is a mess, but easy enough to build if you follow the docs, the trouble begins when you want to give this information to the CPU.
The sample code seem to vary between AT&T and intel syntax (and various different assemblers) and, honestly I find it a bit confusing... my only real clue which it being used is when I see a operand I think should be a destination being used as a source. I'm a 68k guy, so AT&T syntax wins for me.
Anyway, enough ranting. Here is the inline x86 for gcc so others can use it:
Code: Select all
uint32_t ptr = (uint32_t)&gdt_ptr; // get the pointer to your GDT table as a 32bit int
asm volatile("movl %0,%%eax \n\t" //load the pointer int eax
"lgdt (%%eax) \n\t" //Set the CPU GDT pointer to your table
"movl %%cr0,%%eax \n\t" // Get the value of the cr0 register
"or $0x1, %%al \n\t" // set PE (Protection Enable) bit in CR0 (Control Register 0)
"movl %%eax, %%cr0\n\t" // reload the cr0 register with the PE bit set.
//Segments confuse the hell out of me so hopefully this code will make them go away
//16 being the offset to the supervisor Data segment in my GDT
"movw $0x10, %%ax \n\t" // load 16 into the ax register
"movw %%ax, %%ds \n\t" // copy 16 into all of the segment registers
"movw %%ax, %%es \n\t"
"movw %%ax, %%fs \n\t"
"movw %%ax, %%gs \n\t"
"movw %%ax, %%ss \n\t"
"ljmp $0x08,$boing\n\t" // apparently this loads the CS segment register with 8
// 8 being the offset to the Supervisor code segment in my GDT
"boing:" : : "r" (ptr) : "eax"); // tells gcc that %0 = ptr and that I use eax as a temp
}