Page 1 of 1

[solved] Problem with setting up initial TSS

Posted: Wed Jul 02, 2008 1:59 pm
by AdMiNeK
Hi,
Sorry for my bad English.
I'm trying to set up initial TSS for my Higher Half Kernel by this code:

Code: Select all

struct tss
{
    unsigned long backlink;
    unsigned long esp0;
    unsigned long ss0;
    unsigned long esp1;
    unsigned long ss1;
    unsigned long esp2;
    unsigned long ss2;
    unsigned long cr3;
    unsigned long eip;
    unsigned long eflags;
    unsigned long eax;
    unsigned long ecx;
    unsigned long edx;
    unsigned long ebx;
    unsigned long esp;
    unsigned long ebp;
    unsigned long esi;
    unsigned long edi;
    unsigned long es;
    unsigned long cs;
    unsigned long ss;
    unsigned long ds;
    unsigned long fs;
    unsigned long gs;
    unsigned long ldt;
    unsigned long bmoffset;
};

void init_tss( struct tss * tss )
{
    printf( "Task State Segment at 0x%X\n", (unsigned long)tss );
    tss -> esp0 = get_esp();
    tss -> ss0 = 0x10;
    tss -> cr3 = get_cr3();
    tss -> es = 0x10;
    tss -> ds = 0x10;
    tss -> fs = 0x10;
    tss -> gs = 0x10;
    tss -> ss = 0x10;
    tss -> cs = 0x08;
    tss -> ldt = 0;
    tss -> bmoffset = 0xFFFF;
}

Code: Select all

struct gdt_desc {
    unsigned short len15_0;
    unsigned short base15_0; 
    unsigned char base23_16; 
    unsigned char flags1; 
    unsigned char flags2;
    unsigned char base31_24;
};

struct gdtr {
    unsigned short size;
    unsigned long * addr;
};

#define ltr(n) __asm__("ltr %%ax"::"a" (n))
#define lgdt(n) __asm__("lgdt (%%eax)"::"a" (n))

void gdt_set_segment( struct gdt_desc * desc, unsigned long base, unsigned long len, unsigned char flags1, unsigned char flags2 )
{
    desc -> len15_0 = (unsigned short)( len & 0xFFFF );
    desc -> base15_0 = (unsigned short)( base & 0xFFFF );
    desc -> base23_16 = (unsigned char)( ( base >> 16 ) & 0xFF );
    desc -> flags1 = flags1;
    desc -> flags2 = flags2 | ( ( len >> 16 ) & 0xF );
    desc -> base31_24 = (unsigned char)( ( base ) >> 24 );
}

void init_gdt( void )
{
    printf( "GDT at 0x%X\n", (unsigned long *)CPU -> gdt );

    gdt_set_segment( &CPU -> gdt[0], 0, 0, 0, 0 ); //Null descriptor
    gdt_set_segment( &CPU -> gdt[1], 0x0, 0xFFFFF, GDT_PRESENT | GDT_APP | GDT_WRITE | GDT_CODE | GDT_DPL0, GDT_GRANULARITY | GDT_USE32 );
    gdt_set_segment( &CPU -> gdt[2], 0x0, 0xFFFFF, GDT_PRESENT | GDT_APP | GDT_WRITE | GDT_DPL0, GDT_GRANULARITY | GDT_USE32 );
    gdt_set_segment( &CPU -> gdt[3], 0x0, 0xFFFFF, GDT_PRESENT | GDT_APP | GDT_WRITE | GDT_CODE | GDT_DPL3, GDT_GRANULARITY | GDT_USE32 );
    gdt_set_segment( &CPU -> gdt[4], 0x0, 0xFFFFF, GDT_PRESENT | GDT_APP | GDT_WRITE | GDT_DPL3, GDT_GRANULARITY | GDT_USE32 );
    init_tss( &CPU -> tss );
    gdt_set_segment( &CPU -> gdt[5], (unsigned long)&CPU -> tss, sizeof( struct tss ), GDT_PRESENT | GDT_SYS | GDT_TSS32, GDT_USE32 );
    
    CPU -> gdtr.size = GDT_MAX * 8 - 1;
    CPU -> gdtr.addr = (unsigned long *)&CPU -> gdt;
    
    lgdt( (unsigned long)&CPU -> gdtr );
    ltr( 5 << 3 );
}
Bochs returns:

Code: Select all

