Page 1 of 2

task switching

Posted: Tue May 20, 2003 1:42 pm
by udarkman
I need a tutorial, example or link about multitasking, task switching, how to describe tasks and how to switch tasks in protected mode.

Re:task switching

Posted: Tue May 20, 2003 2:36 pm
by distantvoices
... alas, quoth the raven, thou goest hither... but whence comest thou back?

I recommend you look at osdev.neopages.net. there you may find what comforts your need.

But as a kind of introduction, some short words about it:

you have two possibilities to handle it: one is to switch tasks by jumping to their task state segments: you say "jmp [selector of task to jump to]:0" and the processor knows due to the descriptor adressed b<y the selector what to do: it dumps all registers in the task state segment of the previous process and then loads the registers of the new process. Execution will continue at the instruction AFTER the jump-to-tss-instruction. Before you can have it working, you have to provide the tss's with proper values. In the Intel Manual about System-programming is a presentation of the task state segment structure. You can fill it in in C.

The second - and really magnificient - possibility to do this is stack task switching: simply said, you push all registers on the stack of the old process, save the position of the stack pointer, switch to a kernel stack for doing kernel relatied things, then load the position of the stack pointer of the new (or again the old) process, provide the SYSTEM-TSS with the value of ESP0 for new process, pop off the registers and iret to the process. It is that smooth because it doesn't matter whether you restart the old process or a new one. The process just continues running and you don't have to bother with busy tss.

*gg* quite a bit technical, this sermon. If you have questions, do not hesitate to post them.

Re:task switching

Posted: Tue May 20, 2003 3:00 pm
by udarkman
Indeed Im not so ignorant to task switching. I have read a few tutorials. But my first trial is failed and so I think I missed something while coding. I define tss and descriptors. And I use timer interrupt to switch between tasks. Indeed at first it succeeded. But a few times later it gives div by 0 exception. When I try to execute it once more, it crashes the computer.
;-------------- TSS definition
struc TSS
slink dd ?
sesp0 dd ?
sss0 dd ?
sesp1 dd ?
sss1 dd ?
sesp2 dd ?
sss2 dd ?
scr3 dd ?
seip dd ?
seflags dd ?
seax dd ?
secx dd ?
sedx dd ?
sebx dd ?
sesp dd ?
sebp dd ?
sesi dd ?
sedi dd ?
ses dd ?
scs dd ?
sss dd ?
sds dd ?
sfs dd ?
sgs dd ?
sldtr dd ?
strace dw ?
sio_map_addr dw ?
ends TSS

...

in setup gdt proc
--------------------
mov eax, 0
mov ax, Code32Segment
shl eax, 4
add eax, offset MainTaskTSS
mov [ds:MainTask_descriptor.base_addr0_15], ax
shr eax, 8
mov [ds:MainTask_descriptor.base_addr16_23], ah

mov eax, 0
mov ax, Code32Segment
shl eax, 4
add eax, offset Task1TSS
mov [ds:Task1_descriptor.base_addr0_15], ax
shr eax, 8
mov [ds:Task1_descriptor.base_addr16_23], ah

mov eax, 0
mov ax, Code32Segment
shl eax, 4
add eax, offset Task2TSS
mov [ds:Task2_descriptor.base_addr0_15], ax
shr eax, 8
mov [ds:Task2_descriptor.base_addr16_23], ah
...
...

tss decleration
-------------------

MainTaskTSS TSS <0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104>
Task1TSS TSS <0, 0, 0, 0, 0, 0, 0, 0, offset Task1, 202h, 0, 0, 0, 0, offset stacktask1, 0, 0, 0, Data32SegmentID, Code32SegmentID, Data32SegmentID, Data32SegmentID, 0, 0, 0, 0, 104>
Task2TSS TSS <0, 0, 0, 0, 0, 0, 0, 0, offset Task2, 202h, 0, 0, 0, 0, offset stacktask2, 0, 0, 0, Data32SegmentID, Code32SegmentID, Data32SegmentID, Data32SegmentID, 0, 0, 0, 0, 104>

....
after switching pmode
--------------
...
mov es, ax
mov fs, ax
mov gs, ax

mov ax, 0
lldt ax

