Page 1 of 1

confused about multitasking...

Posted: Wed Sep 06, 2006 12:43 am
by CyberP1708
...I don't understand anything with multitasking....
even after reading many of tutorials and documents (but they are all almost identical, what doesn't help me)


What I understand

First I linked IRQ0 to an interrupt handler:
(note: I switched back to the state where everything is identity mapped, so there is no problem about paging)

Code: Select all

onIRQ0_ISR:
   pusha
   push ds
   push es
   push fs
   push gs

   mov eax, cr3
   push eax

   mov eax, cr0
   and eax, 0x7FFFFFFF   ; paging off
   mov cr0, eax

   mov ax, 0x10
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   push esp
   call onIRQ0
   mov esp, eax

   mov al, 0x20
   out 0x20, al

   pop eax
   mov cr3, eax

   mov eax, cr0
   or eax, 0x80000000    ; paging on
   mov cr0, eax

   pop gs
   pop fs
   pop es
   pop ds
   popa


   iret
This code is simple: everything is pushed on the current process's stack, then the onIRQ0 function saves the process's esp and returns the next process's esp. Finally the asm code pops back the registers from the new stack...


What is messy in my head

To switch to ring3, I simply have to use the ds, es, fs, gs, cs corresponding to ring3 (I'm talking about what is initially pushed in the process's stack)
But how do you specify ss?


When there is an IRQ0 (or any other interruption), the CPU can't directly switch to ring0, so we have to use a TSS (that's what I understood, tell me if I'm wrong)

In my IDT, should I use a task gate or an interrupt gate?
If it is a task gate, how do I specify the entry point of the interruption handler? In the TSS (eip register)? But should I reset the TSS'eip register after each interruption?

The TSS's esp0 and ss0 must correspond to the kernel's stack, so when there is an interruption, my asm code is executing with the kernel's stack: but how do you switch stacks?
Do you need to create another stack for each process? (and the esp0 and ss0 must match the next process's second stack?)

I also thought that on task switch the TSS's esp0 and ss0 could be set to the next process's esp, but the esp may probably change during the time the process is running (and so data will be erased on task switch)

Anyway, when there is an interruption, the current esp isn't stored anywhere (because no TSS is running, the TSR register is empty, what happens when it is empty is not precised in the Intel Manuel) so how do you switch back to the former esp?

I presume there is another TSS constantly running which would store it, but if so there would be no advantage for using software task-switching as it would be slower than hardware task switching

Re:I'm maybe stupid but...

Posted: Wed Sep 06, 2006 2:06 am
by Pype.Clicker
CyberP1708 wrote: mov eax, cr0
and eax, 0x7FFFFFFF ; paging off
mov cr0, eax
why on earth do you turn paging off during the ISR?? bugtracking or is it really a feature of yours?
To switch to ring3, I simply have to use the ds, es, fs, gs, cs corresponding to ring3. But how do you specify ss?
SS will be part of the info pushed by the CPU. If you look at cross-rings interrupts in intel manuals, you'll see that IRET behaves differently when the RPL of the caller code segment is not the same as the CPL, and that in that case, ESP and SS are also popped from the stack. Use these.
When there is an IRQ0, the CPU can't directly switch to ring0, so we have to use a TSS.
the CPU can very well do a switch to ring 0 if there is a TSS telling it what values to be used for ESP0 and SS0. There's no need for a task switch here, but yes, you need a valid TSS loaded (LTR) or you'll be stuck.
In my IDT, should I use a task gate or an interrupt gate?
Except for very special events, like stack fault or double faults, you can live happily with trap gates (for exceptions and syscalls) and interrupt gates (for IRQs).
If it is a task gate, how do I specify the entry point of the interruption handler? In the TSS (eip register)? But should I reset the TSS'eip register after each interruption?
yep, the entry point will be the TSS.EIP register, which means you'd have to provide one TSS for every interrupt (and that's why we don't use TSS for interrupts if we're not forced to do so).
To avoid reseting TSS.EIP, there's a simple trick that consist of having a "trash" TSS which you'll never jump to. Load its selector in TR before you do the IRET so that the state for your interrupt-handling TSS remains clean (thanks TRAN/renaissance for the trick :) )
The TSS's esp0 and ss0 must correspond to the kernel's stack, so when there is an interruption, my asm code is executing with the kernel's stack: but how do you switch stacks?
Do you need to create another stack for each process? (and the esp0 and ss0 must match the next process's second stack?)
yes, most of the time, we love to have a separate kernel stack for every thread. that just makes life easier. that means your task-switch code will _also_ have to replace the TSS ss0:esp0 values with the values in the incoming thread control block.



i guess these answers will shed some lights and will help you to figure out answers of your last questions ...

Re:confused about multitasking...

Posted: Wed Sep 06, 2006 2:49 am
by CyberP1708
Thank you, I'm beginning to understand