tss question

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.
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

hardware multitasking is what im trying to do

im just not sure if the mechanisms work as i understand them. do you understand my problem with what i wrote in the last post? it doesnt add up...
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

OK - Hardware Task Switch:

1) Set up a TSS for your kernel. Don't bother filling anything in here.
2) LTR on this TSS. You shouldn't see anything magic happen here - the task register will just contain your TSS descriptor.
3) Set up a TSS for your incoming task. You will need to fill out initial register values (probably just zero for now), and the ESP field should contain a value pointing to the top of an empty stack (malloc'd space, if you like).
4) SS0/ESP0 in the second TSS should also point to the top of a separate empty stack which must have ring 0 privileges. Forget about ESP1/ESP2.
5) Ensure all segment registers in your second TSS contain valid values, and that EIP points to the start of the incoming task.
6) Far Jump / Far Call / IRET to your new TSS descriptor.
7) Add a new available (busy flag clear) TSS descriptor pointing to your second TSS.

The CPU will automagically now fill your first (kernel TSS) in with appropriate values for the outgoing task. New register values will be loaded from the incoming TSS. TR now points to your new TSS descriptor and your new task should be running. When an interrupt happens, ESP0/SS0 will be loaded from this new TSS. This means you are running in kernel mode again (ring0) and can IRET to whatever TSS descriptor you see fit (by modifying the backlink field, IIRC, or by playing with the stack).

Cheers,
Adam
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

I will try that when I get home from work. But if you say "don't bother filling anything in here", then how come my kernel crashed yesterday just after executing the ltr?

I had a tss descriptor set up that was just pointing to arbitrary data and then did

ltr [descriptor]
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

What error message does your emulator give when it crashes with LTR. There aren't really many possibilities. For example - have you double checked that your TSS descriptor is what it should be? It would be good practice to point the TSS descriptor to zeroed data. You may also like to set the IO Map pointer to 0xFFFF.

Can you please post a Bochs register dump following the crash? Just before that register dump, it will say something along the lines of "Panic: LTR Descriptor does not point to available TSS" or something similar.

Cheers,
Adam
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

does that give you a clue?

Code: Select all

