OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Apr 29, 2024 3:06 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 73 posts ]  Go to page 1, 2, 3, 4, 5  Next
Author Message
 Post subject: tss on stack???
PostPosted: Mon Sep 05, 2005 4:57 pm 
hi all, ok im back and ready for multi-tasking, i understand that tss is for storing a tasks state but how? do i, at a switch, push all registers on a stack pointing to my tss table, then move stack pointer to new table, pop registers + iret???, thx


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Mon Sep 05, 2005 7:31 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

GLneo wrote:
hi all, ok im back and ready for multi-tasking, i understand that tss is for storing a tasks state but how? do i, at a switch, push all registers on a stack pointing to my tss table, then move stack pointer to new table, pop registers + iret???, thx


First, decide if you're going to use hardware task switching or software task switching.

For hardware task switching you need one TSS for each task (and some GDT entries, called "task gates" pointing to them).

For software tasks switching you only need one TSS that's shared by all tasks (and mostly unused), with one task gate in the GDT.

You might find this page useful while you're deciding:

http://www.osdev.org/osfaq2/index.php/C ... 0Switching


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.


Top
 Profile  
 
 Post subject: Re:tss on stack???
PostPosted: Tue Sep 06, 2005 5:58 pm 
i'm going for software task switching, but what do you mean 1 place to store all those redgisters???


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Tue Sep 06, 2005 7:18 pm 
GLneo wrote:
i'm going for software task switching, but what do you mean 1 place to store all those redgisters???


When you do software task switching, you use the TSS only to tell the processor what kernel stack pointer and segment to use when it makes a ring3->ring0 transition. You save registers elsewhere.


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Tue Sep 06, 2005 8:29 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

GLneo wrote:
i'm going for software task switching, but what do you mean 1 place to store all those redgisters???


Ahh - with software task switching you don't store all the registers in the TSS. :)

Forget about the TSS for now, and think of a normal function or sub-routine that modifies all of the CPUs registers - what does it do? It just pushes everything on the stack. For software task switching, we do the same thing.

Conceptually, at the start of the task switch you push everything on the stack, then you change stacks (to a different task's stack), and then you pop everything off of the new tasks stack.

Of course nothing is this simple in real life. First, you need somewhere to store each task's ESP, so that you can switch from one stack to another. It's not the only information the OS needs to keep for each task, so it's best to have some form of "Task Structure" that describes the task, and store ESP in that.

Next, some (or maybe all) tasks have different address spaces, which means that you need to store CR3 somewhere. Usually the task's stack can only be accessed when the task's address space is in use, so you couldn't store CR3 on the tasks stack (you'd need CR3 to get CR3 off of the stack again). This is easy to fix - put CR3 in that "Task Structure", just like ESP.

Then, for reasons probably best left for later, it's a good idea to store the CPU's FPU/MMX/SSE/SSE2 state in the "Task Structure" instead of on the stack, because this allows the FPU/MMX/SSE/SSE2 state saving/loading to be postponed or even skipped if some tasks don't use FPU/MMX/SSE/SSE2 instructions. I recommend that you ignore the FPU/MMX/SSE/SSE2 state for now - it just confuses things and it's easy to add to a working scheduler later.

Combining all of this (but ignoring FPU/MMX/SSE/SSE2 state), you end up with something like:

Code:
switch_tasks:
   pushad
   pushfd
   cli
   <push segment registers if necessary>
   <store ESP in the previous task's Task Structure>
   <get new task's CR3 from it's Task Structure>
   <change address spaces if necessary>
   <get new task's ESP from it's Task Structure>
   <switch to the new task's stack>
   <pop segment registers if necessary>
   popfd
   popad
   ret


You may have noticed that saving and restoring the segment registers on the stack is optional. Because of all the protection checks loading a segment register is slow, which is one of the reasons why most people use a flat memory model (so data segment registers never need to be changed). Even if you do allow the segment registers to be changed you must remember that the task switching code is within the kernel. If CPL=3 code uses different segment registers they are often changed to segments that the kernel expects when CPL=3 code enters the CPL=0 kernel, which is what happens automatically for the CPL=3 CS and SS anyway. For these reasons, for almost all OS's, none of the segment registers need to be saved/restored during a task switch.

[continued]

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


Top
 Profile  
 
 Post subject: Re:tss on stack???
PostPosted: Tue Sep 06, 2005 8:30 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
[continued]

