diff options
author | Brian Gerst <brgerst@gmail.com> | 2016-08-13 12:38:18 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-08-24 06:27:41 -0400 |
commit | 7b32aeadbc95d4a41402c1c0da6aa3ab51af4c10 (patch) | |
tree | 8ae68aec049bfffe5fdcd725836bd31c61538fda | |
parent | 163630191ecb0dd9e4146d3c910045aba1cfeec1 (diff) |
sched/x86: Add 'struct inactive_task_frame' to better document the sleeping task stack frame
Add 'struct inactive_task_frame', which defines the layout of the stack for
a sleeping process. For now, the only defined field is the BP register
(frame pointer).
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1471106302-10159-4-git-send-email-brgerst@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/stacktrace.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/switch_to.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/kgdb.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 3 |
4 files changed, 11 insertions, 4 deletions
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index 0944218af9e2..7646fb2772f8 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
10 | #include <linux/ptrace.h> | 10 | #include <linux/ptrace.h> |
11 | #include <asm/switch_to.h> | ||
11 | 12 | ||
12 | extern int kstack_depth_to_print; | 13 | extern int kstack_depth_to_print; |
13 | 14 | ||
@@ -70,8 +71,7 @@ stack_frame(struct task_struct *task, struct pt_regs *regs) | |||
70 | return bp; | 71 | return bp; |
71 | } | 72 | } |
72 | 73 | ||
73 | /* bp is the last reg pushed by switch_to */ | 74 | return ((struct inactive_task_frame *)task->thread.sp)->bp; |
74 | return *(unsigned long *)task->thread.sp; | ||
75 | } | 75 | } |
76 | #else | 76 | #else |
77 | static inline unsigned long | 77 | static inline unsigned long |
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index 14e4b20f0aaf..ec689c62c01f 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h | |||
@@ -30,6 +30,11 @@ static inline void prepare_switch_to(struct task_struct *prev, | |||
30 | #endif | 30 | #endif |
31 | } | 31 | } |
32 | 32 | ||
33 | /* data that is pointed to by thread.sp */ | ||
34 | struct inactive_task_frame { | ||
35 | unsigned long bp; | ||
36 | }; | ||
37 | |||
33 | #ifdef CONFIG_X86_32 | 38 | #ifdef CONFIG_X86_32 |
34 | 39 | ||
35 | #ifdef CONFIG_CC_STACKPROTECTOR | 40 | #ifdef CONFIG_CC_STACKPROTECTOR |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 5e3f294ce264..8e36f249646e 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <asm/apicdef.h> | 50 | #include <asm/apicdef.h> |
51 | #include <asm/apic.h> | 51 | #include <asm/apic.h> |
52 | #include <asm/nmi.h> | 52 | #include <asm/nmi.h> |
53 | #include <asm/switch_to.h> | ||
53 | 54 | ||
54 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = | 55 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
55 | { | 56 | { |
@@ -166,7 +167,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
166 | gdb_regs[GDB_DX] = 0; | 167 | gdb_regs[GDB_DX] = 0; |
167 | gdb_regs[GDB_SI] = 0; | 168 | gdb_regs[GDB_SI] = 0; |
168 | gdb_regs[GDB_DI] = 0; | 169 | gdb_regs[GDB_DI] = 0; |
169 | gdb_regs[GDB_BP] = *(unsigned long *)p->thread.sp; | 170 | gdb_regs[GDB_BP] = ((struct inactive_task_frame *)p->thread.sp)->bp; |
170 | #ifdef CONFIG_X86_32 | 171 | #ifdef CONFIG_X86_32 |
171 | gdb_regs[GDB_DS] = __KERNEL_DS; | 172 | gdb_regs[GDB_DS] = __KERNEL_DS; |
172 | gdb_regs[GDB_ES] = __KERNEL_DS; | 173 | gdb_regs[GDB_ES] = __KERNEL_DS; |
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 62c0b0ea2ce4..0115a4a4db96 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/tlbflush.h> | 32 | #include <asm/tlbflush.h> |
33 | #include <asm/mce.h> | 33 | #include <asm/mce.h> |
34 | #include <asm/vm86.h> | 34 | #include <asm/vm86.h> |
35 | #include <asm/switch_to.h> | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * per-CPU TSS segments. Threads are completely 'soft' on Linux, | 38 | * per-CPU TSS segments. Threads are completely 'soft' on Linux, |
@@ -556,7 +557,7 @@ unsigned long get_wchan(struct task_struct *p) | |||
556 | if (sp < bottom || sp > top) | 557 | if (sp < bottom || sp > top) |
557 | return 0; | 558 | return 0; |
558 | 559 | ||
559 | fp = READ_ONCE_NOCHECK(*(unsigned long *)sp); | 560 | fp = READ_ONCE_NOCHECK(((struct inactive_task_frame *)sp)->bp); |
560 | do { | 561 | do { |
561 | if (fp < bottom || fp > top) | 562 | if (fp < bottom || fp > top) |
562 | return 0; | 563 | return 0; |