Page 2 of 2

Re: wtf?

Posted: Sat Jun 15, 2013 10:06 pm
by Mikemk
BMW wrote:
m12 wrote:
BMW wrote:

Code: Select all

disable_interrupts();
__asm__ __volatile__("lgdt %0" : : "m" (*ptr));
enable_interrupts();
That is an excellent way to crash.
Works fine for me.

Please explain...?
In some cases (probably most), it'll continue working. However, GCC expects/requires the descriptors to remain the same, and if your cpu reloads the descriptors (don't flame me, I've seen this this happen) on lgdt, then it might cause undefined behavior. Grub2 seems to load kernels to 0x10 instead of 0x8, and so if this happens, and your kernel code segment is 0x8, then you will get a #GP, a #DF, and finally a triple fault/cpu reset.

Personally, in cases involving segment register changes, stack changes, gdt, ect. I find it safer/easier to put a callable function in an external file.

Re: GDT Entry

Posted: Sun Jun 16, 2013 3:23 am
by BMW
Ok, but I am not actually changing the GDT, just relocating it due to virtual memory mapping. (and maybe adding entries for user mode).

Re: GDT Entry

Posted: Sun Jun 16, 2013 8:16 am
by Griwes
In some cases (probably most), it'll continue working. However, GCC expects/requires the descriptors to remain the same, and if your cpu reloads the descriptors (don't flame me, I've seen this this happen) on lgdt, then it might cause undefined behavior. Grub2 seems to load kernels to 0x10 instead of 0x8, and so if this happens, and your kernel code segment is 0x8, then you will get a #GP, a #DF, and finally a triple fault/cpu reset.
You surely do know that you have to reload the segment register for any change to actually happen? If lgdt reloaded segments, it would be dead retarded and unusable. And you surely do know no modern compiler messes with segments, so it totally doesn't matter?

Re: GDT Entry

Posted: Sun Jun 16, 2013 2:01 pm
by bluemoon
LGDT only update the CPU's GPT pointer, it does not invalidate and has no effect on current descriptor caches unless a reload of such register is performed.
So you probably want to reload DS/ES/SS/CS(via IRET) before re-enable interrupt.

Re: GDT Entry

Posted: Mon Jun 17, 2013 5:06 pm
by Mikemk
Griwes wrote:
In some cases (probably most), it'll continue working. However, GCC expects/requires the descriptors to remain the same, and if your cpu reloads the descriptors (don't flame me, I've seen this this happen) on lgdt, then it might cause undefined behavior. Grub2 seems to load kernels to 0x10 instead of 0x8, and so if this happens, and your kernel code segment is 0x8, then you will get a #GP, a #DF, and finally a triple fault/cpu reset.
You surely do know that you have to reload the segment register for any change to actually happen? If lgdt reloaded segments, it would be dead retarded and unusable. And you surely do know no modern compiler messes with segments, so it totally doesn't matter?
Didnt i say, "don't flame me, i've seen it happen"?

Re: GDT Entry

Posted: Tue Jun 18, 2013 6:42 pm
by Kazinsal
If an x86 CPU is reloading descriptors on LGDT, it's a very poor implementation of the x86 architecture.
Vol. 2A 3-457 wrote:

Code: Select all

IF OperandSize = 16
    THEN 
        GDTR(Limit) ← SRC[0:15];
        GDTR(Base) ← SRC[16:47] AND 00FFFFFFH; 
ELSE IF 32-bit Operand Size
    THEN
        GDTR(Limit) ← SRC[0:15];
        GDTR(Base) ← SRC[16:47]; 
    FI;
ELSE IF 64-bit Operand Size (* In 64-Bit Mode *)
    THEN
        GDTR(Limit) ← SRC[0:15];
        GDTR(Base) ← SRC[16:79]; 
    FI;
FI;
That's the official pseudocode of how LGDT works. I don't see "reload segment registers" anywhere in there.

Re: GDT Entry

Posted: Wed Jun 19, 2013 10:07 am
by Mikemk
Blacklight wrote:If an x86 CPU is reloading descriptors on LGDT, it's a very poor implementation of the x86 architecture.
I agree.