00002677260i[BIOS ] Booting from 0000:7c00
00003177177e[CPU  ] fetch_raw_descriptor: GDT: index (4f)9 > limit (37)
00003177177i[CPU  ] CPU is in protected mode (active)
00003177177i[CPU  ] CS.d_b = 32 bit
00003177177i[CPU  ] SS.d_b = 32 bit
00003177177i[CPU  ] | EAX=00010048  EBX=00000001  ECX=00000004  EDX=534d0000
00003177177i[CPU  ] | ESP=0000fff0  EBP=0000fff0  ESI=ffff017a  EDI=00080248
00003177177i[CPU  ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00003177177i[CPU  ] | SEG selector     base    limit G D
00003177177i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00003177177i[CPU  ] |  CS:0008( 0001| 0|  0) 00014700 0009b500 0 1
00003177177i[CPU  ] |  DS:0010( 0002| 0|  0) 00014700 0009b500 0 1
00003177177i[CPU  ] |  SS:0018( 0003| 0|  0) 00000700 000ffffc 0 1
00003177177i[CPU  ] |  ES:0010( 0002| 0|  0) 00014700 0009b500 0 1
00003177177i[CPU  ] |  FS:0030( 0006| 0|  0) 00000000 000fffff 1 1
00003177177i[CPU  ] |  GS:0028( 0005| 0|  0) 000b8000 000f0fa0 0 1
00003177177i[CPU  ] | EIP=000000ba (000000ba)
00003177177i[CPU  ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00003177177i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00003177177i[CPU  ] >> ltr ax : 0F00D8
00003177177e[CPU  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00003177177i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
Next at t=3177177
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0
<bochs:6> info registers
eax: 0x00000000 0
ecx: 0x00000000 0
edx: 0x00000543 1347
ebx: 0x00000000 0
esp: 0x00000000 0
ebp: 0x00000000 0
esi: 0x00000000 0
edi: 0x00000000 0
eip: 0x0000fff0
eflags 0x00000002
IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
<bochs:7>
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

You are trying to load a GDT descriptor which is beyond the end of the GDT (you are trying to load descriptor 0x4F, when the table limit is 0x37).

The most likely explanation is that you have created a GDT descriptor and added it to the GDT, but your gdt limit (which you load in to the GDTR with LGDT) is set at a value less than this. You therefore need to increase the GDT limit.

Cheers,
Adam
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

hi

thanks for that tip!
now im getting a different error :-(
i though the ldt wasnt necessary:

Code: Select all

00000720000i[XGUI ] charmap update. Font Height is 16
00000800000i[XGUI ] charmap update. Font Height is 16
00001088736i[BIOS ] Booting from 0000:7c00
00001589165e[CPU  ] LTR: LDT descriptor not present!
00001589165i[CPU  ] CPU is in protected mode (active)
00001589165i[CPU  ] CS.d_b = 32 bit
00001589165i[CPU  ] SS.d_b = 32 bit
00001589165i[CPU  ] | EAX=00010048  EBX=00000001  ECX=00000004  EDX=534d0000
00001589165i[CPU  ] | ESP=0000fff0  EBP=0000fff0  ESI=ffff017a  EDI=00000004
00001589165i[CPU  ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00001589165i[CPU  ] | SEG selector     base    limit G D
00001589165i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00001589165i[CPU  ] |  CS:0008( 0001| 0|  0) 00014700 0009b500 0 1
00001589165i[CPU  ] |  DS:0010( 0002| 0|  0) 00014700 0009b500 0 1
00001589165i[CPU  ] |  SS:0018( 0003| 0|  0) 00000700 000ffffc 0 1
00001589165i[CPU  ] |  ES:0010( 0002| 0|  0) 00014700 0009b500 0 1
00001589165i[CPU  ] |  FS:0030( 0006| 0|  0) 00000000 000fffff 1 1
00001589165i[CPU  ] |  GS:0028( 0005| 0|  0) 000b8000 000f0fa0 0 1
00001589165i[CPU  ] | EIP=000000c1 (000000c1)
00001589165i[CPU  ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00001589165i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00001589165i[CPU  ] >> ltr ax : 0F00D8
00001589165e[CPU  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00001589165i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
Next at t=1589165
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Freenode IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

i though the ldt wasnt necessary:

nah its a typo in the sourcecode:

Code: Select all

  /* #NP(selector) if TSS descriptor is not present */
  if (! IS_PRESENT(descriptor)) {
    BX_ERROR(("LTR: LDT descriptor not present!"));
    exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0);
  }

In other words, the present bit is not set.

In the meantime I'll send a mail to the developers
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

Combuster wrote:In other words, the present bit is not set.


But that's just not true:

Code: Select all

;(9) this is the descriptor for the tss of the (boot) kernel
   dw 104      ;limit of the segment
   dw 0      ;base address of segment
   db 0      ;still belonging to base address of segment
   db 10001001   ;1 for "TSS is present"
         ;00 for DPL of 0
         ;010
         ;0 for "task not busy"
         ;1
   db 00000000   ;0 for byte-granularity
         ;000
         ;0000b for last bits of segment limit

   db 0      ;last byte of base address


the base address in the descriptor is written to at run time!

[edit]Sorry, I didn't know, that in the tss descriptor, 0 means present and 1 not present[/edit]
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

Ok I'm having another problem.

My "kernel" runs and I get the ltr instruction to work. Now I tried the following:

I wrote two procedures called task1 and task2. Both are compiled and linked into the kernel. They also execute in ring 0. I wrote 2 new tss descriptors and 2 new stack segment descriptors for them:

Code: Select all

;(10) this is the descriptor for the tss of task1
   dw 104      ;limit of the segment
   dw 0      ;base address of segment
   db 0      ;still belonging to base address of segment
   db 00001001   ;0 for "TSS is present"
         ;00 for DPL of 0
         ;010
         ;0 for "task not busy"
         ;1
   db 00000000   ;0 for byte-granularity
         ;000
         ;0000b for last bits of segment limit

   db 0      ;last byte of base address
;(11) this is the descriptor for the tss of task2
   dw 104      ;limit of the segment
   dw 0      ;base address of segment
   db 0      ;still belonging to base address of segment
   db 00001001   ;0 for "TSS is present"
         ;00 for DPL of 0
         ;010
         ;0 for "task not busy"
         ;1
   db 00000000   ;0 for byte-granularity
         ;000
         ;0000b for last bits of segment limit

   db 0      ;last byte of base address
;(12)..stack segment for task1

   dw 0      ;limit of the segment

   dw 0      ;base address of segment

   db 011h      ;still belonging to base address of segment

   db 10010010b   ;1 for "segment is present"

         ;00 for "privilege 0"

         ;1 for "data or code segment"

         ;0 for "data segment"

         ;0 for "expand downward"

         ;1 for writable

         ;0 (access flag set by cpu on 1st access)

   db 01001111b   ;0 for byte-granularity

         ;1 for 32-bit stack pointer

         ;0 (reserved bit)

         ;0 (available to system programmers)

         ;1111b for last bits of segment limit

   db 0      ;last byte of base address
;(13)..stack segment for task2

   dw 0      ;limit of the segment

   dw 0      ;base address of segment

   db 012h      ;still belonging to base address of segment

   db 10010010b   ;1 for "segment is present"

         ;00 for "privilege 0"

         ;1 for "data or code segment"

         ;0 for "data segment"

         ;0 for "expand downward"

         ;1 for writable

         ;0 (access flag set by cpu on 1st access)

   db 01001111b   ;0 for byte-granularity

         ;1 for 32-bit stack pointer

         ;0 (reserved bit)

         ;0 (available to system programmers)

         ;1111b for last bits of segment limit

   db 0      ;last byte of base address


The base addresses in these descriptors are again written to at run time to point to the following two TSS:

Code: Select all

   task1state: tss_t := tss_t:[
               0,
               0,
               $fffffffc,
               IDX_TASK1STACK*@size(segdesc),
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               &task1,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               IDX_KERNELDATA*@size(segdesc),
               0,
               IDX_KERNELCODE*@size(segdesc),
               0,
               0,
               0,
               IDX_KERNELDATA*@size(segdesc),
               0,
               IDX_MEMORY*@size(segdesc),
               0,
               IDX_VIDEO*@size(segdesc),
               0,
               0,
               0,
               0,
               0,
               $ffff
            ];

   task2state: tss_t := tss_t:[
               0,
               0,
               $fffffffc,
               IDX_TASK2STACK*@size(segdesc),
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               &task2,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               0,
               IDX_KERNELDATA*@size(segdesc),
               0,
               IDX_KERNELCODE*@size(segdesc),
               0,
               0,
               0,
               IDX_KERNELDATA*@size(segdesc),
               0,
               IDX_MEMORY*@size(segdesc),
               0,
               IDX_VIDEO*@size(segdesc),
               0,
               0,
               0,
               0,
               0,
               $ffff
            ];


of type:

Code: Select all

type tss_t:
   record;
      backlink: word;
      zeroes1: word;
      sp0: dword;
      ss0: word;
      zeroes2: word;
      sp1: dword;
      ss1: word;
      zeroes3: word;
      sp2: dword;
      ss2: word;
      zeroes4: word;
      cr3_reg: dword;
      eip_reg: dword;
      eflag_reg: dword;
      eax_reg: dword;
      ecx_reg: dword;
      edx_reg: dword;
      ebx_reg: dword;
      esp_reg: dword;
      ebp_reg: dword;
      esi_reg: dword;
      edi_reg: dword;
      es_reg: word;
      zeroes5: word;
      cs_reg: word;
      zeroes6: word;
      ss_reg: word;
      zeroes7: word;
      ds_seg: word;
      zeroes8: word;
      fs_seg: word;
      zeroes9: word;
      gs_seg: word;
      zeroes10: word;
      ldt_sel: word;
      zeroes11: word;
      debug: byte; //set lowest bit TRUE to raise a debug exception on a task switch
      zeroes12: byte;
      iomap_base: word;
   endrecord;


Then I introduced a variable task which tells me which task is currently running and rewrote my clock interrupt as follows:

Code: Select all

procedure clock_int; @nodisplay; @noalignstack; @noframe;

begin clock_int;
   push(eax);
   pushfd();
   mov(task,ax);
   if (ax = IDX_TASK2TSS*@size(segdesc)) then
      mov(IDX_TASK1TSS*@size(segdesc),ax);
   else
      mov(IDX_TASK2TSS*@size(segdesc),ax);
   endif;
   mov(ax,task);
mov(IDX_TASK1TSS*@size(segdesc),ax);
   ltreg(ax);
   mov(PIC_EOI,al);

   out(al,PIC1_COMMAND);
   popfd();
   pop(eax);

   iret();

end clock_int;


But as soon as the ltreg(ax) gets executed in the timer, I get:

Code: Select all

0000641512i[VGA  ] VBE known Display Interface b0c0
00000641544i[VGA  ] VBE known Display Interface b0c4
00000644469i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00000720000i[XGUI ] charmap update. Font Height is 16
00000800000i[XGUI ] charmap update. Font Height is 16
00001088736i[BIOS ] Booting from 0000:7c00
00001830923e[CPU  ] LTR: doesn't point to an available TSS descriptor!
00001830923i[CPU  ] CPU is in protected mode (halted)
00001830923i[CPU  ] CS.d_b = 32 bit
00001830923i[CPU  ] SS.d_b = 32 bit
00001830923i[CPU  ] | EAX=00000050  EBX=00000001  ECX=00000004  EDX=534d0000
00001830923i[CPU  ] | ESP=0000ffdc  EBP=0000fff0  ESI=ffff017a  EDI=00080248
00001830923i[CPU  ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00001830923i[CPU  ] | SEG selector     base    limit G D
00001830923i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00001830923i[CPU  ] |  CS:0008( 0001| 0|  0) 00014700 0009b500 0 1
00001830923i[CPU  ] |  DS:0010( 0002| 0|  0) 00014700 0009b500 0 1
00001830923i[CPU  ] |  SS:0018( 0003| 0|  0) 00000700 000ffffc 0 1
00001830923i[CPU  ] |  ES:0010( 0002| 0|  0) 00014700 0009b500 0 1
00001830923i[CPU  ] |  FS:0030( 0006| 0|  0) 00000000 000fffff 1 1
00001830923i[CPU  ] |  GS:0028( 0005| 0|  0) 000b8000 000f0fa0 0 1
00001830923i[CPU  ] | EIP=00000c62 (00000c62)
00001830923i[CPU  ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00001830923i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00001830923i[CPU  ] >> ltr ax : 0F00D8
00001830923e[CPU  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00001830923i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
Next at t=1830923
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0


Can anyone help me again?

PS: the mov syntax in HLA is "mov(source,target)"
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Freenode IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

Your GDT is still borked

I think I figured why:

Code: Select all

db 00001001
gets parsed as a decimal number (1001), but not as binary
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

ahh cheers

didnt see that one!

will try when i get home and let you know!
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Good spot, Combuster :shock:
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Post by sancho1980 »

Alas, it didn't help!

Something still seems to be wrong with the way I set up my TSS descriptors.
Instead of ltr'ing the kernels tss descriptor on startup, I tried with one of the tasks, and it didn't crash.

But ltr'ing in the clock interrupt makes it crash(and gives me the same error: "LTR: doesn't point to an available TSS descriptor!"). So I assume the probleme occurs as soon as the iret is done.

This is what my descriptors look like now:

Code: Select all

;(9) this is the descriptor for the tss of the (boot) kernel
   dw 104      ;limit of the segment
   dw 0      ;base address of segment
   db 0      ;still belonging to base address of segment
   db 10001001b   ;1 for "TSS is present"
         ;00 for DPL of 0
         ;010
         ;0 for "task not busy"
         ;1
   db 00000000b   ;0 for byte-granularity
         ;000
         ;0000b for last bits of segment limit

   db 0      ;last byte of base address
;(10) this is the descriptor for the tss of task1
   dw 104      ;limit of the segment
   dw 0      ;base address of segment
   db 0      ;still belonging to base address of segment
   db 10001001b   ;1 for "TSS is present"
         ;00 for DPL of 0
         ;010
         ;0 for "task not busy"
         ;1
   db 00000000b   ;0 for byte-granularity
         ;000
         ;0000b for last bits of segment limit

   db 0      ;last byte of base address
;(11) this is the descriptor for the tss of task2
   dw 104      ;limit of the segment
   dw 0      ;base address of segment
   db 0      ;still belonging to base address of segment
   db 10001001b   ;1 for "TSS is present"
         ;00 for DPL of 0
         ;010
         ;0 for "task not busy"
         ;1
   db 00000000b   ;0 for byte-granularity
         ;000
         ;0000b for last bits of segment limit

   db 0      ;last byte of base address
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Why do you use LTR in the clock interrupt? You shouldn't be using LTR to switch tasks - the IRET does that for you if you modify the task back-linkage and the nested task flag.

Cheers,
Adam
Post Reply