mariuszp wrote:I do not understand what you are even trying to say here.
switch_task() should ONLY push edi, esi, ebx, ebp (the "preserved" registers). NEVER use pusha/popa as they needlessly push ESP.
Also, this should work because you are preserving "esp" in a task structure, then jumping to another task. When jumping into a task, you restore it's ESP, which then points to the saved registers again, which you pop back.
And I have no idea what your diagram is supposed to be showing.
Also, the 4-5 second crash is probably related to how you switch the task. Do you save the current task pointer in a global variable and set it? Are your links ("next" pointers) valid and initiailised? etc
That is my interrupt handler. It is simply:
Code: Select all
push error_code
push int_no
cld
pusha
push esp
call irq_common
add esp, 4
popa
add esp, 8
iret
in irq_common, I call find_task(), that updates current_task and next_task.
If I call switch_task in my irq handler, these things happen:
Code: Select all
push error_code
push int_no
cld
pusha
push esp
call irq_common
add esp, 4
call switch_task ---> pusha
mov [current_task + 44], esp
mov esp, [next_task + 44]
popa
ret
popa
add esp, 8
iret
Stack before switch_task:
[cs] (pushed by cpu)
[eip] (pushed by cpu)
[flags] (pushed by cpu)
[error code]
[interrupt number]
[pusha regs]
Stack after switch_task's pusha instruction:
[cs] (pushed by cpu)
[eip] (pushed by cpu)
[flags] (pushed by cpu)
[error code]
[interrupt number]
[pusha regs]
[cs] (pushed by call)
[eip] (pushed by call)
[pusha regs (current task's regs?)] (duplicated)
--- Stack switch to new task's stack ---
Stack after stack switch:
[unknown]
[unknown]
[unknown]
[unknown]
[unknown]
[unknown]
[cs] (next task's cs)
[eip] (next task's eip)
[pusha regs (next task's regs)]
Stack after switch_task:
[unknown]
[unknown]
[unknown]
[unknown]
[unknown]
--- Code execution starts in next task after switch_task ---
These instructions are dead, or maybe sleeping? as they will executed when I switch that task again...
Octocontrabass wrote:Those instructions aren't dead, they're just sleeping. Eventually, some other task will call switch_task() and you'll load the original stack, and on that stack will be the return address pointing to them.
Also switch_task left the interrupt without using iret, I read this isn't a good thing and affects NMIs:
"Concurrent NMIs are delivered to the CPU one by one. IRET signals to the NMI circuitry that another NMI can now be delivered. No other instruction can do this signalling." -
https://stackoverflow.com/questions/104 ... -interrupt
And Bochs dump says this way destroys the stack.
Lastly, this is the stack model of the tasks:
Code: Select all
cs - pushed by call instruction
eip - pushed by call instruction
eax -
ecx \
edx \
ebx | pushed by pusha
esp |
ebp /
esi /
edi -
What am I missing? I really can't understand.
This way is suggested by the many people that very knowledgeable about osdeving in this forum, so I'm sure I'm missing something important.
Thanks in advance.