So why do you need a single TSS? The problem is that when the CPU changes from CPL=3 to CPL=0 it changes from the CPL=3 stack to a CPL=0 stack (and for 32 bit protected mode there is no way to avoid it). The CPU is hardwired to load the CPL=0 stack from the TSS (specifically the "SS0" and "ESP0" fields in the TSS).

Therefore (if you support CPL=3 code) you must have one TSS where the only fields that are actually used are the "SS0" and "ESP0" fields. If you also allow CPL=1 or CPL=2 code (for e.g. for device drivers or something) then you must also use the corresponding "SS1", "ESP1", "SS2" and "ESP2" fields in the TSS, but most people do not use these privelge levels and can skip them.

Because each task has it's own CPL=0 stack, you need to correct the ESP0 field in the TSS during the task switch. The "SS0" field is usually set once during boot and left alone after that (it's the same for all of the kernel's stacks). I guess I should also point out that the "ESP0" value in the TSS should not be confused with ESP - ESP0 is always be the address for the top of the stack, where ESP (when you're running at CPL=0) rarely equals the address of the top of the stack.

This gives something like:

Code:
switch_tasks:
   pushad
   pushfd
   cli
   <push segment registers if necessary>
   <store ESP in previous task's task structure>
   <get new task's CR3 from it's task structure>
   <change address spaces if necessary>
   <get new task's top of CPL=0 stack address from it's task structure>
   <set ESP0 in the TSS for the new task>
   <get new task's ESP from it's task structure>
   <switch to the new task's stack>
   <pop segment registers if necessary>
   popfd
   popad
   ret


Each task's "Task Structure" would contain the following items:
    ESP
    ESP0
    CR3
    A FPU/MMX/SSE/SSE2 state save area (512 bytes IIRC)

Other things can also be stored in this "Task Structure". Examples include the name of the task, the amount of CPU time it's used so far, it's priority, how much memory it's currently using, a set of flags (e.g. used to enable/disable IPC and memory management options), it's CPU affinity (for multi-CPU systems), some IPC details, etc.

I usually make the "Task Structure" 4 KB big and put the task's CPL=0 stack in it. It means each "kernel" stack is less than 3.5 KB and you'd need to be carefull with your kernel's code (don't use more stack than you've got), but for me this is easy because I'm doing a micro-kernel written in assembly. For a monolithic kernel in C++ you'd probably want much larger kernel stacks.


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.


Top
 Profile  
 
 Post subject: Re:tss on stack???
PostPosted: Wed Sep 07, 2005 5:39 am 
thx, very informative :), i think i got the idea:
Code:
struct task_state
{
    unsigned int eax;
    unsigned int ebx;
    unsigned int ecx;
    unsigned int edx;
    unsigned int edi;
    unsigned int esi;
    unsigned int cs;
    unsigned int eflags;
    unsigned int eip;
    unsigned int esp;
}; 

struct task_data
{
    unsigned char name[32]
    unsigned int esp;
    unsigned int time;
    unsigned int priority;
    struct task_state *state;
};

unsigned int create_task(void (*function)(), unsigned int priority)
{
   struct task_data *new_task = (struct task_data *)malloc(sizeof(struct task_data));
   new_task[0].esp = getesp();
   new_task[0].time = 10;
   new_task[0].task_priority = priority;
   new_task[0].state = (struct task_state *)malloc(sizeof(struct task_state));
   new_task[0].state->eax = 0;
   new_task[0].state->ebx = 0;
   new_task[0].state->ecx = 0;
   new_task[0].state->edx = 0;
   new_task[0].state->edi = 0;
   new_task[0].state->esi = 0;
   new_task[0].state->cs = 0x8;
   new_task[0].state->eflags = 0x202;
   new_task[0].state->eip = (unsigned)function;
   new_task[0].state->esp = (unsigned int)new_task[0].state;
   return (unsigned int) new_task;
}

but how do i put it together???, what do i do at a switch???


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Thu Sep 08, 2005 1:51 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

GLneo wrote:
but how do i put it together???, what do i do at a switch???


The key to doing the task switch is swapping from one task's stack to another task's stack (everything else, like changing address spaces, etc, can be added to this after it works).

In assembly this is 2 instructions - "mov <somewhere>,esp" and "mov esp,<somewhere>". Of course what "<somewhere>" is will depend on your OS, but for you it looks like it would be the "esp" field in the "task_data" structures.

