x86: page-aligned stacks with guard page

Subsequent patches will set this guard page as unmapped,
triggering a page fault on access. If this is due to
stack overflow, a double fault will be triggered,
which we are now capable of handling with a switch to
a know good stack.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2017-07-14 09:38:59 -07:00 committed by Anas Nashif
commit 0fab8a6dc5
4 changed files with 35 additions and 14 deletions

View file

@ -204,6 +204,9 @@ void _new_thread(struct k_thread *thread, char *pStackMem, size_t stackSize,
unsigned long *pInitialThread; unsigned long *pInitialThread;
#if _STACK_GUARD_SIZE
pStackMem += _STACK_GUARD_SIZE;
#endif
_new_thread_init(thread, pStackMem, stackSize, priority, options); _new_thread_init(thread, pStackMem, stackSize, priority, options);
/* carve the thread entry struct from the "base" of the stack */ /* carve the thread entry struct from the "base" of the stack */

View file

@ -20,6 +20,8 @@ extern "C" {
#define STACK_ROUND_UP(x) ROUND_UP(x, STACK_ALIGN_SIZE) #define STACK_ROUND_UP(x) ROUND_UP(x, STACK_ALIGN_SIZE)
#define STACK_ROUND_DOWN(x) ROUND_DOWN(x, STACK_ALIGN_SIZE) #define STACK_ROUND_DOWN(x) ROUND_DOWN(x, STACK_ALIGN_SIZE)
extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE);
/** /**
* *
* @brief Performs architecture-specific initialization * @brief Performs architecture-specific initialization
@ -32,10 +34,9 @@ extern "C" {
*/ */
static inline void kernel_arch_init(void) static inline void kernel_arch_init(void)
{ {
extern char _interrupt_stack[CONFIG_ISR_STACK_SIZE];
_kernel.nested = 0; _kernel.nested = 0;
_kernel.irq_stack = _interrupt_stack + CONFIG_ISR_STACK_SIZE; _kernel.irq_stack = K_THREAD_STACK_BUFFER(_interrupt_stack) +
CONFIG_ISR_STACK_SIZE;
} }
/** /**

View file

@ -18,6 +18,7 @@
#include <arch/x86/irq_controller.h> #include <arch/x86/irq_controller.h>
#include <kernel_arch_thread.h> #include <kernel_arch_thread.h>
#include <generated_dts_board.h> #include <generated_dts_board.h>
#include <mmustructs.h>
#ifndef _ASMLANGUAGE #ifndef _ASMLANGUAGE
#include <arch/x86/asm_inline.h> #include <arch/x86/asm_inline.h>
@ -530,25 +531,38 @@ extern FUNC_NORETURN void _SysFatalErrorHandler(unsigned int reason,
const NANO_ESF * pEsf); const NANO_ESF * pEsf);
#ifdef CONFIG_X86_STACK_PROTECTION
#define _STACK_GUARD_SIZE MMU_PAGE_SIZE
#define _STACK_BASE_ALIGN MMU_PAGE_SIZE
#else
#define _STACK_GUARD_SIZE 0
#define _STACK_BASE_ALIGN STACK_ALIGN
#endif
/* All thread stacks, regardless of whether owned by application or kernel, /* All thread stacks, regardless of whether owned by application or kernel,
* go in the .stacks input section, which will end up in the kernel's * go in the .stacks input section, which will end up in the kernel's
* noinit. * noinit.
*/ */
#define _ARCH_THREAD_STACK_DEFINE(sym, size) \ #define _ARCH_THREAD_STACK_DEFINE(sym, size) \
char _GENERIC_SECTION(.stacks) __aligned(STACK_ALIGN) sym[size] char _GENERIC_SECTION(.stacks) __aligned(_STACK_BASE_ALIGN) \
sym[size + _STACK_GUARD_SIZE]
#define _ARCH_THREAD_STACK_ARRAY_DEFINE(sym, nmemb, size) \ #define _ARCH_THREAD_STACK_ARRAY_DEFINE(sym, nmemb, size) \
char _GENERIC_SECTION(.stacks) __aligned(STACK_ALIGN) sym[nmemb][size] char _GENERIC_SECTION(.stacks) __aligned(_STACK_BASE_ALIGN) \
sym[nmemb][ROUND_UP(size, _STACK_BASE_ALIGN) + \
_STACK_GUARD_SIZE]
#define _ARCH_THREAD_STACK_MEMBER(sym, size) \ #define _ARCH_THREAD_STACK_MEMBER(sym, size) \
char __aligned(STACK_ALIGN) sym[size] char __aligned(_STACK_BASE_ALIGN) sym[size + _STACK_GUARD_SIZE]
#define _ARCH_THREAD_STACK_SIZEOF(sym) \ #define _ARCH_THREAD_STACK_SIZEOF(sym) \
sizeof(sym) (sizeof(sym) - _STACK_GUARD_SIZE)
#define _ARCH_THREAD_STACK_BUFFER(sym) \ #define _ARCH_THREAD_STACK_BUFFER(sym) \
sym (sym + _STACK_GUARD_SIZE)
#if CONFIG_X86_KERNEL_OOPS #if CONFIG_X86_KERNEL_OOPS
#define _ARCH_EXCEPT(reason_p) do { \ #define _ARCH_EXCEPT(reason_p) do { \

View file

@ -121,14 +121,16 @@ K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE);
extern void idle(void *unused1, void *unused2, void *unused3); extern void idle(void *unused1, void *unused2, void *unused3);
void k_call_stacks_analyze(void)
{
#if defined(CONFIG_INIT_STACKS) && defined(CONFIG_PRINTK) #if defined(CONFIG_INIT_STACKS) && defined(CONFIG_PRINTK)
extern char sys_work_q_stack[CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE]; extern K_THREAD_STACK_DEFINE(sys_work_q_stack,
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE);
#if defined(CONFIG_ARC) && CONFIG_RGF_NUM_BANKS != 1 #if defined(CONFIG_ARC) && CONFIG_RGF_NUM_BANKS != 1
extern char _firq_stack[CONFIG_FIRQ_STACK_SIZE]; extern K_THREAD_STACK_DEFINE(_firq_stack, CONFIG_FIRQ_STACK_SIZE);
#endif /* CONFIG_ARC */ #endif /* CONFIG_ARC */
void k_call_stacks_analyze(void)
{
printk("Kernel stacks:\n"); printk("Kernel stacks:\n");
STACK_ANALYZE("main ", _main_stack); STACK_ANALYZE("main ", _main_stack);
STACK_ANALYZE("idle ", _idle_stack); STACK_ANALYZE("idle ", _idle_stack);
@ -137,9 +139,10 @@ void k_call_stacks_analyze(void)
#endif /* CONFIG_ARC */ #endif /* CONFIG_ARC */
STACK_ANALYZE("interrupt", _interrupt_stack); STACK_ANALYZE("interrupt", _interrupt_stack);
STACK_ANALYZE("workqueue", sys_work_q_stack); STACK_ANALYZE("workqueue", sys_work_q_stack);
#endif /* CONFIG_INIT_STACKS && CONFIG_PRINTK */
} }
#else
void k_call_stacks_analyze(void) { }
#endif
/** /**
* *