blob: b0f7308f78a6809135c8d84a163c1b4568d9bd8c [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>
Abhishek Sagar395a59d2008-06-21 23:47:27 +053054#include <asm/ftrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56 .code64
57
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020058#ifdef CONFIG_FTRACE
Steven Rostedtd61f82d2008-05-12 21:20:43 +020059#ifdef CONFIG_DYNAMIC_FTRACE
60ENTRY(mcount)
61
62 subq $0x38, %rsp
63 movq %rax, (%rsp)
64 movq %rcx, 8(%rsp)
65 movq %rdx, 16(%rsp)
66 movq %rsi, 24(%rsp)
67 movq %rdi, 32(%rsp)
68 movq %r8, 40(%rsp)
69 movq %r9, 48(%rsp)
70
71 movq 0x38(%rsp), %rdi
Abhishek Sagar395a59d2008-06-21 23:47:27 +053072 subq $MCOUNT_INSN_SIZE, %rdi
Steven Rostedtd61f82d2008-05-12 21:20:43 +020073
74.globl mcount_call
75mcount_call:
76 call ftrace_stub
77
78 movq 48(%rsp), %r9
79 movq 40(%rsp), %r8
80 movq 32(%rsp), %rdi
81 movq 24(%rsp), %rsi
82 movq 16(%rsp), %rdx
83 movq 8(%rsp), %rcx
84 movq (%rsp), %rax
85 addq $0x38, %rsp
86
87 retq
88END(mcount)
89
90ENTRY(ftrace_caller)
91
92 /* taken from glibc */
93 subq $0x38, %rsp
94 movq %rax, (%rsp)
95 movq %rcx, 8(%rsp)
96 movq %rdx, 16(%rsp)
97 movq %rsi, 24(%rsp)
98 movq %rdi, 32(%rsp)
99 movq %r8, 40(%rsp)
100 movq %r9, 48(%rsp)
101
102 movq 0x38(%rsp), %rdi
103 movq 8(%rbp), %rsi
Abhishek Sagar395a59d2008-06-21 23:47:27 +0530104 subq $MCOUNT_INSN_SIZE, %rdi
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200105
106.globl ftrace_call
107ftrace_call:
108 call ftrace_stub
109
110 movq 48(%rsp), %r9
111 movq 40(%rsp), %r8
112 movq 32(%rsp), %rdi
113 movq 24(%rsp), %rsi
114 movq 16(%rsp), %rdx
115 movq 8(%rsp), %rcx
116 movq (%rsp), %rax
117 addq $0x38, %rsp
118
119.globl ftrace_stub
120ftrace_stub:
121 retq
122END(ftrace_caller)
123
124#else /* ! CONFIG_DYNAMIC_FTRACE */
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200125ENTRY(mcount)
126 cmpq $ftrace_stub, ftrace_trace_function
127 jnz trace
128.globl ftrace_stub
129ftrace_stub:
130 retq
131
132trace:
133 /* taken from glibc */
134 subq $0x38, %rsp
135 movq %rax, (%rsp)
136 movq %rcx, 8(%rsp)
137 movq %rdx, 16(%rsp)
138 movq %rsi, 24(%rsp)
139 movq %rdi, 32(%rsp)
140 movq %r8, 40(%rsp)
141 movq %r9, 48(%rsp)
142
143 movq 0x38(%rsp), %rdi
144 movq 8(%rbp), %rsi
Abhishek Sagar395a59d2008-06-21 23:47:27 +0530145 subq $MCOUNT_INSN_SIZE, %rdi
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200146
147 call *ftrace_trace_function
148
149 movq 48(%rsp), %r9
150 movq 40(%rsp), %r8
151 movq 32(%rsp), %rdi
152 movq 24(%rsp), %rsi
153 movq 16(%rsp), %rdx
154 movq 8(%rsp), %rcx
155 movq (%rsp), %rax
156 addq $0x38, %rsp
157
158 jmp ftrace_stub
159END(mcount)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200160#endif /* CONFIG_DYNAMIC_FTRACE */
161#endif /* CONFIG_FTRACE */
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200162
Andi Kleendc37db42005-04-16 15:25:05 -0700163#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164#define retint_kernel retint_restore_args
165#endif
Ingo Molnar2601e642006-07-03 00:24:45 -0700166
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100167#ifdef CONFIG_PARAVIRT
168ENTRY(native_irq_enable_syscall_ret)
169 movq %gs:pda_oldrsp,%rsp
170 swapgs
171 sysretq
172#endif /* CONFIG_PARAVIRT */
173
Ingo Molnar2601e642006-07-03 00:24:45 -0700174
175.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
176#ifdef CONFIG_TRACE_IRQFLAGS
177 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
178 jnc 1f
179 TRACE_IRQS_ON
1801:
181#endif
182.endm
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184/*
185 * C code is not supposed to know about undefined top of stack. Every time
186 * a C function with an pt_regs argument is called from the SYSCALL based
187 * fast path FIXUP_TOP_OF_STACK is needed.
188 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
189 * manipulation.
190 */
191
192 /* %rsp:at FRAMEEND */
193 .macro FIXUP_TOP_OF_STACK tmp
194 movq %gs:pda_oldrsp,\tmp
195 movq \tmp,RSP(%rsp)
196 movq $__USER_DS,SS(%rsp)
197 movq $__USER_CS,CS(%rsp)
198 movq $-1,RCX(%rsp)
199 movq R11(%rsp),\tmp /* get eflags */
200 movq \tmp,EFLAGS(%rsp)
201 .endm
202
203 .macro RESTORE_TOP_OF_STACK tmp,offset=0
204 movq RSP-\offset(%rsp),\tmp
205 movq \tmp,%gs:pda_oldrsp
206 movq EFLAGS-\offset(%rsp),\tmp
207 movq \tmp,R11-\offset(%rsp)
208 .endm
209
210 .macro FAKE_STACK_FRAME child_rip
211 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -0700212 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 pushq %rax /* ss */
214 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200215 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 pushq %rax /* rsp */
217 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200218 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 pushq $(1<<9) /* eflags - interrupts on */
220 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200221 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 pushq $__KERNEL_CS /* cs */
223 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200224 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 pushq \child_rip /* rip */
226 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200227 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 pushq %rax /* orig rax */
229 CFI_ADJUST_CFA_OFFSET 8
230 .endm
231
232 .macro UNFAKE_STACK_FRAME
233 addq $8*6, %rsp
234 CFI_ADJUST_CFA_OFFSET -(6*8)
235 .endm
236
Jan Beulich7effaa82005-09-12 18:49:24 +0200237 .macro CFI_DEFAULT_STACK start=1
238 .if \start
239 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200240 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200241 CFI_DEF_CFA rsp,SS+8
242 .else
243 CFI_DEF_CFA_OFFSET SS+8
244 .endif
245 CFI_REL_OFFSET r15,R15
246 CFI_REL_OFFSET r14,R14
247 CFI_REL_OFFSET r13,R13
248 CFI_REL_OFFSET r12,R12
249 CFI_REL_OFFSET rbp,RBP
250 CFI_REL_OFFSET rbx,RBX
251 CFI_REL_OFFSET r11,R11
252 CFI_REL_OFFSET r10,R10
253 CFI_REL_OFFSET r9,R9
254 CFI_REL_OFFSET r8,R8
255 CFI_REL_OFFSET rax,RAX
256 CFI_REL_OFFSET rcx,RCX
257 CFI_REL_OFFSET rdx,RDX
258 CFI_REL_OFFSET rsi,RSI
259 CFI_REL_OFFSET rdi,RDI
260 CFI_REL_OFFSET rip,RIP
261 /*CFI_REL_OFFSET cs,CS*/
262 /*CFI_REL_OFFSET rflags,EFLAGS*/
263 CFI_REL_OFFSET rsp,RSP
264 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 .endm
266/*
267 * A newly forked process directly context switches into this.
268 */
269/* rdi: prev */
270ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 CFI_DEFAULT_STACK
Andi Kleen658fdbe2006-09-26 10:52:41 +0200272 push kernel_eflags(%rip)
273 CFI_ADJUST_CFA_OFFSET 4
274 popf # reset kernel eflags
275 CFI_ADJUST_CFA_OFFSET -4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 call schedule_tail
277 GET_THREAD_INFO(%rcx)
278 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
279 jnz rff_trace
280rff_action:
281 RESTORE_REST
282 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
283 je int_ret_from_sys_call
284 testl $_TIF_IA32,threadinfo_flags(%rcx)
285 jnz int_ret_from_sys_call
286 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
287 jmp ret_from_sys_call
288rff_trace:
289 movq %rsp,%rdi
290 call syscall_trace_leave
291 GET_THREAD_INFO(%rcx)
292 jmp rff_action
293 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200294END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296/*
297 * System call entry. Upto 6 arguments in registers are supported.
298 *
299 * SYSCALL does not save anything on the stack and does not change the
300 * stack pointer.
301 */
302
303/*
304 * Register setup:
305 * rax system call number
306 * rdi arg0
307 * rcx return address for syscall/sysret, C arg3
308 * rsi arg1
309 * rdx arg2
310 * r10 arg3 (--> moved to rcx for C)
311 * r8 arg4
312 * r9 arg5
313 * r11 eflags for syscall/sysret, temporary for C
314 * r12-r15,rbp,rbx saved by C code, not touched.
315 *
316 * Interrupts are off on entry.
317 * Only called from user space.
318 *
319 * XXX if we had a free scratch register we could save the RSP into the stack frame
320 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200321 *
322 * When user can change the frames always force IRET. That is because
323 * it deals with uncanonical addresses better. SYSRET has trouble
324 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 */
326
327ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200328 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200329 CFI_SIGNAL_FRAME
Jan Beulichdffead42006-06-26 13:57:38 +0200330 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200331 CFI_REGISTER rip,rcx
332 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100333 SWAPGS_UNSAFE_STACK
334 /*
335 * A hypervisor implementation might want to use a label
336 * after the swapgs, so that it can do the swapgs
337 * for the guest and jump here on syscall.
338 */
339ENTRY(system_call_after_swapgs)
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 movq %rsp,%gs:pda_oldrsp
342 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700343 /*
344 * No need to follow this irqs off/on section - it's straight
345 * and short:
346 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100347 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 SAVE_ARGS 8,1
349 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200350 movq %rcx,RIP-ARGOFFSET(%rsp)
351 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 GET_THREAD_INFO(%rcx)
353 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
354 jnz tracesys
355 cmpq $__NR_syscall_max,%rax
356 ja badsys
357 movq %r10,%rcx
358 call *sys_call_table(,%rax,8) # XXX: rip relative
359 movq %rax,RAX-ARGOFFSET(%rsp)
360/*
361 * Syscall return path ending with SYSRET (fast path)
362 * Has incomplete stack frame and undefined top of stack.
363 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700365 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 /* edi: flagmask */
367sysret_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200368 LOCKDEP_SYS_EXIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100370 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700371 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 movl threadinfo_flags(%rcx),%edx
373 andl %edi,%edx
374 jnz sysret_careful
Jan Beulichbcddc012006-12-07 02:14:02 +0100375 CFI_REMEMBER_STATE
Ingo Molnar2601e642006-07-03 00:24:45 -0700376 /*
377 * sysretq will re-enable interrupts:
378 */
379 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200381 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200383 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100384 ENABLE_INTERRUPTS_SYSCALL_RET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Jan Beulichbcddc012006-12-07 02:14:02 +0100386 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /* Handle reschedules */
388 /* edx: work, edi: workmask */
389sysret_careful:
390 bt $TIF_NEED_RESCHED,%edx
391 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700392 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100393 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200395 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 call schedule
397 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200398 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 jmp sysret_check
400
401 /* Handle a signal */
402sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700403 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100404 ENABLE_INTERRUPTS(CLBR_NONE)
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100405 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700406 jz 1f
407
408 /* Really a signal */
409 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 leaq do_notify_resume(%rip),%rax
411 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
412 xorl %esi,%esi # oldset -> arg2
413 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07004141: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200415 /* Use IRET because user could have changed frame. This
416 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100417 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700418 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200419 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Jan Beulich7effaa82005-09-12 18:49:24 +0200421badsys:
422 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
423 jmp ret_from_sys_call
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 /* Do syscall tracing */
426tracesys:
427 SAVE_REST
Roland McGratha31f8dd2008-03-16 21:59:11 -0700428 movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 FIXUP_TOP_OF_STACK %rdi
430 movq %rsp,%rdi
431 call syscall_trace_enter
432 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
433 RESTORE_REST
434 cmpq $__NR_syscall_max,%rax
Roland McGratha31f8dd2008-03-16 21:59:11 -0700435 ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 movq %r10,%rcx /* fixup for C */
437 call *sys_call_table(,%rax,8)
Roland McGratha31f8dd2008-03-16 21:59:11 -0700438 movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200439 /* Use IRET because user could have changed frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441/*
442 * Syscall return path ending with IRET.
443 * Has correct top of stack, but partial stack frame.
Jan Beulichbcddc012006-12-07 02:14:02 +0100444 */
445 .globl int_ret_from_sys_call
446int_ret_from_sys_call:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100447 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700448 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 testl $3,CS-ARGOFFSET(%rsp)
450 je retint_restore_args
451 movl $_TIF_ALLWORK_MASK,%edi
452 /* edi: mask to check */
453int_with_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200454 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 GET_THREAD_INFO(%rcx)
456 movl threadinfo_flags(%rcx),%edx
457 andl %edi,%edx
458 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100459 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 jmp retint_swapgs
461
462 /* Either reschedule or signal or syscall exit tracking needed. */
463 /* First do a reschedule test. */
464 /* edx: work, edi: workmask */
465int_careful:
466 bt $TIF_NEED_RESCHED,%edx
467 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700468 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100469 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200471 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 call schedule
473 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200474 CFI_ADJUST_CFA_OFFSET -8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100475 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700476 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 jmp int_with_check
478
479 /* handle signals and tracing -- both require a full stack frame */
480int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700481 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100482 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 SAVE_REST
484 /* Check for syscall exit trace */
485 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
486 jz int_signal
487 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200488 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 leaq 8(%rsp),%rdi # &ptregs -> arg1
490 call syscall_trace_leave
491 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200492 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700493 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 jmp int_restore_rest
495
496int_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100497 testl $_TIF_DO_NOTIFY_MASK,%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 jz 1f
499 movq %rsp,%rdi # &ptregs -> arg1
500 xorl %esi,%esi # oldset -> arg2
501 call do_notify_resume
5021: movl $_TIF_NEED_RESCHED,%edi
503int_restore_rest:
504 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100505 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700506 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 jmp int_with_check
508 CFI_ENDPROC
Jan Beulichbcddc012006-12-07 02:14:02 +0100509END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511/*
512 * Certain special system calls that need to save a complete full stack frame.
513 */
514
515 .macro PTREGSCALL label,func,arg
516 .globl \label
517\label:
518 leaq \func(%rip),%rax
519 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
520 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200521END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 .endm
523
Jan Beulich7effaa82005-09-12 18:49:24 +0200524 CFI_STARTPROC
525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 PTREGSCALL stub_clone, sys_clone, %r8
527 PTREGSCALL stub_fork, sys_fork, %rdi
528 PTREGSCALL stub_vfork, sys_vfork, %rdi
529 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
530 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
531 PTREGSCALL stub_iopl, sys_iopl, %rsi
532
533ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200535 CFI_ADJUST_CFA_OFFSET -8
536 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 SAVE_REST
538 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200539 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 FIXUP_TOP_OF_STACK %r11
541 call *%rax
542 RESTORE_TOP_OF_STACK %r11
543 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200544 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 RESTORE_REST
546 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200547 CFI_ADJUST_CFA_OFFSET 8
548 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 ret
550 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200551END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553ENTRY(stub_execve)
554 CFI_STARTPROC
555 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200556 CFI_ADJUST_CFA_OFFSET -8
557 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 FIXUP_TOP_OF_STACK %r11
Ingo Molnar5d119b22008-02-26 12:55:57 +0100560 movq %rsp, %rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 movq %rax,RAX(%rsp)
564 RESTORE_REST
565 jmp int_ret_from_sys_call
566 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200567END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569/*
570 * sigreturn is special because it needs to restore all registers on return.
571 * This cannot be done with SYSRET, so use the IRET return path instead.
572 */
573ENTRY(stub_rt_sigreturn)
574 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200575 addq $8, %rsp
576 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 SAVE_REST
578 movq %rsp,%rdi
579 FIXUP_TOP_OF_STACK %r11
580 call sys_rt_sigreturn
581 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
582 RESTORE_REST
583 jmp int_ret_from_sys_call
584 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200585END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Jan Beulich7effaa82005-09-12 18:49:24 +0200587/*
588 * initial frame state for interrupts and exceptions
589 */
590 .macro _frame ref
591 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200592 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200593 CFI_DEF_CFA rsp,SS+8-\ref
594 /*CFI_REL_OFFSET ss,SS-\ref*/
595 CFI_REL_OFFSET rsp,RSP-\ref
596 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
597 /*CFI_REL_OFFSET cs,CS-\ref*/
598 CFI_REL_OFFSET rip,RIP-\ref
599 .endm
600
601/* initial frame state for interrupts (and exceptions without error code) */
602#define INTR_FRAME _frame RIP
603/* initial frame state for exceptions with error code (and interrupts with
604 vector already pushed) */
605#define XCPT_FRAME _frame ORIG_RAX
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607/*
608 * Interrupt entry/exit.
609 *
610 * Interrupt entry points save only callee clobbered registers in fast path.
611 *
612 * Entry runs with interrupts off.
613 */
614
615/* 0(%rsp): interrupt number */
616 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 SAVE_ARGS
619 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200620 pushq %rbp
621 CFI_ADJUST_CFA_OFFSET 8
622 CFI_REL_OFFSET rbp, 0
623 movq %rsp,%rbp
624 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 testl $3,CS(%rdi)
626 je 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100627 SWAPGS
Andi Kleen96e54042006-09-26 10:52:39 +0200628 /* irqcount is used to check if a CPU is already on an interrupt
629 stack or not. While this is essentially redundant with preempt_count
630 it is a little cheaper to use a separate counter in the PDA
631 (short of moving irq_enter into assembly, which would be too
632 much work) */
6331: incl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200634 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200635 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700636 /*
637 * We entered an interrupt context - irqs are off:
638 */
639 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 call \func
641 .endm
642
643ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200644 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 interrupt do_IRQ
646 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200647ret_from_intr:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100648 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700649 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700650 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200651 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200652 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200653 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200654exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 GET_THREAD_INFO(%rcx)
656 testl $3,CS-ARGOFFSET(%rsp)
657 je retint_kernel
658
659 /* Interrupt came from user space */
660 /*
661 * Has a correct top of stack, but a partial stack frame
662 * %rcx: thread info. Interrupts off.
663 */
664retint_with_reschedule:
665 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200666retint_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200667 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 movl threadinfo_flags(%rcx),%edx
669 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200670 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200672
673retint_swapgs: /* return to user-space */
Ingo Molnar2601e642006-07-03 00:24:45 -0700674 /*
675 * The iretq could re-enable interrupts:
676 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100677 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700678 TRACE_IRQS_IRETQ
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100679 SWAPGS
Ingo Molnar2601e642006-07-03 00:24:45 -0700680 jmp restore_args
681
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200682retint_restore_args: /* return to kernel space */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100683 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700684 /*
685 * The iretq could re-enable interrupts:
686 */
687 TRACE_IRQS_IRETQ
688restore_args:
Ingo Molnar3701d8632008-02-09 23:24:08 +0100689 RESTORE_ARGS 0,8,0
690
Adrian Bunkf7f3d792008-02-13 23:29:53 +0200691irq_return:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100692 INTERRUPT_RETURN
Ingo Molnar3701d8632008-02-09 23:24:08 +0100693
694 .section __ex_table, "a"
695 .quad irq_return, bad_iret
696 .previous
697
698#ifdef CONFIG_PARAVIRT
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100699ENTRY(native_iret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 iretq
701
702 .section __ex_table,"a"
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100703 .quad native_iret, bad_iret
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 .previous
Ingo Molnar3701d8632008-02-09 23:24:08 +0100705#endif
706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 .section .fixup,"ax"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708bad_iret:
Roland McGrath3aa4b372008-02-06 22:39:43 +0100709 /*
710 * The iret traps when the %cs or %ss being restored is bogus.
711 * We've lost the original trap vector and error code.
712 * #GPF is the most likely one to get for an invalid selector.
713 * So pretend we completed the iret and took the #GPF in user mode.
714 *
715 * We are now running with the kernel GS after exception recovery.
716 * But error_entry expects us to have user GS to match the user %cs,
717 * so swap back.
718 */
719 pushq $0
720
721 SWAPGS
722 jmp general_protection
723
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100724 .previous
725
Jan Beulich7effaa82005-09-12 18:49:24 +0200726 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200728 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 bt $TIF_NEED_RESCHED,%edx
730 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700731 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100732 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200734 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 call schedule
736 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200737 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100739 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700740 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 jmp retint_check
742
743retint_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100744 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700745 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700746 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100747 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 SAVE_REST
749 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700750 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 movq %rsp,%rdi # &pt_regs
752 call do_notify_resume
753 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100754 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700755 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700756 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700757 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 jmp retint_check
759
760#ifdef CONFIG_PREEMPT
761 /* Returning to kernel space. Check if we need preemption */
762 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200763ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 cmpl $0,threadinfo_preempt_count(%rcx)
765 jnz retint_restore_args
766 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
767 jnc retint_restore_args
768 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
769 jnc retint_restore_args
770 call preempt_schedule_irq
771 jmp exit_intr
772#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200775END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777/*
778 * APIC interrupts.
779 */
780 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200781 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700782 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200783 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 interrupt \func
785 jmp ret_from_intr
786 CFI_ENDPROC
787 .endm
788
789ENTRY(thermal_interrupt)
790 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200791END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Jacob Shin89b831e2005-11-05 17:25:53 +0100793ENTRY(threshold_interrupt)
794 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200795END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797#ifdef CONFIG_SMP
798ENTRY(reschedule_interrupt)
799 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200800END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Andi Kleene5bc8b62005-09-12 18:49:24 +0200802 .macro INVALIDATE_ENTRY num
803ENTRY(invalidate_interrupt\num)
804 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200805END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200806 .endm
807
808 INVALIDATE_ENTRY 0
809 INVALIDATE_ENTRY 1
810 INVALIDATE_ENTRY 2
811 INVALIDATE_ENTRY 3
812 INVALIDATE_ENTRY 4
813 INVALIDATE_ENTRY 5
814 INVALIDATE_ENTRY 6
815 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817ENTRY(call_function_interrupt)
818 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200819END(call_function_interrupt)
Eric W. Biederman61014292007-02-23 04:40:58 -0700820ENTRY(irq_move_cleanup_interrupt)
821 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
822END(irq_move_cleanup_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823#endif
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825ENTRY(apic_timer_interrupt)
826 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200827END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829ENTRY(error_interrupt)
830 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200831END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833ENTRY(spurious_interrupt)
834 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200835END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837/*
838 * Exception entry points.
839 */
840 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200841 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200843 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200845 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200846 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 leaq \sym(%rip),%rax
848 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200849 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 .endm
851
852 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200853 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200855 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200856 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 leaq \sym(%rip),%rax
858 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200859 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 .endm
861
862 /* error code is on the stack already */
863 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700864 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 SAVE_ALL
866 cld
867 movl $1,%ebx
868 movl $MSR_GS_BASE,%ecx
869 rdmsr
870 testl %edx,%edx
871 js 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100872 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01008741:
875 .if \ist
876 movq %gs:pda_data_offset, %rbp
877 .endif
878 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 movq ORIG_RAX(%rsp),%rsi
880 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100881 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100882 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100883 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100885 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100886 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100887 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100888 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700889 .if \irqtrace
890 TRACE_IRQS_OFF
891 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700893
894 /*
895 * "Paranoid" exit path from exception stack.
896 * Paranoid because this is used by NMIs and cannot take
897 * any kernel state for granted.
898 * We don't do kernel preemption checks here, because only
899 * NMI should be common and it does not enable IRQs and
900 * cannot get reschedule ticks.
901 *
902 * "trace" is 0 for the NMI handler only, because irq-tracing
903 * is fundamentally NMI-unsafe. (we cannot change the soft and
904 * hard flags at once, atomically)
905 */
906 .macro paranoidexit trace=1
907 /* ebx: no swapgs flag */
908paranoid_exit\trace:
909 testl %ebx,%ebx /* swapgs needed? */
910 jnz paranoid_restore\trace
911 testl $3,CS(%rsp)
912 jnz paranoid_userspace\trace
913paranoid_swapgs\trace:
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200914 .if \trace
Ingo Molnar2601e642006-07-03 00:24:45 -0700915 TRACE_IRQS_IRETQ 0
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200916 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100917 SWAPGS_UNSAFE_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -0700918paranoid_restore\trace:
919 RESTORE_ALL 8
Ingo Molnar3701d8632008-02-09 23:24:08 +0100920 jmp irq_return
Ingo Molnar2601e642006-07-03 00:24:45 -0700921paranoid_userspace\trace:
922 GET_THREAD_INFO(%rcx)
923 movl threadinfo_flags(%rcx),%ebx
924 andl $_TIF_WORK_MASK,%ebx
925 jz paranoid_swapgs\trace
926 movq %rsp,%rdi /* &pt_regs */
927 call sync_regs
928 movq %rax,%rsp /* switch stack for scheduling */
929 testl $_TIF_NEED_RESCHED,%ebx
930 jnz paranoid_schedule\trace
931 movl %ebx,%edx /* arg3: thread flags */
932 .if \trace
933 TRACE_IRQS_ON
934 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100935 ENABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700936 xorl %esi,%esi /* arg2: oldset */
937 movq %rsp,%rdi /* arg1: &pt_regs */
938 call do_notify_resume
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100939 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700940 .if \trace
941 TRACE_IRQS_OFF
942 .endif
943 jmp paranoid_userspace\trace
944paranoid_schedule\trace:
945 .if \trace
946 TRACE_IRQS_ON
947 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100948 ENABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700949 call schedule
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100950 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700951 .if \trace
952 TRACE_IRQS_OFF
953 .endif
954 jmp paranoid_userspace\trace
955 CFI_ENDPROC
956 .endm
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/*
959 * Exception entry point. This expects an error code/orig_rax on the stack
960 * and the exception handler in %rax.
961 */
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200962KPROBE_ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200963 _frame RDI
Jan Beulich37550902007-05-02 19:27:05 +0200964 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 /* rdi slot contains rax, oldrax contains error code */
966 cld
967 subq $14*8,%rsp
968 CFI_ADJUST_CFA_OFFSET (14*8)
969 movq %rsi,13*8(%rsp)
970 CFI_REL_OFFSET rsi,RSI
971 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
Jan Beulich37550902007-05-02 19:27:05 +0200972 CFI_REGISTER rax,rsi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 movq %rdx,12*8(%rsp)
974 CFI_REL_OFFSET rdx,RDX
975 movq %rcx,11*8(%rsp)
976 CFI_REL_OFFSET rcx,RCX
977 movq %rsi,10*8(%rsp) /* store rax */
978 CFI_REL_OFFSET rax,RAX
979 movq %r8, 9*8(%rsp)
980 CFI_REL_OFFSET r8,R8
981 movq %r9, 8*8(%rsp)
982 CFI_REL_OFFSET r9,R9
983 movq %r10,7*8(%rsp)
984 CFI_REL_OFFSET r10,R10
985 movq %r11,6*8(%rsp)
986 CFI_REL_OFFSET r11,R11
987 movq %rbx,5*8(%rsp)
988 CFI_REL_OFFSET rbx,RBX
989 movq %rbp,4*8(%rsp)
990 CFI_REL_OFFSET rbp,RBP
991 movq %r12,3*8(%rsp)
992 CFI_REL_OFFSET r12,R12
993 movq %r13,2*8(%rsp)
994 CFI_REL_OFFSET r13,R13
995 movq %r14,1*8(%rsp)
996 CFI_REL_OFFSET r14,R14
997 movq %r15,(%rsp)
998 CFI_REL_OFFSET r15,R15
999 xorl %ebx,%ebx
1000 testl $3,CS(%rsp)
1001 je error_kernelspace
1002error_swapgs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001003 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004error_sti:
1005 movq %rdi,RDI(%rsp)
Jan Beulich37550902007-05-02 19:27:05 +02001006 CFI_REL_OFFSET rdi,RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 movq %rsp,%rdi
1008 movq ORIG_RAX(%rsp),%rsi /* get error code */
1009 movq $-1,ORIG_RAX(%rsp)
1010 call *%rax
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001011 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
1012error_exit:
1013 movl %ebx,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001015 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -07001016 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 GET_THREAD_INFO(%rcx)
1018 testl %eax,%eax
1019 jne retint_kernel
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001020 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 movl threadinfo_flags(%rcx),%edx
1022 movl $_TIF_WORK_MASK,%edi
1023 andl %edi,%edx
1024 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001025 jmp retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 CFI_ENDPROC
1027
1028error_kernelspace:
1029 incl %ebx
1030 /* There are two places in the kernel that can potentially fault with
1031 usergs. Handle them here. The exception handlers after
1032 iret run with kernel gs again, so don't set the user space flag.
1033 B stepping K8s sometimes report an truncated RIP for IRET
1034 exceptions returning to compat mode. Check for these here too. */
Ingo Molnar3701d8632008-02-09 23:24:08 +01001035 leaq irq_return(%rip),%rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 cmpq %rbp,RIP(%rsp)
1037 je error_swapgs
1038 movl %ebp,%ebp /* zero extend */
1039 cmpq %rbp,RIP(%rsp)
1040 je error_swapgs
1041 cmpq $gs_change,RIP(%rsp)
1042 je error_swapgs
1043 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001044KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 /* Reload gs selector with exception handling */
1047 /* edi: new selector */
1048ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +02001049 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +02001051 CFI_ADJUST_CFA_OFFSET 8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001052 DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
1053 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054gs_change:
1055 movl %edi,%gs
10562: mfence /* workaround */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001057 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 popf
Jan Beulich7effaa82005-09-12 18:49:24 +02001059 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001061 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001062ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064 .section __ex_table,"a"
1065 .align 8
1066 .quad gs_change,bad_gs
1067 .previous
1068 .section .fixup,"ax"
1069 /* running with kernelgs */
1070bad_gs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001071 SWAPGS /* switch back to user gs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 xorl %eax,%eax
1073 movl %eax,%gs
1074 jmp 2b
1075 .previous
1076
1077/*
1078 * Create a kernel thread.
1079 *
1080 * C extern interface:
1081 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
1082 *
1083 * asm input arguments:
1084 * rdi: fn, rsi: arg, rdx: flags
1085 */
1086ENTRY(kernel_thread)
1087 CFI_STARTPROC
1088 FAKE_STACK_FRAME $child_rip
1089 SAVE_ALL
1090
1091 # rdi: flags, rsi: usp, rdx: will be &pt_regs
1092 movq %rdx,%rdi
1093 orq kernel_thread_flags(%rip),%rdi
1094 movq $-1, %rsi
1095 movq %rsp, %rdx
1096
1097 xorl %r8d,%r8d
1098 xorl %r9d,%r9d
1099
1100 # clone now
1101 call do_fork
1102 movq %rax,RAX(%rsp)
1103 xorl %edi,%edi
1104
1105 /*
1106 * It isn't worth to check for reschedule here,
1107 * so internally to the x86_64 port you can rely on kernel_thread()
1108 * not to reschedule the child before returning, this avoids the need
1109 * of hacks for example to fork off the per-CPU idle tasks.
1110 * [Hopefully no generic code relies on the reschedule -AK]
1111 */
1112 RESTORE_ALL
1113 UNFAKE_STACK_FRAME
1114 ret
1115 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001116ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +02001119 pushq $0 # fake return address
1120 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 /*
1122 * Here we are in the child and the registers are set as they were
1123 * at kernel_thread() invocation in the parent.
1124 */
1125 movq %rdi, %rax
1126 movq %rsi, %rdi
1127 call *%rax
1128 # exit
Andrey Mirkin1c5b5cf2007-10-17 18:04:33 +02001129 mov %eax, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +02001131 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001132ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134/*
1135 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1136 *
1137 * C extern interface:
1138 * extern long execve(char *name, char **argv, char **envp)
1139 *
1140 * asm input arguments:
1141 * rdi: name, rsi: argv, rdx: envp
1142 *
1143 * We want to fallback into:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001144 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 *
1146 * do_sys_execve asm fallback arguments:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001147 * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 */
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001149ENTRY(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 CFI_STARTPROC
1151 FAKE_STACK_FRAME $0
1152 SAVE_ALL
Ingo Molnar5d119b22008-02-26 12:55:57 +01001153 movq %rsp,%rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 call sys_execve
1155 movq %rax, RAX(%rsp)
1156 RESTORE_REST
1157 testq %rax,%rax
1158 je int_ret_from_sys_call
1159 RESTORE_ARGS
1160 UNFAKE_STACK_FRAME
1161 ret
1162 CFI_ENDPROC
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001163ENDPROC(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001165KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001167KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169ENTRY(coprocessor_error)
1170 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001171END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173ENTRY(simd_coprocessor_error)
1174 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001175END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177ENTRY(device_not_available)
1178 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001179END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001182KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001183 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 pushq $0
1185 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001186 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001187 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001188KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001191KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001192 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001194 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001195 paranoidentry do_nmi, 0, 0
1196#ifdef CONFIG_TRACE_IRQFLAGS
1197 paranoidexit 0
1198#else
1199 jmp paranoid_exit1
1200 CFI_ENDPROC
1201#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001202KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001203
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001204KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001205 INTR_FRAME
1206 pushq $0
1207 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001208 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001209 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001210 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001211KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213ENTRY(overflow)
1214 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001215END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217ENTRY(bounds)
1218 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001219END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221ENTRY(invalid_op)
1222 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001223END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225ENTRY(coprocessor_segment_overrun)
1226 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001227END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229ENTRY(reserved)
1230 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001231END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 /* runs on exception stack */
1234ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001235 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001237 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001239END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241ENTRY(invalid_TSS)
1242 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001243END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245ENTRY(segment_not_present)
1246 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001247END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 /* runs on exception stack */
1250ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001251 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001253 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001255END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001257KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001259KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261ENTRY(alignment_check)
1262 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001263END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265ENTRY(divide_error)
1266 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001267END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269ENTRY(spurious_interrupt_bug)
1270 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001271END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273#ifdef CONFIG_X86_MCE
1274 /* runs on exception stack */
1275ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001276 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 pushq $0
1278 CFI_ADJUST_CFA_OFFSET 8
1279 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001280 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001282END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283#endif
1284
Andi Kleen26995002006-08-02 22:37:28 +02001285/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001286ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001287 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001288 push %rbp
1289 CFI_ADJUST_CFA_OFFSET 8
1290 CFI_REL_OFFSET rbp,0
1291 mov %rsp,%rbp
1292 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001293 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001294 cmove %gs:pda_irqstackptr,%rsp
1295 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001296 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001297 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001298 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001299 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001300 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001301 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001302 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001303ENDPROC(call_softirq)
Andi Kleen75154f42007-06-23 02:29:25 +02001304
1305KPROBE_ENTRY(ignore_sysret)
1306 CFI_STARTPROC
1307 mov $-ENOSYS,%eax
1308 sysret
1309 CFI_ENDPROC
1310ENDPROC(ignore_sysret)