mov ax, MainTaskID
ltr ax
...

and in timer int
-------------
cmp [TaskNo], 0
jne t2
mov [TaskNo], 1
db 0eah ;far jmp
dw 0, 0, Task2ID

t2:
mov [TaskNo], 0
db 0eah
dw 0, 0, Task1ID

Those are what I have seen and understood from Alexei A. Frounze's tutorial and examples. I think I m missing something. So Ill be glad if someone advice me a link, tutorial or example to study.

Re:task switching

Posted: Tue May 20, 2003 4:03 pm
by Pype.Clicker
i cannot see any preparation of your TSS (i mean setting the entry point, code segment, data segments, stack pointer, etc ...)

Re:task switching

Posted: Wed May 21, 2003 12:21 am
by udarkman
Pype.Clicker wrote: i cannot see any preparation of your TSS (i mean setting the entry point, code segment, data segments, stack pointer, etc ...)
Isnt this enough for TSS preparation?

MainTaskTSS TSS <0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104>
Task1TSS TSS <0, 0, 0, 0, 0, 0, 0, 0, offset Task1, 202h, 0, 0, 0, 0, offset stacktask1, 0, 0, 0, Data32SegmentID, Code32SegmentID, Data32SegmentID, Data32SegmentID, 0, 0, 0, 0, 104>
Task2TSS TSS <0, 0, 0, 0, 0, 0, 0, 0, offset Task2, 202h, 0, 0, 0, 0, offset stacktask2, 0, 0, 0, Data32SegmentID, Code32SegmentID, Data32SegmentID, Data32SegmentID, 0, 0, 0, 0, 104>
Ill be glad if anyone has a working example...

Re:task switching

Posted: Wed May 21, 2003 1:41 am
by Beyond Infinity lazy
i doubt you can induce a failure in taskswitching mechanism of a div by zero exception. I recommend you check your printf function (there of course you have something to convert integers to ascii - something that divides) or similar stuff where you DIVIDE something.

Re:task switching

Posted: Wed May 21, 2003 2:00 am
by udarkman
Beyond Infinity lazy wrote: i doubt you can induce a failure in taskswitching mechanism of a div by zero exception. I recommend you check your printf function (there of course you have something to convert integers to ascii - something that divides) or similar stuff where you DIVIDE something.
I just give a message in my task and then enter into an infinite loop. There is no division in my task procs. But there is an interesting thing.

proc Task1
mov esi, offset Task1Message
call PMWriteMessage
tl1:
mov al, [esi+22]
inc al
cmp al, 39h
jb t1dnorst
mov al, 30h
t1dnorst:
mov [esi+22], al
jmp tl1
ret
endp Task1
proc Int20
mov esi, offset Int20Message
call PMWriteMessage
mov al, [esi+27]
inc al
cmp al, 39h
jne norst
mov al, 30h
norst:
mov [esi+27], al

mov al, 20h
out PIC8259MASTER, al

cmp [TaskNo], 0 ;switch to task once
jne t2
mov [TaskNo], 1
db 0eah ; far jmp
dw 0, 0, Task1ID

t2:

iretd
endp Int20
In my timer code I change a byte(27th) of timer message and print it.(not includes ascii-str conversion). In my task, I also change a byte(22nd) of message but not prints it on screen(print part is out of loop). When execute my code, both 27th and 22nd bytes of timer message changes. So my task switching jumps to code but with failer of changing(pushing and popping) registers.

And as my curiosity, does exception 0 occurs only with a division by 0?

Re:task switching

Posted: Wed May 21, 2003 2:28 am
by Pype.Clicker
udarkman wrote:
Pype.Clicker wrote: i cannot see any preparation of your TSS (i mean setting the entry point, code segment, data segments, stack pointer, etc ...)
Isnt this enough for TSS preparation?
this sets up the TSS descriptor, but your task's state is described by the CONTENT of the task state segment, thus if you want your task to start with a given value of the stack pointer, you must set it up in the ESP field of the TSS ...

Re:task switching

Posted: Wed May 21, 2003 2:33 am
by beyond infinity lazy
First you tell it triggers a div by zero exception. I take you by word. Then you ask whether exception nr 0 is always div by zero exception??!!!! Shame on you, this is exactly explained in the intel manual regarding system programming.

