Hey all, Im finally entering the zone where I can start work on Multitasking!
However, Bonafide is down for me - so Im having trouble.
And the Books I have just babble about the concept, which is all good and jolly.
Questions!.
I have an Interrupt stub, in ASM that is called when the Timer interrupt fires, which calls a Kernel function - which figures out what Kernel Handler to execute - in thsi case, k_timer_handler.
Anywho, I figure we have to save a processes state.
Its registers, like EIP, CS/DS/ES/.. CR0-CR3, ESP/EBP.
Atleast, I Figure.
THe problem is, The TImer interrupt is in C.
How do I set all the new values, without botching the interrupt call?
Secondly, How would I change DPL? Is a TSS needed? What is a TSS?
(Ill dive into the Intel docs shortly ).
Thirdly, The Context. Which is the addressing space the current process lives in, yes? Like, its page directory, etc.
So... We map what needs to be mapped, with all that stuff set to DPL3 for the Processes things, with the Kernel at 3GB, DPL0?
Forgive me if I sound like a Moron, Im just a little confused .
As per usual, Help is greatly appreciated!
The caffiene fueled nicotine starved codaholic,
~Zeii.
Multitasking questions!
Re:Multitasking questions!
Note: I'm implementing hardware task switching because this is my first attempt - ergo, I can give no information on software task switching.
If you are changing DPL, then a TSS will be required (even for software task switching). This is certainly true for 32 bit protected, but in EM64T protected mode I think it still holds (although, IIRC, it won't allow hardware task switching?). A TSS is a task state segment. It stores the state of the processor for each task. There's a nice detailed description in the Intel manuals of what the various sections are. Basically the base TSS itself is 104 bytes long, and contains register states, etc. When it gets more complicated is
a) when you want to switch tasks that use the FPU - you then need to support the FXSAVE and FXRSTR instructions to save and restore the FPU registers on task switch. I'm not sure where these get saved, since I'm not quite there yet.
b) you want to start including an IO permissions map for each task. Again, I haven't quite got there yet (about all the multitasking I've implemented has been pulled out again, and was simply a round-robin of two threads with very little complexity - it was just for the fun of seeing it) but this involves setting a 16-bit field in the TSS to the address of a bitmap for the IO permissions.
A TSS also contains a backlink to the previous task (for hardware task switching of nested tasks) which, IIRC, is a descriptor index to a descriptor pointing to the TSS of that previous task.
In hardware task switching, most (not the FPU registers, by default) of the registers are saved in the TSS on a task switch. This includes CR3, so page directories are switched (and obviously the TLB flushed) when the task switch is performed - not sure how it works with PAE enabled, though (again, because it isn't relevant to me as of yet). A task switch can be performed by a call or long jump the TSS segment descriptor. It's up to you how you implement this in your scheduler.
EDIT2: Also, I guess that if you didn't want to have pre-emptive multitasking, that you could just alter the backlinks in the TSSes, and wait for each task to return.
EDIT3: Actually, that wouldn't be multitasking as such... But my point was that there was more than one way of switching the tasks, even in hardware task switching.
Hope this helped a little (and that someone more knowledgeable can both correct what I've said, and add to it ).
EDIT: Also, the TSS absolutely must be page aligned if you're using paging. Otherwise, the task switch will fail (and throw an invalid TSS (10? I think) exception).
EDIT3: The Linux v0.01 kernel task switching is pretty self explanatory, if you want to get a grip on what happens.
If you are changing DPL, then a TSS will be required (even for software task switching). This is certainly true for 32 bit protected, but in EM64T protected mode I think it still holds (although, IIRC, it won't allow hardware task switching?). A TSS is a task state segment. It stores the state of the processor for each task. There's a nice detailed description in the Intel manuals of what the various sections are. Basically the base TSS itself is 104 bytes long, and contains register states, etc. When it gets more complicated is
a) when you want to switch tasks that use the FPU - you then need to support the FXSAVE and FXRSTR instructions to save and restore the FPU registers on task switch. I'm not sure where these get saved, since I'm not quite there yet.
b) you want to start including an IO permissions map for each task. Again, I haven't quite got there yet (about all the multitasking I've implemented has been pulled out again, and was simply a round-robin of two threads with very little complexity - it was just for the fun of seeing it) but this involves setting a 16-bit field in the TSS to the address of a bitmap for the IO permissions.
A TSS also contains a backlink to the previous task (for hardware task switching of nested tasks) which, IIRC, is a descriptor index to a descriptor pointing to the TSS of that previous task.
In hardware task switching, most (not the FPU registers, by default) of the registers are saved in the TSS on a task switch. This includes CR3, so page directories are switched (and obviously the TLB flushed) when the task switch is performed - not sure how it works with PAE enabled, though (again, because it isn't relevant to me as of yet). A task switch can be performed by a call or long jump the TSS segment descriptor. It's up to you how you implement this in your scheduler.
EDIT2: Also, I guess that if you didn't want to have pre-emptive multitasking, that you could just alter the backlinks in the TSSes, and wait for each task to return.
EDIT3: Actually, that wouldn't be multitasking as such... But my point was that there was more than one way of switching the tasks, even in hardware task switching.
Hope this helped a little (and that someone more knowledgeable can both correct what I've said, and add to it ).
EDIT: Also, the TSS absolutely must be page aligned if you're using paging. Otherwise, the task switch will fail (and throw an invalid TSS (10? I think) exception).
EDIT3: The Linux v0.01 kernel task switching is pretty self explanatory, if you want to get a grip on what happens.
Regards,
Angus [Óengus] 'Midas' Lepper
Angus [Óengus] 'Midas' Lepper
Re:Multitasking questions!
I am using a stack based task switching but i don't know is it more efficient or not?Note: I'm implementing hardware task switching because this is my first attempt - ergo, I can give no information on software task switching.
To write an OS you need 2 minds one for coding and other for debugging.
Re:Multitasking questions!
FXSAVE and FXRSTR are only needed (and supported) with SSE: on other computers, FPSAVE and FPRSTR will do the trick for both the FPU and MMX/3DNow! state. AFAIK, all information is stored in the TSS.Midas wrote: a) when you want to switch tasks that use the FPU - you then need to support the FXSAVE and FXRSTR instructions to save and restore the FPU registers on task switch. I'm not sure where these get saved, since I'm not quite there yet.
Re:Multitasking questions!
Im still confused, I still dont know how to start going about Multitasking.
My idea is each process has a thread list. Each thread exists in the Processes context, using the Processes Page directory, etc.
New processes have new contexts.
But, I mean - How do I make it so I run a seperate thread in my Kernel as a test?
I have to set the EIP itll run from? Where as, I was hoping to store all of that on the stack etc. Hmm, which can still happen, hmm...
Confused
TSS still scares me .
~Z
My idea is each process has a thread list. Each thread exists in the Processes context, using the Processes Page directory, etc.
New processes have new contexts.
But, I mean - How do I make it so I run a seperate thread in my Kernel as a test?
I have to set the EIP itll run from? Where as, I was hoping to store all of that on the stack etc. Hmm, which can still happen, hmm...
Confused
TSS still scares me .
~Z
Re:Multitasking questions!
Hi,
For step 2, something like this might do:
For step 3, the minimum you'd need to do is allocate some memory somewhere for the new task's stack, then pre-set some values on this stack, and finally put the address of the top of the stack into the data structure you created in step 1. The stuff you pre-set on the new stack must match the stuff you take off the stack in step 2. For the code above this would be the general registers and EIP.
Before you do any task switch you also need to prepare the original task, so that you've got one task you're switching from and another task you're switching to. The task you're switching from is the task you've been using since boot - you need to add details for it to the structure from step 1 (if any) and set "current_task_structure" to point to the address of this structure.
If everything goes well you should be able to create a new task, then manually switch to it and manually switch back. Next you'd need to add a scheduler so the task switching happens automatically, and then start improving it - for e.g. changing address spaces during a task switch (when necessary), handling FPU/MMX/SSE state, etc.
Eventually you'll want to support user-level tasks, which is where the TSS comes in (you don't need the TSS until then). When the CPU switches from CPL=3 to CPL=0 it'll also switch stacks, and it'll get the address for the kernel's stack from the TSS. All you'd need to do is put the address for the top of the task's kernel stack into the TSS (in the SS0 and ESP0 fields) each time you do a task switch.
That's basically all there is to it. Of course there's a lot of different ways you can implement each part, but that's up to you...
Cheers,
Brendan
There are only 3 steps in implementing software task switching...zeii wrote:But, I mean - How do I make it so I run a seperate thread in my Kernel as a test?
- 1) create something to store some details for each task
2) write some code to switch tasks
3) write code to create a new task
For step 2, something like this might do:
Code: Select all
;Input
; ebx Address of new task's data
switchTasks:
pushad
mov eax,[current_task_structure]
mov [eax + task_data_structure.stack],esp
cli
mov esp,[ebx + task_data_structure.stack]
mov [current_task_structure],ebx
sti
popad
ret
Before you do any task switch you also need to prepare the original task, so that you've got one task you're switching from and another task you're switching to. The task you're switching from is the task you've been using since boot - you need to add details for it to the structure from step 1 (if any) and set "current_task_structure" to point to the address of this structure.
If everything goes well you should be able to create a new task, then manually switch to it and manually switch back. Next you'd need to add a scheduler so the task switching happens automatically, and then start improving it - for e.g. changing address spaces during a task switch (when necessary), handling FPU/MMX/SSE state, etc.
Eventually you'll want to support user-level tasks, which is where the TSS comes in (you don't need the TSS until then). When the CPU switches from CPL=3 to CPL=0 it'll also switch stacks, and it'll get the address for the kernel's stack from the TSS. All you'd need to do is put the address for the top of the task's kernel stack into the TSS (in the SS0 and ESP0 fields) each time you do a task switch.
That's basically all there is to it. Of course there's a lot of different ways you can implement each part, but that's up to you...
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:Multitasking questions!
Aye, thanks brendan.
With some good old school 'lets try and see if it breaks it' attitude,
I got a basic 'SWITCH_TO_THIS' working.
It doesnt save anything, its just to see if I can shunt control from the kernel, through Assembly and custom stack creation to another function,
and I did.
So im glad.
Now, im thinking of how I can do this - on a grand scale. (How roman of me. ;P).
Anywho, I was thinking.
On all contexts, even when I Start doing Usermode stuff - 0 to FFFF (0-1mib) is ID Mapped.
I was thinking how I can store.. the Kernel stack location aswel as how I can store the location of the currently running Threads Descriptor.
All I need to save about the Thread (so the kernel can restart it), is its ESP/EBP. Since all of its registers are pushed on preempt.
Just, I need to know what the KErnel stack is, because I could maybe push the Thread Descriptor Address on kernel stack.
i dotn know, its fun brainstorming.
Thanks brendan!
~Z
With some good old school 'lets try and see if it breaks it' attitude,
I got a basic 'SWITCH_TO_THIS' working.
It doesnt save anything, its just to see if I can shunt control from the kernel, through Assembly and custom stack creation to another function,
and I did.
So im glad.
Now, im thinking of how I can do this - on a grand scale. (How roman of me. ;P).
Anywho, I was thinking.
On all contexts, even when I Start doing Usermode stuff - 0 to FFFF (0-1mib) is ID Mapped.
I was thinking how I can store.. the Kernel stack location aswel as how I can store the location of the currently running Threads Descriptor.
All I need to save about the Thread (so the kernel can restart it), is its ESP/EBP. Since all of its registers are pushed on preempt.
Just, I need to know what the KErnel stack is, because I could maybe push the Thread Descriptor Address on kernel stack.
i dotn know, its fun brainstorming.
Thanks brendan!
~Z