Page 1 of 1

Unable to switch task via stack

Posted: Thu Sep 10, 2020 5:59 pm
by mrjbom
Hi.
Previously, I was able to switch tasks using the stack, but I decided to completely rewrite the code and now I have problems.

I'll describe how my task switching works:
When I get an interrupt from PIT, control is passed to the first handler(isr_common_stub:) which passes control to a high-level handler (isr_handler), which causes the PIT handler(pit_handler) to call the scheduler(scheduler_switch), the scheduler(scheduler_switch) configures next_thread(this is where control should be passed), then the main function scheduler_low_thread_switch: which saves the stack of the interrupted task and loads a new stack.

So, what we have in this case: isr_common_stub -> isr_handler -> pit_handler -> scheduler_switch -> scheduler_low_thread_switch(problem here)
In this case, there is one thread in the system - the main thread of the kernel, this function should continue its execution.

(in this case, current_thread and next_thread are absolutely equal)
сurrent_thread uses the eax register, and next_thread uses ebx.
ecx and edx do not play any role in this case)
Offsets described here(just in case)

Its logic is very simple at the moment: first, it saves eflags and general-purpose registers, then it saves the stack of the interrupted task to the current_thread structure, then it goes to the check_kernel_init_or_continue: label, there it goes to the continue_kernel_thread: label and loads the stack, then it tries to pass control to the function using ret.

Since current_thread and next_thread are equal, the stack loaded before ret will be exactly the same as we saved earlier.

(I have previously used this function(it looks bad and so I decided to rewrite it, but it worked correctly))

Re: Unable to switch task via stack

Posted: Thu Sep 10, 2020 6:05 pm
by Octocontrabass
The stack is first-in, last-out (FILO). When you push EBP, EFLAGS, and the general-purpose registers, you must later pop the general-purpose registers, EFLAGS, and then EBP in that order, or it won't work.

Also, you should separate your task-switching code from your IRQ-handling code.

Re: Unable to switch task via stack

Posted: Thu Sep 10, 2020 6:13 pm
by mrjbom
Octocontrabass wrote:The stack is first-in, last-out (FILO). When you push EBP, EFLAGS, and the general-purpose registers, you must later pop the general-purpose registers, EFLAGS, and then EBP in that order, or it won't work.
I fixed the order for "pop", now it's like this:

Code: Select all

popa
popf
pop %ebp
However RET still transfers control to somewhere else.
Octocontrabass wrote:Also, you should separate your task-switching code from your IRQ-handling code.
Yes, you are right, I will do it.
Thank you for your help, my inattention hurt me again(

P.S.
The wrong esp is loaded before ret, it is corrupted for some reason.
Before the RET, the offset is 32, but it should be 16.
I fixed the offset, but the ESP still loads garbage(before ret).

SOLVED! (it seems), popa restored the old ebx and the address of the structure was overwritten.
Although apparently there is still an error in this code because it behaves differently from the previous version.