Task switch at interrupt?

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.
Post Reply
Peter_Vigren

Task switch at interrupt?

Post by Peter_Vigren »

Hellooo. I have some questions about task switching...

1. If the timer interrupt is its own task, then a task switch (store current task, load timer/multitasker) should occur every 1024th (of what is specified) second, am I right?

2. If the answer to my first question is yes, then is anything pushed onto the stack and if so, on which stack? Or is the "back link" and NT-flag used instead?

3. If the timer/multitasker then loads the new task's stored EIP and TSS-descriptor and jmps to it, with the code below, another task switch occur (store timer/multitasker, load new task)?

Code: Select all

db   0xEA   ; Jmp opcode
dd   0   ; New EIP
dw   0   ; New TSS
4. Everytime the timer interrupt is called and the task switch to it is done, the entry point to the interrupt is still the one specified in the IDT-entry and not dependent on the EIP stored in the TSS?

Hopefully you understand my questions even if they are badly explained... :-)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Task switch at interrupt?

Post by Pype.Clicker »

If you set IRQ0 to be a task gate, the CPU will indeed perform a task switch every 1/N second. BUT it will leave the previous task 'BUSY' and will try to return to it at IRET ...

I hardly see how it could be used to implement multitasking, because the next task might be in user mode and thus will not be able to send "clear for next interrupt (out 0x20,0x20)" signal to the PIC, nor will it be able to change the IDT for the next switch or reset the old task to "AVAILABLE" (remember switching to a BUSY task lead to GPF)

The usual approach is to have a trap gate for IRQ0 which will do a JMP to the task selector (thus clearing the BUSY bit of the old task) after having OUT 0x20,0x20.

This way, the task you switch to is in a well-known state (the IRQ0 handler just after the task switch instruction) and can resume to user operations normally.
Peter_Vigren

Re:Task switch at interrupt?

Post by Peter_Vigren »

Pype.Clicker wrote: I hardly see how it could be used to implement multitasking, because the next task might be in user mode and thus will not be able to send "clear for next interrupt (out 0x20,0x20)" signal to the PIC, nor will it be able to change the IDT for the next switch or reset the old task to "AVAILABLE" (remember switching to a BUSY task lead to GPF)
But of course the timer will send the EOI.
Pype.Clicker wrote: The usual approach is to have a trap gate for IRQ0 which will do a JMP to the task selector (thus clearing the BUSY bit of the old task) after having OUT 0x20,0x20.
What is the difference between a task gate and a trap gate?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Task switch at interrupt?

Post by Pype.Clicker »

the task gate will do a task switch and serve the interrupt in another task. The trap gate (like the interrupt gate) serves the interrupt on the kernel (SS0) stack of the current task.

when a task gate is used, the processor performs the following actions:

Code: Select all

1. old_tss <- TR (task register)
2. switch-to(gate.tss_selector) throws TaskFault,StackFault, GPF ...
3. TR <- gate.tss_selector
4. GDT[TR].type=TSS_BUSY
5. TSS.back = old_tss
6. eflags.NT = true
7. push eflags
8. push fake-CS (??? i should rtfm)
9. push fake-eip
10. continue executing in the new context (eip,cs, all registers read from TSS)
And IRET:

Code: Select all

pop return_eip
pop return_cs
pop return_eflags
if (return_eflags.NT==true) switch_to(TSS.back);
else if (cs.dpl == 0) { eip <- return_eip ; cs <- return_cs; }
else ...
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Task switch at interrupt?

Post by Pype.Clicker »

Peter_Vigren wrote:
3. If the timer/multitasker then loads the new task's stored EIP and TSS-descriptor and jmps to it, with the code below, another task switch occur (store timer/multitasker, load new task)?

Code: Select all

db   0xEA   ; Jmp opcode
dd   0   ; New EIP
dw   0   ; New TSS
Watch out: when using call/jump with a TSS/task gate selector, the offset is ignored by the cpu (just as it is when you use a call gate) and the 'eip' value from the target TSS is used instead...
Peter_Vigren

Re:Task switch at interrupt?

Post by Peter_Vigren »

Pype.Clicker wrote:
Peter_Vigren wrote:
3. If the timer/multitasker then loads the new task's stored EIP and TSS-descriptor and jmps to it, with the code below, another task switch occur (store timer/multitasker, load new task)?

Code: Select all

db   0xEA   ; Jmp opcode
dd   0   ; New EIP
dw   0   ; New TSS
Watch out: when using call/jump with a TSS/task gate selector, the offset is ignored by the cpu (just as it is when you use a call gate) and the 'eip' value from the target TSS is used instead...
I thought that was the case but I wasn't sure until now. So you could have EIP=0 then and it doesn't matter?

Back to the multitasker... If I use a trap gate and the multitasker jmp to the new task, then it would work fine?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Task switch at interrupt?

Post by Pype.Clicker »

Yes.

I strongly suggest you make sure *only one function* will do the switch (so that you can easily switch to a stack-switch approach later if you want to) and send the "out 0x20,0x20" before you do the task switch ...

With these two small things (plus maybe a "waiter" task that will be called when there is no runnable task), i think you can do it.
Peter_Vigren

Re:Task switch at interrupt?

Post by Peter_Vigren »

Pype.Clicker wrote: Yes.

I strongly suggest you make sure *only one function* will do the switch (so that you can easily switch to a stack-switch approach later if you want to) and send the "out 0x20,0x20" before you do the task switch ...
You mean that the timer should call for example SwitchTask instead of doing the switch itself?

What do you mean with stack switch approach?
Pype.Clicker wrote:
With these two small things (plus maybe a "waiter" task that will be called when there is no runnable task), i think you can do it.
If there is no task (except for the kernel), can I use Iret to return then?

Two more things...

Isn't it possible to skip the EOI? I have read it somewhere... And if not... Must I first read Status C of the CMOS _and_ send an EOI to get the timer ready again?

The selector part of the jump... should that be the new task's TSS descriptor in the GDT?
Post Reply