Page 1 of 1

How to use the Local Descriptor Table

Posted: Sun Apr 22, 2007 4:43 am
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.

Posted: Sun Apr 22, 2007 5:24 pm
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.

Posted: Mon Apr 23, 2007 12:10 am
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)

Posted: Mon Apr 23, 2007 12:14 am
by pcmattman
** Warning: I think this is right, not validated yet. **

LLDT needs the address of the actual LDT, not just the segment descriptor.

Posted: Mon Apr 23, 2007 12:16 am
by XCHG
Doesn't LLDT need the Segment Selector?

Posted: Mon Apr 23, 2007 12:17 am
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.

Posted: Mon Apr 23, 2007 12:21 am
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

Posted: Mon Apr 23, 2007 12:31 am
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.

Posted: Mon Apr 23, 2007 12:39 am
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.

Posted: Mon Apr 23, 2007 3:04 am
by XCHG
Okay my problem is fixed. Thank you everyone for your help. Appreciations.