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
I plan scratch the next or "current" task descriptor instead of changing the selector in the isr tss...
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.
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
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!
Thanks anyway for the chat