Page 1 of 1

Some more help on MultiTasking

Posted: Fri Feb 12, 2016 11:09 pm
by ashishkumar4
As adviced by Brenden sir, I made a co-operative multitasking system first. But as said by others to not to use inline asm with optimizations, I tried to use nasm-only for the task_switch but I failed at it (believe me I tried a lot) So instead I made use of inlines BUT WITHOUT OPTIMIZATIONS. and guess what? IT WORKED! :D but now as you see, I have only co-operative multitasking. But I want a better one means using interrupts. Now I modified my switch code a bit for the interrupts and DISABLED the "save earlier EIP before switch to next task" but retained all the other code like saving the registers, segment registers etc. So as you can guess, It works in round-robin fashion but goes straight to the start of the task function everytime a new task is switched to (that's what I intended, going in through cycles starting from 1st task to last task and again to 1st task but not saving the eip)

Though That WONT BE MULTITASKING either (I just did it for testing). For it I need to save the EIP also along with registers. I know that when an interrupt occurs, the last EIP and eflags, cs are pushed on the stack and I can pop them from there but I don't know EXACTLY HOW TO DO THAT.
I have registered my switch_task function in the interrupt handler of my PIT. I tried to pop the eax reg in the start of the function thinking EIP would be the last to be pushed. But that didn't worked. Also I tried to make my function as
void switch_task(irqregs_t regs) and do this inside: old_task->regs.eip=regs.eip; (the old_task-> regs is a separate struct, not related to irqregs_t)
the definition of irqregs_t is similar to :
typedef struct
{
uint32_t eflags,cs,eip;
}irqregs_t;

because I got to know from somewhere that its pushed in that fashion
but this didn't worked too.
I tried with this struct then:
typedef struct
{
uint32_t eip,cs,eflags;
}irqregs_t;
This too didn't worked after 1st cycle
In all the cases above, everything works fine for the 1st cycle that is, everything works fine until the "saved state of the task" is switched to rather then the "initial state of the task that I made while creating it"
my tasks are infinite while loops printing 1,2,3,4,5 depending on the task it is (1st task,2nd task...)
if everything works fine, I should print an infinite sequence like this :
1111111222222233333334444444555555511111112222222333333344444445555555.....
but its like this :
11111112222222333333344444445555555 that's it :/

Please give me a good way of handling the interrupt and getting the EIP from the stack (Please give me code with explanation and not only explanation because that's why I am in this situation :p)

here is my switch_task function:

Code: Select all



void switch_task(irqregs_t regs)
{
    // If we haven't initialised tasking yet, just return.
    //printf("\nSwitching Task\n");
    asm volatile("cli");

    old_task=current_task;
    current_task=current_task->next;
    //asm volatile("popl %%eax;": "=a"(old_task->regs.eip));
    //printf("\nEIP: %x",old_task->regs.eip);
    //asm volatile("add $0xc, %esp");
    //switchTask(&old_task->regs, &current_task->regs);

  	asm volatile("movl %%ebx, %0;":"=r"(old_task->regs.ebx));
  	asm volatile("movl %%ecx, %0;":"=r"(old_task->regs.ecx));
  	asm volatile("movl %%edx, %0;":"=r"(old_task->regs.edx));
  	asm volatile("movl %%esi, %0;":"=r"(old_task->regs.esi));
  	asm volatile("movl %%edi, %0;":"=r"(old_task->regs.edi));
  	asm volatile("movl %%ebp, %0;":"=r"(old_task->regs.ebp));

    asm volatile("pushl %eax");
	  asm volatile("pushl %ebx");
  	asm volatile("pushl %ecx");
  	asm volatile("pushl %edx");
  	asm volatile("pushl %esi");
  	asm volatile("pushl %edi");
  	asm volatile("pushl %ebp");
  	asm volatile("pushl %ds");
  	asm volatile("pushl %es");
  	asm volatile("pushl %fs");
  	asm volatile("pushl %gs");//*/
  	//asm volatile("mov %%esp, %0":"=r"(old_task->StackTop));
    //old_task->regs.eip=regs.eip;

    asm volatile("    movw    $16, %ax		"); /* KERNEL_DATA_SEG!!!! */
    asm volatile("    movw    %ax, %ds		");
    asm volatile("    movw    %ax, %es		");
    asm volatile("    movw    %ax, %fs		");
    asm volatile("    movw    %ax, %gs		");

  	asm volatile("movl %%ds, %0;":"=r"(old_task->ds));
  	asm volatile("movl %%es, %0;":"=r"(old_task->es));
  	asm volatile("movl %%fs, %0;":"=r"(old_task->fs));
  	asm volatile("movl %%gs, %0;":"=r"(old_task->gs));
  	asm volatile("movl %%ss, %0;":"=r"(old_task->ss));

    stack=(uint32_t*)current_task->StackTop;
    *--stack = current_task->regs.eflags; // eflags
    *--stack = current_task->regs.cs; // cs
    *--stack = current_task->regs.eip; // eip
  	*--stack = current_task->regs.eax; // eax
  	*--stack = current_task->regs.ebx; // ebx
  	*--stack = current_task->regs.ecx; // ecx
  	*--stack = current_task->regs.edx; //edx
  	*--stack = current_task->regs.esi; //esi
  	*--stack = current_task->regs.edi; //edi
  	*--stack = current_task->regs.ebp; //ebp
  	*--stack = current_task->ds; // ds
  	*--stack = current_task->fs; // fs
  	*--stack = current_task->es; // es
  	*--stack = current_task->gs; // gs


    //old_task->regs.eip=regs.eip;
  	asm volatile("movl %%eax, %%esp;": :"a"(current_task->regs.esp));
  	asm volatile("movl %%eax, %%ss;": :"a"(current_task->ss));
  	asm volatile("popl %gs");
  	asm volatile("popl %fs");
  	asm volatile("pop %es");
  	asm volatile("popl %ds");
  	asm volatile("popl %ebp");
  	asm volatile("popl %edi");
  	asm volatile("popl %esi");
  	asm volatile("out %%al, %%dx": :"d"(0x20), "a"(0x20)); // send EoI to master PIC
  	asm volatile("popl %edx");
  	asm volatile("popl %ecx");
  	asm volatile("popl %ebx");
  	asm volatile("popl %eax");
    //asm volatile("addl $8, %esp");
  	//asm volatile("push %0"::"r"(current_task->regs.eip));
  /*  asm volatile("\
    sti; \
    jmp *%0": :"r"(current_task->regs.eip));
    //asm volatile("jmp *%0" :: "r"(current_task->regs.eip));
    asm volatile("sti");
    asm volatile("iret");/*
    saveState();
    asm volatile("mov %%esp, %%eax;":"=a"(old_task->regs.esp));
    asm volatile("mov %%eax, %%esp;"::"a"(current_task->regs.esp));
    loadState();*/
    asm volatile("sti");
    asm volatile("iret");
}

:p I am a newbie :p

Re: Some more help on MultiTasking

Posted: Sat Feb 13, 2016 1:46 am
by Brendan
Hi,
ashishkumar4 wrote:As adviced by Brenden sir, I made a co-operative multitasking system first. But as said by others to not to use inline asm with optimizations, I tried to use nasm-only for the task_switch but I failed at it (believe me I tried a lot) So instead I made use of inlines BUT WITHOUT OPTIMIZATIONS. and guess what? IT WORKED! :D
It doesn't work; it only seems like it works because you've only found one of the problems so far (enabling optimisations breaks it) and haven't found the other problems yet.

For a simple example, imagine you're writing a kernel API function that waits for data to arrive then returns it (e.g. "getMessage()" or "read()" or something). The basic idea for these types of functions is:

Code: Select all

    while( no_data() ) {

        block_task();              // Wait for the arrival of data to unblock this task and
                                   //   cause a task switch back to this task
    }
    data = get_data_from_wherever();
    return data;                   // Return the data back to user-space
How do you intend to implement anything like this when a task switch causes an implied "return to CPL=3 without the data"?

Something causes a switch from CPL=3 to CPL=0 (which may be an IRQ or exception or SYSCALL or SYSENTER or...); the kernel does stuff (that may or may not involve one or more task switches); then when the kernel has nothing else to do it returns to CPL=3 (to whatever task happens to be the current task at the time).

Note that when a task switch happens; it's always from CPL=0 to CPL=0 and has nothing at all to do with CPL=3 in any way whatsoever.

This means (e.g.) there is never any need to load/save segment registers during task switches because the kernel's segment registers are always the same for all tasks. Something causes a switch from CPL=3 to CPL=0 (and CPL=3 segment registers are saved and kernel segment registers are set to fixed values); then the kernel does stuff (that may or may not involve task switches between tasks at CPL=0); then when the kernel has nothing else to do it returns to CPL=3 (and kernel's segment registers are discarded and not saved, and CPL=3 segment registers are loaded).


Cheers,

Brendan

Re: Some more help on MultiTasking

Posted: Sat Feb 13, 2016 6:04 am
by ashishkumar4
I haven't thought about them because I want the simplest possible multitasking (Just a scheduler) right now because I want my program to evolve. I want to understand every possible way to do one thing. Later on when I get a success doing this, I would go on to this locking and unlocking tasks stuff :p for now please help me do this first because I want to achieve success in this first, then think of other possibilities so that I can make a better code. Otherwise I wont understand it to the fullest :/ please sir, help me in my question above :p

Re: Some more help on MultiTasking

Posted: Sat Feb 13, 2016 7:46 am
by Brendan
Hi,
ashishkumar4 wrote:please sir, help me in my question above :p
Imagine someone needs to travel 2 Km to the west, but for no sane reason they're heading towards the east and expecting people to help them with problems that are directly caused by the fact that they're heading in the wrong direction. Do you dislike the person enough to help them continue getting further and further away from their goal; or do you like the person enough to force them to go in the right direction instead of helping them make their situation worse?

You are going in the wrong direction. I don't dislike you enough to provide the "anti-help" you're asking for.


Cheers,

brendan

Re: Some more help on MultiTasking

Posted: Sat Feb 13, 2016 1:11 pm
by tsdnz
Brendan wrote:Hi,
ashishkumar4 wrote:please sir, help me in my question above :p
Imagine someone needs to travel 2 Km to the west, but for no sane reason they're heading towards the east and expecting people to help them with problems that are directly caused by the fact that they're heading in the wrong direction. Do you dislike the person enough to help them continue getting further and further away from their goal; or do you like the person enough to force them to go in the right direction instead of helping them make their situation worse?

You are going in the wrong direction. I don't dislike you enough to provide the "anti-help" you're asking for.


Cheers,

brendan
Also..... You will learn a lot by figuring it out, once you are heading in the right direction.
Read the manuals on interrupts, put pen to paper and write down exactly the stack, check your code, check the assembly output.
Good luck.

Re: Some more help on MultiTasking

Posted: Sat Feb 13, 2016 8:16 pm
by SpyderTL
This feels like deja vu, but why do you need the value of EIP?

If it's sitting on the stack, it will still be there when you want to switch back to that thread in the future?

If you are inside a subroutine, just swap to the new stack and call RET. If you are in an interrupt handler, just swap to the new stack and call IRET.

Re: Some more help on MultiTasking

Posted: Sun Feb 14, 2016 3:45 am
by ashishkumar4
lol ok i got it. not making anything now because my PC dies :'( my PSU burnt up :/

Re: Some more help on MultiTasking

Posted: Sun Feb 14, 2016 3:52 am
by ashishkumar4
ok i got that point, not to save segment registers because it isnt needed, right? will do this once my pc is back to life again :'(