diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 0e613e7..6edc1d3 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -43,3 +43,25 @@ void arch_task_cache_init(void) __alignof__(union thread_xstate), SLAB_PANIC, NULL); } + + +/* + * Used to check if we can recurse without risking stack overflow + * Rules are : + * 32 bits and 4K stacks (separate irq stacks) : can use up to 25% of stack + * 64 bits, 8K stacks (separate irq stacks) : can use up to 25% of stack + * 32 bits and 8K stacks (no irq stacks) : can use up to 50% of stack + */ +#if defined(CONFIG_4KSTACKS) || defined(CONFIG_X86_64) +# define STACK_RECURSE_LIMIT (THREAD_SIZE/4) +#else +# define STACK_RECURSE_LIMIT (THREAD_SIZE/2) +#endif + +int arch_stack_can_recurse() +{ + unsigned long offset_stack = current_stack_pointer & (THREAD_SIZE - 1); + unsigned long avail_stack = offset_stack - sizeof(struct thread_info); + + return avail_stack >= STACK_RECURSE_LIMIT; +} diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h index f23fefc..9a913c4 100644 --- a/include/asm-x86/thread_info_64.h +++ b/include/asm-x86/thread_info_64.h @@ -60,6 +60,9 @@ struct thread_info { #define init_thread_info (init_thread_union.thread_info) #define init_stack (init_thread_union.stack) +/* how to get the current stack pointer from C */ +register unsigned long current_stack_pointer asm("rsp") __used; + static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; diff --git a/include/linux/sched.h b/include/linux/sched.h index ca720f0..445b8da 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1600,6 +1600,8 @@ union thread_union { unsigned long stack[THREAD_SIZE/sizeof(long)]; }; +extern int arch_stack_can_recurse(void); + #ifndef __HAVE_ARCH_KSTACK_END static inline int kstack_end(void *addr) { diff --git a/kernel/fork.c b/kernel/fork.c index a19df75..cd5d1e1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -136,6 +136,11 @@ void __attribute__((weak)) arch_task_cache_init(void) { } +int __attribute__((weak)) arch_stack_can_recurse(void) +{ + return 0; +} + void __init fork_init(unsigned long mempages) { #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR