Page 1 of 1

Task Switching

Posted: Wed Jun 28, 2006 4:32 pm
by Bob the Avenger
I'm attempting to impliment multitasking (well only multithreading at its current level) in my kernel using stack swtiching, but I'm having a proglem with it. I've managed to narrow it down to my addTask() function. Not all the values are added to the stack correctly and none of the combinations I've tried have worked.

My stump does this:

Code: Select all

    # error code and interrupt number already pushed
    pusha
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs

    movw  $0x10,%ax
    movw  %ax,%ds
    movw  %ax,%es
    movw  %ax,%fs
    movw  %ax,%gs
    movw  %ax,%ss
    movl  %esp,%eax

    pushl %eax
    movl  $irqHandler, %eax
    call  *%eax                 # replace the old stack esp with the new one 
    popl  %eax
    movl  %eax,%esp

    popl  %gs
    popl  %fs
    popl  %es
    popl  %ds
    popa
    addl  $8,%esp
    iret
and this is how the values are added to the stack in addTask()

Code: Select all

   /* stacksetup = stacktop */
   *stacksetup-- = 0x10;             // gs
   *stacksetup-- = 0x10;             // fs
   *stacksetup-- = 0x10;             // es
   *stacksetup-- = 0x10;             // ds
   *stacksetup-- = 0;                // eax
   *stacksetup-- = 0;                // ecx
   *stacksetup-- = 0;                // edx
   *stacksetup-- = 0;                // ebx
   *stacksetup-- = 0;                // esp
   *stacksetup-- = 0;                // ebp
   *stacksetup-- = 0;                // esi
   *stacksetup-- = 0;                // edi
   *stacksetup-- = 0x10;             // ss
   *stacksetup-- = 0x0202;           // eflags
   *stacksetup-- = 0x08;             // cs
   *stacksetup   = entry;            // eip
When the new stack is loaded, eip is loaded with value 0x0D and eflags is loaded with 0x00010046. I've tried looking at different tutorials and working out the order the values are poped off the stack, but i haven't managed to fix this. Thanks for any help in adavance

Re:Task Switching

Posted: Wed Jun 28, 2006 5:31 pm
by bluecode
You mixed it up a "little" bit ;) The stack is growing downwards ;)
What I do is the following (s points to 0 e.g., when you want the last page in the virtual address space to be the stack):

Code: Select all

unsigned int *s = reinterpret_cast<unsigned int*>(kernelStack);
*--s = 0x202;//eflags
*--s = 0x10;//CS
*--s = entryPoint;//EIP
*--s = 0; //EAX
*--s = 0; //ECX
*--s = 0; //EDX
*--s = 0; //EBX
*--s = 0; //EBP
*--s = 0; //ESI
*--s = 0; //EDI
*--s = DS;
*--s = ES;
*--s = FS;
*--s = GS
There actually is no ESP in the pusha/popa. And there is no ss on the stack when you don't do priviledge level changes.

Re:Task Switching

Posted: Thu Jun 29, 2006 4:58 am
by Bob the Avenger
Thanks, I think it's like your sig, i was confused on a higher level. I know that the stack grows downwards, but somehow when working out the order of values on the stack, that got mangled and reversed in my head. Thanks for the help, i'll try using that set-up asap.

Re:Task Switching

Posted: Fri Jun 30, 2006 5:19 am
by Bob the Avenger
Hmm, now my task-switch is messed up. The task switch code i am using currently is:

Code: Select all

void taskHandler(regs *r){
   
   clockHandler(r);
   
   /* can/do we need to make a switch */
   if(numTasks < 2) return;
   /* save old stack */
   queue[next++].esp = (dword)r;
   /* is next too big? */
   if(next >= (numTasks - 1)) next = 0;
   /* load new stack */
   r = (regs *)queue[next].esp;
   
}
i have also tried using asm to adjust 'r' in the stack with both the 'movl' and using 'push' and 'pop' instructions with no luck.
TaskHandler() is being called by this:

