Multitasking questions!

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
elderK

Multitasking questions!

Post by elderK »

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 :D).

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.
Midas
Member
Member
Posts: 140
Joined: Sat Jun 24, 2006 4:40 pm
Location: Falkirk, Scotland
Contact:

Re:Multitasking questions!

Post by Midas »

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 :P).

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
User avatar
ces_mohab
Member
Member
Posts: 77
Joined: Wed Oct 18, 2006 3:08 am

Re:Multitasking questions!

Post by ces_mohab »

Note: I'm implementing hardware task switching because this is my first attempt - ergo, I can give no information on software task switching.
I am using a stack based task switching but i don't know is it more efficient or not?
To write an OS you need 2 minds one for coding and other for debugging.
Habbit

Re:Multitasking questions!

Post by Habbit »

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.
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.
elderK

Re:Multitasking questions!

Post by elderK »

Im still confused, I still dont know how to start going about Multitasking.

My idea is each process has a thread list. :P 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 :P.

~Z
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Multitasking questions!

Post by Brendan »

Hi,
zeii wrote:But, I mean - How do I make it so I run a seperate thread in my Kernel as a test?
There are only 3 steps in implementing software task switching...
  • 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 1, the minimum you'd need is an array containing the kernel's ESP for each task (but I'd recommend an array of structures).

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
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
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.
smiddy

Re:Multitasking questions!

Post by smiddy »

Brenden,

That was very helpful, thanks for sharing! ;D
elderK

Re:Multitasking questions!

Post by elderK »

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