Page 1 of 1

Stack size

Posted: Sun Feb 26, 2006 9:30 am
by Rico
I am finally getting along with osdev, but now I'm wondering how big a stack should be.
I'd like to know how big the kernel stack should be and where it is best placed. Is it possible to dynamically grow or shrink a stack or the kernel stack.

I like the idea of a single address space (SAS), but that leaves memory protection in my own hands instead of letting the hardware take care of it. To prevent stack overflows, I put a non-present page below the stack, but (not yet happened, only in theory) if it reaches the non-present page, it will page fault, but since it can't push cs and eip on the stack, it will double fault. Only if the double fault is a task gate, it will not triple fault. That leaves me with the fact that a stack overflow will crash the system.

Does anybody has any sollution to this problem?

Re:Stack size

Posted: Sun Feb 26, 2006 11:37 am
by OZ
Reread what you already said and you will realize you almost already got half of a solution :)
First of all a dynamically growing stack is possible - what you thought of as a simple protection mechanism (page fault) can be extended to a call for another page added to the kernel's stack.
It's then just a matter of how you design your address space so that this doesn't waste too much address space but on the other hand doesn't become ugly limit too early.

I use a single address space aswell (namely using the same pagedir for everything - hope that's correct) but setting pages to be kernel/userland accessable provides even for SAS a hardware based memory protection mechanism.

For userland the system crash shouldn't happen as the process's kernel stack will be fetched upon interupt from the current tss.
Apart from that you should think of a process that overflows the stack as something that's not repairable in terms of the normal page fault.
Therefore you should just kill a userland process which attempts to overflow.
For everything else that overflows the stack and runs in kernel mode you should do the same, perhaps even halt the whole system if it's possible that the process is essential.

hope it helps

Re:Stack size

Posted: Sun Feb 26, 2006 11:41 am
by JAAman
you cannot, directly, use exceptions to demand-expand your kernel stack (unless you are in LMode) -- you can however if you use a task gate (with a separate kernel stack)

afaik, most people allocate a fixed kernel stack (based on the largest expected stack size) to avoid this, (of course in LMode you don't have this since you can allocate individual stacks to special exceptions)

unfortunatly, i cannot help more than this, as my knowledge on this problem is purely theory (so far)

is there a specific reason you prefer single address space? because it will make things much more complicated (and in the end it will prob also run slower, and/or be much less stable)

Re:Stack size

Posted: Sun Feb 26, 2006 11:50 am
by OZ
damn, he's right I wrote crap, for the kernel that's not possible as the reg save can't take place - I guess I worked too much on userland lately... :-[

Re:Stack size

Posted: Sun Feb 26, 2006 7:48 pm
by Brendan
Hi,

You can calculate the kernel's stack space requirements (e.g. stack space for worst operation plus stack space for IRQ handlers, including IRQ nesting if necessary).

You can also fill the kernel's stack with some value (e.g. 0x5AA55AA5) and run the kernel for a while to see how much space was used, and then allow some extra for IRQ handlers. With this approach you could also insert some code into the kernel to explicitly check stack usage (e.g. search from the lowest allocated address up to ESP looking for the first dword that doesn't contain 0x5AA55AA5 anymore).
JAAman wrote:you cannot, directly, use exceptions to demand-expand your kernel stack (unless you are in LMode) -- you can however if you use a task gate (with a separate kernel stack)
You can, depending on a lot of things :).

The trick is to pick the right exception - exception #1 "Debug Exception".

The idea is to set a data breakpoint about X bytes before the end of the kernel stack, so that when the data breakpoint is reached (or when the debug exception occurs) you've still got X bytes of kernel stack left.

The hard part is that the kernel must use the stack in a sequential way, because a single data breakpoint can only be 4 bytes or smaller. For example, if the kernel does "mov eax,[esp-0x12345678]" or "sub esp,0x12345678" then it'd skip over the breakpoint.

For assembly this would be easy enough to do - just use dummy "pushes" instead of "sub esp" if you ever need to make space for local variables.

For compilers it'd be a problem when the breakpoint lines up with a local variable. If the local variable is not used then the debug exception won't happen at all. If the local variable is used then ESP will be lower than the address of the breakpoint.

These problems might be avoidable by assigning values to all local variables when they are declared (but I wouldn't trust this - the compiler's optimizer might optimize this out), and making sure that the breakpoint is far enough from the end of the stack to account for the distance between the first local variable and ESP for all functions.

You could also use more than one breakpoint. For example, if you calculate that your debug exception handler will use X dwords of stack space to extend the kernel stack, then you could use 4 breakpoints that are X bytes apart. In this case you'd want to disable the breakpoints before extending the kernel stack to make sure that the debug exception handler doesn't generate a debug exception while extending the kernel stack.

Of course you'd also want to make sure that the debug exception handler runs with IRQs disabled (i.e. use an interrupt gate).


Cheers,

Brendan