Code: Select all

void irqHandler(regs *r){

   void (*handler)(regs *r);

   /* does a handler exist? */
   handler = irqRoutines[r->intNo - 32];
   if (handler){
      handler(r);
   }
    
   /* do we need to signal chip2? */
   if (r->intNo >= 40){
      outportb(0xA0, 0x20); 

   /* signal chip1 */
   outportb(0x20, 0x20);

}
If thats any help. Thanks in advance.

Re:Task Switching

Posted: Fri Jun 30, 2006 6:18 am
by bluecode
Sorry, but I have to correct myself (there was a dword missing)

Code: Select all

unsigned int *s = reinterpret_cast<unsigned int*>(kernelStack);
*--s = 0x202;//eflags
*--s = 0x10;//CS
*--s = entryPoint;//EIP
*--s = 0; //EAX
*--s = 0; //ECX
*--s = 0; //EDX
*--s = 0; //EBX
*--s = 0; //ESP <----- (it's ignored when executing popa)
*--s = 0; //EBP
*--s = 0; //ESI
*--s = 0; //EDI
*--s = DS;
*--s = ES;
*--s = FS;
*--s = GS
So there is an ESP in popa/pusha ;) sorry about that :-\

Re:Task Switching

Posted: Fri Jun 30, 2006 6:27 am
by Bob the Avenger
Thanks and dont worry about forgetting esp. by the way, I've added 2 empty values between eip and eax because i have a stub before that which pushes an interrupt number and error code, if the interrupt itself doesnt push them. So there needed to be 2 values between what the interrupt causes to be pushed and the pusha.

The problem with it does seem to be in my task-switching code though. I'm thinking of renaming this version of my kernel 666 because its driving me mad.

Edit: No matter if I have set the stack up right it is not working because no switch takes place. That value in loaded into esp is the same value as before the task switching function is called.

Re:Task Switching

Posted: Mon Jul 03, 2006 10:17 pm
by proxy

Code: Select all


    # error code and interrupt number already pushed
    pusha
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs

    movw  $0x10,%ax
    movw  %ax,%ds
    movw  %ax,%es
    movw  %ax,%fs
    movw  %ax,%gs
    movw  %ax,%ss
    movl  %esp,%eax

    pushl %eax
    movl  $irqHandler, %eax
    call  *%eax                # replace the old stack esp with the new one
    popl  %eax
    movl  %eax,%esp

    popl  %gs
    popl  %fs
    popl  %es
    popl  %ds
    popa
    addl  $8,%esp
    iret
i think i see the problem here, you "call *%eax" which i assume is a function expected to return the new stack...then you immidiately "pop %eax"! and just before a "mov %eax, %esp"...so you are assigning esp to some valuye off the stack, not what the function returned...

I think if you just remove the pop it'll work fine.

proxy

Re:Task Switching

Posted: Tue Jul 04, 2006 2:44 pm
by Bob the Avenger
Yer, well the idea is that a pointer to the stack top gets passed to my task switching function in the arguments, then the taskswitching function changes the value in that bit of the stack to the new esp, so the new esp get popped into eax and then mov'd into esp. No values.

Sorry my code is probably really unclear about that.

Anyway the problem is, the value for the esp, somehow, doesn't get changed (thats shown in the C i posted before)

Re:Task Switching

Posted: Tue Jul 04, 2006 9:59 pm
by proxy
ok, that's fine, but then you have another problem:

you pass r like this:

Code: Select all

