multitasking problems

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
Poseidon

multitasking problems

Post by Poseidon »

I'm having some problems with my software taskswitching system... I have or a triple fault, or a bochs error (LDTR.valid=0), or bochs crashes in it's own loop with everytime the message CPU LOOP 1. This is my code:

timer isr:

Code: Select all

timer_isr:    cli
         pusha
              push %ds
              push %es
              push %fs
              push %gs
              
         movl (task_curr), %eax         // move the stack pointer in the process's structure
         movl %esp, (%eax)
         movl (task_head), %eax       // get the kernel stack
         movl (%eax), %esp
         
              call schedule
         
         movl (tss), %eax                  // put kernel stack pointer in the tss
         addl $0x4, %eax
         mov %esp, (%eax)
         
         movl (task_head), %eax       // put kernel stack pointer in the kernel process's task
         movl %esp, (%eax)
         movl (task_curr), %eax         // get the stack pointer from the process
         movl (%eax), %esp
         
              pop %gs
              pop %fs
              pop %es
              pop %ds
              popa
         sti
ret_here:
         add $0x8, %esp
              iret
scheduler:

Code: Select all

void schedule(void) {
   
   if(task_count > 0) {
      if (task_curr->time < 1) {
         if (task_curr->next != 0) {
            task_curr = task_curr->next;
         } else
            task_curr = task_head;
         
         task_curr->time = 10;
         task_curr->time_ran++;
         write_cr3(task_curr->cr3);
      } else
         task_curr->time--;
   }
   
   p_outb(0x20, 0x20);
}    
... and some other pieces of code:

Code: Select all

// create tss descriptor
   GDT[3].limit =       sizeof(tss_t) - 1;
   GDT[3].base_lo =   (int) tss;
   GDT[3].base_hi =   (int) tss >> 16;
   GDT[3].type =       TSS_PRESENT + TSS_READY;
   GDT[3].type2 =       0x0;
   GDT[3].base_vhi =    (int) tss >> 24;

// create tss
   tss->esp0 = read_esp();
   tss->cr3 = read_cr3();
   set_tr(24);
does anybody see any errors? if more code needed, just request it ;)

thanks :)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:multitasking problems

Post by Pype.Clicker »

the kind of behaviour you report is typical from a desynchronization on the stack ...

commonmistake #1. You *don't* need CLI/STI in interrupt handlers

Code: Select all

movl (task_head), %eax      // get the kernel stack
         movl (%eax), %esp
seems very risky to me ... why don't you simply remain on your stack ?
Poseidon

Re:multitasking problems

Post by Poseidon »

still won't work.. :(

Code: Select all

timer_isr:    
         pusha
              push %ds
              push %es
              push %fs
              push %gs
              
         movl (task_curr), %eax
         movl %esp, (%eax)
         
              call schedule

         movl (task_curr), %eax
         movl (%eax), %esp
         
         movl (tss), %eax
         addl $0x4, %eax
         mov %esp, (%eax)
         
         mov $0x20, %al
         outb %al, $0x20
   
              pop %gs
              pop %fs
              pop %es
              pop %ds
              popa
ret_here:
              iret
that's what it is now.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:multitasking problems

Post by Pype.Clicker »

so if i try to make it clearer:

* task_curr is the pointer towards your currently running task.
* the first field in a task is the ESP storage area.

pseudo_code

Code: Select all

    // save all registers
    current.sp=%esp;
    // call schedule(), which may be changing the content of "current"
    // *and* the current page table.
    %esp=(new)current.sp;

    // the value of esp0 in the (only one) TSS is modified.
    PIC.sendEOI();
    // restore all registers
    iret
honnestly, i wouldn't be changing the CR3 right in schedule(), if i was you. Instead, i'd defer that to the ASM part (e.g. you could be returning the new CR3 value and let the ASM part do "change CR3, set new stack pointer" without any other memory reference between the two.

Also, i'd check if the newly submitted CR3 is different from the current CR3 before writing the new value (that'll boost performances)


Any chance the new task's "SP"'s value is pointing towards a stack that hasn't ds/es/fs/gs and friends ready ?
Poseidon

Re:multitasking problems

Post by Poseidon »

didn't move the changing of cr3 to the asm part, but i don't think that would be the problem... maybe there is something wrong with the task creation part?

Code: Select all

// copy > 0xC0000000 to the new pagedirectory
void task_copy_kernelspace(int *o_pagedir) {
   uint kernel_space = 0xC0000000 >> 22;
   
   int i;
   int *pagedir = (int *) MEM_PAGEDIR;
   
   for (i = kernel_space; i < 1023; i++) {
      o_pagedir[i] = pagedir[i];
   }
}

