blob: fe25e5febca386a5dc75a8891c45abf4953c97b9 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9/*
10 * entry.S contains the system-call and fault low-level handling routines.
11 *
12 * NOTE: This code handles signal-recognition, which happens every time
13 * after an interrupt and after each system call.
14 *
15 * Normal syscalls and interrupts don't save a full stack frame, this is
16 * only done for syscall tracing, signals or fork/exec et.al.
17 *
18 * A note on terminology:
19 * - top of stack: Architecture defined interrupt frame from SS to RIP
20 * at the top of the kernel process stack.
21 * - partial stack frame: partially saved registers upto R11.
22 * - full stack frame: Like partial stack frame, but all register saved.
Andi Kleen2e91a172006-09-26 10:52:29 +020023 *
24 * Some macro usage:
25 * - CFI macros are used to generate dwarf2 unwind information for better
26 * backtraces. They don't change any code.
27 * - SAVE_ALL/RESTORE_ALL - Save/restore all registers
28 * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify.
29 * There are unfortunately lots of special cases where some registers
30 * not touched. The macro is a big mess that should be cleaned up.
31 * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS.
32 * Gives a full stack frame.
33 * - ENTRY/END Define functions in the symbol table.
34 * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack
35 * frame that is otherwise undefined after a SYSCALL
36 * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
37 * - errorentry/paranoidentry/zeroentry - Define exception entry points.
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 */
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/linkage.h>
41#include <asm/segment.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/cache.h>
43#include <asm/errno.h>
44#include <asm/dwarf2.h>
45#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020046#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/msr.h>
48#include <asm/unistd.h>
49#include <asm/thread_info.h>
50#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010051#include <asm/page.h>
Ingo Molnar2601e642006-07-03 00:24:45 -070052#include <asm/irqflags.h>
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +010053#include <asm/paravirt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55 .code64
56
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020057#ifdef CONFIG_FTRACE
Steven Rostedtd61f82d2008-05-12 21:20:43 +020058#ifdef CONFIG_DYNAMIC_FTRACE
59ENTRY(mcount)
60
61 subq $0x38, %rsp
62 movq %rax, (%rsp)
63 movq %rcx, 8(%rsp)
64 movq %rdx, 16(%rsp)
65 movq %rsi, 24(%rsp)
66 movq %rdi, 32(%rsp)
67 movq %r8, 40(%rsp)
68 movq %r9, 48(%rsp)
69
70 movq 0x38(%rsp), %rdi
71
72.globl mcount_call
73mcount_call:
74 call ftrace_stub
75
76 movq 48(%rsp), %r9
77 movq 40(%rsp), %r8
78 movq 32(%rsp), %rdi
79 movq 24(%rsp), %rsi
80 movq 16(%rsp), %rdx
81 movq 8(%rsp), %rcx
82 movq (%rsp), %rax
83 addq $0x38, %rsp
84
85 retq
86END(mcount)
87
88ENTRY(ftrace_caller)
89
90 /* taken from glibc */
91 subq $0x38, %rsp
92 movq %rax, (%rsp)
93 movq %rcx, 8(%rsp)
94 movq %rdx, 16(%rsp)
95 movq %rsi, 24(%rsp)
96 movq %rdi, 32(%rsp)
97 movq %r8, 40(%rsp)
98 movq %r9, 48(%rsp)
99
100 movq 0x38(%rsp), %rdi
101 movq 8(%rbp), %rsi
102
103.globl ftrace_call
104ftrace_call:
105 call ftrace_stub
106
107 movq 48(%rsp), %r9
108 movq 40(%rsp), %r8
109 movq 32(%rsp), %rdi
110 movq 24(%rsp), %rsi
111 movq 16(%rsp), %rdx
112 movq 8(%rsp), %rcx
113 movq (%rsp), %rax
114 addq $0x38, %rsp
115
116.globl ftrace_stub
117ftrace_stub:
118 retq
119END(ftrace_caller)
120
121#else /* ! CONFIG_DYNAMIC_FTRACE */
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200122ENTRY(mcount)
123 cmpq $ftrace_stub, ftrace_trace_function
124 jnz trace
125.globl ftrace_stub
126ftrace_stub:
127 retq
128
129trace:
130 /* taken from glibc */
131 subq $0x38, %rsp
132 movq %rax, (%rsp)
133 movq %rcx, 8(%rsp)
134 movq %rdx, 16(%rsp)
135 movq %rsi, 24(%rsp)
136 movq %rdi, 32(%rsp)
137 movq %r8, 40(%rsp)
138 movq %r9, 48(%rsp)
139
140 movq 0x38(%rsp), %rdi
141 movq 8(%rbp), %rsi
142
143 call *ftrace_trace_function
144
145 movq 48(%rsp), %r9
146 movq 40(%rsp), %r8
147 movq 32(%rsp), %rdi
148 movq 24(%rsp), %rsi
149 movq 16(%rsp), %rdx
150 movq 8(%rsp), %rcx
151 movq (%rsp), %rax
152 addq $0x38, %rsp
153
154 jmp ftrace_stub
155END(mcount)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200156#endif /* CONFIG_DYNAMIC_FTRACE */
157#endif /* CONFIG_FTRACE */
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200158
Andi Kleendc37db42005-04-16 15:25:05 -0700159#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160#define retint_kernel retint_restore_args
161#endif
Ingo Molnar2601e642006-07-03 00:24:45 -0700162
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100163#ifdef CONFIG_PARAVIRT
164ENTRY(native_irq_enable_syscall_ret)
165 movq %gs:pda_oldrsp,%rsp
166 swapgs
167 sysretq
168#endif /* CONFIG_PARAVIRT */
169
Ingo Molnar2601e642006-07-03 00:24:45 -0700170
171.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
172#ifdef CONFIG_TRACE_IRQFLAGS
173 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
174 jnc 1f
175 TRACE_IRQS_ON
1761:
177#endif
178.endm
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180/*
181 * C code is not supposed to know about undefined top of stack. Every time
182 * a C function with an pt_regs argument is called from the SYSCALL based
183 * fast path FIXUP_TOP_OF_STACK is needed.
184 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
185 * manipulation.
186 */
187
188 /* %rsp:at FRAMEEND */
189 .macro FIXUP_TOP_OF_STACK tmp
190 movq %gs:pda_oldrsp,\tmp
191 movq \tmp,RSP(%rsp)
192 movq $__USER_DS,SS(%rsp)
193 movq $__USER_CS,CS(%rsp)
194 movq $-1,RCX(%rsp)
195 movq R11(%rsp),\tmp /* get eflags */
196 movq \tmp,EFLAGS(%rsp)
197 .endm
198
199 .macro RESTORE_TOP_OF_STACK tmp,offset=0
200 movq RSP-\offset(%rsp),\tmp
201 movq \tmp,%gs:pda_oldrsp
202 movq EFLAGS-\offset(%rsp),\tmp
203 movq \tmp,R11-\offset(%rsp)
204 .endm
205
206 .macro FAKE_STACK_FRAME child_rip
207 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -0700208 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 pushq %rax /* ss */
210 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200211 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 pushq %rax /* rsp */
213 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200214 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 pushq $(1<<9) /* eflags - interrupts on */
216 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200217 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 pushq $__KERNEL_CS /* cs */
219 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200220 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 pushq \child_rip /* rip */
222 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200223 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 pushq %rax /* orig rax */
225 CFI_ADJUST_CFA_OFFSET 8
226 .endm
227
228 .macro UNFAKE_STACK_FRAME
229 addq $8*6, %rsp
230 CFI_ADJUST_CFA_OFFSET -(6*8)
231 .endm
232
Jan Beulich7effaa82005-09-12 18:49:24 +0200233 .macro CFI_DEFAULT_STACK start=1
234 .if \start
235 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200236 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200237 CFI_DEF_CFA rsp,SS+8
238 .else
239 CFI_DEF_CFA_OFFSET SS+8
240 .endif
241 CFI_REL_OFFSET r15,R15
242 CFI_REL_OFFSET r14,R14
243 CFI_REL_OFFSET r13,R13
244 CFI_REL_OFFSET r12,R12
245 CFI_REL_OFFSET rbp,RBP
246 CFI_REL_OFFSET rbx,RBX
247 CFI_REL_OFFSET r11,R11
248 CFI_REL_OFFSET r10,R10
249 CFI_REL_OFFSET r9,R9
250 CFI_REL_OFFSET r8,R8
251 CFI_REL_OFFSET rax,RAX
252 CFI_REL_OFFSET rcx,RCX
253 CFI_REL_OFFSET rdx,RDX
254 CFI_REL_OFFSET rsi,RSI
255 CFI_REL_OFFSET rdi,RDI
256 CFI_REL_OFFSET rip,RIP
257 /*CFI_REL_OFFSET cs,CS*/
258 /*CFI_REL_OFFSET rflags,EFLAGS*/
259 CFI_REL_OFFSET rsp,RSP
260 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 .endm
262/*
263 * A newly forked process directly context switches into this.
264 */
265/* rdi: prev */
266ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 CFI_DEFAULT_STACK
Andi Kleen658fdbe2006-09-26 10:52:41 +0200268 push kernel_eflags(%rip)
269 CFI_ADJUST_CFA_OFFSET 4
270 popf # reset kernel eflags
271 CFI_ADJUST_CFA_OFFSET -4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 call schedule_tail
273 GET_THREAD_INFO(%rcx)
274 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
275 jnz rff_trace
276rff_action:
277 RESTORE_REST
278 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
279 je int_ret_from_sys_call
280 testl $_TIF_IA32,threadinfo_flags(%rcx)
281 jnz int_ret_from_sys_call
282 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
283 jmp ret_from_sys_call
284rff_trace:
285 movq %rsp,%rdi
286 call syscall_trace_leave
287 GET_THREAD_INFO(%rcx)
288 jmp rff_action
289 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200290END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292/*
293 * System call entry. Upto 6 arguments in registers are supported.
294 *
295 * SYSCALL does not save anything on the stack and does not change the
296 * stack pointer.
297 */
298
299/*
300 * Register setup:
301 * rax system call number
302 * rdi arg0
303 * rcx return address for syscall/sysret, C arg3
304 * rsi arg1
305 * rdx arg2
306 * r10 arg3 (--> moved to rcx for C)
307 * r8 arg4
308 * r9 arg5
309 * r11 eflags for syscall/sysret, temporary for C
310 * r12-r15,rbp,rbx saved by C code, not touched.
311 *
312 * Interrupts are off on entry.
313 * Only called from user space.
314 *
315 * XXX if we had a free scratch register we could save the RSP into the stack frame
316 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200317 *
318 * When user can change the frames always force IRET. That is because
319 * it deals with uncanonical addresses better. SYSRET has trouble
320 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 */
322
323ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200324 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200325 CFI_SIGNAL_FRAME
Jan Beulichdffead42006-06-26 13:57:38 +0200326 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200327 CFI_REGISTER rip,rcx
328 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100329 SWAPGS_UNSAFE_STACK
330 /*
331 * A hypervisor implementation might want to use a label
332 * after the swapgs, so that it can do the swapgs
333 * for the guest and jump here on syscall.
334 */
335ENTRY(system_call_after_swapgs)
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 movq %rsp,%gs:pda_oldrsp
338 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700339 /*
340 * No need to follow this irqs off/on section - it's straight
341 * and short:
342 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100343 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 SAVE_ARGS 8,1
345 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200346 movq %rcx,RIP-ARGOFFSET(%rsp)
347 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 GET_THREAD_INFO(%rcx)
349 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
350 jnz tracesys
351 cmpq $__NR_syscall_max,%rax
352 ja badsys
353 movq %r10,%rcx
354 call *sys_call_table(,%rax,8) # XXX: rip relative
355 movq %rax,RAX-ARGOFFSET(%rsp)
356/*
357 * Syscall return path ending with SYSRET (fast path)
358 * Has incomplete stack frame and undefined top of stack.
359 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700361 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 /* edi: flagmask */
363sysret_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200364 LOCKDEP_SYS_EXIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100366 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700367 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 movl threadinfo_flags(%rcx),%edx
369 andl %edi,%edx
370 jnz sysret_careful
Jan Beulichbcddc012006-12-07 02:14:02 +0100371 CFI_REMEMBER_STATE
Ingo Molnar2601e642006-07-03 00:24:45 -0700372 /*
373 * sysretq will re-enable interrupts:
374 */
375 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200377 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200379 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100380 ENABLE_INTERRUPTS_SYSCALL_RET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Jan Beulichbcddc012006-12-07 02:14:02 +0100382 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* Handle reschedules */
384 /* edx: work, edi: workmask */
385sysret_careful:
386 bt $TIF_NEED_RESCHED,%edx
387 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700388 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100389 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200391 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 call schedule
393 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200394 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 jmp sysret_check
396
397 /* Handle a signal */
398sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700399 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100400 ENABLE_INTERRUPTS(CLBR_NONE)
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100401 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700402 jz 1f
403
404 /* Really a signal */
405 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 leaq do_notify_resume(%rip),%rax
407 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
408 xorl %esi,%esi # oldset -> arg2
409 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07004101: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200411 /* Use IRET because user could have changed frame. This
412 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100413 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700414 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200415 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Jan Beulich7effaa82005-09-12 18:49:24 +0200417badsys:
418 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
419 jmp ret_from_sys_call
420
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 /* Do syscall tracing */
422tracesys:
423 SAVE_REST
Roland McGratha31f8dd2008-03-16 21:59:11 -0700424 movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 FIXUP_TOP_OF_STACK %rdi
426 movq %rsp,%rdi
427 call syscall_trace_enter
428 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
429 RESTORE_REST
430 cmpq $__NR_syscall_max,%rax
Roland McGratha31f8dd2008-03-16 21:59:11 -0700431 ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 movq %r10,%rcx /* fixup for C */
433 call *sys_call_table(,%rax,8)
Roland McGratha31f8dd2008-03-16 21:59:11 -0700434 movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200435 /* Use IRET because user could have changed frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437/*
438 * Syscall return path ending with IRET.
439 * Has correct top of stack, but partial stack frame.
Jan Beulichbcddc012006-12-07 02:14:02 +0100440 */
441 .globl int_ret_from_sys_call
442int_ret_from_sys_call:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100443 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700444 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 testl $3,CS-ARGOFFSET(%rsp)
446 je retint_restore_args
447 movl $_TIF_ALLWORK_MASK,%edi
448 /* edi: mask to check */
449int_with_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200450 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 GET_THREAD_INFO(%rcx)
452 movl threadinfo_flags(%rcx),%edx
453 andl %edi,%edx
454 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100455 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 jmp retint_swapgs
457
458 /* Either reschedule or signal or syscall exit tracking needed. */
459 /* First do a reschedule test. */
460 /* edx: work, edi: workmask */
461int_careful:
462 bt $TIF_NEED_RESCHED,%edx
463 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700464 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100465 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200467 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 call schedule
469 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200470 CFI_ADJUST_CFA_OFFSET -8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100471 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700472 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 jmp int_with_check
474
475 /* handle signals and tracing -- both require a full stack frame */
476int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700477 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100478 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 SAVE_REST
480 /* Check for syscall exit trace */
481 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
482 jz int_signal
483 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200484 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 leaq 8(%rsp),%rdi # &ptregs -> arg1
486 call syscall_trace_leave
487 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200488 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700489 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 jmp int_restore_rest
491
492int_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100493 testl $_TIF_DO_NOTIFY_MASK,%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 jz 1f
495 movq %rsp,%rdi # &ptregs -> arg1
496 xorl %esi,%esi # oldset -> arg2
497 call do_notify_resume
4981: movl $_TIF_NEED_RESCHED,%edi
499int_restore_rest:
500 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100501 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700502 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 jmp int_with_check
504 CFI_ENDPROC
Jan Beulichbcddc012006-12-07 02:14:02 +0100505END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507/*
508 * Certain special system calls that need to save a complete full stack frame.
509 */
510
511 .macro PTREGSCALL label,func,arg
512 .globl \label
513\label:
514 leaq \func(%rip),%rax
515 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
516 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200517END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 .endm
519
Jan Beulich7effaa82005-09-12 18:49:24 +0200520 CFI_STARTPROC
521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 PTREGSCALL stub_clone, sys_clone, %r8
523 PTREGSCALL stub_fork, sys_fork, %rdi
524 PTREGSCALL stub_vfork, sys_vfork, %rdi
525 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
526 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
527 PTREGSCALL stub_iopl, sys_iopl, %rsi
528
529ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200531 CFI_ADJUST_CFA_OFFSET -8
532 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 SAVE_REST
534 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200535 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 FIXUP_TOP_OF_STACK %r11
537 call *%rax
538 RESTORE_TOP_OF_STACK %r11
539 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200540 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 RESTORE_REST
542 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200543 CFI_ADJUST_CFA_OFFSET 8
544 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ret
546 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200547END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549ENTRY(stub_execve)
550 CFI_STARTPROC
551 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200552 CFI_ADJUST_CFA_OFFSET -8
553 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 FIXUP_TOP_OF_STACK %r11
Ingo Molnar5d119b22008-02-26 12:55:57 +0100556 movq %rsp, %rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 movq %rax,RAX(%rsp)
560 RESTORE_REST
561 jmp int_ret_from_sys_call
562 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200563END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
565/*
566 * sigreturn is special because it needs to restore all registers on return.
567 * This cannot be done with SYSRET, so use the IRET return path instead.
568 */
569ENTRY(stub_rt_sigreturn)
570 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200571 addq $8, %rsp
572 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 SAVE_REST
574 movq %rsp,%rdi
575 FIXUP_TOP_OF_STACK %r11
576 call sys_rt_sigreturn
577 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
578 RESTORE_REST
579 jmp int_ret_from_sys_call
580 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200581END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Jan Beulich7effaa82005-09-12 18:49:24 +0200583/*
584 * initial frame state for interrupts and exceptions
585 */
586 .macro _frame ref
587 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200588 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200589 CFI_DEF_CFA rsp,SS+8-\ref
590 /*CFI_REL_OFFSET ss,SS-\ref*/
591 CFI_REL_OFFSET rsp,RSP-\ref
592 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
593 /*CFI_REL_OFFSET cs,CS-\ref*/
594 CFI_REL_OFFSET rip,RIP-\ref
595 .endm
596
597/* initial frame state for interrupts (and exceptions without error code) */
598#define INTR_FRAME _frame RIP
599/* initial frame state for exceptions with error code (and interrupts with
600 vector already pushed) */
601#define XCPT_FRAME _frame ORIG_RAX
602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603/*
604 * Interrupt entry/exit.
605 *
606 * Interrupt entry points save only callee clobbered registers in fast path.
607 *
608 * Entry runs with interrupts off.
609 */
610
611/* 0(%rsp): interrupt number */
612 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 SAVE_ARGS
615 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200616 pushq %rbp
617 CFI_ADJUST_CFA_OFFSET 8
618 CFI_REL_OFFSET rbp, 0
619 movq %rsp,%rbp
620 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 testl $3,CS(%rdi)
622 je 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100623 SWAPGS
Andi Kleen96e54042006-09-26 10:52:39 +0200624 /* irqcount is used to check if a CPU is already on an interrupt
625 stack or not. While this is essentially redundant with preempt_count
626 it is a little cheaper to use a separate counter in the PDA
627 (short of moving irq_enter into assembly, which would be too
628 much work) */
6291: incl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200630 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200631 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700632 /*
633 * We entered an interrupt context - irqs are off:
634 */
635 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 call \func
637 .endm
638
639ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200640 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 interrupt do_IRQ
642 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200643ret_from_intr:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100644 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700645 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700646 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200647 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200648 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200649 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200650exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 GET_THREAD_INFO(%rcx)
652 testl $3,CS-ARGOFFSET(%rsp)
653 je retint_kernel
654
655 /* Interrupt came from user space */
656 /*
657 * Has a correct top of stack, but a partial stack frame
658 * %rcx: thread info. Interrupts off.
659 */
660retint_with_reschedule:
661 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200662retint_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200663 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 movl threadinfo_flags(%rcx),%edx
665 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200666 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200668
669retint_swapgs: /* return to user-space */
Ingo Molnar2601e642006-07-03 00:24:45 -0700670 /*
671 * The iretq could re-enable interrupts:
672 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100673 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700674 TRACE_IRQS_IRETQ
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100675 SWAPGS
Ingo Molnar2601e642006-07-03 00:24:45 -0700676 jmp restore_args
677
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200678retint_restore_args: /* return to kernel space */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100679 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700680 /*
681 * The iretq could re-enable interrupts:
682 */
683 TRACE_IRQS_IRETQ
684restore_args:
Ingo Molnar3701d8632008-02-09 23:24:08 +0100685 RESTORE_ARGS 0,8,0
686
Adrian Bunkf7f3d792008-02-13 23:29:53 +0200687irq_return:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100688 INTERRUPT_RETURN
Ingo Molnar3701d8632008-02-09 23:24:08 +0100689
690 .section __ex_table, "a"
691 .quad irq_return, bad_iret
692 .previous
693
694#ifdef CONFIG_PARAVIRT
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100695ENTRY(native_iret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 iretq
697
698 .section __ex_table,"a"
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100699 .quad native_iret, bad_iret
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 .previous
Ingo Molnar3701d8632008-02-09 23:24:08 +0100701#endif
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 .section .fixup,"ax"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704bad_iret:
Roland McGrath3aa4b372008-02-06 22:39:43 +0100705 /*
706 * The iret traps when the %cs or %ss being restored is bogus.
707 * We've lost the original trap vector and error code.
708 * #GPF is the most likely one to get for an invalid selector.
709 * So pretend we completed the iret and took the #GPF in user mode.
710 *
711 * We are now running with the kernel GS after exception recovery.
712 * But error_entry expects us to have user GS to match the user %cs,
713 * so swap back.
714 */
715 pushq $0
716
717 SWAPGS
718 jmp general_protection
719
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100720 .previous
721
Jan Beulich7effaa82005-09-12 18:49:24 +0200722 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200724 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 bt $TIF_NEED_RESCHED,%edx
726 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700727 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100728 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200730 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 call schedule
732 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200733 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100735 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700736 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 jmp retint_check
738
739retint_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100740 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700741 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700742 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100743 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 SAVE_REST
745 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700746 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 movq %rsp,%rdi # &pt_regs
748 call do_notify_resume
749 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100750 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700751 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700752 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700753 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 jmp retint_check
755
756#ifdef CONFIG_PREEMPT
757 /* Returning to kernel space. Check if we need preemption */
758 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200759ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 cmpl $0,threadinfo_preempt_count(%rcx)
761 jnz retint_restore_args
762 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
763 jnc retint_restore_args
764 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
765 jnc retint_restore_args
766 call preempt_schedule_irq
767 jmp exit_intr
768#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200771END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
773/*
774 * APIC interrupts.
775 */
776 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200777 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700778 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200779 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 interrupt \func
781 jmp ret_from_intr
782 CFI_ENDPROC
783 .endm
784
785ENTRY(thermal_interrupt)
786 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200787END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Jacob Shin89b831e2005-11-05 17:25:53 +0100789ENTRY(threshold_interrupt)
790 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200791END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793#ifdef CONFIG_SMP
794ENTRY(reschedule_interrupt)
795 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200796END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Andi Kleene5bc8b62005-09-12 18:49:24 +0200798 .macro INVALIDATE_ENTRY num
799ENTRY(invalidate_interrupt\num)
800 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200801END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200802 .endm
803
804 INVALIDATE_ENTRY 0
805 INVALIDATE_ENTRY 1
806 INVALIDATE_ENTRY 2
807 INVALIDATE_ENTRY 3
808 INVALIDATE_ENTRY 4
809 INVALIDATE_ENTRY 5
810 INVALIDATE_ENTRY 6
811 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813ENTRY(call_function_interrupt)
814 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200815END(call_function_interrupt)
Eric W. Biederman61014292007-02-23 04:40:58 -0700816ENTRY(irq_move_cleanup_interrupt)
817 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
818END(irq_move_cleanup_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819#endif
820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821ENTRY(apic_timer_interrupt)
822 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200823END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825ENTRY(error_interrupt)
826 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200827END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829ENTRY(spurious_interrupt)
830 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200831END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833/*
834 * Exception entry points.
835 */
836 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200837 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200839 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200841 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200842 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 leaq \sym(%rip),%rax
844 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200845 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 .endm
847
848 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200849 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200851 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200852 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 leaq \sym(%rip),%rax
854 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200855 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 .endm
857
858 /* error code is on the stack already */
859 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700860 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 SAVE_ALL
862 cld
863 movl $1,%ebx
864 movl $MSR_GS_BASE,%ecx
865 rdmsr
866 testl %edx,%edx
867 js 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100868 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01008701:
871 .if \ist
872 movq %gs:pda_data_offset, %rbp
873 .endif
874 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 movq ORIG_RAX(%rsp),%rsi
876 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100877 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100878 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100879 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100881 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100882 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100883 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100884 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700885 .if \irqtrace
886 TRACE_IRQS_OFF
887 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700889
890 /*
891 * "Paranoid" exit path from exception stack.
892 * Paranoid because this is used by NMIs and cannot take
893 * any kernel state for granted.
894 * We don't do kernel preemption checks here, because only
895 * NMI should be common and it does not enable IRQs and
896 * cannot get reschedule ticks.
897 *
898 * "trace" is 0 for the NMI handler only, because irq-tracing
899 * is fundamentally NMI-unsafe. (we cannot change the soft and
900 * hard flags at once, atomically)
901 */
902 .macro paranoidexit trace=1
903 /* ebx: no swapgs flag */
904paranoid_exit\trace:
905 testl %ebx,%ebx /* swapgs needed? */
906 jnz paranoid_restore\trace
907 testl $3,CS(%rsp)
908 jnz paranoid_userspace\trace
909paranoid_swapgs\trace:
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200910 .if \trace
Ingo Molnar2601e642006-07-03 00:24:45 -0700911 TRACE_IRQS_IRETQ 0
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200912 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100913 SWAPGS_UNSAFE_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -0700914paranoid_restore\trace:
915 RESTORE_ALL 8
Ingo Molnar3701d8632008-02-09 23:24:08 +0100916 jmp irq_return
Ingo Molnar2601e642006-07-03 00:24:45 -0700917paranoid_userspace\trace:
918 GET_THREAD_INFO(%rcx)
919 movl threadinfo_flags(%rcx),%ebx
920 andl $_TIF_WORK_MASK,%ebx
921 jz paranoid_swapgs\trace
922 movq %rsp,%rdi /* &pt_regs */
923 call sync_regs
924 movq %rax,%rsp /* switch stack for scheduling */
925 testl $_TIF_NEED_RESCHED,%ebx
926 jnz paranoid_schedule\trace
927 movl %ebx,%edx /* arg3: thread flags */
928 .if \trace
929 TRACE_IRQS_ON
930 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100931 ENABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700932 xorl %esi,%esi /* arg2: oldset */
933 movq %rsp,%rdi /* arg1: &pt_regs */
934 call do_notify_resume
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100935 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700936 .if \trace
937 TRACE_IRQS_OFF
938 .endif
939 jmp paranoid_userspace\trace
940paranoid_schedule\trace:
941 .if \trace
942 TRACE_IRQS_ON
943 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100944 ENABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700945 call schedule
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100946 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700947 .if \trace
948 TRACE_IRQS_OFF
949 .endif
950 jmp paranoid_userspace\trace
951 CFI_ENDPROC
952 .endm
953
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954/*
955 * Exception entry point. This expects an error code/orig_rax on the stack
956 * and the exception handler in %rax.
957 */
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200958KPROBE_ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200959 _frame RDI
Jan Beulich37550902007-05-02 19:27:05 +0200960 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /* rdi slot contains rax, oldrax contains error code */
962 cld
963 subq $14*8,%rsp
964 CFI_ADJUST_CFA_OFFSET (14*8)
965 movq %rsi,13*8(%rsp)
966 CFI_REL_OFFSET rsi,RSI
967 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
Jan Beulich37550902007-05-02 19:27:05 +0200968 CFI_REGISTER rax,rsi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 movq %rdx,12*8(%rsp)
970 CFI_REL_OFFSET rdx,RDX
971 movq %rcx,11*8(%rsp)
972 CFI_REL_OFFSET rcx,RCX
973 movq %rsi,10*8(%rsp) /* store rax */
974 CFI_REL_OFFSET rax,RAX
975 movq %r8, 9*8(%rsp)
976 CFI_REL_OFFSET r8,R8
977 movq %r9, 8*8(%rsp)
978 CFI_REL_OFFSET r9,R9
979 movq %r10,7*8(%rsp)
980 CFI_REL_OFFSET r10,R10
981 movq %r11,6*8(%rsp)
982 CFI_REL_OFFSET r11,R11
983 movq %rbx,5*8(%rsp)
984 CFI_REL_OFFSET rbx,RBX
985 movq %rbp,4*8(%rsp)
986 CFI_REL_OFFSET rbp,RBP
987 movq %r12,3*8(%rsp)
988 CFI_REL_OFFSET r12,R12
989 movq %r13,2*8(%rsp)
990 CFI_REL_OFFSET r13,R13
991 movq %r14,1*8(%rsp)
992 CFI_REL_OFFSET r14,R14
993 movq %r15,(%rsp)
994 CFI_REL_OFFSET r15,R15
995 xorl %ebx,%ebx
996 testl $3,CS(%rsp)
997 je error_kernelspace
998error_swapgs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100999 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000error_sti:
1001 movq %rdi,RDI(%rsp)
Jan Beulich37550902007-05-02 19:27:05 +02001002 CFI_REL_OFFSET rdi,RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 movq %rsp,%rdi
1004 movq ORIG_RAX(%rsp),%rsi /* get error code */
1005 movq $-1,ORIG_RAX(%rsp)
1006 call *%rax
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001007 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
1008error_exit:
1009 movl %ebx,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001011 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -07001012 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 GET_THREAD_INFO(%rcx)
1014 testl %eax,%eax
1015 jne retint_kernel
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001016 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 movl threadinfo_flags(%rcx),%edx
1018 movl $_TIF_WORK_MASK,%edi
1019 andl %edi,%edx
1020 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001021 jmp retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 CFI_ENDPROC
1023
1024error_kernelspace:
1025 incl %ebx
1026 /* There are two places in the kernel that can potentially fault with
1027 usergs. Handle them here. The exception handlers after
1028 iret run with kernel gs again, so don't set the user space flag.
1029 B stepping K8s sometimes report an truncated RIP for IRET
1030 exceptions returning to compat mode. Check for these here too. */
Ingo Molnar3701d8632008-02-09 23:24:08 +01001031 leaq irq_return(%rip),%rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 cmpq %rbp,RIP(%rsp)
1033 je error_swapgs
1034 movl %ebp,%ebp /* zero extend */
1035 cmpq %rbp,RIP(%rsp)
1036 je error_swapgs
1037 cmpq $gs_change,RIP(%rsp)
1038 je error_swapgs
1039 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001040KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 /* Reload gs selector with exception handling */
1043 /* edi: new selector */
1044ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +02001045 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +02001047 CFI_ADJUST_CFA_OFFSET 8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001048 DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
1049 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050gs_change:
1051 movl %edi,%gs
10522: mfence /* workaround */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001053 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 popf
Jan Beulich7effaa82005-09-12 18:49:24 +02001055 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001057 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001058ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 .section __ex_table,"a"
1061 .align 8
1062 .quad gs_change,bad_gs
1063 .previous
1064 .section .fixup,"ax"
1065 /* running with kernelgs */
1066bad_gs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001067 SWAPGS /* switch back to user gs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 xorl %eax,%eax
1069 movl %eax,%gs
1070 jmp 2b
1071 .previous
1072
1073/*
1074 * Create a kernel thread.
1075 *
1076 * C extern interface:
1077 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
1078 *
1079 * asm input arguments:
1080 * rdi: fn, rsi: arg, rdx: flags
1081 */
1082ENTRY(kernel_thread)
1083 CFI_STARTPROC
1084 FAKE_STACK_FRAME $child_rip
1085 SAVE_ALL
1086
1087 # rdi: flags, rsi: usp, rdx: will be &pt_regs
1088 movq %rdx,%rdi
1089 orq kernel_thread_flags(%rip),%rdi
1090 movq $-1, %rsi
1091 movq %rsp, %rdx
1092
1093 xorl %r8d,%r8d
1094 xorl %r9d,%r9d
1095
1096 # clone now
1097 call do_fork
1098 movq %rax,RAX(%rsp)
1099 xorl %edi,%edi
1100
1101 /*
1102 * It isn't worth to check for reschedule here,
1103 * so internally to the x86_64 port you can rely on kernel_thread()
1104 * not to reschedule the child before returning, this avoids the need
1105 * of hacks for example to fork off the per-CPU idle tasks.
1106 * [Hopefully no generic code relies on the reschedule -AK]
1107 */
1108 RESTORE_ALL
1109 UNFAKE_STACK_FRAME
1110 ret
1111 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001112ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +02001115 pushq $0 # fake return address
1116 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /*
1118 * Here we are in the child and the registers are set as they were
1119 * at kernel_thread() invocation in the parent.
1120 */
1121 movq %rdi, %rax
1122 movq %rsi, %rdi
1123 call *%rax
1124 # exit
Andrey Mirkin1c5b5cf2007-10-17 18:04:33 +02001125 mov %eax, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +02001127 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001128ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130/*
1131 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1132 *
1133 * C extern interface:
1134 * extern long execve(char *name, char **argv, char **envp)
1135 *
1136 * asm input arguments:
1137 * rdi: name, rsi: argv, rdx: envp
1138 *
1139 * We want to fallback into:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001140 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 *
1142 * do_sys_execve asm fallback arguments:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001143 * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 */
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001145ENTRY(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 CFI_STARTPROC
1147 FAKE_STACK_FRAME $0
1148 SAVE_ALL
Ingo Molnar5d119b22008-02-26 12:55:57 +01001149 movq %rsp,%rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 call sys_execve
1151 movq %rax, RAX(%rsp)
1152 RESTORE_REST
1153 testq %rax,%rax
1154 je int_ret_from_sys_call
1155 RESTORE_ARGS
1156 UNFAKE_STACK_FRAME
1157 ret
1158 CFI_ENDPROC
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001159ENDPROC(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001161KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001163KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165ENTRY(coprocessor_error)
1166 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001167END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169ENTRY(simd_coprocessor_error)
1170 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001171END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173ENTRY(device_not_available)
1174 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001175END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001178KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001179 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 pushq $0
1181 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001182 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001183 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001184KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001187KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001188 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001190 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001191 paranoidentry do_nmi, 0, 0
1192#ifdef CONFIG_TRACE_IRQFLAGS
1193 paranoidexit 0
1194#else
1195 jmp paranoid_exit1
1196 CFI_ENDPROC
1197#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001198KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001199
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001200KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001201 INTR_FRAME
1202 pushq $0
1203 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001204 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001205 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001206 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001207KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209ENTRY(overflow)
1210 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001211END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213ENTRY(bounds)
1214 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001215END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217ENTRY(invalid_op)
1218 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001219END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221ENTRY(coprocessor_segment_overrun)
1222 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001223END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225ENTRY(reserved)
1226 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001227END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229 /* runs on exception stack */
1230ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001231 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001233 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001235END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237ENTRY(invalid_TSS)
1238 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001239END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241ENTRY(segment_not_present)
1242 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001243END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 /* runs on exception stack */
1246ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001247 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001249 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001251END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001253KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001255KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257ENTRY(alignment_check)
1258 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001259END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261ENTRY(divide_error)
1262 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001263END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265ENTRY(spurious_interrupt_bug)
1266 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001267END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269#ifdef CONFIG_X86_MCE
1270 /* runs on exception stack */
1271ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001272 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 pushq $0
1274 CFI_ADJUST_CFA_OFFSET 8
1275 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001276 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001278END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279#endif
1280
Andi Kleen26995002006-08-02 22:37:28 +02001281/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001282ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001283 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001284 push %rbp
1285 CFI_ADJUST_CFA_OFFSET 8
1286 CFI_REL_OFFSET rbp,0
1287 mov %rsp,%rbp
1288 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001289 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001290 cmove %gs:pda_irqstackptr,%rsp
1291 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001292 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001293 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001294 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001295 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001296 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001297 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001298 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001299ENDPROC(call_softirq)
Andi Kleen75154f42007-06-23 02:29:25 +02001300
1301KPROBE_ENTRY(ignore_sysret)
1302 CFI_STARTPROC
1303 mov $-ENOSYS,%eax
1304 sysret
1305 CFI_ENDPROC
1306ENDPROC(ignore_sysret)