diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2015-03-09 14:39:23 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-03-10 08:56:10 -0400 |
commit | 263042e4630a85e856b4a8cd72f28dab33ef4741 (patch) | |
tree | 268f16dc93d2f111ffd484300042df3bb089e050 /arch | |
parent | 616ab249f1e42f6135642183529f910fcedc2642 (diff) |
x86/asm/entry/64: Save user RSP in pt_regs->sp on SYSCALL64 fastpath
Prepare for the removal of 'usersp', by simplifying PER_CPU(old_rsp) usage:
- use it only as temp storage
- store the userspace stack pointer immediately in pt_regs->sp
on syscall entry, instead of using it later, on syscall exit.
- change C code to use pt_regs->sp only, instead of PER_CPU(old_rsp)
and task->thread.usersp.
FIXUP/RESTORE_TOP_OF_STACK are simplified as well.
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Will Drewry <wad@chromium.org>
Link: http://lkml.kernel.org/r/1425926364-9526-4-git-send-email-dvlasenk@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/compat.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/ptrace.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 18 | ||||
-rw-r--r-- | arch/x86/kernel/perf_regs.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 3 |
5 files changed, 12 insertions, 21 deletions
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 59c6c401f79f..acdee09228b3 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h | |||
@@ -301,7 +301,7 @@ static inline void __user *arch_compat_alloc_user_space(long len) | |||
301 | sp = task_pt_regs(current)->sp; | 301 | sp = task_pt_regs(current)->sp; |
302 | } else { | 302 | } else { |
303 | /* -128 for the x32 ABI redzone */ | 303 | /* -128 for the x32 ABI redzone */ |
304 | sp = this_cpu_read(old_rsp) - 128; | 304 | sp = task_pt_regs(current)->sp - 128; |
305 | } | 305 | } |
306 | 306 | ||
307 | return (void __user *)round_down(sp - len, 16); | 307 | return (void __user *)round_down(sp - len, 16); |
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 4077d963a1a0..74bb2e0f3030 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -145,12 +145,8 @@ static inline bool user_64bit_mode(struct pt_regs *regs) | |||
145 | #endif | 145 | #endif |
146 | } | 146 | } |
147 | 147 | ||
148 | #define current_user_stack_pointer() this_cpu_read(old_rsp) | 148 | #define current_user_stack_pointer() current_pt_regs()->sp |
149 | /* ia32 vs. x32 difference */ | 149 | #define compat_user_stack_pointer() current_pt_regs()->sp |
150 | #define compat_user_stack_pointer() \ | ||
151 | (test_thread_flag(TIF_IA32) \ | ||
152 | ? current_pt_regs()->sp \ | ||
153 | : this_cpu_read(old_rsp)) | ||
154 | #endif | 150 | #endif |
155 | 151 | ||
156 | #ifdef CONFIG_X86_32 | 152 | #ifdef CONFIG_X86_32 |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 703ced057199..d86788c3257b 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -128,8 +128,6 @@ ENDPROC(native_usergs_sysret64) | |||
128 | * manipulation. | 128 | * manipulation. |
129 | */ | 129 | */ |
130 | .macro FIXUP_TOP_OF_STACK tmp offset=0 | 130 | .macro FIXUP_TOP_OF_STACK tmp offset=0 |
131 | movq PER_CPU_VAR(old_rsp),\tmp | ||
132 | movq \tmp,RSP+\offset(%rsp) | ||
133 | movq $__USER_DS,SS+\offset(%rsp) | 131 | movq $__USER_DS,SS+\offset(%rsp) |
134 | movq $__USER_CS,CS+\offset(%rsp) | 132 | movq $__USER_CS,CS+\offset(%rsp) |
135 | movq RIP+\offset(%rsp),\tmp /* get rip */ | 133 | movq RIP+\offset(%rsp),\tmp /* get rip */ |
@@ -139,8 +137,7 @@ ENDPROC(native_usergs_sysret64) | |||
139 | .endm | 137 | .endm |
140 | 138 | ||
141 | .macro RESTORE_TOP_OF_STACK tmp offset=0 | 139 | .macro RESTORE_TOP_OF_STACK tmp offset=0 |
142 | movq RSP+\offset(%rsp),\tmp | 140 | /* nothing to do */ |
143 | movq \tmp,PER_CPU_VAR(old_rsp) | ||
144 | .endm | 141 | .endm |
145 | 142 | ||
146 | /* | 143 | /* |
@@ -222,9 +219,6 @@ ENDPROC(native_usergs_sysret64) | |||
222 | * Interrupts are off on entry. | 219 | * Interrupts are off on entry. |
223 | * Only called from user space. | 220 | * Only called from user space. |
224 | * | 221 | * |
225 | * XXX if we had a free scratch register we could save the RSP into the stack frame | ||
226 | * and report it properly in ps. Unfortunately we haven't. | ||
227 | * | ||
228 | * When user can change the frames always force IRET. That is because | 222 | * When user can change the frames always force IRET. That is because |
229 | * it deals with uncanonical addresses better. SYSRET has trouble | 223 | * it deals with uncanonical addresses better. SYSRET has trouble |
230 | * with them due to bugs in both AMD and Intel CPUs. | 224 | * with them due to bugs in both AMD and Intel CPUs. |
@@ -253,11 +247,13 @@ GLOBAL(system_call_after_swapgs) | |||
253 | */ | 247 | */ |
254 | ENABLE_INTERRUPTS(CLBR_NONE) | 248 | ENABLE_INTERRUPTS(CLBR_NONE) |
255 | ALLOC_PT_GPREGS_ON_STACK 8 /* +8: space for orig_ax */ | 249 | ALLOC_PT_GPREGS_ON_STACK 8 /* +8: space for orig_ax */ |
250 | movq %rcx,RIP(%rsp) | ||
251 | movq PER_CPU_VAR(old_rsp),%rcx | ||
252 | movq %r11,EFLAGS(%rsp) | ||
253 | movq %rcx,RSP(%rsp) | ||
254 | movq_cfi rax,ORIG_RAX | ||
256 | SAVE_C_REGS_EXCEPT_RAX_RCX_R11 | 255 | SAVE_C_REGS_EXCEPT_RAX_RCX_R11 |
257 | movq $-ENOSYS,RAX(%rsp) | 256 | movq $-ENOSYS,RAX(%rsp) |
258 | movq_cfi rax,ORIG_RAX | ||
259 | movq %r11,EFLAGS(%rsp) | ||
260 | movq %rcx,RIP(%rsp) | ||
261 | CFI_REL_OFFSET rip,RIP | 257 | CFI_REL_OFFSET rip,RIP |
262 | testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP) | 258 | testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP) |
263 | jnz tracesys | 259 | jnz tracesys |
@@ -293,7 +289,7 @@ ret_from_sys_call: | |||
293 | CFI_REGISTER rip,rcx | 289 | CFI_REGISTER rip,rcx |
294 | movq EFLAGS(%rsp),%r11 | 290 | movq EFLAGS(%rsp),%r11 |
295 | /*CFI_REGISTER rflags,r11*/ | 291 | /*CFI_REGISTER rflags,r11*/ |
296 | movq PER_CPU_VAR(old_rsp), %rsp | 292 | movq RSP(%rsp),%rsp |
297 | /* | 293 | /* |
298 | * 64bit SYSRET restores rip from rcx, | 294 | * 64bit SYSRET restores rip from rcx, |
299 | * rflags from r11 (but RF and VM bits are forced to 0), | 295 | * rflags from r11 (but RF and VM bits are forced to 0), |
diff --git a/arch/x86/kernel/perf_regs.c b/arch/x86/kernel/perf_regs.c index 781861cc5ee8..02a8720414c0 100644 --- a/arch/x86/kernel/perf_regs.c +++ b/arch/x86/kernel/perf_regs.c | |||
@@ -177,7 +177,7 @@ void perf_get_regs_user(struct perf_regs *regs_user, | |||
177 | * than just blindly copying user_regs. | 177 | * than just blindly copying user_regs. |
178 | */ | 178 | */ |
179 | regs_user->abi = PERF_SAMPLE_REGS_ABI_64; | 179 | regs_user->abi = PERF_SAMPLE_REGS_ABI_64; |
180 | regs_user_copy->sp = this_cpu_read(old_rsp); | 180 | regs_user_copy->sp = user_regs->sp; |
181 | regs_user_copy->cs = __USER_CS; | 181 | regs_user_copy->cs = __USER_CS; |
182 | regs_user_copy->ss = __USER_DS; | 182 | regs_user_copy->ss = __USER_DS; |
183 | regs_user_copy->cx = -1; /* usually contains garbage */ | 183 | regs_user_copy->cx = -1; /* usually contains garbage */ |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 1e393d27d701..e8c124a1f885 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -602,6 +602,5 @@ long sys_arch_prctl(int code, unsigned long addr) | |||
602 | 602 | ||
603 | unsigned long KSTK_ESP(struct task_struct *task) | 603 | unsigned long KSTK_ESP(struct task_struct *task) |
604 | { | 604 | { |
605 | return (test_tsk_thread_flag(task, TIF_IA32)) ? | 605 | return task_pt_regs(task)->sp; |
606 | (task_pt_regs(task)->sp) : ((task)->thread.usersp); | ||
607 | } | 606 | } |