self pointer to thread info is added in thread info. It is base change required for IRQ stack on ARM.
both stacks will have pointer to thread_info at bottom. Co-developed-by: Vaneet Narang <v.nar...@samsung.com> Signed-off-by: Vaneet Narang <v.nar...@samsung.com> Signed-off-by: Maninder Singh <maninder...@samsung.com> --- arch/arm/Kconfig | 10 ++++++++++ arch/arm/include/asm/assembler.h | 3 +++ arch/arm/include/asm/thread_info.h | 27 +++++++++++++++++++++++++++ include/linux/thread_info.h | 4 ++++ kernel/fork.c | 1 + 5 files changed, 45 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fe2f17eb2..434442f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1667,6 +1667,16 @@ config STACKPROTECTOR_PER_TASK Enable this option to switch to a different method that uses a different canary value for each task. +config IRQ_STACK + bool "use separate stacks for Interrupts" + default n + depends on FRAME_POINTER && !CC_IS_CLANG + help + Select this option to use separate stacks for Interrupt handling code. + It will add latency in fetching thread info of one more derefer operation + and add latency in Interrupt serve at time as for each Interrupt, thread_info + pointer needs to be stored at bottom of interrupt stack. + endmenu menu "Boot options" diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index fce52eed..8512bdc 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -207,6 +207,9 @@ THUMB( mov \rd, sp ) THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT ) mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT +#ifdef CONFIG_IRQ_STACK + ldr \rd, [\rd] +#endif .endm /* diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 536b6b9..a4d5f76 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -44,6 +44,9 @@ struct cpu_context_save { * __switch_to() assumes cpu_context follows immediately after cpu_domain. */ struct thread_info { +#ifdef CONFIG_IRQ_STACK + void *tinfo_ptr; /* pointer to self thread_info */ +#endif unsigned long flags; /* low level flags */ int preempt_count; /* 0 => preemptable, <0 => bug */ mm_segment_t addr_limit; /* address limit */ @@ -67,14 +70,33 @@ struct thread_info { #endif }; + +#ifdef CONFIG_IRQ_STACK +#define INIT_THREAD_SELF_PTR \ + .tinfo_ptr = &init_thread_union.thread_info, +#else +#define INIT_THREAD_SELF_PTR +#endif + #define INIT_THREAD_INFO(tsk) \ { \ + INIT_THREAD_SELF_PTR \ .task = &tsk, \ .flags = 0, \ .preempt_count = INIT_PREEMPT_COUNT, \ .addr_limit = KERNEL_DS, \ } + +#ifdef CONFIG_IRQ_STACK +#define TASK_THREAD_SELF_POINTER(tsk) \ +{ \ + struct thread_info *ti = task_thread_info(tsk); \ + \ + ti->tinfo_ptr = ti; \ +} +#endif + /* * how to get the thread information struct from C */ @@ -82,8 +104,13 @@ struct thread_info { static inline struct thread_info *current_thread_info(void) { +#ifdef CONFIG_IRQ_STACK + return (struct thread_info *) + (*((unsigned long *)(current_stack_pointer & ~(THREAD_SIZE - 1)))); +#else return (struct thread_info *) (current_stack_pointer & ~(THREAD_SIZE - 1)); +#endif } #define thread_saved_pc(tsk) \ diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index e93e249..ddf7b43 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -43,6 +43,10 @@ enum { #define THREAD_ALIGN THREAD_SIZE #endif +#ifndef TASK_THREAD_SELF_POINTER +#define TASK_THREAD_SELF_POINTER(tsk) +#endif + #define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO) /* diff --git a/kernel/fork.c b/kernel/fork.c index 7ef3eb3..d53f5eb 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -901,6 +901,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) #endif setup_thread_stack(tsk, orig); + TASK_THREAD_SELF_POINTER(tsk); clear_user_return_notifier(tsk); clear_tsk_need_resched(tsk); set_task_stack_end_magic(tsk); -- 1.9.1