aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorBrian Gerst <brgerst@gmail.com>2016-08-13 12:38:19 -0400
committerIngo Molnar <mingo@kernel.org>2016-08-24 06:31:41 -0400
commit0100301bfdf56a2a370c7157b5ab0fbf9313e1cd (patch)
treef8a339f20fb486a1ebe029d1c409e94c9bf8d67a /arch/x86/kernel
parent7b32aeadbc95d4a41402c1c0da6aa3ab51af4c10 (diff)
sched/x86: Rewrite the switch_to() code
Move the low-level context switch code to an out-of-line asm stub instead of using complex inline asm. This allows constructing a new stack frame for the child process to make it seamlessly flow to ret_from_fork without an extra test and branch in __switch_to(). It also improves code generation for __schedule() by using the C calling convention instead of clobbering all registers. 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-5-git-send-email-brgerst@gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/asm-offsets.c6
-rw-r--r--arch/x86/kernel/asm-offsets_32.c5
-rw-r--r--arch/x86/kernel/asm-offsets_64.c5
-rw-r--r--arch/x86/kernel/process_32.c9
-rw-r--r--arch/x86/kernel/process_64.c9
-rw-r--r--arch/x86/kernel/smpboot.c1
6 files changed, 29 insertions, 6 deletions
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 2bd5c6ff7ee7..db3a0af9b9ec 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -29,6 +29,12 @@
29 29
30void common(void) { 30void common(void) {
31 BLANK(); 31 BLANK();
32 OFFSET(TASK_threadsp, task_struct, thread.sp);
33#ifdef CONFIG_CC_STACKPROTECTOR
34 OFFSET(TASK_stack_canary, task_struct, stack_canary);
35#endif
36
37 BLANK();
32 OFFSET(TI_flags, thread_info, flags); 38 OFFSET(TI_flags, thread_info, flags);
33 OFFSET(TI_status, thread_info, status); 39 OFFSET(TI_status, thread_info, status);
34 40
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index ecdc1d217dc0..880aa093268d 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -57,6 +57,11 @@ void foo(void)
57 /* Size of SYSENTER_stack */ 57 /* Size of SYSENTER_stack */
58 DEFINE(SIZEOF_SYSENTER_stack, sizeof(((struct tss_struct *)0)->SYSENTER_stack)); 58 DEFINE(SIZEOF_SYSENTER_stack, sizeof(((struct tss_struct *)0)->SYSENTER_stack));
59 59
60#ifdef CONFIG_CC_STACKPROTECTOR
61 BLANK();
62 OFFSET(stack_canary_offset, stack_canary, canary);
63#endif
64
60#if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE) 65#if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE)
61 BLANK(); 66 BLANK();
62 OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); 67 OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index d875f97d4e0b..210927ee2e74 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -56,6 +56,11 @@ int main(void)
56 OFFSET(TSS_sp0, tss_struct, x86_tss.sp0); 56 OFFSET(TSS_sp0, tss_struct, x86_tss.sp0);
57 BLANK(); 57 BLANK();
58 58
59#ifdef CONFIG_CC_STACKPROTECTOR
60 DEFINE(stack_canary_offset, offsetof(union irq_stack_union, stack_canary));
61 BLANK();
62#endif
63
59 DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1); 64 DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1);
60 DEFINE(NR_syscalls, sizeof(syscalls_64)); 65 DEFINE(NR_syscalls, sizeof(syscalls_64));
61 66
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index d86be29c38c7..4bedbc08e53c 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -133,17 +133,20 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
133 unsigned long arg, struct task_struct *p, unsigned long tls) 133 unsigned long arg, struct task_struct *p, unsigned long tls)
134{ 134{
135 struct pt_regs *childregs = task_pt_regs(p); 135 struct pt_regs *childregs = task_pt_regs(p);
136 struct fork_frame *fork_frame = container_of(childregs, struct fork_frame, regs);
137 struct inactive_task_frame *frame = &fork_frame->frame;
136 struct task_struct *tsk; 138 struct task_struct *tsk;
137 int err; 139 int err;
138 140
139 p->thread.sp = (unsigned long) childregs; 141 frame->bp = 0;
142 p->thread.sp = (unsigned long) fork_frame;
140 p->thread.sp0 = (unsigned long) (childregs+1); 143 p->thread.sp0 = (unsigned long) (childregs+1);
141 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); 144 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
142 145
143 if (unlikely(p->flags & PF_KTHREAD)) { 146 if (unlikely(p->flags & PF_KTHREAD)) {
144 /* kernel thread */ 147 /* kernel thread */
145 memset(childregs, 0, sizeof(struct pt_regs)); 148 memset(childregs, 0, sizeof(struct pt_regs));
146 p->thread.ip = (unsigned long) ret_from_kernel_thread; 149 frame->ret_addr = (unsigned long) ret_from_kernel_thread;
147 task_user_gs(p) = __KERNEL_STACK_CANARY; 150 task_user_gs(p) = __KERNEL_STACK_CANARY;
148 childregs->ds = __USER_DS; 151 childregs->ds = __USER_DS;
149 childregs->es = __USER_DS; 152 childregs->es = __USER_DS;
@@ -161,7 +164,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
161 if (sp) 164 if (sp)
162 childregs->sp = sp; 165 childregs->sp = sp;
163 166
164 p->thread.ip = (unsigned long) ret_from_fork; 167 frame->ret_addr = (unsigned long) ret_from_fork;
165 task_user_gs(p) = get_user_gs(current_pt_regs()); 168 task_user_gs(p) = get_user_gs(current_pt_regs());
166 169
167 p->thread.io_bitmap_ptr = NULL; 170 p->thread.io_bitmap_ptr = NULL;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 63236d8f84bf..827eeed03e16 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -141,12 +141,17 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
141{ 141{
142 int err; 142 int err;
143 struct pt_regs *childregs; 143 struct pt_regs *childregs;
144 struct fork_frame *fork_frame;
145 struct inactive_task_frame *frame;
144 struct task_struct *me = current; 146 struct task_struct *me = current;
145 147
146 p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE; 148 p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE;
147 childregs = task_pt_regs(p); 149 childregs = task_pt_regs(p);
148 p->thread.sp = (unsigned long) childregs; 150 fork_frame = container_of(childregs, struct fork_frame, regs);
149 set_tsk_thread_flag(p, TIF_FORK); 151 frame = &fork_frame->frame;
152 frame->bp = 0;
153 frame->ret_addr = (unsigned long) ret_from_fork;
154 p->thread.sp = (unsigned long) fork_frame;
150 p->thread.io_bitmap_ptr = NULL; 155 p->thread.io_bitmap_ptr = NULL;
151 156
152 savesegment(gs, p->thread.gsindex); 157 savesegment(gs, p->thread.gsindex);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c85d2c636092..7e52f83d3a4b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -942,7 +942,6 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle)
942 per_cpu(cpu_current_top_of_stack, cpu) = 942 per_cpu(cpu_current_top_of_stack, cpu) =
943 (unsigned long)task_stack_page(idle) + THREAD_SIZE; 943 (unsigned long)task_stack_page(idle) + THREAD_SIZE;
944#else 944#else
945 clear_tsk_thread_flag(idle, TIF_FORK);
946 initial_gs = per_cpu_offset(cpu); 945 initial_gs = per_cpu_offset(cpu);
947#endif 946#endif
948} 947}