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 .
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.
Some questions - tasks, the stack
Re: Some questions - tasks, the stack
Are you using hardware task switching now?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.
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?
If you have seen bad English in my words, tell me what's wrong, please.
Re: Some questions - tasks, the stack
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.
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
You should save last changeable instruction pointer of current task before switching to next task... Show the code. It will be better.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.
If you have seen bad English in my words, tell me what's wrong, please.
Re: Some questions - tasks, the stack
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
Let me know if you'd like to see anything else. Thanks for taking a look
Re: Some questions - tasks, the stack
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.
Initial stack frame for kernel thread:
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
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
Last edited by egos on Tue Aug 02, 2011 12:27 pm, edited 1 time in total.
If you have seen bad English in my words, tell me what's wrong, please.
Re: Some questions - tasks, the stack
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?
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
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.Luns wrote:If you don't mind though, what do you think the problems will be with supporting user mode?
If you have seen bad English in my words, tell me what's wrong, please.
Re: Some questions - tasks, the stack
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!
Thanks again for all your help!