Page 1 of 1

Task switch from a Task Gate

Posted: Sat Nov 24, 2007 8:37 pm
by Dandee Yuyo
Hi, guys. I'm trying to do task-switching from a task gate. To accomplish this I'm setting the back-link field of the interrupt gate TSS to the new task selector. But after the iret, the processor seems to continue to keep running the previous task. Do I need to modify the EIP and CS on the interupt stack frame too?

Here is the code of my isr0 interrupt that illustrates this:

Code: Select all

[GLOBAL _irq0_proc]
_irq0_proc:
	cli
_irq0_loop:	
	inc	dword [_ticks]		; tick
		
	mov	al, 0x20			; reset timer
	out	0x20, al
	
[EXTERN _irq0_task] ; IRQ0 TSS

	mov	eax, [_ticks]
	and	eax, dword 0x01
	cmp	eax, dword 0x01
	jz	resch1
		
	lea	eax, [_irq0_task]
	mov	[eax], dword 0x30	; switch to task 2
	mov 	[_gdt8 + 5], byte 0x8b ; set busy bit
	
	jmp	resch2
	
resch1:	

	lea	eax, [_irq0_task]
	mov	[eax], dword 0x20    ; switch to task 1
	mov 	[_gdt6 + 5], byte 0x8b ; set busy bit
	
resch2:
	iret	
	cli						; next time we are called we continue here!
	jmp   _irq0_loop
Keep in mind it's just a "proof of concept" code :D I plan scratch the next or "current" task descriptor instead of changing the selector in the isr tss... :roll:

Posted: Sun Nov 25, 2007 9:38 am
by frank
You need to set the nested task bit in eflags. Bit 14 I believe.

Posted: Sun Nov 25, 2007 11:08 am
by Dandee Yuyo
It is already set. Is set when the processor calls de Interrupt Task. I cannot grasp what's missing.

Posted: Sun Nov 25, 2007 11:35 am
by frank
Also the task that you are trying to IRET to should have its busy bit set.

Posted: Sun Nov 25, 2007 12:52 pm
by Dandee Yuyo
Well, this is already being done by:

Code: Select all

   mov    [_gdt8 + 5], byte 0x8b ; set busy bit 
and

Code: Select all

   mov    [_gdt6 + 5], byte 0x8b ; set busy bit 
If it would be that, I'll get an invalid TSS, which is not happening.

386 programer's reference says about IRET:

Code: Select all

ELSE (*PROTECTED MODE*)
   IF VM = 1
     ..
   ELSE
     IF NT = 1
     THEN GOTO TASK-RETURN;		// I HAVE FLAG 0x400 set
     ELSE
        ...
     FI;
   FI;
...


TASK-RETURN:
   Examine Back Link Selector in TSS addressed by the current task
      register:
      Must specify global in the local/global bit, else #TS(new TSS selector);
      Index must be within GDT limits, else #TS(new TSS selector);
      AR byte must specify TSS, else #TS(new TSS selector);
      New TSS must be busy, else #TS(new TSS selector);
      TSS must be present, else #NP(new TSS selector);
   SWITCH-TASKS without nesting to TSS specified by back link selector;
   Mark the task just abandoned as NOT BUSY;
   Instruction pointer must be within code segment limit ELSE #GP(0);
I don't get any "Invalid TSS" or GPF so all checks pass...

It also says on section 7.6.2 Modifying Task Linkages:
Any modification of the linkage order of tasks should be accomplished only
by software that can be trusted to correctly update the back-link and the
busy-bit. Such changes may be needed to resume an interrupted task before
the task that interrupted it. Trusted software that removes a task from the
back-link chain must follow one of the following policies:
1. First change the back-link field in the TSS of the interrupting task,
then clear the busy-bit in the TSS descriptor of the task removed from
the list.
2. Ensure that no interrupts occur between updating the back-link chain
and the busy bit.

Code: Select all

So I added this: 
	lea		eax, [_irq0_task]
	mov		[eax], dword 0x30
	mov 	[_gdt8 + 5], byte 0x8b ; set busy bit
	mov		[_gdt6 + 5], byte 0x89 ; clear current task busy bit
	jmp		resch2
	
resch1:

	lea		eax, [_irq0_task]
	mov		[eax], dword 0x20
	mov 	[_gdt6 + 5], byte 0x8b ; set busy bit
	mov		[_gdt8 + 5], byte 0x89 ; clear current task busy bit 
..but it still goes on running the previous task , not the next one "in schedule" by tampering the TSS back-link selector field. :shock:

I checked every single line with my own debug routines... there's nothing to do on the stack as with interrupt gates. I dumped the stack and it's clear and empty. All I got were the parameters I pushed myself for the dumpMem proc :D

Posted: Sun Nov 25, 2007 1:16 pm
by Dandee Yuyo
Gosh I'm such an idiot. It's perfectly running and it has always been!!!. I was expecting to see "task2" appearing... but I was switching between "kernel idle" and task1... and it's working perfectly. Ouf, sometimes you are so deep in all this hardware details that you forgot what you were expecting as a result. Shame on me! :oops:

Thanks anyway for the chat