Cannot resume a previously interrupted user process

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Cannot resume a previously interrupted user process

Post by mrjbom »

Hi.
I'm trying to get my task switching code to continue executing previously interrupted threads running in ring 3.
To do this, I have to put the correct return address on the stack at this point, but I can't find it in the user thread stack.

When a thread is interrupted(by an interrupt from PIT), the return address is stored in its stack, but when the user thread is interrupted, its stack is replaced with tss.esp0, but I save the stack of the interrupted thread using the parameters of the interrupt handler. Everything is fine here, the address is correct.

I tried examining the user stack for the presence of a return address(in my case, it should be equal to one of the two known values), but I can't find it there.
I also tried to study the TSS.esp0 stack, there is no return address there either.

As a result: there are no return addresses in the TSS.esp0 stack or in the saved user stack.
(I tried artificially pushing an address into the stack that looks like a return address to me, but it doesn't help, so I may be wrong about the lack of a return address in the stack, I don't understand which one is correct)
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Cannot resume a previously interrupted user process

Post by Octocontrabass »

Wouldn't it be easier to switch kernel stacks? It's not enough to change the user ESP, you must also restore all of the other registers for the user. Since you probably put those on the stack when an interrupt happens, switching stacks will switch everything at once.
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Cannot resume a previously interrupted user process

Post by mrjbom »

Octocontrabass wrote:Wouldn't it be easier to switch kernel stacks? It's not enough to change the user ESP, you must also restore all of the other registers for the user. Since you probably put those on the stack when an interrupt happens, switching stacks will switch everything at once.
I don't fully understand what you're talking about.
I switch to the user stack and try to use the return address stored there for iret...
And I'm not good at restoring all general-purpose registers, and I don't think it's necessary(I switch between kernel tasks without restoring general-purpose registers, and everything works correctly)
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Cannot resume a previously interrupted user process

Post by Octocontrabass »

mrjbom wrote:I don't fully understand what you're talking about.
I switch to the user stack and try to use the return address stored there for iret...
The return address for whatever called your function is stored on the kernel stack, so all you need to do is switch kernel stacks and you'll return to whichever function you interrupted when you switched tasks. Then that function can simply IRET to user mode with the values on the kernel stack, without changing any of them.

The only time that won't work is in a new thread with an empty stack. When you create a new thread, you can either handle it specially when you switch to it, or fill the new kernel stack with appropriate return addresses before adding it to the scheduler's queue.
mrjbom wrote:And I'm not good at restoring all registers, and I don't think it's necessary(I switch between kernel tasks without restoring General-purpose registers, and everything works correctly)
Interrupt handlers must save and restore all registers. Called functions must save and restore the callee-saved registers. If you don't do this, you will have problems in the future.
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Cannot resume a previously interrupted user process

Post by mrjbom »

Octocontrabass wrote:
mrjbom wrote:The return address for whatever called your function is stored on the kernel stack
The most basic kernel stack? What do I create at the very beginning when I start the kernel?
I'll investigate it tomorrow and try to find the return address there...
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Cannot resume a previously interrupted user process

Post by Octocontrabass »

mrjbom wrote:The most basic kernel stack?
What does "the most basic" mean?
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Cannot resume a previously interrupted user process

Post by mrjbom »

Octocontrabass wrote:
mrjbom wrote:The most basic kernel stack?
What does "the most basic" mean?
have no idea.
I want to know what you mean by "kernel stack"
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Cannot resume a previously interrupted user process

Post by mrjbom »

Octocontrabass wrote:
mrjbom wrote:I don't fully understand what you're talking about.
I switch to the user stack and try to use the return address stored there for iret...
The return address for whatever called your function is stored on the kernel stack, so all you need to do is switch kernel stacks and you'll return to whichever function you interrupted when you switched tasks.
You are talking about the function being called and its return address.
But in my case, the user function is interrupted by an interrupt and I try to find the return address in its stack, but it is not there.

When kernel threads are interrupted, I can find their return address, but in the case of user threads, I can't find the return address. I tried looking at the saved user stack and the tss.esp0 stack, but there is no return address anywhere.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Cannot resume a previously interrupted user process

Post by iansjack »

Perhaps you should re-read Chapter 6 of Volume 3 of the Intel Programmer's Manual to be sure that you understand how interrupts work, particularly when there is a change of privilege level. In brief, the processor switches to the kernel stack then pushes the return address (and other information) to that stack. So that is where you should be looking for the return address - although there's no need to look for it.

When you change context you switch to the kernel stack for that process (each process has its own user and kernel stacks) so the iret will return you to the point at which the switched-to process was interrupted. When you create a new process you need to create a new kernel stack (and a user stack) for it, and fake the information on it so that an iret will transfer control to the first instruction of the process.

Read that chapter, and read it again, until you are confident that you fully understand how interrupts work. They are an essential component of your OS. It would help to single-step through an interrupt call in a debugger, watching what happens to the stack(s).

And, yes - you need to save and restore all registers used by a process (which means - at least - all the general-purpose registers) when doing a context switch. This is not like a function call where you have "scratch" registers that needn't be saved. The cpu needs to return to the exact state that it was in when it was last running the process.
Post Reply