blob: 2dc5c01f754d76e33dc727a414d3cfe097975b53 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/entry.S
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
6 * Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
7 *
8 * $Id$
9 */
10
11/*
12 * entry.S contains the system-call and fault low-level handling routines.
13 *
14 * NOTE: This code handles signal-recognition, which happens every time
15 * after an interrupt and after each system call.
16 *
17 * Normal syscalls and interrupts don't save a full stack frame, this is
18 * only done for syscall tracing, signals or fork/exec et.al.
19 *
20 * A note on terminology:
21 * - top of stack: Architecture defined interrupt frame from SS to RIP
22 * at the top of the kernel process stack.
23 * - partial stack frame: partially saved registers upto R11.
24 * - full stack frame: Like partial stack frame, but all register saved.
25 *
26 * TODO:
27 * - schedule it carefully for the final hardware.
28 */
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/linkage.h>
31#include <asm/segment.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/cache.h>
33#include <asm/errno.h>
34#include <asm/dwarf2.h>
35#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020036#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/msr.h>
38#include <asm/unistd.h>
39#include <asm/thread_info.h>
40#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010041#include <asm/page.h>
Ingo Molnar2601e642006-07-03 00:24:45 -070042#include <asm/irqflags.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44 .code64
45
Andi Kleendc37db42005-04-16 15:25:05 -070046#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#define retint_kernel retint_restore_args
48#endif
Ingo Molnar2601e642006-07-03 00:24:45 -070049
50
51.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
52#ifdef CONFIG_TRACE_IRQFLAGS
53 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
54 jnc 1f
55 TRACE_IRQS_ON
561:
57#endif
58.endm
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060/*
61 * C code is not supposed to know about undefined top of stack. Every time
62 * a C function with an pt_regs argument is called from the SYSCALL based
63 * fast path FIXUP_TOP_OF_STACK is needed.
64 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
65 * manipulation.
66 */
67
68 /* %rsp:at FRAMEEND */
69 .macro FIXUP_TOP_OF_STACK tmp
70 movq %gs:pda_oldrsp,\tmp
71 movq \tmp,RSP(%rsp)
72 movq $__USER_DS,SS(%rsp)
73 movq $__USER_CS,CS(%rsp)
74 movq $-1,RCX(%rsp)
75 movq R11(%rsp),\tmp /* get eflags */
76 movq \tmp,EFLAGS(%rsp)
77 .endm
78
79 .macro RESTORE_TOP_OF_STACK tmp,offset=0
80 movq RSP-\offset(%rsp),\tmp
81 movq \tmp,%gs:pda_oldrsp
82 movq EFLAGS-\offset(%rsp),\tmp
83 movq \tmp,R11-\offset(%rsp)
84 .endm
85
86 .macro FAKE_STACK_FRAME child_rip
87 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -070088 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 pushq %rax /* ss */
90 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020091 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 pushq %rax /* rsp */
93 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020094 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 pushq $(1<<9) /* eflags - interrupts on */
96 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020097 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 pushq $__KERNEL_CS /* cs */
99 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200100 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 pushq \child_rip /* rip */
102 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200103 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 pushq %rax /* orig rax */
105 CFI_ADJUST_CFA_OFFSET 8
106 .endm
107
108 .macro UNFAKE_STACK_FRAME
109 addq $8*6, %rsp
110 CFI_ADJUST_CFA_OFFSET -(6*8)
111 .endm
112
Jan Beulich7effaa82005-09-12 18:49:24 +0200113 .macro CFI_DEFAULT_STACK start=1
114 .if \start
115 CFI_STARTPROC simple
116 CFI_DEF_CFA rsp,SS+8
117 .else
118 CFI_DEF_CFA_OFFSET SS+8
119 .endif
120 CFI_REL_OFFSET r15,R15
121 CFI_REL_OFFSET r14,R14
122 CFI_REL_OFFSET r13,R13
123 CFI_REL_OFFSET r12,R12
124 CFI_REL_OFFSET rbp,RBP
125 CFI_REL_OFFSET rbx,RBX
126 CFI_REL_OFFSET r11,R11
127 CFI_REL_OFFSET r10,R10
128 CFI_REL_OFFSET r9,R9
129 CFI_REL_OFFSET r8,R8
130 CFI_REL_OFFSET rax,RAX
131 CFI_REL_OFFSET rcx,RCX
132 CFI_REL_OFFSET rdx,RDX
133 CFI_REL_OFFSET rsi,RSI
134 CFI_REL_OFFSET rdi,RDI
135 CFI_REL_OFFSET rip,RIP
136 /*CFI_REL_OFFSET cs,CS*/
137 /*CFI_REL_OFFSET rflags,EFLAGS*/
138 CFI_REL_OFFSET rsp,RSP
139 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 .endm
141/*
142 * A newly forked process directly context switches into this.
143 */
144/* rdi: prev */
145ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 CFI_DEFAULT_STACK
147 call schedule_tail
148 GET_THREAD_INFO(%rcx)
149 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
150 jnz rff_trace
151rff_action:
152 RESTORE_REST
153 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
154 je int_ret_from_sys_call
155 testl $_TIF_IA32,threadinfo_flags(%rcx)
156 jnz int_ret_from_sys_call
157 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
158 jmp ret_from_sys_call
159rff_trace:
160 movq %rsp,%rdi
161 call syscall_trace_leave
162 GET_THREAD_INFO(%rcx)
163 jmp rff_action
164 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200165END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167/*
168 * System call entry. Upto 6 arguments in registers are supported.
169 *
170 * SYSCALL does not save anything on the stack and does not change the
171 * stack pointer.
172 */
173
174/*
175 * Register setup:
176 * rax system call number
177 * rdi arg0
178 * rcx return address for syscall/sysret, C arg3
179 * rsi arg1
180 * rdx arg2
181 * r10 arg3 (--> moved to rcx for C)
182 * r8 arg4
183 * r9 arg5
184 * r11 eflags for syscall/sysret, temporary for C
185 * r12-r15,rbp,rbx saved by C code, not touched.
186 *
187 * Interrupts are off on entry.
188 * Only called from user space.
189 *
190 * XXX if we had a free scratch register we could save the RSP into the stack frame
191 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200192 *
193 * When user can change the frames always force IRET. That is because
194 * it deals with uncanonical addresses better. SYSRET has trouble
195 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 */
197
198ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200199 CFI_STARTPROC simple
Jan Beulichdffead42006-06-26 13:57:38 +0200200 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200201 CFI_REGISTER rip,rcx
202 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 swapgs
204 movq %rsp,%gs:pda_oldrsp
205 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700206 /*
207 * No need to follow this irqs off/on section - it's straight
208 * and short:
209 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 sti
211 SAVE_ARGS 8,1
212 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200213 movq %rcx,RIP-ARGOFFSET(%rsp)
214 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 GET_THREAD_INFO(%rcx)
216 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200217 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 jnz tracesys
219 cmpq $__NR_syscall_max,%rax
220 ja badsys
221 movq %r10,%rcx
222 call *sys_call_table(,%rax,8) # XXX: rip relative
223 movq %rax,RAX-ARGOFFSET(%rsp)
224/*
225 * Syscall return path ending with SYSRET (fast path)
226 * Has incomplete stack frame and undefined top of stack.
227 */
228 .globl ret_from_sys_call
229ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700230 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 /* edi: flagmask */
232sysret_check:
233 GET_THREAD_INFO(%rcx)
234 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700235 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 movl threadinfo_flags(%rcx),%edx
237 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200238 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 jnz sysret_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700240 /*
241 * sysretq will re-enable interrupts:
242 */
243 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200245 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200247 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 movq %gs:pda_oldrsp,%rsp
249 swapgs
250 sysretq
251
252 /* Handle reschedules */
253 /* edx: work, edi: workmask */
254sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200255 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 bt $TIF_NEED_RESCHED,%edx
257 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700258 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 sti
260 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200261 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 call schedule
263 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200264 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 jmp sysret_check
266
267 /* Handle a signal */
268sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700269 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700271 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
272 jz 1f
273
274 /* Really a signal */
275 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 leaq do_notify_resume(%rip),%rax
277 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
278 xorl %esi,%esi # oldset -> arg2
279 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002801: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200281 /* Use IRET because user could have changed frame. This
282 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
283 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700284 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200285 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Jan Beulich7effaa82005-09-12 18:49:24 +0200287badsys:
288 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
289 jmp ret_from_sys_call
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 /* Do syscall tracing */
292tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200293 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 SAVE_REST
295 movq $-ENOSYS,RAX(%rsp)
296 FIXUP_TOP_OF_STACK %rdi
297 movq %rsp,%rdi
298 call syscall_trace_enter
299 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
300 RESTORE_REST
301 cmpq $__NR_syscall_max,%rax
302 ja 1f
303 movq %r10,%rcx /* fixup for C */
304 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02003051: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200306 /* Use IRET because user could have changed frame */
307 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200308 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200309END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311/*
312 * Syscall return path ending with IRET.
313 * Has correct top of stack, but partial stack frame.
314 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200315ENTRY(int_ret_from_sys_call)
316 CFI_STARTPROC simple
317 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
318 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
319 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
320 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
321 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
322 CFI_REL_OFFSET rip,RIP-ARGOFFSET
323 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
324 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
325 CFI_REL_OFFSET rax,RAX-ARGOFFSET
326 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
327 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
328 CFI_REL_OFFSET r8,R8-ARGOFFSET
329 CFI_REL_OFFSET r9,R9-ARGOFFSET
330 CFI_REL_OFFSET r10,R10-ARGOFFSET
331 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700333 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 testl $3,CS-ARGOFFSET(%rsp)
335 je retint_restore_args
336 movl $_TIF_ALLWORK_MASK,%edi
337 /* edi: mask to check */
338int_with_check:
339 GET_THREAD_INFO(%rcx)
340 movl threadinfo_flags(%rcx),%edx
341 andl %edi,%edx
342 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100343 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 jmp retint_swapgs
345
346 /* Either reschedule or signal or syscall exit tracking needed. */
347 /* First do a reschedule test. */
348 /* edx: work, edi: workmask */
349int_careful:
350 bt $TIF_NEED_RESCHED,%edx
351 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700352 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 sti
354 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200355 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 call schedule
357 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200358 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700359 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700360 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 jmp int_with_check
362
363 /* handle signals and tracing -- both require a full stack frame */
364int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700365 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sti
367 SAVE_REST
368 /* Check for syscall exit trace */
369 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
370 jz int_signal
371 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200372 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 leaq 8(%rsp),%rdi # &ptregs -> arg1
374 call syscall_trace_leave
375 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200376 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700377 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700378 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700379 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 jmp int_restore_rest
381
382int_signal:
383 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
384 jz 1f
385 movq %rsp,%rdi # &ptregs -> arg1
386 xorl %esi,%esi # oldset -> arg2
387 call do_notify_resume
3881: movl $_TIF_NEED_RESCHED,%edi
389int_restore_rest:
390 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700391 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700392 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 jmp int_with_check
394 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200395END(int_ret_from_sys_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
397/*
398 * Certain special system calls that need to save a complete full stack frame.
399 */
400
401 .macro PTREGSCALL label,func,arg
402 .globl \label
403\label:
404 leaq \func(%rip),%rax
405 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
406 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200407END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 .endm
409
Jan Beulich7effaa82005-09-12 18:49:24 +0200410 CFI_STARTPROC
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 PTREGSCALL stub_clone, sys_clone, %r8
413 PTREGSCALL stub_fork, sys_fork, %rdi
414 PTREGSCALL stub_vfork, sys_vfork, %rdi
415 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
416 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
417 PTREGSCALL stub_iopl, sys_iopl, %rsi
418
419ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200421 CFI_ADJUST_CFA_OFFSET -8
422 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 SAVE_REST
424 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200425 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 FIXUP_TOP_OF_STACK %r11
427 call *%rax
428 RESTORE_TOP_OF_STACK %r11
429 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200430 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 RESTORE_REST
432 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200433 CFI_ADJUST_CFA_OFFSET 8
434 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 ret
436 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200437END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439ENTRY(stub_execve)
440 CFI_STARTPROC
441 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200442 CFI_ADJUST_CFA_OFFSET -8
443 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 FIXUP_TOP_OF_STACK %r11
446 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 movq %rax,RAX(%rsp)
449 RESTORE_REST
450 jmp int_ret_from_sys_call
451 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200452END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
454/*
455 * sigreturn is special because it needs to restore all registers on return.
456 * This cannot be done with SYSRET, so use the IRET return path instead.
457 */
458ENTRY(stub_rt_sigreturn)
459 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200460 addq $8, %rsp
461 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 SAVE_REST
463 movq %rsp,%rdi
464 FIXUP_TOP_OF_STACK %r11
465 call sys_rt_sigreturn
466 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
467 RESTORE_REST
468 jmp int_ret_from_sys_call
469 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200470END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Jan Beulich7effaa82005-09-12 18:49:24 +0200472/*
473 * initial frame state for interrupts and exceptions
474 */
475 .macro _frame ref
476 CFI_STARTPROC simple
477 CFI_DEF_CFA rsp,SS+8-\ref
478 /*CFI_REL_OFFSET ss,SS-\ref*/
479 CFI_REL_OFFSET rsp,RSP-\ref
480 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
481 /*CFI_REL_OFFSET cs,CS-\ref*/
482 CFI_REL_OFFSET rip,RIP-\ref
483 .endm
484
485/* initial frame state for interrupts (and exceptions without error code) */
486#define INTR_FRAME _frame RIP
487/* initial frame state for exceptions with error code (and interrupts with
488 vector already pushed) */
489#define XCPT_FRAME _frame ORIG_RAX
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491/*
492 * Interrupt entry/exit.
493 *
494 * Interrupt entry points save only callee clobbered registers in fast path.
495 *
496 * Entry runs with interrupts off.
497 */
498
499/* 0(%rsp): interrupt number */
500 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 SAVE_ARGS
503 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200504 pushq %rbp
505 CFI_ADJUST_CFA_OFFSET 8
506 CFI_REL_OFFSET rbp, 0
507 movq %rsp,%rbp
508 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 testl $3,CS(%rdi)
510 je 1f
511 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07005121: incl %gs:pda_irqcount # RED-PEN should check preempt count
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200513 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200514 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700515 /*
516 * We entered an interrupt context - irqs are off:
517 */
518 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 call \func
520 .endm
521
522ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200523 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 interrupt do_IRQ
525 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200526ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700528 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700529 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200530 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200531 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200532 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200533exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 GET_THREAD_INFO(%rcx)
535 testl $3,CS-ARGOFFSET(%rsp)
536 je retint_kernel
537
538 /* Interrupt came from user space */
539 /*
540 * Has a correct top of stack, but a partial stack frame
541 * %rcx: thread info. Interrupts off.
542 */
543retint_with_reschedule:
544 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200545retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 movl threadinfo_flags(%rcx),%edx
547 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200548 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 jnz retint_careful
550retint_swapgs:
Ingo Molnar2601e642006-07-03 00:24:45 -0700551 /*
552 * The iretq could re-enable interrupts:
553 */
554 cli
555 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700557 jmp restore_args
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559retint_restore_args:
560 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700561 /*
562 * The iretq could re-enable interrupts:
563 */
564 TRACE_IRQS_IRETQ
565restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 RESTORE_ARGS 0,8,0
567iret_label:
568 iretq
569
570 .section __ex_table,"a"
571 .quad iret_label,bad_iret
572 .previous
573 .section .fixup,"ax"
574 /* force a signal here? this matches i386 behaviour */
575 /* running with kernel gs */
576bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100577 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700578 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100579 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 jmp do_exit
581 .previous
582
Jan Beulich7effaa82005-09-12 18:49:24 +0200583 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200585 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 bt $TIF_NEED_RESCHED,%edx
587 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700588 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 sti
590 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200591 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 call schedule
593 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200594 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 GET_THREAD_INFO(%rcx)
596 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700597 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 jmp retint_check
599
600retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700601 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
602 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700603 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 sti
605 SAVE_REST
606 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700607 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 movq %rsp,%rdi # &pt_regs
609 call do_notify_resume
610 RESTORE_REST
611 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700612 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700613 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700614 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 jmp retint_check
616
617#ifdef CONFIG_PREEMPT
618 /* Returning to kernel space. Check if we need preemption */
619 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200620ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 cmpl $0,threadinfo_preempt_count(%rcx)
622 jnz retint_restore_args
623 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
624 jnc retint_restore_args
625 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
626 jnc retint_restore_args
627 call preempt_schedule_irq
628 jmp exit_intr
629#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200632END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634/*
635 * APIC interrupts.
636 */
637 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200638 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700639 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200640 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 interrupt \func
642 jmp ret_from_intr
643 CFI_ENDPROC
644 .endm
645
646ENTRY(thermal_interrupt)
647 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200648END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Jacob Shin89b831e2005-11-05 17:25:53 +0100650ENTRY(threshold_interrupt)
651 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200652END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654#ifdef CONFIG_SMP
655ENTRY(reschedule_interrupt)
656 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200657END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Andi Kleene5bc8b62005-09-12 18:49:24 +0200659 .macro INVALIDATE_ENTRY num
660ENTRY(invalidate_interrupt\num)
661 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200662END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200663 .endm
664
665 INVALIDATE_ENTRY 0
666 INVALIDATE_ENTRY 1
667 INVALIDATE_ENTRY 2
668 INVALIDATE_ENTRY 3
669 INVALIDATE_ENTRY 4
670 INVALIDATE_ENTRY 5
671 INVALIDATE_ENTRY 6
672 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674ENTRY(call_function_interrupt)
675 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200676END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677#endif
678
679#ifdef CONFIG_X86_LOCAL_APIC
680ENTRY(apic_timer_interrupt)
681 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200682END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684ENTRY(error_interrupt)
685 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200686END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688ENTRY(spurious_interrupt)
689 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200690END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691#endif
692
693/*
694 * Exception entry points.
695 */
696 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200697 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200699 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200701 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 leaq \sym(%rip),%rax
703 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200704 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 .endm
706
707 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200708 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200710 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 leaq \sym(%rip),%rax
712 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200713 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 .endm
715
716 /* error code is on the stack already */
717 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700718 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 SAVE_ALL
720 cld
721 movl $1,%ebx
722 movl $MSR_GS_BASE,%ecx
723 rdmsr
724 testl %edx,%edx
725 js 1f
726 swapgs
727 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01007281:
729 .if \ist
730 movq %gs:pda_data_offset, %rbp
731 .endif
732 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 movq ORIG_RAX(%rsp),%rsi
734 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100735 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100736 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100737 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100739 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100740 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100741 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700742 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700743 .if \irqtrace
744 TRACE_IRQS_OFF
745 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700747
748 /*
749 * "Paranoid" exit path from exception stack.
750 * Paranoid because this is used by NMIs and cannot take
751 * any kernel state for granted.
752 * We don't do kernel preemption checks here, because only
753 * NMI should be common and it does not enable IRQs and
754 * cannot get reschedule ticks.
755 *
756 * "trace" is 0 for the NMI handler only, because irq-tracing
757 * is fundamentally NMI-unsafe. (we cannot change the soft and
758 * hard flags at once, atomically)
759 */
760 .macro paranoidexit trace=1
761 /* ebx: no swapgs flag */
762paranoid_exit\trace:
763 testl %ebx,%ebx /* swapgs needed? */
764 jnz paranoid_restore\trace
765 testl $3,CS(%rsp)
766 jnz paranoid_userspace\trace
767paranoid_swapgs\trace:
768 TRACE_IRQS_IRETQ 0
769 swapgs
770paranoid_restore\trace:
771 RESTORE_ALL 8
772 iretq
773paranoid_userspace\trace:
774 GET_THREAD_INFO(%rcx)
775 movl threadinfo_flags(%rcx),%ebx
776 andl $_TIF_WORK_MASK,%ebx
777 jz paranoid_swapgs\trace
778 movq %rsp,%rdi /* &pt_regs */
779 call sync_regs
780 movq %rax,%rsp /* switch stack for scheduling */
781 testl $_TIF_NEED_RESCHED,%ebx
782 jnz paranoid_schedule\trace
783 movl %ebx,%edx /* arg3: thread flags */
784 .if \trace
785 TRACE_IRQS_ON
786 .endif
787 sti
788 xorl %esi,%esi /* arg2: oldset */
789 movq %rsp,%rdi /* arg1: &pt_regs */
790 call do_notify_resume
791 cli
792 .if \trace
793 TRACE_IRQS_OFF
794 .endif
795 jmp paranoid_userspace\trace
796paranoid_schedule\trace:
797 .if \trace
798 TRACE_IRQS_ON
799 .endif
800 sti
801 call schedule
802 cli
803 .if \trace
804 TRACE_IRQS_OFF
805 .endif
806 jmp paranoid_userspace\trace
807 CFI_ENDPROC
808 .endm
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810/*
811 * Exception entry point. This expects an error code/orig_rax on the stack
812 * and the exception handler in %rax.
813 */
814ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200815 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 /* rdi slot contains rax, oldrax contains error code */
817 cld
818 subq $14*8,%rsp
819 CFI_ADJUST_CFA_OFFSET (14*8)
820 movq %rsi,13*8(%rsp)
821 CFI_REL_OFFSET rsi,RSI
822 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
823 movq %rdx,12*8(%rsp)
824 CFI_REL_OFFSET rdx,RDX
825 movq %rcx,11*8(%rsp)
826 CFI_REL_OFFSET rcx,RCX
827 movq %rsi,10*8(%rsp) /* store rax */
828 CFI_REL_OFFSET rax,RAX
829 movq %r8, 9*8(%rsp)
830 CFI_REL_OFFSET r8,R8
831 movq %r9, 8*8(%rsp)
832 CFI_REL_OFFSET r9,R9
833 movq %r10,7*8(%rsp)
834 CFI_REL_OFFSET r10,R10
835 movq %r11,6*8(%rsp)
836 CFI_REL_OFFSET r11,R11
837 movq %rbx,5*8(%rsp)
838 CFI_REL_OFFSET rbx,RBX
839 movq %rbp,4*8(%rsp)
840 CFI_REL_OFFSET rbp,RBP
841 movq %r12,3*8(%rsp)
842 CFI_REL_OFFSET r12,R12
843 movq %r13,2*8(%rsp)
844 CFI_REL_OFFSET r13,R13
845 movq %r14,1*8(%rsp)
846 CFI_REL_OFFSET r14,R14
847 movq %r15,(%rsp)
848 CFI_REL_OFFSET r15,R15
849 xorl %ebx,%ebx
850 testl $3,CS(%rsp)
851 je error_kernelspace
852error_swapgs:
853 swapgs
854error_sti:
855 movq %rdi,RDI(%rsp)
856 movq %rsp,%rdi
857 movq ORIG_RAX(%rsp),%rsi /* get error code */
858 movq $-1,ORIG_RAX(%rsp)
859 call *%rax
860 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
861error_exit:
862 movl %ebx,%eax
863 RESTORE_REST
864 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700865 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 GET_THREAD_INFO(%rcx)
867 testl %eax,%eax
868 jne retint_kernel
869 movl threadinfo_flags(%rcx),%edx
870 movl $_TIF_WORK_MASK,%edi
871 andl %edi,%edx
872 jnz retint_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700873 /*
874 * The iret might restore flags:
875 */
876 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 swapgs
878 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100879 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 CFI_ENDPROC
881
882error_kernelspace:
883 incl %ebx
884 /* There are two places in the kernel that can potentially fault with
885 usergs. Handle them here. The exception handlers after
886 iret run with kernel gs again, so don't set the user space flag.
887 B stepping K8s sometimes report an truncated RIP for IRET
888 exceptions returning to compat mode. Check for these here too. */
889 leaq iret_label(%rip),%rbp
890 cmpq %rbp,RIP(%rsp)
891 je error_swapgs
892 movl %ebp,%ebp /* zero extend */
893 cmpq %rbp,RIP(%rsp)
894 je error_swapgs
895 cmpq $gs_change,RIP(%rsp)
896 je error_swapgs
897 jmp error_sti
Jan Beulich4b787e02006-06-26 13:56:55 +0200898END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 /* Reload gs selector with exception handling */
901 /* edi: new selector */
902ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200903 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200905 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 cli
907 swapgs
908gs_change:
909 movl %edi,%gs
9102: mfence /* workaround */
911 swapgs
912 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200913 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200915 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200916ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 .section __ex_table,"a"
919 .align 8
920 .quad gs_change,bad_gs
921 .previous
922 .section .fixup,"ax"
923 /* running with kernelgs */
924bad_gs:
925 swapgs /* switch back to user gs */
926 xorl %eax,%eax
927 movl %eax,%gs
928 jmp 2b
929 .previous
930
931/*
932 * Create a kernel thread.
933 *
934 * C extern interface:
935 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
936 *
937 * asm input arguments:
938 * rdi: fn, rsi: arg, rdx: flags
939 */
940ENTRY(kernel_thread)
941 CFI_STARTPROC
942 FAKE_STACK_FRAME $child_rip
943 SAVE_ALL
944
945 # rdi: flags, rsi: usp, rdx: will be &pt_regs
946 movq %rdx,%rdi
947 orq kernel_thread_flags(%rip),%rdi
948 movq $-1, %rsi
949 movq %rsp, %rdx
950
951 xorl %r8d,%r8d
952 xorl %r9d,%r9d
953
954 # clone now
955 call do_fork
956 movq %rax,RAX(%rsp)
957 xorl %edi,%edi
958
959 /*
960 * It isn't worth to check for reschedule here,
961 * so internally to the x86_64 port you can rely on kernel_thread()
962 * not to reschedule the child before returning, this avoids the need
963 * of hacks for example to fork off the per-CPU idle tasks.
964 * [Hopefully no generic code relies on the reschedule -AK]
965 */
966 RESTORE_ALL
967 UNFAKE_STACK_FRAME
968 ret
969 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200970ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +0200973 pushq $0 # fake return address
974 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 /*
976 * Here we are in the child and the registers are set as they were
977 * at kernel_thread() invocation in the parent.
978 */
979 movq %rdi, %rax
980 movq %rsi, %rdi
981 call *%rax
982 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700983 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +0200985 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200986ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988/*
989 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
990 *
991 * C extern interface:
992 * extern long execve(char *name, char **argv, char **envp)
993 *
994 * asm input arguments:
995 * rdi: name, rsi: argv, rdx: envp
996 *
997 * We want to fallback into:
998 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
999 *
1000 * do_sys_execve asm fallback arguments:
1001 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1002 */
1003ENTRY(execve)
1004 CFI_STARTPROC
1005 FAKE_STACK_FRAME $0
1006 SAVE_ALL
1007 call sys_execve
1008 movq %rax, RAX(%rsp)
1009 RESTORE_REST
1010 testq %rax,%rax
1011 je int_ret_from_sys_call
1012 RESTORE_ARGS
1013 UNFAKE_STACK_FRAME
1014 ret
1015 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001016ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001018KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 errorentry do_page_fault
Jan Beulich4b787e02006-06-26 13:56:55 +02001020END(page_fault)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001021 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023ENTRY(coprocessor_error)
1024 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001025END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027ENTRY(simd_coprocessor_error)
1028 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001029END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031ENTRY(device_not_available)
1032 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001033END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001036KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001037 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 pushq $0
1039 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001040 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001041 paranoidexit
Jan Beulich4b787e02006-06-26 13:56:55 +02001042END(debug)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001043 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001046KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001047 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001049 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001050 paranoidentry do_nmi, 0, 0
1051#ifdef CONFIG_TRACE_IRQFLAGS
1052 paranoidexit 0
1053#else
1054 jmp paranoid_exit1
1055 CFI_ENDPROC
1056#endif
Jan Beulich4b787e02006-06-26 13:56:55 +02001057END(nmi)
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001058 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001059
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001060KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001061 INTR_FRAME
1062 pushq $0
1063 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001064 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001065 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001066 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001067END(int3)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001068 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070ENTRY(overflow)
1071 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001072END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
1074ENTRY(bounds)
1075 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001076END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078ENTRY(invalid_op)
1079 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001080END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082ENTRY(coprocessor_segment_overrun)
1083 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001084END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086ENTRY(reserved)
1087 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001088END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090 /* runs on exception stack */
1091ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001092 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001094 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001096END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098ENTRY(invalid_TSS)
1099 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001100END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
1102ENTRY(segment_not_present)
1103 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001104END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 /* runs on exception stack */
1107ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001108 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001110 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001112END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001114KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 errorentry do_general_protection
Jan Beulich4b787e02006-06-26 13:56:55 +02001116END(general_protection)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001117 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119ENTRY(alignment_check)
1120 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001121END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123ENTRY(divide_error)
1124 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001125END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127ENTRY(spurious_interrupt_bug)
1128 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001129END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131#ifdef CONFIG_X86_MCE
1132 /* runs on exception stack */
1133ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001134 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 pushq $0
1136 CFI_ADJUST_CFA_OFFSET 8
1137 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001138 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001140END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141#endif
1142
Andi Kleen26995002006-08-02 22:37:28 +02001143/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001144ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001145 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001146 push %rbp
1147 CFI_ADJUST_CFA_OFFSET 8
1148 CFI_REL_OFFSET rbp,0
1149 mov %rsp,%rbp
1150 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001151 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001152 cmove %gs:pda_irqstackptr,%rsp
1153 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001154 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001155 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001156 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001157 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001158 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001159 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001160 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001161ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001162
1163#ifdef CONFIG_STACK_UNWIND
1164ENTRY(arch_unwind_init_running)
1165 CFI_STARTPROC
1166 movq %r15, R15(%rdi)
1167 movq %r14, R14(%rdi)
1168 xchgq %rsi, %rdx
1169 movq %r13, R13(%rdi)
1170 movq %r12, R12(%rdi)
1171 xorl %eax, %eax
1172 movq %rbp, RBP(%rdi)
1173 movq %rbx, RBX(%rdi)
1174 movq (%rsp), %rcx
1175 movq %rax, R11(%rdi)
1176 movq %rax, R10(%rdi)
1177 movq %rax, R9(%rdi)
1178 movq %rax, R8(%rdi)
1179 movq %rax, RAX(%rdi)
1180 movq %rax, RCX(%rdi)
1181 movq %rax, RDX(%rdi)
1182 movq %rax, RSI(%rdi)
1183 movq %rax, RDI(%rdi)
1184 movq %rax, ORIG_RAX(%rdi)
1185 movq %rcx, RIP(%rdi)
1186 leaq 8(%rsp), %rcx
1187 movq $__KERNEL_CS, CS(%rdi)
1188 movq %rax, EFLAGS(%rdi)
1189 movq %rcx, RSP(%rdi)
1190 movq $__KERNEL_DS, SS(%rdi)
1191 jmpq *%rdx
1192 CFI_ENDPROC
1193ENDPROC(arch_unwind_init_running)
1194#endif