How to use the Local Descriptor Table

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

How to use the Local Descriptor Table

Post by XCHG »

I am having doubts on how I should use the LDT and the LLDT instruction. I don't know if this is correct or not but here is my level of understanding about the subject. LLDT should be fed a segment selector into the GDT. The processor then looks into the GDT for the values that should be given to the LDTR. What Intel Manuals don't point out is what values should be put into the GDT and in what format? does the first WORD represent the length of the LDT or should it be a DWORD? any help is greatly appreciated.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Post by jnc100 »

All the info you need is in the Intel manuals.

E.g. Part 3, Section 3.5

Type field 0010b == LDT

The rest is just a standard system segment descriptor as described in section 3.4.5.
Hint: for system selectors (not code or data) clear the 'S' bit.

Regards,
John.
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

These are my LDT's properties:

Base Physical Address: 0x0010AE8C
Length in Bytes : 0x00000800


The function that I have coded puts the below values for the LDT's segment descriptor in the GDT:

DWORD#0 = 0xAE8C0800
DWORD#1 = 0x00409210

The segment selector that (for now) is chosen for the LDT in the GDT is 24. Then I try to do:

Code: Select all

LLDT    [24]
And right there, BAM! I get a GPF. Can someone tell me what I might be doing wrong?

The error that is reported by Bochs is:

Code: Select all

00002963012e[CPU0 ] fetch_raw_descriptor: GDT: index (ff57)1fea > limit (800)
Last edited by XCHG on Mon Apr 23, 2007 12:14 am, edited 1 time in total.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

** Warning: I think this is right, not validated yet. **

LLDT needs the address of the actual LDT, not just the segment descriptor.
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

Doesn't LLDT need the Segment Selector?
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Post by jnc100 »

I assume 24 is decimal, 0x18 in hex.

Try:

(Intel syntax)

Code: Select all

mov ax, 0x18
lldt ax
I think you're trying to load it with the value of whatever's stored at memory address 0x00000018.

Regards,
John.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

could you post the 'full' source because the error you explained got nothing to do widt LDT but GDT so me is confused.

i think you are right that you need the segment selector so it should be
lldt $24 or lldt $0x18
Author of COBOS
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

Okay I changed the LLDT invocation to:

Code: Select all

LLDT    AX
While the AX holds the segment selector of the LDT in the GDT and I am getting at least a more relevant error:

Code: Select all

00002963067e[CPU0 ] LLDT: doesn't point to an LDT descriptor!
I'm sorry that the code is not yet fully commented. I normally don't comment codes that do not work.

What I am doing in this code is that I first zero all entries in the LDT, check its length for accuracy (divisible by 8 and etc). I then start searching in the GDT for the first empty slot. After having found it, I keep its index (0..x) in EDX. Then I put the LDT's segment descriptor in the found spot in the GDT. Retrieve EDX again and multiply it by 8 to get the actual segment selector of the LDT in the GDT.

Code: Select all

  __InitializeLDT:
    ; Boolean __InitializeLDT (void* GDTR, void* LDTR); StdCall;
    PUSH    ECX
    PUSH    EDX
    PUSH    EDI
    PUSH    EBP
    MOV     EBP , ESP
    XOR     EAX , EAX
    MOV     EBP , ESP
    MOV     EDI , DWORD PTR [EBP + 0x18] ; LDTR
    MOV     ECX , DWORD PTR [EDI]
    TEST    ECX , ECX
    JNZ     .Continue1
    JMP     .EP
    
    ; The length should be divisible by 8
    .Continue1
    TEST    ECX , 0x00000007
    JZ      .Continue2
    JMP     .EP
    
    
    
    .Continue2:   
      PUSHFD
      CLD
      SHR     ECX , 0x00000003
      MOV     EDI , DWORD PTR [EDI + 0x04]
      REP     STOSD
      POPFD
    
    
    ; Now set the LDT Segment Descriptor in the Global Descriptor Table
    MOV     EDI , DWORD PTR [EBP + 0x14] ; GDTR
    MOV     ECX , DWORD PTR [EDI]
    AND     ECX , 0x0000FFFF
    JZ      .EP
    TEST    ECX , 0x00000007
    JNZ     .EP
    SHR     ECX , 0x00000003
    MOV     EDI , DWORD PTR [EDI + 0x02]
    XOR     EDX , EDX
    .FindFirstEmptyGDTEntry:
      MOV     EAX , DWORD PTR [EDI]
      OR      EAX , DWORD PTR [EDI + 0x08]
      JNZ     .FindNextGDTEntry
      
      ; We have found the empty GDT entry
      ; Now read the LDT entry from LDTR and put it into the current Segment Descriptor into the GDT
      PUSH    EDX
      MOV     ECX , DWORD PTR [EBP + 0x18]
      ; EDI = The Pointer to the empty slot in the GDT
      ; ECX = The pointer to the LDTR parameter
      
      ; First set the base and the limit of the LDT 31:0 in the GDT, DWORD#0
      MOV     EAX , DWORD PTR [ECX]        ; Limit
      MOV     EDX , DWORD PTR [ECX + 0x04] ; Base Address
      AND     EAX , 0x0000FFFF
      SHL     EDX , 0x00000010
      OR      EAX , EDX
      MOV     DWORD PTR [EDI] , EAX
      
      
      
      ; Now set the DWORD#1 of the GDT
      ; Base 31:24
      MOV     EAX , DWORD PTR [ECX + 0x04]
      MOV     EDX , EAX
      SHR     EDX , 0x00000010
      AND     EDX , 0x000000FF
      AND     EAX , 0xFF000000
      OR      EAX , EDX ; EAX = Base:31:24 and Base:23:16
      
      
      ; Segment Limit 19:16 in DWORD#1
      MOV     EDX , DWORD PTR [ECX]
      AND     EDX , 0x000F0000
      OR      EDX , 0x00409200
      OR      EAX , EDX
      MOV     DWORD PTR [EDI + 0x04], EAX
      
      
      
      
      POP     EDX
      MOV     EAX , EDX
      SHL     EAX , 0x00000003
      LLDT    AX
      JMP     .EP
      
      
      
      .FindNextGDTEntry:
        ADD     EDI , 0x00000008
        INC     EDX
        DEC     ECX
        JNZ     .FindFirstEmptyGDTEntry
        XOR     EAX , EAX

    .EP:
      POP     EBP
      POP     EDI
      POP     EDX
      POP     ECX
    RET   0x08
For clarity, I should point this out. I have defined a LDTR like this:

Code: Select all

  LDTR:
    DD (LDT_END - LDT)
    DD LDT
So the first DWORD is the length and the second is the base address of the LDT.

Any help would be appreciated.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

Holly Golly, I was setting the "S" bit of the second DWORD of the segment descriptor of the LDT in the GDT. So the LDT was becoming a Code/Data segment. I changed this:

Code: Select all

      ; Segment Limit 19:16 in DWORD#1
      MOV     EDX , DWORD PTR [ECX]
      AND     EDX , 0x000F0000
      OR      EDX , 0x00409200
      OR      EAX , EDX
      MOV     DWORD PTR [EDI + 0x04], EAX
To this:

Code: Select all

      ; Segment Limit 19:16 in DWORD#1
      MOV     EDX , DWORD PTR [ECX]
      AND     EDX , 0x000F0000
      OR      EDX , 0x00408200
      OR      EAX , EDX
      MOV     DWORD PTR [EDI + 0x04], EAX
And everything seems to be working fine. If that was the real problem then I must be a diungus because jnc100 actually pointed that out.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

Okay my problem is fixed. Thank you everyone for your help. Appreciations.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
Post Reply