Page 2 of 2

Re: Some questions - tasks, the stack

Posted: Sun Jul 31, 2011 8:06 pm
by Luns
Alright, I've fixed that problem - on a task switch the esp I saved I got from within the task switch method, but the one I should have been saving was the value from before the ISR was called. I had a problem where the child returning from the fork function would page fault, but I've fixed that too :D.

Now, I have a new problem. Both tasks now just return from the fork function, and I check the value returned to determine which task is which. If the task is the child, I call a function which infinitely loops, printing a letter and a new line (by calling my kprintf function now, not in inline assembly). The parent task enters an infinite loop too, doing the same thing but printing a different letter. After two task switches (parent->child->parent), the tasks stop switching. According to QEMU, the IF bit in the EFLAGS register is not set. Is there anything that might clear interrupts without my knowing about it? I can't see in my code anywhere interrupts are disabled without later being enabled again.

If it changes anything, I now 'jmp' to the new task, instead of 'ret'-ing to it. Apparently unless you use jmp the processor assumes the next task should be linked back and sets the NT bit in EFLAGS.

Re: Some questions - tasks, the stack

Posted: Sun Jul 31, 2011 9:30 pm
by egos
If it changes anything, I now 'jmp' to the new task, instead of 'ret'-ing to it. Apparently unless you use jmp the processor assumes the next task should be linked back and sets the NT bit in EFLAGS.
Are you using hardware task switching now?

Anyway check initial EFLAGS state for every task. What kind of parent->child task switching does occur at first time, by hand or by timer?

Re: Some questions - tasks, the stack

Posted: Mon Aug 01, 2011 8:55 am
by Luns
No. Before, I would push the next task's eip onto the stack, and then use a ret command to pop it off and jump to it. Now I just jmp to it.

During each task switch, the original EFLAGS had interrupts enabled. The first parent->child switch is done by a timer, not by hand.

Re: Some questions - tasks, the stack

Posted: Mon Aug 01, 2011 10:19 am
by egos
Luns wrote:No. Before, I would push the next task's eip onto the stack, and then use a ret command to pop it off and jump to it. Now I just jmp to it.
You should save last changeable instruction pointer of current task before switching to next task... Show the code. It will be better.

Re: Some questions - tasks, the stack

Posted: Mon Aug 01, 2011 12:55 pm
by Luns
I do - I grab it from the stack when the ISR is called. You're right, it'll probably be easier to understand with the code... http://pastebin.com/untMSCRn .

Let me know if you'd like to see anything else. Thanks for taking a look :)

Re: Some questions - tasks, the stack

Posted: Tue Aug 02, 2011 6:31 am
by egos
You should save/restore general purpose and segment registers within interrupt handler. And I think you will have some problems with supporting user mode while using that task switching technique.

Look at my simplified example. Maybe it will be useful for you.

Code: Select all

struc TS ; ThreadStructure
  {
  .pred dd ?
  .next dd ?
  .stackpointer dd ?
  .activepriority dd ?
  .priority dd ?
  }

  proc SwitchToNext ; cs=KCODE, ds=es=ss=KDATA
  push fs
  push gs
  pushf
  cli
;  mov eax,[TSS.sp0]
  mov [eax+TS.stackpointer],esp
  mov eax,[eax+TS.next]
  mov esp,[eax+TS.stackpointer]
  mov [TSS.sp0],eax
  popf
  pop gs
  pop fs
  ret

  proc IRQ0Handler
  pusha
  push ds
  push es

  mov al,20h
  out 20h,al

  push ss
  pop ds ; ds <- KDATA
  push ss
  pop es ; es <- KDATA

  mov eax,[TSS.sp0]

;  dec,[eax+TS.activepriority]
;  jnz @f
;  mov ecx,[eax+TS.priority]
;  mov [eax+TS.activepriority],ecx

;  cmp eax,[eax+TS.next]
;  je @f

  call SwitchToNext
@@:
  pop es
  pop ds
  popa
  iret
Initial stack frame for kernel thread:

Code: Select all

TS+16:  PRIORITY
TS+12:  PRIORITY
TS+08:  TS-16
TS+04:  ? ; undefined before InsertTSInRunQueue operation
TS+00:  ? ; undefined before InsertTSInRunQueue operation
TS-04:  START
TS-08:  FS
TS-12:  GS
TS-16:  EFLAGS

Re: Some questions - tasks, the stack

Posted: Tue Aug 02, 2011 8:56 am
by Luns
#-o of course! I use the general registers in the ISR, so clearly I need to save them before that. Saving them after that saves the modified values, like what was happening before with ESP.

It seems so obvious now, but I'm not sure if I would have ever figured that out on my own. Thank you so much for helping me out!

If you don't mind though, what do you think the problems will be with supporting user mode?

Re: Some questions - tasks, the stack

Posted: Tue Aug 02, 2011 12:27 pm
by egos
Luns wrote:If you don't mind though, what do you think the problems will be with supporting user mode?
If timer interrupt will occur in user mode then kernel stack will contain return address for user mode (user mode code selector, offset in user space) and moreover stack pointer for user mode. In this case you can't jump to the return address. I also mentioned about saving/restoring segment registers for supporting user mode because in kernel mode you should use them with specific values to be assured of their correctness.

Re: Some questions - tasks, the stack

Posted: Wed Aug 03, 2011 7:50 pm
by Luns
Ah, alright. I don't plan on implementing a user mode for quite some time, so I won't worry about that now.

Thanks again for all your help!