SS/ESP on stack after interrupt

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.
DarylD

SS/ESP on stack after interrupt

Post by DarylD »

Is there a way of forcing the processor to always put SS/ESP on the stack during an interrupt and than an IRET popping this??

I have software task switching working (well!!) but I wan't to have separate stacks for each thread.

According the the intel manuals it will put ss/esp during a privilige level change but is there a way of forcing this?? (Maybe using a different descriptor type?)

Thanks.
richie

Re:SS/ESP on stack after interrupt

Post by richie »

Hello
I think there is a very easy way to force the processor to always push ss and esp on the stack: Run only your kernel in ring 0 and all other processes run in ring 3 to 1. But I think there is no way to force the processor to push esp and ss if there is a task-switch within the same privilege level. I have never heart about that. Correct me if I'm wrong!
Another way to do this is using Task State Segments.
Tim

Re:SS/ESP on stack after interrupt

Post by Tim »

There's no way of forcing the CPU to use the same stack frame for all privilege level transitions. However, this isn't much of a problem since the CPU always removes everything it's put on the stack (except the error code).

How could a system without separate stacks for each thread work? This is the whole point of threads: to give each thread its own context (registers) and stack (local variables). This applies to both the user-mode and kernel-mode stacks (you want to separate threads in kernel mode, too).
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:SS/ESP on stack after interrupt

Post by Pype.Clicker »

no, no way to enforce this (at least about IRQ) unless you CLI your whole kernel (what you probably don't want : the kernel will not be preemptible anymore ...)

the only case when SS/ESP is pushed is when a ring-crossing occurs (not necessarily from ring 3, but also from ring 2 or 1) to handle the interrupt.
DarylD

Re:SS/ESP on stack after interrupt

Post by DarylD »

Um, this is what I thought.

My kernel is going to be heavily threaded, with worker threads for most devices and fs for a start, but I don't want them bumping into each others stacks.

Maybe I should force a stack reload with each switch to a kernel thread, that might do it, but a little clumsy.
Tim

Re:SS/ESP on stack after interrupt

Post by Tim »

If you think about it, this isn't a problem.

Potential problem: CPU doesn't grab SS0:ESP0 from the current TSS on a ring0->ring0 interrupt.

CPU pushes its registers onto the current stack. Your ISR pushes the other registers onto the current stack and reschedules. The ISR switches stacks (mov esp, xxx), pops the context and returns to a new thread.

All that has happened when switching between two kernel threads is that the context (registers) has been saved on the same stack as the local variables; the user-mode stack doesn't get touched.

For a while I thought that threading in ring 0 would require special treatment, because of the different stack frames, but it doesn't.
DarylD

Re:SS/ESP on stack after interrupt

Post by DarylD »

My only worry is this (A and B are ring 0 threads)..

1. Thread A executing.
2. IRQ 0 timer interrupt occurs, kernel switches threads
3. Thread B executing, calls a procedure dumping call data on stack
4. Task switch occurs back to thread A
5. Bamn..stack clobbered

Unless, I have mechanism where a task switch can not occur during kernel threads (which I think linux does) then the stack could be left in an unexpected state.

Unless I have this all wrong of course?!! ;)
Curufir

Re:SS/ESP on stack after interrupt

Post by Curufir »

Can't you just have all threads use the same stack and partition the stack by assigning each a base ESP? Then on a thread switch you deliberately load the ESP with the reference for that particular thread's stack.

Difficult for me to explain, not sure if I've got it clear in my head myself :).

Eg Process A has a stack of base 0 and limit FFFF (Just some values to work with, they have no significance)
Thread 1 stack starts at 1000
Thread 2 stack starts at 2000
...etc

Now when thread 2 dumps variables into the stack it doesn't matter, because it's dumping into an area unoccupied by thread 1's stack so when the timer switches threads and loads thread 1's stack pointer into ESP everything is fine. So long as none of the threads go beyond their personal stack area everything will run nicely and they all run in the same segment so no selector loads are required. Of course this allows a malicious thread to trash another thread's stack, so it needs some design problems sorting out, but in theory it could work I think (If not please tell me why not, I haven't looked deeply at threading yet so I'd really like to know).

Curufir
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:SS/ESP on stack after interrupt

Post by Pype.Clicker »

DarylD wrote:
Unless, I have mechanism where a task switch can not occur during kernel threads (which I think linux does) then the stack could be left in an unexpected state.

Unless I have this all wrong of course?!! ;)
Say Task A is on SSa (current stack segment): ESP0a (stack entry point for system calls & interrupt from ring3): ESPa(current stack pointer),
And say task B is on SSb, ESP0b, ESPb

when your thread A is interrupted by the IRQ0, we have

Code: Select all

    SSa[ESPa--] = current flags
    SSa[ESPa--] = current CS
    SSa[ESPa--] = current eip
    ... your handler is called ...
now, say you have a stack_switch routine that looks like

Code: Select all

    pusha
    mov eax, [current_TSS.ESP0]
    mov [threadA_context.esp0],eax
    mov [threadA_context.ss],ss
    mov [threadA_context.esp],esp
    lss esp,[threadB_context.esp]
    mov eax,[threadB_context.esp0]
    mov [currentTSS.ESP0],eax
    popa
    ret
when called, this one will gently save all the current task's registers on the stack (we should push segment registers as well) and store the stack pointers in the thread's storage place.

Then, the next thread's stack context is restored with LSS operation (loads SS and ESP atomically). Once this has been issued, we're in the next thread, but with corrupted registers value (only SS & ESP are valid), so we just POP all the registers we saved the last time we left B...

I don't see any problem with that mechanism... It works fine in Clicker from about 2 monthes ...
Tim

Re:SS/ESP on stack after interrupt

Post by Tim »

I don't see any problem with that mechanism... It works fine in Clicker from about 2 monthes ...
Same here. Mobius has user and kernel threads and either can be interrupted and switched at any time.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:SS/ESP on stack after interrupt

Post by Pype.Clicker »

In fact, what happens is that any thread (in virtually every OS i know) has 2 stacks : its user stack (at DPL3) and its kernel stack (protected at DPL0) ... The task switch always occurs between 2 kernel stacks because only the kernel can sleep/wakeup/preempt user threads...
DarylD

Re:SS/ESP on stack after interrupt

Post by DarylD »

I think I see what you mean now, I will have a go when I get home tonight and see what happens with my code and the stack.

Although I am still tempted to just make kernel threads non-preemtible, as long as they execute quickly it shouldn't be a problem.

In my design kernel calls just drop a request into a queue which is then picked up by a worker thread, so most only execute for very short periods, so pre-empting kernel threads should not be necessary.

I will keep all informed.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:SS/ESP on stack after interrupt

Post by Pype.Clicker »

most kernels that were firstly built on non-preemptible kernel threads finally moved to preemptible, but with harder effort than if they were built fully-preemptible from start.

Look at Linux: it start moving to preemption with 2.2.x (iirc), and finally get it with 2.4.x ...

Having a non-preemptible kernel will mean that you will not be able to do complex tasks (and memory management sometimes include complex tasks) without disminishing the whole system's responsiveness ...

better think about it
Tim

Re:SS/ESP on stack after interrupt

Post by Tim »

More importantly, as long as you have a non-preemptable kernel, you can't take advantage of multiple CPUs.
Curufir

Re:SS/ESP on stack after interrupt

Post by Curufir »

Doesn't Linux use multiple task selectors to handle multiple cpus?

If that's the case couldn't you get away with it being non-premptive so long as a thread could be guaranteed never to be run by two different cpus at the same time?

Curufir
Post Reply