Page 1 of 2

LTR doesn't like my TSS descriptor.

Posted: Thu May 06, 2004 11:11 am
by mr. x2
I'm feeding LTR with 0x20 (ti = 0, dpl = 0, index = 4).
My descriptor at entry 4 in the GDT is 0x4A800068 (00000000000000000000000000000000 1001010100000000000000001101000b).

The error from bochs is:
LTR: doesn't point to an available TSS descriptor!

There may be two's of stuff, but this code is just experimenting.

Code: Select all

int InitializeMemManager() {
        SetupGDTDescriptor(0, 0x0, 0x0, 0x0, 0x0, 0x0);
        SetupGDTDescriptor(1, 0x0, 0xFFFFF, GDT_DPL0|GDT_READABLE|GDT_SEG_CODE|GDT_PRESENT, GDT_286_CALL_GATE, 1);
        SetupGDTDescriptor(2, 0x0, 0xFFFFF, GDT_DPL0|GDT_READABLE|GDT_SEG_DATA|GDT_PRESENT, GDT_286_CALL_GATE, 1);

        InitTask(0, task1);

        SetGDTDesc(4, getTasks(), sizeof(tss_seg), 0x9, SEG_DESC_ATTR_PRESENT|SEG_DESC_ATTR_SYSTEM, SEG_DESC_ATTR2_32BIT);
        
        LoadGDTDescriptor(20);
        LoadTaskRegister(getSelector(4, 0, 0));
    
        return 0;
}

Code: Select all

#define SEG_DESC_ATTR_SYSTEM    0x1 // 0001b
#define SEG_DESC_ATTR_DPL0              0x0 // 0000b
#define SEG_DESC_ATTR_DPL1      0x2     // 0010b
#define SEG_DESC_ATTR_DPL2      0x4     // 0100b
#define SEG_DESC_ATTR_DPL3      0x6     // 0110b
#define SEG_DESC_ATTR_PRESENT   0x8     // 1000b

#define SEG_DESC_ATTR2_AVAIL    0x1     // 0001b
#define SEG_DESC_ATTR2_32BIT    0x4     // 0100b
#define SEG_DESC_ATTR2_GRAN             0x8     // 1000b


typedef struct {
        uint16 low_limit;
        uint16 low_base;
        uint8 middle_base;
        uint8 settings;
        uint8 high_limit:4;
        uint8 attributes:3;
        uint8 granularity:1;
        uint8 high_base;
} ATTR_PACKED x86_gdt;


typedef struct {
        uint16 limit;
        x86_gdt* base;
} ATTR_PACKED gdtr;


typedef struct {
        uint8 rpl:2;
        uint8 ti:1;
        uint16 index:13;
} ATTR_PACKED seg_selector;


typedef struct {
        uint16 limit_0_15;
        uint16 base_0_15;
        uint8 base_16_23;
        uint8 type:4;
        uint8 attr:4;
        uint8 limit_16_19:4;
        uint8 atrr2:4;
        uint8 base_24_31;
} ATTR_PACKED seg_descriptor;




x86_gdt g_GDT[256] = {0};

void SetGDTDesc(uint16 _num, uint32 _base, uint32 _limit, uint8 _type, uint8 _attr, uint8 _attr2) {
        seg_descriptor *pDesc = &g_GDT[_num];
        pDesc->base_0_15 = (uint16)_base;
        pDesc->base_16_23 = (uint8)(_base >> 16);
        pDesc->base_24_31 = (uint8)(_base >> 24);
        pDesc->limit_0_15 = (uint16)_limit;
        pDesc->limit_16_19 = (uint8)(_limit >> 16);
        pDesc->type = _type;
        pDesc->attr = _attr;
        pDesc->atrr2 = _attr2;


}

void SetupGDTDescriptor(uint32 _selector, uint32 _base, uint32 _limit, uint32 _settings, uint32 _attributes, uint8 _granul$
        _settings |= 0x10;

        g_GDT[_selector].attributes = _attributes;
        g_GDT[_selector].settings = _settings;
        g_GDT[_selector].granularity = _granularity;
        g_GDT[_selector].low_base = (uint16)_base;
        g_GDT[_selector].middle_base = (uint8)(_base >> 16);
        g_GDT[_selector].high_base = (uint8)(_base >> 24);
        g_GDT[_selector].low_limit = (uint16)_limit;
        g_GDT[_selector].high_limit = (uint8)(_limit >> 16);
}

Code: Select all

#define TSS_DPL0 0x00
#define TSS_DPL1 0x20
#define TSS_DPL2 0x40
#define TSS_DPL3 0x60

#define TSS_PRESENT 0x80

#define EFLAGS_V86 0x40000

typedef struct {
        uint8 reserved1;
        uint8 type:4;
        uint8 reserved2:1;
        uint8 dpl:2;
        uint8 p:1;
} ATTR_PACKED task_gate;




typedef struct {
        uint16 seg_limit_0_15;
        uint16 addr_0_15;
        uint8 addr_16_23;
        uint8 type;
        uint8 seg_limit_16_19;
        uint8 addr_24_31;
} ATTR_PACKED tss_desc;

typedef struct {
        uint16 backlink, _blh;
        uint32 esp0;
        uint16 ss0, _ss0h;
        uint32 esp1;
        uint16 ss1, _ss1h;
        uint32 esp2;
        uint16 ss2, _ss2h;
        uint32 cr3;
        uint32 eip;
        uint32 eflags;
        uint32 eax;
        uint32 ecx;
        uint32 edx;
        uint32 ebx;
        uint32 esp;
        uint32 ebp;
        uint32 esi;
        uint32 edi;
        uint16 es, _esh;
        uint16 cs, _csh;
        uint16 ss, _ssh;
        uint16 ds, _dsh;
        uint16 fs, _fsh;
        uint16 gs, _gsh;
        uint16 ldt, _ldth;
        uint16 trace, iomapbase;
} ATTR_PACKED tss_seg;