00014043604i[CPU0 ] >> ltr ax : 0F00D8
00014043604p[CPU0 ] >>PANIC<< exception(): 3rd (14) exception with no resolution
00014043604i[CPU0 ] CPU is in protected mode (active)
00014043604i[CPU0 ] CS.d_b = 32 bit
00014043604i[CPU0 ] SS.d_b = 32 bit
00014043604i[CPU0 ] | EAX=00000028  EBX=0002b1a0  ECX=00000040  EDX=000007ff
00014043604i[CPU0 ] | ESP=c012b1f0  EBP=c012b224  ESI=00103000  EDI=0002b317
00014043604i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af pf cf
00014043604i[CPU0 ] | SEG selector     base    limit G D
00014043604i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00014043604i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00014043604i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00014043604i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00014043604i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00014043604i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00014043604i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00014043604i[CPU0 ] | EIP=c010122f (c010122f)
00014043604i[CPU0 ] | CR0=0x80000011 CR1=0 CR2=0x00000040
00014043604i[CPU0 ] | CR3=0x0012d000 CR4=0x00000010
Where I do wrong?

Re: Problem with setting up initial TSS

Posted: Wed Jul 02, 2008 4:59 pm
by oscoder
Do you know precisely where the error happens? You could try using bochs in debugging mode, or printing more messages to the screen, to find this out. Out of interest, what output does your OS give to the screen?

Re: Problem with setting up initial TSS

Posted: Wed Jul 02, 2008 5:16 pm
by Combuster
The location of the error is obvious - LTR AX, where AX points to the appropriate GDT entry.

The usual errors are because of the wrong GDT contents. By the looks of it you are setting the D bit where it is reserved (GDT_USE32)

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 1:06 am
by AdMiNeK
Combuster wrote:(...) The usual errors are because of the wrong GDT contents. By the looks of it you are setting the D bit where it is reserved (GDT_USE32)
I've removed GDT_USE32 from TSS descriptor, but I have the same problem again.
oscoder wrote:(...) Out of interest, what output does your OS give to the screen?
OS print:

Code: Select all

GDT at 0xC01050E0
Task State Segment at 0xC01060E0
First 4MB is mapped to 0xC0000000.

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 2:15 am
by jnc100
Bochs debugger: run 'info gdt' prior to ltr ax.

Regards,
John.

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 3:52 am
by ChristianF
Mmmhhh....
I think the Problem is in this line:

Code: Select all

ltr( 5 << 3 );
Remember you start with 0, so it should be 6 instead of 5, because you have 6 Entries and the sixth Entry is the tss.

Code: Select all

ltr( 6 << 3 );

Hope it helps! :lol:
Cheers Christian


*EDIT*
hummmm
Do you want to use Hardware Multitasking?

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 9:38 am
by AdMiNeK
jnc100 wrote:Bochs debugger: run 'info gdt' prior to ltr ax.

Regards,
John.
Bochs returns:

Code: Select all

Global Descriptor Table (base=0x50e00000, limit=47):
bx_dbg_read_linear: physical address not available for linear 0x50e00000
error: GDTR+8*0 points to invalid linear address 0x 50e00000
bx_dbg_read_linear: physical address not available for linear 0x50e00008
error: GDTR+8*1 points to invalid linear address 0x 50e00000
bx_dbg_read_linear: physical address not available for linear 0x50e00010
error: GDTR+8*2 points to invalid linear address 0x 50e00000
bx_dbg_read_linear: physical address not available for linear 0x50e00018
error: GDTR+8*3 points to invalid linear address 0x 50e00000
bx_dbg_read_linear: physical address not available for linear 0x50e00020
error: GDTR+8*4 points to invalid linear address 0x 50e00000
bx_dbg_read_linear: physical address not available for linear 0x50e00028
error: GDTR+8*5 points to invalid linear address 0x 50e00000
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
I think base should be 0xC01050E0, but it isn't.

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 9:51 am
by Combuster
AdMiNeK wrote:I think base should be 0xC01050E0, but it isn't.
Then fix it :wink:

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 10:12 am
by AdMiNeK
Combuster wrote:
AdMiNeK wrote:I think base should be 0xC01050E0, but it isn't.
Then fix it :wink:
But code looks OK:

Code: Select all

    CPU -> gdtr.size = GDT_MAX * 8 - 1;
    CPU -> gdtr.addr = (unsigned long)&CPU -> gdt;
    lgdt( &CPU -> gdtr );
I added line to check it:

Code: Select all

printf( "0x%X\n", CPU -> gdtr.addr );
but it prints valid address (0xC01050E0)

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 10:23 am
by Combuster
Remember that GCC aligns struct members:

2 bytes size (word-aligned)
2 bytes padding
4 bytes offset (dword-aligned)

Which the CPU obviously does not like. Try helping GCC with __attribute__ ((packed))

Re: Problem with setting up initial TSS

Posted: Thu Jul 03, 2008 10:50 am
by AdMiNeK
Combuster wrote:Remember that GCC aligns struct members:

2 bytes size (word-aligned)
2 bytes padding
4 bytes offset (dword-aligned)

Which the CPU obviously does not like. Try helping GCC with __attribute__ ((packed))
It's work! :D

Thank you very much!