I'm no C expert, but I doubt it's possible to do the task switch without some (inline?) assembly because C doesn't allow the stack (or ESP) to be manually messed with.

You would also need to be very careful with C's stack frames, input parameters and local variables (unless you do the entire task switch routine in assembly). The reason for this is that the input parameters and local variables will be on the previous task's stack, which you'd stop using half way through the task switch.

To complicate this the compiler's optimizer may store some of these values in the CPUs registers, so that after switching stacks you won't know which input parameters and local variables are still current, and you won't be able to rely on tested behaviour because it could change every time the code is changed (or the compiler/optimizer's settings, or the compiler itself).


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.


Top
 Profile  
 
 Post subject: Re:tss on stack???
PostPosted: Thu Sep 08, 2005 3:11 am 
Offline
Member
Member

Joined: Wed Oct 18, 2006 11:59 am
Posts: 1600
Location: Vienna/Austria
indeed you need some assembly in order to switch stacks.

Go here to find an example of how it can be done:

http://www.distantvoices.org/html/multitasking.html

Hope this helps. I'm lazy in that article about other needed nitty gritty because I just concentrate on multitasking stuff.

important: you don't need to reload cr3 upon each end every task switch, only at those where new cr3 != old cr3. If you're doing your threads the fine way, you can increase overall performance quite nice. :-)

_________________
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image


Top
 Profile  
 
 Post subject: Re:tss on stack???
PostPosted: Thu Sep 08, 2005 9:40 am 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 6:06 pm
Posts: 1437
Location: Vancouver, BC, Canada
Brendan wrote:
You would also need to be very careful with C's stack frames, input parameters and local variables (unless you do the entire task switch routine in assembly). The reason for this is that the input parameters and local variables will be on the previous task's stack, which you'd stop using half way through the task switch.

To complicate this the compiler's optimizer may store some of these values in the CPUs registers, so that after switching stacks you won't know which input parameters and local variables are still current, and you won't be able to rely on tested behaviour because it could change every time the code is changed (or the compiler/optimizer's settings, or the compiler itself).


And this is why you don't use a do_task_switch() function if you're writing your OS in C. ;)

beyond_infinity's example is pretty close to what I do -- do task switching in the asm stubs that surround every ISR.

_________________
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!


Top
 Profile  
 
 Post subject: Re:tss on stack???
PostPosted: Sat Sep 10, 2005 12:18 pm 
OK, my kernel is based on bkerndev, so for isr i have:
Code:
_irq0:
     cli
     push byte 0
     push byte 32
     jmp irq

Code:
irq:
    pusha
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp
    push eax
    mov eax, _irq_handler
    call eax
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

Code:
void irq_handler(struct registers *r)
{
    void (*handler)(struct registers *r);
    handler = irq_pointers[r->int_no - 32];
    if (handler)
    {
        handler(r);
    }
    if (r->int_no >= 40)
    {
        outport(0xA0, 0x20);
    }
    outport(0x20, 0x20);
}

Code:
void timer_handler()
{
    if(cur_task_time() > 0)
    {
        dec_cur_task_time();
        if(cur_task_time() < 1)
            schedule();
    }
}

so i dont know if that counts as surrounding the irq???
and if so what do i switch around???, thx


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Sat Sep 10, 2005 1:41 pm 
Hmm... I have a question. What are you going to do if you schedule() and the EOI code never gets executed?


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Sat Sep 10, 2005 3:29 pm 
what is EOI???


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Sat Sep 10, 2005 3:57 pm 
End Of Interrupt
irq 0-7 -> outb (0x20, 0x20);
irq 8-f -> outb (0x20, 0x20); and outb (0xa1, 0x20);


Top
  
 
 Post subject: Re:tss on stack???
PostPosted: Sat Sep 10, 2005 5:16 pm 
all schedule() does is deturmin what task gets run next, then returns
Code:
    if (r->int_no >= 40)
    {
        outport(0xA0, 0x20);
    }
    outport(0x20, 0x20);
}

does EOI
Then when it returns back though:
Code:
irq:
    pusha
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp
    push eax
    mov eax, _irq_handler
    call eax
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

it should pop registers and iret, the question is what should schedule() contain???


Top
  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 73 posts ]  Go to page 1, 2, 3, 4, 5  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], SemrushBot [Bot] and 21 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group