mark you: the cpu always takes you by word. It has no other choice.

Re:task switching

Posted: Wed May 21, 2003 3:04 am
by Pype.Clicker
now, if you jump to garbage memory because of a bad instruction pointer, you could execute virtually anything - including a DIV instruction - and if you left all registers initialized to 0, chances are that you actually have some 0 operand when you'll execute that division ...

The debug process is roughly the same than for any other exception: get the Instruction Pointer value and you'll know where that DIV is ...

Note that data in your kernel may also look like a DIV if interpreted as code ... not even mentionning the BIOS code, bootsector etc.

If you run it in BOCHS and get "running in bogus memory" message, it means you're executing garbage memory. If you execute BIOS code or data ... well ... i can't help.

Re:task switching

Posted: Wed May 21, 2003 5:26 am
by udarkman
Pype.Clicker wrote: this sets up the TSS descriptor, but your task's state is described by the CONTENT of the task state segment, thus if you want your task to start with a given value of the stack pointer, you must set it up in the ESP field of the TSS ...
I think I set ESP field in my TSS (offset stacktask1)... arent I right? ???
Task1TSS TSS <0, 0, 0, 0, 0, 0, 0, 0, offset Task1, 202h, 0, 0, 0, 0, offset stacktask1, 0, 0, 0, Data32SegmentID, Code32SegmentID, Data32SegmentID, Data32SegmentID, 0, 0, 0, 0, 104>
and here is my TSS descriptor..
MainTask_descriptor segment_descriptor < -1, 0, 0, 89h, 0cfh, 0>
Task1_descriptor segment_descriptor < -1, 0, 0, 89h, 0cfh, 0>
Task2_descriptor segment_descriptor < -1, 0, 0, 89h, 0cfh, 0>
and I think you are right about Div by 0 exception. I think I do sthg wrong and processor jumps garbage memory and execute nonsense codes. But where did I wrong? :-\

(And as for beyond infinity lazy, shame is always on people who is just on debug process and gets irrelevant errors ::))

Re:task switching

