Kernel utilizing a DPL3 stack segment?

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
nullify

Kernel utilizing a DPL3 stack segment?

Post by nullify »

Greetings all -
I'm trying to task-switch from kernel to a user app. I loaded and ran the app in ring 0 and it seems to work fine. When I go and change it to ring 3 it fails. I tracked the problem down to where the task-switching code is loading the app's DPL3 stack segment into SS, which for some reason causes a GPF. Note that this worked fine when it was a DPL0 stack segment.

Since ring 0 is more privileged than ring 3 I think that what its doing should be valid. I go to change my kernel's stack segment to DPL3, and it also yields a GPF.

Is there a reason why the kernel wouldn't able to use a DPL3 stack segment?
Tim

Re:Kernel utilizing a DPL3 stack segment?

Post by Tim »

Yes, because it's DPL3. CPL0 code must use a DPL0 stack.
nullify

Re:Kernel utilizing a DPL3 stack segment?

Post by nullify »

How can the task switcher (CPL0) switch to a ring 3 app then? Chicken and egg problem: It needs to load the PL3 stack in order to pop off the ring 3 code segment... (?)
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:Kernel utilizing a DPL3 stack segment?

Post by Pype.Clicker »

the ring3 app has a dpl0 stack that is used when it calls (or is interrupted by) the kernel. Switches occurs between those 'kernal stacks', and when the switch is complete, the kernel returns to the normal APP that called it whith IRET.
Tim

Re:Kernel utilizing a DPL3 stack segment?

Post by Tim »

Specifically, the kernel loads the ring 0 SS and ESP from the TSS when an interrupt from ring 3 to ring 0 occurs.

In general, an interrupt from ring n to ring m, where n > m (n is less privileged than m), causes the CPU to load SSm and ESPm. The CPU does not update SSm and ESPm on IRET.
nullify

Re:Kernel utilizing a DPL3 stack segment?

Post by nullify »

Thanks for the info about a ring3->ring0 switch, I didn't know that before... but I was originally asking about a ring0->ring3 switch.

Since ring0 code cannot load a ring3 SS, how do I perform a software task switch? It seems like I need to load both the ring3 CS and SS at the same time which is impossible.

Or am I missing something?
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:Kernel utilizing a DPL3 stack segment?

Post by Pype.Clicker »

Let's say you're loading a new user process. It will have a DPL0 stack (for IRQ, EXC and SYSCALLs) and a DPL3 stack (for the user process)

You will set your task object so that it claims the active stack is SS0 and active code segment is CS0, *but* you will set up the SS0 stack content so that it will return to the user stack when a switch occur.

For instance, let's say you have

Code: Select all

;; from task in eax, target task in edx
task_switch:
pusha
mov [eax+4],ss
mov [eax],esp
lss esp,[edx]
popa
ret

end_of_interrupt:
pop fs
pop gs
pop es
pop ds
iret
Initially, the task's DPL0 stack will have zeroes for the "popa" instruction and will have the address of "end_of_interrupt" for the "ret" instruction.
Once you returned to end_of_interrupt, the DPL0 stack will also have values of segment registers that will fit the expectations of the user process, and IRET will find the user-level code segment as well as the user program entry point and the segment & offset of the user-level stack.

So there is no real DPL0->DPL3 switch: all the task switches are DPL0->DPL0 and then the DPL0 code returns to the interrupted process.

If the user process was never interrupted, well ... you don't care and make the processor believe it was :-)
nullify

Re:Kernel utilizing a DPL3 stack segment?

Post by nullify »

Ah... ingenius! Thank you for explaining. :-)

There's just one thing: I thought IRET only pops off EFLAGS and CS:EIP. So if the method you describe indeed works, I assume that when there is a privilege change it pops the following in order:

EIP
CS
EFLAGS
SS
ESP

Is this correct?
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:Kernel utilizing a DPL3 stack segment?

Post by Pype.Clicker »

better check the intel manuals (and i don't have 'm here), but i wonder if SS isn't the last thing popped.

What happens is that the CPU can detect the "return back to user mode" because it tries to restore a CS value which has a DPL value different from the current DPL.
Post Reply