Page 2 of 3
Posted: Thu Aug 23, 2007 1:33 pm
by jerryleecooper
I store the esp/eip/ss all registers of my processes in the ingeniously named "process" struct. Everytime there's a context switch I save the registers as saved on the user stack by entering in the timer interrupt, and I choose another process, and copy in the old process's stack its registers, and when the interrupt gets called again, this process's registers gets saved on from its user stack, and another process's registers are copied on the process's stack. My timer code is in c, called from my global interrupt code in assembler, and I don't want to change my assembler code too much because it is pretty code. My doing is probably clunky, but it works, and well enough for me.
But I would like to know, is saving the registers in the users stacks correct? Oh, I think I have the answer, the only time the registers gets read is from the interrupt, and it is known from there that the registers comes from entering in the interrupt.
Posted: Fri Aug 24, 2007 3:39 am
by JoeKayzA
bewing wrote:A ring0 app will store EFLAGS/CS/EIP on its own stack. This is very nice.
If I only have one ring0 stack, then an interrupted ring3 app will store SS/ESP/EFLAGS/CS/EIP on the ring0 system stack! Isn't that correct? This is totally unacceptable -- I may not be returning to ring 3. I need that "state" info stored somewhere with the task -- preferably in the task's own memory space. So I have to remove it from the ring0 system stack, right? So I'm back with trying to determine whether I interrupted from CPL0 or 3.
*If* you only have one ring0 stack, of course, that changes the design completely. You should of course differentiate whether a ring0 or a ring3 task was interrupted, but that shouldn't be the problem as the interrupted task's CS-value is pushed onto the stack during an interrupt.
bewing wrote:use a seperate stack in kernel space for each userspace thread
OK, now I'm seeing what you meant by this -- so every single userspace thread that gets spawned allocates both a new stack in userspace AND a new stack in physical kernelspace? Gawd, that's horrifying. I don't want to waste that quantity of memory in kernelspace just to handle interrupts from every possible running thread in userspace.
You got it right, yes. But as I said, that's the way most multitasking systems do it. You need some place in kernel space to store a ring3 task's saved state, just for security reasons (otherwise ring3 code could for example change it's own privilege level...) Typically the ring0 stack is kept small to not exhaust kernel address space, Linux for example uses 4K per kernel stack. If you design a microkernel system (and you don't have much systemcall-code to execute in a thread's context) you could make the kernel stack even smaller, of course.
cheers
Joe
Posted: Fri Aug 24, 2007 10:42 am
by bewing
JoeKayzA wrote:You need some place in kernel space to store a ring3 task's saved state, just for security reasons (otherwise ring3 code could for example change it's own privilege level...)
Actually, it couldn't. During the time that any IRET info is stored in the userland app's memory space
the app is swapped out. So it can't change a damned thing. If you were to implement stupid OS level memory security, then it is true that running userapp2 could change the priv level of userapp1 (by modifying userapp1's memory space) -- but that could easily be fixed by setting userapp1's stack pages (if that's where the IRET info is) to "read only" while the app is swapped out.
JoeKayzA wrote:you could make the kernel stack even smaller, of course.
Yeah, I'm thinking about just making it 48 bytes, and sticking it on the end of each ring3 job table entry.
Posted: Fri Aug 24, 2007 7:39 pm
by frank
This only applies if there can only be one thread in each application. Think about it, if you stored the iret information on the user stack couldn't another thread from the same process change it? That's why I suggest you leave it on the kernel stack.
Posted: Fri Aug 24, 2007 7:45 pm
by Tyler
frank wrote:This only applies if there can only be one thread in each application. Think about it, if you stored the iret information on the user stack couldn't another thread from the same process change it? That's why I suggest you leave it on the kernel stack.
Thread's need their own stack... or else they wouldn't be able to use Automatic Storage Variables.
Posted: Sat Aug 25, 2007 3:13 am
by urxae
Tyler wrote:frank wrote:This only applies if there can only be one thread in each application. Think about it, if you stored the iret information on the user stack couldn't another thread from the same process change it? That's why I suggest you leave it on the kernel stack.
Thread's need their own stack... or else they wouldn't be able to use Automatic Storage Variables.
But (usually) they can still legally access data on the stack of another thread.
Posted: Sat Aug 25, 2007 9:07 am
by Tyler
urxae wrote:Tyler wrote:frank wrote:This only applies if there can only be one thread in each application. Think about it, if you stored the iret information on the user stack couldn't another thread from the same process change it? That's why I suggest you leave it on the kernel stack.
Thread's need their own stack... or else they wouldn't be able to use Automatic Storage Variables.
But (usually) they can still legally access data on the stack of another thread.
Well i don't know about Linux, but in My Operating System and i am pretty sure Windows, the stack is swapped out in order to prevent having to dedicate new areas of the virtual address space for each thread's stack.
Posted: Sat Aug 25, 2007 12:04 pm
by Colonel Kernel
Tyler wrote:Well i don't know about Linux, but in My Operating System and i am pretty sure Windows, the stack is swapped out in order to prevent having to dedicate new areas of the virtual address space for each thread's stack.
I don't know about Linux either, but that's not how it works in Windows. Within a single process, all threads' stacks co-exist in the same address space at different locations.
Posted: Sat Aug 25, 2007 8:46 pm
by frank
Colonel Kernel wrote:Tyler wrote:Well i don't know about Linux, but in My Operating System and i am pretty sure Windows, the stack is swapped out in order to prevent having to dedicate new areas of the virtual address space for each thread's stack.
I don't know about Linux either, but that's not how it works in Windows. Within a single process, all threads' stacks co-exist in the same address space at different locations.
Yeah exactly, if the stack existed at the same location or was inaccessible to the other threads that would mean that the page directory would be different in between the different threads.
Posted: Mon Aug 27, 2007 11:10 am
by Tyler
frank wrote:Colonel Kernel wrote:Tyler wrote:Well i don't know about Linux, but in My Operating System and i am pretty sure Windows, the stack is swapped out in order to prevent having to dedicate new areas of the virtual address space for each thread's stack.
I don't know about Linux either, but that's not how it works in Windows. Within a single process, all threads' stacks co-exist in the same address space at different locations.
Yeah exactly, if the stack existed at the same location or was inaccessible to the other threads that would mean that the page directory would be different in between the different threads.
That's the basic idea...
Posted: Tue Aug 28, 2007 3:29 am
by JamesM
It would also mean that you couldn't use a local stack variable for a synchronous inter-thread call. Heap/global vars would have to be used, which is dangerous in the case of globals and maybe slow in the case of heap vars. Seems an unnecessary policy to me...
Posted: Tue Aug 28, 2007 10:55 am
by Crazed123
And it's better to reference the stack of a running thread when sending a message to another running thread?
Posted: Wed Aug 29, 2007 3:33 am
by JamesM
It's commonly done with synchronous cross-thread calls. Whether it's safe or not is another matter, the fact is muchos code uses it
Posted: Wed Aug 29, 2007 1:29 pm
by Crazed123
JamesM wrote:It's commonly done with synchronous cross-thread calls. Whether it's safe or not is another matter, the fact is muchos code uses it
What, exactly, are synchronous cross-thread calls? I thought the point of a thread was that it ran its own instruction stream, and therefore couldn't "called" into or out of.
But this stuff sounds interesting and right up my alley (I'm into portal-based IPC.), so please do explain.
Posted: Fri Aug 31, 2007 9:50 pm
by Avarok
Heh...
Threads are supposed to be parallel transformations on a data set, however that would require that data not be shared at all between them. Then you have processes. Threads are *supposed* to share the data they transform.
With that understood, often the data needs to be in a certain state for the a given thread to continue execution. This will typically rely on the output of another thread or external event. The thread *could* just infinitely loop until the result came, or we can have it give up it's execution time to something else. The desireable thing often appears to be to cede it's time to the thread it's waiting for.
So yeah, again, the difference between threads and processes is that threads aren't isolated from one another in memory, and so can share memory without any additional abstraction. This is better in all cases except when one thread cannot trust another thread (the bad thread could change my stack, or overwrite my code -
)