Posted: Wed May 21, 2003 7:17 am
by Pype.Clicker
Ooops ... sorry i didn't noticed this was a TSS initializor. I'm not much used to that STRUCT < val, val, v...al> syntax. What assembler does it come from ? (i'm just curious :p )

Code: Select all

proc Int20
    mov esi, offset Int20Message
    call PMWriteMessage
    mov al, [esi+27]
    inc al
    cmp al, 39h
    jne norst
    mov al, 30h
norst:
    mov [esi+27], al

    mov al, 20h
    out PIC8259MASTER, al

    cmp [TaskNo], 0            ;switch to task once
    jne t2
    mov [TaskNo], 1
    db  0eah                      ; far jmp
    dw  0, 0, Task1ID

t2:

    iretd
endp Int20
is proc Int20 called directly by the hardware interrupt or do you have something that jumps to it ? if called directly by the hardware (which i assume to be true due to the fact it ends with "iretd", you should pushad/popad around it, so that your interrupt don't mess registers up...

let's fake an execution: we're in task X with [taskno] == 0. We take the far jmp and launch TAskID1, keeping the task X sleeping with its state in the TSS.
When TaskID1 will receive a timer interrupt (i should check your flags to make sure those tasks have their IF bit set), it will modify some registers al, and esi and then return ... thus potentially making the task 1 unstable.

now let's get a look at

Code: Select all

    cmp [TaskNo], 0
    jne t2
    mov [TaskNo], 1
    jmp far Task2ID:0

t2:
    mov [TaskNo], 0
    jmp far Task1ID:0
what will occur once you execute t2 (in the context of TaskID2) ? you will restore the state of TaskID1 -- which is, among other things having eip just after jmp far Task2ID:0, so the TaskID1 will execute mov [TaskNo],0 ; jmp far Task1ID:0

err ... huston ? we got a problem ...

Task 1 jumping to task 1 ? the CPU will not like this and issue a TASK FAULT or a GPF (can't remember which one).

Do you have tested interrupt handlers for these ones ?

If not, this could lead to weird things...

you should have

Code: Select all

IRQ0_handler :
   save_state
   whatever
   if x==0 jmp T2
   switch to task 1
   jmp exit
T2:
   switch to task 2
exit:
   restore state
   iretd

Re:task switching

Posted: Wed May 21, 2003 11:36 am
by udarkman
What assembler does it come from ? (i'm just curious :p )
Im using tasm.

And... Pype you are right. I forgot to push registers in IRQ handlers and when I push them tasks worked successfully. But this time I can not switch into my main task. Indeed I can not switch the task which I used with ltr instruction.
....
mov ax, 0
lldt ax

mov ax, MainTaskID
ltr ax
With this code I can not jump into my main task. The other tasks works fine unless I jump into main task. And also if I change the line like:
mov ax, Task1ID
ltr ax
this time I couldnt jump into task1. What may couse this?

And another question. here is my IRQ0 handler.
proc Int20
pushad
push eax esi

mov esi, offset Int20Message
call PMWriteMessage
mov al, [esi+27]
inc al
cmp al, 39h
jne norst
mov al, 30h
norst:
mov [esi+27], al

mov al, 20h
out PIC8259MASTER, al


SwitchToTask1:
cmp [TaskNo], 0
jne SwitchToTask2
mov [TaskNo], 1
db 0eah
dw 0, 0, Task1ID
jmp Exit

SwitchToTask2:
cmp [TaskNo], 1
jne SwitchToMainTask
mov [TaskNo], 2
db 0eah
dw 0, 0, Task2ID
jmp Exit

SwitchToMainTask:
mov [TaskNo], 0
db 0eah
dw 0, 0, MainTaskID

Exit:
pop esi eax
popad
iretd
endp Int20
My tasks includes infinite loop, I mean never returns. So I think 'jmp exit' command not necessary. But when I comment them the program crashes.

And also for the registers. Is it necessary to push and pop registers?? Because, the program never executes pop instructions. (Because every time it jumps to a task before returning) But also whenever I comment them out, it crashes.

So I feel myself yet not so qualified with tasks. Still good links, tutorial and examples will be appreciated...:))

Re:task switching

Posted: Thu May 22, 2003 2:59 am
by Pype.Clicker
Every task has a "busy" bit in the GDT, and the cpu will enforce that you will not jump or call a task that is busy (as long as you have a single CPU system and don't do any task calls, only one task has its busy bit set at once).

You should therefore take care that you'll never try to switch to a busy task, or exceptions will occur. When you say you cannot switch to the MainTask, is it switching to it (as the first task) or switching *back* to it (after a successful switch to task1, for instance) ?

The 'jmp exit' *is* mandatory, as i tried (and failed) to explain in my previous post. When a task is restored (not the first time it is called, but the second one), its state is just after the instruction that made it interrupted earlier. And the event that had interrupted the task is not the IRQ0, as one could think, but the jmp TaskID2:0 instruction.

If you don't believe me, put some debugging instruction like changing the background color in the VGA palette or displaying a character somewhere on screen just between jmp task:0 and jmp exit and you'll see it is executed ...

If you don't do this, when task 1 will be restored, it will do as if it was task 2 switching to task 1 and this is an error ...

Hope i made myself clearer this time...

Re:task switching

Posted: Fri May 23, 2003 2:39 pm
by udarkman
Hi, sorry for the lateness of my answer but due to the earthquake there is no internet for a while in my country. And sorry for the keeping on tasking subject, but in the net there is so few usefull knowledge about multitasking and switching between tasks.

My main problem is switching between tasks. Indeed I succeed switching between tasks, but errors begins whenever I switch to main task and try to return calling function from it. I mean when I execute ret instruction, I get GPE(int 13)
is it switching to it (as the first task) or switching *back* to it (after a successful switch to task1, for instance) ?
As I said, switching back to main task from task1 for ins.
If you don't believe me,
:))Pype, Im sure you are right, but my repetation is due to my poor english. (Indeed, still dont understand why to need an exit instruction although will never return from task, but dont mind)

Guys, Im sending tasking related part of my code, (perhaps someone might want to see it) and still need good tutorials, links or good explanations about multitasking and switching.

Thanks.

[attachment deleted by admin]