tss_seg g_Tasks[10];

void InitTask(uint8 _num, void *_task) {
        g_Tasks[_num].esp = 0xFFFF;
        g_Tasks[_num].es = 0x8;
        g_Tasks[_num].cs = 0x10;
        g_Tasks[_num].ss = 0x18;
        g_Tasks[_num].ds = 0x8;
        g_Tasks[_num].fs = 0x0;
        g_Tasks[_num].gs = 0x0;
        g_Tasks[_num].eip = _task;
        g_Tasks[_num].eflags = 0x0002;
        g_Tasks[_num].iomapbase = sizeof(tss_seg);
}





Re:LTR doesn't like my TSS descriptor.

Posted: Thu May 06, 2004 11:29 am
by seraph9

Code: Select all

[quote]
        
        LoadGDTDescriptor(20);

I couldn't completely understand the code, but shouldn't it be 0x20 instead of 20. Just guessing, 20 seems to be the odd one in there. please do correct me if I'm wrong.

Vivek[/quote]

Re:LTR doesn't like my TSS descriptor.

Posted: Thu May 06, 2004 5:55 pm
by mr. x2
It's worked all the time when it was 20, so that's not the problem :(

Re:LTR doesn't like my TSS descriptor.

Posted: Thu May 06, 2004 11:49 pm
by Brendan
Hi,
mr. x2 wrote: I'm feeding LTR with 0x20 (ti = 0, dpl = 0, index = 4).
My descriptor at entry 4 in the GDT is 0x4A800068 (00000000000000000000000000000000 01001010100000000000000001101000b).
I'm assuming (based on binary) that your GDT entry is 0x00000000:0x4a800068, which would imply that the base is 0x4a80 (can't check if that's right), the limit is 104 bytes (which is right), and that the type is 0x00 and it's not marked as present (which would cause your trouble).

Everything that creates this descriptor looks correct, but then I've no way of telling what the compiler is generating (I've heard some compilers don't pack structures as expected - ANSI C isn't very specific). In any case I'd recommend checking the assembly generated by the compiler (if my earlier assumption is right).

Cheers,

Brendan

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 3:27 am
by mr. x2
OK, the compiler packs data together correct and it's working for paging etc.
My descriptor is now low32:0x4A800068 high32:0x409914
low32: 1001010100000000000000001101000b
high32: 00000000010000001001100100010100b

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 3:41 am
by mr. x2
Oh well, I think it's working now! It doesn't complain anyway!
The problem was that I entered a 1 where it should be a 0, and the present bit wasn't set.

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 3:48 am
by mr. x2
Sorry for replying to my own thread this much, but there's another problem. I can't switch task :(

Code: Select all

InitTask(0, test);
InitTask(1, test2);

SwitchTask(getSelector(4, 0, 0));
Will result in this:
jump_protected: cs == 0

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 3:59 am
by mr. x2
Oh, I forgot to post the SwitchTask function.

Code: Select all

void SwitchTask(uint16 _selector) {
        uint16 iSel[2];
        iSel[0] = _selector;

        asm("ljmp $0x8:%0"::"m"(*iSel));
}

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 7:14 am
by Brendan
Hi,
mr. x2 wrote: Oh, I forgot to post the SwitchTask function.

Code: Select all

void SwitchTask(uint16 _selector) {
        uint16 iSel[2];
        iSel[0] = _selector;

        asm("ljmp $0x8:%0"::"m"(*iSel));
}
Is GDT offset 0x08 a TSS? Offset 0x08 would be GDT entry 1... From original code:

Code: Select all

        SetupGDTDescriptor(1, 0x0, 0xFFFFF,GDT_DPL0|GDT_READABLE|GDT_SEG_CODE|GDT_PRESENT, GDT_286_CALL_GATE, 1);
Perhaps you meant:

Code: Select all

        asm("ljmp $0x40:%0");

Cheers,

Brendan

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 7:25 am
by mr. x2
The ljmp was just an experiment ;), inline asm in GCC didn't want me to do that, "asm("ljmp %0")" would work though, but it would generate that error message later on.

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 7:47 am
by mr. x2
Hahaha, I can't think!
asm("ljmp $0x20,0x0") is working, but it's now complaining about it's a busy task, but I'll see if I can fix that.

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 7:54 am
by Brendan
Hi,

So did you mean this?

Code: Select all

void SwitchTask(uint16 _selector) {
        uint32 iSel[2];
        iSel[1] = _selector * 8;

        asm("ljmp (%0)"::"m"(*iSel));
}
If this is a task switch then the offset is ignored. Also I've got no idea what "getSelector()" returns and inline GAS isn't my specialty (I usually use NASM)...

In NASM I'd do something like:

Code: Select all

            section .bss
currentTSS:    resw 1
            section .text

SwitchTask:
            mov [currentTSS],ax
            jmp far [currentTSS-4]

Cheers,

Brendan

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 9:34 am
by mr. x2
There's another problem now. (new problems pop up all the time :()
When I jump to a TSS I get a General Protection Fault followed by lots of page faults.

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 9:37 am
by Pype.Clicker
did you fill your TSS with correct value for segments (esp. stack & code ?)
are you trying to start user or kernel code through that TSS ?

Re:LTR doesn't like my TSS descriptor.

Posted: Fri May 07, 2004 10:02 am
by mr. x2
Pype.Clicker wrote: did you fill your TSS with correct value for segments (esp. stack & code ?)
are you trying to start user or kernel code through that TSS ?
CS and SS and every segment register is the same as the kernel.
The code is kernel, and the task is a ring 0 one.