2020-10-08 07:23:36

by Maninder Singh

[permalink] [raw]
Subject: [PATCH 1/3] arm: introduce self pointer in thread info

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 <[email protected]>
Signed-off-by: Vaneet Narang <[email protected]>
Signed-off-by: Maninder Singh <[email protected]>
---
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