task_t *create_task(uint v_addr, uint p_addr) { // p_addr is just temporary
   task_t *ret_proc = malloc(sizeof(task_t));
   
   uint stack_ptr = 0x404000;
   int j;
   
   /* set up the memory for the kernel to work in */
   uint p_pagedir = mm_page_bind(0x400000, 2, 1);
   uint p_pagetable = mm_page_bind(0x401000, 2, 1);
   uint p_page = mm_page_bind2(0x402000, p_addr, 2, 1); // bind p_addr to 0x402000
   uint p_stackpage = mm_page_bind(0x403000, 2, 1);
   uint p_stacktable = mm_page_bind(0x404000, 2, 1);
   
   int *pagedir = (int *) 0x400000;
   int *pagetable = (int *) 0x401000;
   int *page = (int *) 0x402000;
   int *stackpage = (int *) 0x403000;
   int *stacktable = (int *) 0x404000;
   

   /* fill in the stack */
   stack_pushl(0, &stack_ptr);
   stack_pushl(0, &stack_ptr);
   stack_pushl(0x0202, &stack_ptr);
   stack_pushl(0x08, &stack_ptr);
   stack_pushl((uint) &ret_here, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(v_addr, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x0, &stack_ptr);
   stack_pushl(0x10, &stack_ptr);
   stack_pushl(0x10, &stack_ptr);
   stack_pushl(0x10, &stack_ptr);
   stack_pushl(0x10, &stack_ptr);
   
   uint *stack_ptr2 = stack_ptr;
   dbg_printf("New task - stack:\n");
   for (j = 0; j < 20; j++)
      dbg_printf(" 0x%x", stack_ptr2[j]);
   
   mm_fillin_dir(pagedir, p_pagedir); // empty the pagedir and put itself in its last entry
   task_copy_kernelspace(pagedir); // copy the kernelspace to the pagedir
   
   pagedir[1] = 0 | 2;
   pagedir[v_addr >> 22] = p_pagetable | 3; // put the page in the dir
   pagedir[(0xBFFFE000 >> 22)] = p_stacktable | 3; // put the stacktable in the dir
   
   int i;
   /* empty the tables */
   for (i = 0; i < 1024; i++) {
      stacktable[i] = 0 | 2;
      pagetable[i] = 0 | 2;
   }
   
   /* put the pages on their places in the tables */
   pagetable[(v_addr >> 12) & 1023] = p_page | 7;
   stacktable[(0xBFFFE000 >> 12) & 1023] = p_stackpage | 7;
   
   /* unbind the pages from the kernel dir */
   mm_page_unbind(0x400000, 0);
   mm_page_unbind(0x401000, 0);
   mm_page_unbind(0x402000, 0);
   mm_page_unbind(0x403000, 0);
   mm_page_unbind(0x404000, 0);
   
   /* fill in the struct */
   ret_proc->cr3 = p_pagedir;
   ret_proc->esp = 0xBFFFF000 - (0x404000 - stack_ptr);
   ret_proc->time = 10;
   ret_proc->next = 0;
   
   task_count++; // this is for the scheduler
   
   dbg_brp(); // just a breakpoint
   return ret_proc; // return the address of the struct
}


void stack_pushl(uint value, uint *esp) { // push a value on the new task its stack
   *esp -= 4;
   uint *wr_addr = (uint *) *esp;
   
   *wr_addr = value;   
}
thanks :)
Poseidon

Re:multitasking problems

Post by Poseidon »

the taskswitching works now without errors, there were some things wrong in my stack.. the weird thing is: i can let my new task let crash, but i don't get any errors... i believe it does switch from stack. anyone ideas?

thanks
Poseidon

Re:multitasking problems

Post by Poseidon »

yes! it works! (i've just done a recompile and it worked ???) weird.. but who cares, it works ;D
DruG5t0r3

Re:multitasking problems

Post by DruG5t0r3 »

are you creating a new Page table Directory for each task? (not that its bad) just asking.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:multitasking problems

Post by Candy »

Poseidon wrote: yes! it works! (i've just done a recompile and it worked ???) weird.. but who cares, it works ;D
You should. If you had a bug which went away without fixing, it's still there but not visible. Don't trust your code, know your code.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:multitasking problems

Post by Pype.Clicker »

Candy wrote:
Poseidon wrote: yes! it works! (i've just done a recompile and it worked ???) weird.. but who cares, it works ;D
You should. If you had a bug which went away without fixing, it's still there but not visible.
Another option is that the parts of the code should have been rebuilt, but for some purpose (wrong dependencies, corrupted makefiles or building scripts), it wasn't.

For instance

Code: Select all

// point.h
struct point {
    int x,y;
};

// points.c
#include <point.h>
struct point vertices[N];
void drawline(vid from, vid to) {
    line(vertices[from].x, vertices[from].y, vertices[to].x, vertices[to].y);
}

// engine.c
#include <point.h>
extern struct point vertices[];
vertices[3]={0,0};  // this breaks any possible rule
vertices[4]={1,1};  // about OO encapsulation and stuff

drawline(3,4);
Now if you modify struct point to add a Z coordinate and recompile only one of the two file, there will be a flaw in the final object in the sense that
- index computation will not match
- the Z coordinate may be left/used uninitialized by other code
- many other horrors i could think of.

gcc -M can help you producing dependencies automatically ...
under linux, there are also automake tools and stuff, but i don't exactly know how they work ...
Don't trust your code, know your code.
LOL ;D
Post Reply