task switching
task switching
I need a tutorial, example or link about multitasking, task switching, how to describe tasks and how to switch tasks in protected mode.
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:task switching
... 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.
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.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
BlueillusionOS iso image
Re:task switching
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.
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.;-------------- 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
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:task switching
i cannot see any preparation of your TSS (i mean setting the entry point, code segment, data segments, stack pointer, etc ...)
Re:task switching
Isnt this enough for TSS preparation?Pype.Clicker wrote: i cannot see any preparation of your TSS (i mean setting the entry point, code segment, data segments, stack pointer, etc ...)
Ill be glad if anyone has a working example...
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>
Re:task switching
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
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.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.
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
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.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
And as my curiosity, does exception 0 occurs only with a division by 0?
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:task switching
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 ...udarkman wrote:Isnt this enough for TSS preparation?Pype.Clicker wrote: i cannot see any preparation of your TSS (i mean setting the entry point, code segment, data segments, stack pointer, etc ...)
Re:task switching
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.
mark you: the cpu always takes you by word. It has no other choice.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:task switching
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.
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
I think I set ESP field in my TSS (offset stacktask1)... arent I right? ???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 ...
and here is my TSS descriptor..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 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? :-\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 as for beyond infinity lazy, shame is always on people who is just on debug process and gets irrelevant errors ::))
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:task switching
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 )
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
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
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
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
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
Im using tasm.What assembler does it come from ? (i'm just curious :p )
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.
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, 0
lldt ax
mov ax, MainTaskID
ltr ax
this time I couldnt jump into task1. What may couse this?mov ax, Task1ID
ltr ax
And another question. here is my IRQ0 handler.
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.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
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...)
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:task switching
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...
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
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)
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]
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)
As I said, switching back to main task from task1 for ins.is it switching to it (as the first task) or switching *back* to it (after a successful switch to task1, for instance) ?
)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)If you don't believe me,
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]