void irqHandler(regs *r){
but then assign to it like this:

Code: Select all

r = (regs *)queue[next].esp;
well that wont work, because you are passing a copy of the pointer, I would try passing like this: "regs **r" and do "*r = (regs *)queue[next].esp;"

see if that works (and it definitely should)

proxy

Re:Task Switching

Posted: Wed Jul 05, 2006 11:38 am
by Bob the Avenger
Thanks, i'll try that now, although I think your right about its working, because thats what i've told people when they've been editing arguments which are pointers

Re:Task Switching

Posted: Wed Jul 05, 2006 1:45 pm
by Bob the Avenger
Thanks, it does work, now for the minor problem that something thinks my task-switch function is in some very weird memory and page faults when i try to install it in the irq handler. Except, this occurs AFTER i've done all the installing of irqs ???

AND the regs dump, which occurs BEFORE the custom isr handler is called, dupms regs which i would expect AFTER the custom isr handler is called ???

Re:Task Switching

Posted: Wed Jul 12, 2006 5:48 am
by Bob the Avenger
I'm making progress, but after 3 stack swaps, the stack becomes mangled. the correct value of 0x10 is pop'd into gs, 0 is pop'd into es and fs and pop ds causes a GPF. Here is the code i'm using:

Code: Select all

irq0: 
    cli
    pushl $0
    pushl $32
    jmp   irqCommonStub

irqCommonStub: 
    pusha
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs

    movw  $0x10,%ax
    movw  %ax,%ds
    movw  %ax,%es
    movw  %ax,%fs
    movw  %ax,%gs
    movw  %ax,%ss
    movl  %esp,%eax
    movl  %eax,stack(,1)
    movl  $sysStack, %esp

    pushl %eax
    movl  $irqHandler, %eax
    call  *%eax
    popl  %eax
    movl  stack(,1),%eax
    movl  %eax,%esp

    popl  %gs
    popl  %fs
    popl  %es
    popl  %ds
    popa
    addl  $8,%esp
    iret

Code: Select all

void irqHandler(regs *r){

  void (*handler)(regs *r);

  /* does a handler exist? */
  handler = irqRoutines[r->intNo - 32];
  if (handler){
      handler(r);
  }
   
  /* do we need to signal chip2? */
  if (r->intNo >= 40){
      outportb(0xA0, 0x20);

  /* signal chip1 */
  outportb(0x20, 0x20);

}

void taskHandler(regs *r){
   
   clockHandler(r);
   
   #ifdef DEBUG    
   /* Output error string to screen. */
   printf("PID: %u\n"
          "Regs Dump: \n"
          " eax: 0x%X ebx: 0x%X ecx: 0x%X edx: 0x%X esp: 0x%X\n"
          " ebp: 0x%X esi: 0x%X edi: 0x%X eip: 0x%X eflags: 0x%X\n"
          " cs: 0x%X ds: 0x%X es: 0x%X fs: 0x%X gs: 0x%X ss: 0x%X\n",
          queue[next].pid, r->eax, r->ebx, r->ecx, r->edx, r->esp, r->ebp, 
          r->esi, r->edi, r->eip, r->eflags, r->cs, r->ds, r->es, r->fs, r->gs, 
          r->ss);
   #endif /* DEBUG */
   
   /* can/do we need to make a switch */
   if(numTasks < 2) return;
   /* save old stack */
   if(i != 0) queue[next].esp = stack;
   printf("Stack: %X\n", stack);   
   next++;
   /* is next too big? */
   if(next > (numTasks - 1)) next = 0;
   /* load new stack */
   stack = queue[next].esp;
   printf("Stack: %X\n", stack); 
   i++;
   /* halt after 4 switches to examine regs dump */
   if(i == 4) for(;;);
}
Thanks in advance for any help you can give me

Re:Task Switching

Posted: Wed Jul 12, 2006 10:43 pm
by Cody
Hi, Bob

I am just a beginner to OS implementation and by accident I am reading the same tutorial these days.

I have a simple question and I wonder whether you can tell me:

What's the "stacktop" in your first post? Is that the top of the system kernel stack? And is that part of code only used for adding tasks? I read your latest sample code carefully and seems they are nowhere to be found.

Thanks in advance for any of your help!

Best regards,
Cody

Re:Task Switching

Posted: Thu Jul 13, 2006 4:14 am
by Bob the Avenger
its the 'esp' of the stack i am creating for the task, the "*stacksetup-- = ...;" simulate pushes