blob: 63001c6ecf6d0805afe72cfe78d906249d323f54 [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
Jeremy Fitzhardinge2be29982008-06-25 00:19:28 -0400168ENTRY(native_usergs_sysret64)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100169 swapgs
170 sysretq
171#endif /* CONFIG_PARAVIRT */
172
Ingo Molnar2601e642006-07-03 00:24:45 -0700173
174.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
175#ifdef CONFIG_TRACE_IRQFLAGS
176 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
177 jnc 1f
178 TRACE_IRQS_ON
1791:
180#endif
181.endm
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183/*
184 * C code is not supposed to know about undefined top of stack. Every time
185 * a C function with an pt_regs argument is called from the SYSCALL based
186 * fast path FIXUP_TOP_OF_STACK is needed.
187 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
188 * manipulation.
189 */
190
191 /* %rsp:at FRAMEEND */
192 .macro FIXUP_TOP_OF_STACK tmp
193 movq %gs:pda_oldrsp,\tmp
194 movq \tmp,RSP(%rsp)
195 movq $__USER_DS,SS(%rsp)
196 movq $__USER_CS,CS(%rsp)
197 movq $-1,RCX(%rsp)
198 movq R11(%rsp),\tmp /* get eflags */
199 movq \tmp,EFLAGS(%rsp)
200 .endm
201
202 .macro RESTORE_TOP_OF_STACK tmp,offset=0
203 movq RSP-\offset(%rsp),\tmp
204 movq \tmp,%gs:pda_oldrsp
205 movq EFLAGS-\offset(%rsp),\tmp
206 movq \tmp,R11-\offset(%rsp)
207 .endm
208
209 .macro FAKE_STACK_FRAME child_rip
210 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -0700211 xorl %eax, %eax
Jeremy Fitzhardingee04e0a62008-06-25 00:19:25 -0400212 pushq $__KERNEL_DS /* ss */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200214 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 pushq %rax /* rsp */
216 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200217 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 pushq $(1<<9) /* eflags - interrupts on */
219 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200220 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 pushq $__KERNEL_CS /* cs */
222 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200223 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 pushq \child_rip /* rip */
225 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200226 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 pushq %rax /* orig rax */
228 CFI_ADJUST_CFA_OFFSET 8
229 .endm
230
231 .macro UNFAKE_STACK_FRAME
232 addq $8*6, %rsp
233 CFI_ADJUST_CFA_OFFSET -(6*8)
234 .endm
235
Jan Beulich7effaa82005-09-12 18:49:24 +0200236 .macro CFI_DEFAULT_STACK start=1
237 .if \start
238 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200239 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200240 CFI_DEF_CFA rsp,SS+8
241 .else
242 CFI_DEF_CFA_OFFSET SS+8
243 .endif
244 CFI_REL_OFFSET r15,R15
245 CFI_REL_OFFSET r14,R14
246 CFI_REL_OFFSET r13,R13
247 CFI_REL_OFFSET r12,R12
248 CFI_REL_OFFSET rbp,RBP
249 CFI_REL_OFFSET rbx,RBX
250 CFI_REL_OFFSET r11,R11
251 CFI_REL_OFFSET r10,R10
252 CFI_REL_OFFSET r9,R9
253 CFI_REL_OFFSET r8,R8
254 CFI_REL_OFFSET rax,RAX
255 CFI_REL_OFFSET rcx,RCX
256 CFI_REL_OFFSET rdx,RDX
257 CFI_REL_OFFSET rsi,RSI
258 CFI_REL_OFFSET rdi,RDI
259 CFI_REL_OFFSET rip,RIP
260 /*CFI_REL_OFFSET cs,CS*/
261 /*CFI_REL_OFFSET rflags,EFLAGS*/
262 CFI_REL_OFFSET rsp,RSP
263 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 .endm
265/*
266 * A newly forked process directly context switches into this.
267 */
268/* rdi: prev */
269ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 CFI_DEFAULT_STACK
Andi Kleen658fdbe2006-09-26 10:52:41 +0200271 push kernel_eflags(%rip)
272 CFI_ADJUST_CFA_OFFSET 4
273 popf # reset kernel eflags
274 CFI_ADJUST_CFA_OFFSET -4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 call schedule_tail
276 GET_THREAD_INFO(%rcx)
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300277 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 jnz rff_trace
279rff_action:
280 RESTORE_REST
281 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
282 je int_ret_from_sys_call
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300283 testl $_TIF_IA32,TI_flags(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 jnz int_ret_from_sys_call
285 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
286 jmp ret_from_sys_call
287rff_trace:
288 movq %rsp,%rdi
289 call syscall_trace_leave
290 GET_THREAD_INFO(%rcx)
291 jmp rff_action
292 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200293END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295/*
296 * System call entry. Upto 6 arguments in registers are supported.
297 *
298 * SYSCALL does not save anything on the stack and does not change the
299 * stack pointer.
300 */
301
302/*
303 * Register setup:
304 * rax system call number
305 * rdi arg0
306 * rcx return address for syscall/sysret, C arg3
307 * rsi arg1
308 * rdx arg2
309 * r10 arg3 (--> moved to rcx for C)
310 * r8 arg4
311 * r9 arg5
312 * r11 eflags for syscall/sysret, temporary for C
313 * r12-r15,rbp,rbx saved by C code, not touched.
314 *
315 * Interrupts are off on entry.
316 * Only called from user space.
317 *
318 * XXX if we had a free scratch register we could save the RSP into the stack frame
319 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200320 *
321 * When user can change the frames always force IRET. That is because
322 * it deals with uncanonical addresses better. SYSRET has trouble
323 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 */
325
326ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200327 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200328 CFI_SIGNAL_FRAME
Jan Beulichdffead42006-06-26 13:57:38 +0200329 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200330 CFI_REGISTER rip,rcx
331 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100332 SWAPGS_UNSAFE_STACK
333 /*
334 * A hypervisor implementation might want to use a label
335 * after the swapgs, so that it can do the swapgs
336 * for the guest and jump here on syscall.
337 */
338ENTRY(system_call_after_swapgs)
339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 movq %rsp,%gs:pda_oldrsp
341 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700342 /*
343 * No need to follow this irqs off/on section - it's straight
344 * and short:
345 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100346 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 SAVE_ARGS 8,1
348 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200349 movq %rcx,RIP-ARGOFFSET(%rsp)
350 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 GET_THREAD_INFO(%rcx)
Roland McGrathd4d67152008-07-09 02:38:07 -0700352 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 jnz tracesys
354 cmpq $__NR_syscall_max,%rax
355 ja badsys
356 movq %r10,%rcx
357 call *sys_call_table(,%rax,8) # XXX: rip relative
358 movq %rax,RAX-ARGOFFSET(%rsp)
359/*
360 * Syscall return path ending with SYSRET (fast path)
361 * Has incomplete stack frame and undefined top of stack.
362 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700364 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 /* edi: flagmask */
366sysret_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200367 LOCKDEP_SYS_EXIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100369 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700370 TRACE_IRQS_OFF
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300371 movl TI_flags(%rcx),%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 andl %edi,%edx
373 jnz sysret_careful
Jan Beulichbcddc012006-12-07 02:14:02 +0100374 CFI_REMEMBER_STATE
Ingo Molnar2601e642006-07-03 00:24:45 -0700375 /*
376 * sysretq will re-enable interrupts:
377 */
378 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200380 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200382 /*CFI_REGISTER rflags,r11*/
Jeremy Fitzhardingec7245da2008-06-25 00:19:27 -0400383 movq %gs:pda_oldrsp, %rsp
Jeremy Fitzhardinge2be29982008-06-25 00:19:28 -0400384 USERGS_SYSRET64
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
Roland McGratheca91e72008-07-10 14:50:39 -07004141: movl $_TIF_WORK_MASK,%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
Roland McGrathd4d67152008-07-09 02:38:07 -0700432 /*
433 * Reload arg registers from stack in case ptrace changed them.
434 * We don't reload %rax because syscall_trace_enter() returned
435 * the value it wants us to use in the table lookup.
436 */
437 LOAD_ARGS ARGOFFSET, 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 RESTORE_REST
439 cmpq $__NR_syscall_max,%rax
Roland McGratha31f8dd2008-03-16 21:59:11 -0700440 ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 movq %r10,%rcx /* fixup for C */
442 call *sys_call_table(,%rax,8)
Roland McGratha31f8dd2008-03-16 21:59:11 -0700443 movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200444 /* Use IRET because user could have changed frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446/*
447 * Syscall return path ending with IRET.
448 * Has correct top of stack, but partial stack frame.
Jan Beulichbcddc012006-12-07 02:14:02 +0100449 */
450 .globl int_ret_from_sys_call
451int_ret_from_sys_call:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100452 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700453 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 testl $3,CS-ARGOFFSET(%rsp)
455 je retint_restore_args
456 movl $_TIF_ALLWORK_MASK,%edi
457 /* edi: mask to check */
458int_with_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200459 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 GET_THREAD_INFO(%rcx)
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300461 movl TI_flags(%rcx),%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 andl %edi,%edx
463 jnz int_careful
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300464 andl $~TS_COMPAT,TI_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 jmp retint_swapgs
466
467 /* Either reschedule or signal or syscall exit tracking needed. */
468 /* First do a reschedule test. */
469 /* edx: work, edi: workmask */
470int_careful:
471 bt $TIF_NEED_RESCHED,%edx
472 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700473 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100474 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200476 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 call schedule
478 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200479 CFI_ADJUST_CFA_OFFSET -8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100480 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700481 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 jmp int_with_check
483
484 /* handle signals and tracing -- both require a full stack frame */
485int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700486 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100487 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 SAVE_REST
489 /* Check for syscall exit trace */
Roland McGrathd4d67152008-07-09 02:38:07 -0700490 testl $_TIF_WORK_SYSCALL_EXIT,%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 jz int_signal
492 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200493 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 leaq 8(%rsp),%rdi # &ptregs -> arg1
495 call syscall_trace_leave
496 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200497 CFI_ADJUST_CFA_OFFSET -8
Roland McGrathd4d67152008-07-09 02:38:07 -0700498 andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 jmp int_restore_rest
500
501int_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100502 testl $_TIF_DO_NOTIFY_MASK,%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 jz 1f
504 movq %rsp,%rdi # &ptregs -> arg1
505 xorl %esi,%esi # oldset -> arg2
506 call do_notify_resume
Roland McGratheca91e72008-07-10 14:50:39 -07005071: movl $_TIF_WORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508int_restore_rest:
509 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100510 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700511 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 jmp int_with_check
513 CFI_ENDPROC
Jan Beulichbcddc012006-12-07 02:14:02 +0100514END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516/*
517 * Certain special system calls that need to save a complete full stack frame.
518 */
519
520 .macro PTREGSCALL label,func,arg
521 .globl \label
522\label:
523 leaq \func(%rip),%rax
524 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
525 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200526END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 .endm
528
Jan Beulich7effaa82005-09-12 18:49:24 +0200529 CFI_STARTPROC
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 PTREGSCALL stub_clone, sys_clone, %r8
532 PTREGSCALL stub_fork, sys_fork, %rdi
533 PTREGSCALL stub_vfork, sys_vfork, %rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
535 PTREGSCALL stub_iopl, sys_iopl, %rsi
536
537ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200539 CFI_ADJUST_CFA_OFFSET -8
540 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 SAVE_REST
542 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200543 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 FIXUP_TOP_OF_STACK %r11
545 call *%rax
546 RESTORE_TOP_OF_STACK %r11
547 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200548 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 RESTORE_REST
550 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200551 CFI_ADJUST_CFA_OFFSET 8
552 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 ret
554 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200555END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557ENTRY(stub_execve)
558 CFI_STARTPROC
559 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200560 CFI_ADJUST_CFA_OFFSET -8
561 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 FIXUP_TOP_OF_STACK %r11
Ingo Molnar5d119b22008-02-26 12:55:57 +0100564 movq %rsp, %rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 movq %rax,RAX(%rsp)
568 RESTORE_REST
569 jmp int_ret_from_sys_call
570 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200571END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573/*
574 * sigreturn is special because it needs to restore all registers on return.
575 * This cannot be done with SYSRET, so use the IRET return path instead.
576 */
577ENTRY(stub_rt_sigreturn)
578 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200579 addq $8, %rsp
580 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 SAVE_REST
582 movq %rsp,%rdi
583 FIXUP_TOP_OF_STACK %r11
584 call sys_rt_sigreturn
585 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
586 RESTORE_REST
587 jmp int_ret_from_sys_call
588 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200589END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Jan Beulich7effaa82005-09-12 18:49:24 +0200591/*
592 * initial frame state for interrupts and exceptions
593 */
594 .macro _frame ref
595 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200596 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200597 CFI_DEF_CFA rsp,SS+8-\ref
598 /*CFI_REL_OFFSET ss,SS-\ref*/
599 CFI_REL_OFFSET rsp,RSP-\ref
600 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
601 /*CFI_REL_OFFSET cs,CS-\ref*/
602 CFI_REL_OFFSET rip,RIP-\ref
603 .endm
604
605/* initial frame state for interrupts (and exceptions without error code) */
606#define INTR_FRAME _frame RIP
607/* initial frame state for exceptions with error code (and interrupts with
608 vector already pushed) */
609#define XCPT_FRAME _frame ORIG_RAX
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611/*
612 * Interrupt entry/exit.
613 *
614 * Interrupt entry points save only callee clobbered registers in fast path.
615 *
616 * Entry runs with interrupts off.
617 */
618
619/* 0(%rsp): interrupt number */
620 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 SAVE_ARGS
623 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200624 pushq %rbp
625 CFI_ADJUST_CFA_OFFSET 8
626 CFI_REL_OFFSET rbp, 0
627 movq %rsp,%rbp
628 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 testl $3,CS(%rdi)
630 je 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100631 SWAPGS
Andi Kleen96e54042006-09-26 10:52:39 +0200632 /* irqcount is used to check if a CPU is already on an interrupt
633 stack or not. While this is essentially redundant with preempt_count
634 it is a little cheaper to use a separate counter in the PDA
635 (short of moving irq_enter into assembly, which would be too
636 much work) */
6371: incl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200638 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200639 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700640 /*
641 * We entered an interrupt context - irqs are off:
642 */
643 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 call \func
645 .endm
646
647ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200648 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 interrupt do_IRQ
650 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200651ret_from_intr:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100652 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700653 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700654 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200655 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200656 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200657 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200658exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 GET_THREAD_INFO(%rcx)
660 testl $3,CS-ARGOFFSET(%rsp)
661 je retint_kernel
662
663 /* Interrupt came from user space */
664 /*
665 * Has a correct top of stack, but a partial stack frame
666 * %rcx: thread info. Interrupts off.
667 */
668retint_with_reschedule:
669 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200670retint_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200671 LOCKDEP_SYS_EXIT_IRQ
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300672 movl TI_flags(%rcx),%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200674 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200676
677retint_swapgs: /* return to user-space */
Ingo Molnar2601e642006-07-03 00:24:45 -0700678 /*
679 * The iretq could re-enable interrupts:
680 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100681 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700682 TRACE_IRQS_IRETQ
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100683 SWAPGS
Ingo Molnar2601e642006-07-03 00:24:45 -0700684 jmp restore_args
685
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200686retint_restore_args: /* return to kernel space */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100687 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700688 /*
689 * The iretq could re-enable interrupts:
690 */
691 TRACE_IRQS_IRETQ
692restore_args:
Ingo Molnar3701d8632008-02-09 23:24:08 +0100693 RESTORE_ARGS 0,8,0
694
Adrian Bunkf7f3d792008-02-13 23:29:53 +0200695irq_return:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100696 INTERRUPT_RETURN
Ingo Molnar3701d8632008-02-09 23:24:08 +0100697
698 .section __ex_table, "a"
699 .quad irq_return, bad_iret
700 .previous
701
702#ifdef CONFIG_PARAVIRT
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100703ENTRY(native_iret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 iretq
705
706 .section __ex_table,"a"
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100707 .quad native_iret, bad_iret
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 .previous
Ingo Molnar3701d8632008-02-09 23:24:08 +0100709#endif
710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 .section .fixup,"ax"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712bad_iret:
Roland McGrath3aa4b372008-02-06 22:39:43 +0100713 /*
714 * The iret traps when the %cs or %ss being restored is bogus.
715 * We've lost the original trap vector and error code.
716 * #GPF is the most likely one to get for an invalid selector.
717 * So pretend we completed the iret and took the #GPF in user mode.
718 *
719 * We are now running with the kernel GS after exception recovery.
720 * But error_entry expects us to have user GS to match the user %cs,
721 * so swap back.
722 */
723 pushq $0
724
725 SWAPGS
726 jmp general_protection
727
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100728 .previous
729
Jan Beulich7effaa82005-09-12 18:49:24 +0200730 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200732 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 bt $TIF_NEED_RESCHED,%edx
734 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700735 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100736 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200738 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 call schedule
740 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200741 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100743 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700744 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 jmp retint_check
746
747retint_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100748 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700749 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700750 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100751 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 SAVE_REST
753 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700754 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 movq %rsp,%rdi # &pt_regs
756 call do_notify_resume
757 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100758 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700759 TRACE_IRQS_OFF
Andi Kleenbe9e6872005-05-01 08:58:51 -0700760 GET_THREAD_INFO(%rcx)
Roland McGratheca91e72008-07-10 14:50:39 -0700761 jmp retint_with_reschedule
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763#ifdef CONFIG_PREEMPT
764 /* Returning to kernel space. Check if we need preemption */
765 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200766ENTRY(retint_kernel)
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300767 cmpl $0,TI_preempt_count(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 jnz retint_restore_args
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300769 bt $TIF_NEED_RESCHED,TI_flags(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 jnc retint_restore_args
771 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
772 jnc retint_restore_args
773 call preempt_schedule_irq
774 jmp exit_intr
775#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200778END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780/*
781 * APIC interrupts.
782 */
783 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200784 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700785 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200786 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 interrupt \func
788 jmp ret_from_intr
789 CFI_ENDPROC
790 .endm
791
792ENTRY(thermal_interrupt)
793 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200794END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Jacob Shin89b831e2005-11-05 17:25:53 +0100796ENTRY(threshold_interrupt)
797 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200798END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800#ifdef CONFIG_SMP
801ENTRY(reschedule_interrupt)
802 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200803END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Andi Kleene5bc8b62005-09-12 18:49:24 +0200805 .macro INVALIDATE_ENTRY num
806ENTRY(invalidate_interrupt\num)
807 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200808END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200809 .endm
810
811 INVALIDATE_ENTRY 0
812 INVALIDATE_ENTRY 1
813 INVALIDATE_ENTRY 2
814 INVALIDATE_ENTRY 3
815 INVALIDATE_ENTRY 4
816 INVALIDATE_ENTRY 5
817 INVALIDATE_ENTRY 6
818 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820ENTRY(call_function_interrupt)
821 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200822END(call_function_interrupt)
Jens Axboe3b16cf82008-06-26 11:21:54 +0200823ENTRY(call_function_single_interrupt)
824 apicinterrupt CALL_FUNCTION_SINGLE_VECTOR,smp_call_function_single_interrupt
825END(call_function_single_interrupt)
Eric W. Biederman61014292007-02-23 04:40:58 -0700826ENTRY(irq_move_cleanup_interrupt)
827 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
828END(irq_move_cleanup_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829#endif
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831ENTRY(apic_timer_interrupt)
832 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200833END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Cliff Wickman18129242008-06-02 08:56:14 -0500835ENTRY(uv_bau_message_intr1)
836 apicinterrupt 220,uv_bau_message_interrupt
837END(uv_bau_message_intr1)
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839ENTRY(error_interrupt)
840 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200841END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843ENTRY(spurious_interrupt)
844 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200845END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
847/*
848 * Exception entry points.
849 */
850 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200851 INTR_FRAME
Jeremy Fitzhardingefab58422008-06-25 00:19:31 -0400852 PARAVIRT_ADJUST_EXCEPTION_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200854 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200856 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200857 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 leaq \sym(%rip),%rax
859 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200860 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 .endm
862
863 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200864 XCPT_FRAME
Jeremy Fitzhardingefab58422008-06-25 00:19:31 -0400865 PARAVIRT_ADJUST_EXCEPTION_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200867 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200868 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 leaq \sym(%rip),%rax
870 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200871 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 .endm
873
874 /* error code is on the stack already */
875 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700876 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 SAVE_ALL
878 cld
879 movl $1,%ebx
880 movl $MSR_GS_BASE,%ecx
881 rdmsr
882 testl %edx,%edx
883 js 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100884 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01008861:
887 .if \ist
888 movq %gs:pda_data_offset, %rbp
889 .endif
890 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 movq ORIG_RAX(%rsp),%rsi
892 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100893 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100894 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100895 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100897 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100898 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100899 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100900 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700901 .if \irqtrace
902 TRACE_IRQS_OFF
903 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700905
906 /*
907 * "Paranoid" exit path from exception stack.
908 * Paranoid because this is used by NMIs and cannot take
909 * any kernel state for granted.
910 * We don't do kernel preemption checks here, because only
911 * NMI should be common and it does not enable IRQs and
912 * cannot get reschedule ticks.
913 *
914 * "trace" is 0 for the NMI handler only, because irq-tracing
915 * is fundamentally NMI-unsafe. (we cannot change the soft and
916 * hard flags at once, atomically)
917 */
918 .macro paranoidexit trace=1
919 /* ebx: no swapgs flag */
920paranoid_exit\trace:
921 testl %ebx,%ebx /* swapgs needed? */
922 jnz paranoid_restore\trace
923 testl $3,CS(%rsp)
924 jnz paranoid_userspace\trace
925paranoid_swapgs\trace:
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200926 .if \trace
Ingo Molnar2601e642006-07-03 00:24:45 -0700927 TRACE_IRQS_IRETQ 0
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200928 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100929 SWAPGS_UNSAFE_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -0700930paranoid_restore\trace:
931 RESTORE_ALL 8
Ingo Molnar3701d8632008-02-09 23:24:08 +0100932 jmp irq_return
Ingo Molnar2601e642006-07-03 00:24:45 -0700933paranoid_userspace\trace:
934 GET_THREAD_INFO(%rcx)
Glauber Costa26ccb8a2008-06-24 11:19:35 -0300935 movl TI_flags(%rcx),%ebx
Ingo Molnar2601e642006-07-03 00:24:45 -0700936 andl $_TIF_WORK_MASK,%ebx
937 jz paranoid_swapgs\trace
938 movq %rsp,%rdi /* &pt_regs */
939 call sync_regs
940 movq %rax,%rsp /* switch stack for scheduling */
941 testl $_TIF_NEED_RESCHED,%ebx
942 jnz paranoid_schedule\trace
943 movl %ebx,%edx /* arg3: thread flags */
944 .if \trace
945 TRACE_IRQS_ON
946 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100947 ENABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700948 xorl %esi,%esi /* arg2: oldset */
949 movq %rsp,%rdi /* arg1: &pt_regs */
950 call do_notify_resume
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100951 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700952 .if \trace
953 TRACE_IRQS_OFF
954 .endif
955 jmp paranoid_userspace\trace
956paranoid_schedule\trace:
957 .if \trace
958 TRACE_IRQS_ON
959 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100960 ENABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700961 call schedule
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100962 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700963 .if \trace
964 TRACE_IRQS_OFF
965 .endif
966 jmp paranoid_userspace\trace
967 CFI_ENDPROC
968 .endm
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970/*
971 * Exception entry point. This expects an error code/orig_rax on the stack
972 * and the exception handler in %rax.
973 */
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200974KPROBE_ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200975 _frame RDI
Jan Beulich37550902007-05-02 19:27:05 +0200976 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 /* rdi slot contains rax, oldrax contains error code */
978 cld
979 subq $14*8,%rsp
980 CFI_ADJUST_CFA_OFFSET (14*8)
981 movq %rsi,13*8(%rsp)
982 CFI_REL_OFFSET rsi,RSI
983 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
Jan Beulich37550902007-05-02 19:27:05 +0200984 CFI_REGISTER rax,rsi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 movq %rdx,12*8(%rsp)
986 CFI_REL_OFFSET rdx,RDX
987 movq %rcx,11*8(%rsp)
988 CFI_REL_OFFSET rcx,RCX
989 movq %rsi,10*8(%rsp) /* store rax */
990 CFI_REL_OFFSET rax,RAX
991 movq %r8, 9*8(%rsp)
992 CFI_REL_OFFSET r8,R8
993 movq %r9, 8*8(%rsp)
994 CFI_REL_OFFSET r9,R9
995 movq %r10,7*8(%rsp)
996 CFI_REL_OFFSET r10,R10
997 movq %r11,6*8(%rsp)
998 CFI_REL_OFFSET r11,R11
999 movq %rbx,5*8(%rsp)
1000 CFI_REL_OFFSET rbx,RBX
1001 movq %rbp,4*8(%rsp)
1002 CFI_REL_OFFSET rbp,RBP
1003 movq %r12,3*8(%rsp)
1004 CFI_REL_OFFSET r12,R12
1005 movq %r13,2*8(%rsp)
1006 CFI_REL_OFFSET r13,R13
1007 movq %r14,1*8(%rsp)
1008 CFI_REL_OFFSET r14,R14
1009 movq %r15,(%rsp)
1010 CFI_REL_OFFSET r15,R15
1011 xorl %ebx,%ebx
1012 testl $3,CS(%rsp)
1013 je error_kernelspace
1014error_swapgs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001015 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016error_sti:
1017 movq %rdi,RDI(%rsp)
Jan Beulich37550902007-05-02 19:27:05 +02001018 CFI_REL_OFFSET rdi,RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 movq %rsp,%rdi
1020 movq ORIG_RAX(%rsp),%rsi /* get error code */
1021 movq $-1,ORIG_RAX(%rsp)
1022 call *%rax
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001023 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
1024error_exit:
1025 movl %ebx,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001027 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -07001028 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 GET_THREAD_INFO(%rcx)
1030 testl %eax,%eax
1031 jne retint_kernel
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001032 LOCKDEP_SYS_EXIT_IRQ
Glauber Costa26ccb8a2008-06-24 11:19:35 -03001033 movl TI_flags(%rcx),%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 movl $_TIF_WORK_MASK,%edi
1035 andl %edi,%edx
1036 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +02001037 jmp retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 CFI_ENDPROC
1039
1040error_kernelspace:
1041 incl %ebx
1042 /* There are two places in the kernel that can potentially fault with
1043 usergs. Handle them here. The exception handlers after
1044 iret run with kernel gs again, so don't set the user space flag.
1045 B stepping K8s sometimes report an truncated RIP for IRET
1046 exceptions returning to compat mode. Check for these here too. */
Vegard Nossum9d8ad5d2008-06-27 17:22:17 +02001047 leaq irq_return(%rip),%rcx
1048 cmpq %rcx,RIP(%rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 je error_swapgs
Vegard Nossum9d8ad5d2008-06-27 17:22:17 +02001050 movl %ecx,%ecx /* zero extend */
1051 cmpq %rcx,RIP(%rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 je error_swapgs
1053 cmpq $gs_change,RIP(%rsp)
1054 je error_swapgs
1055 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001056KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 /* Reload gs selector with exception handling */
1059 /* edi: new selector */
Jeremy Fitzhardinge9f9d4892008-06-25 00:19:32 -04001060ENTRY(native_load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +02001061 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +02001063 CFI_ADJUST_CFA_OFFSET 8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001064 DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
1065 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066gs_change:
1067 movl %edi,%gs
10682: mfence /* workaround */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001069 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 popf
Jan Beulich7effaa82005-09-12 18:49:24 +02001071 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001073 CFI_ENDPROC
Jeremy Fitzhardinge9f9d4892008-06-25 00:19:32 -04001074ENDPROC(native_load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 .section __ex_table,"a"
1077 .align 8
1078 .quad gs_change,bad_gs
1079 .previous
1080 .section .fixup,"ax"
1081 /* running with kernelgs */
1082bad_gs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001083 SWAPGS /* switch back to user gs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 xorl %eax,%eax
1085 movl %eax,%gs
1086 jmp 2b
1087 .previous
1088
1089/*
1090 * Create a kernel thread.
1091 *
1092 * C extern interface:
1093 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
1094 *
1095 * asm input arguments:
1096 * rdi: fn, rsi: arg, rdx: flags
1097 */
1098ENTRY(kernel_thread)
1099 CFI_STARTPROC
1100 FAKE_STACK_FRAME $child_rip
1101 SAVE_ALL
1102
1103 # rdi: flags, rsi: usp, rdx: will be &pt_regs
1104 movq %rdx,%rdi
1105 orq kernel_thread_flags(%rip),%rdi
1106 movq $-1, %rsi
1107 movq %rsp, %rdx
1108
1109 xorl %r8d,%r8d
1110 xorl %r9d,%r9d
1111
1112 # clone now
1113 call do_fork
1114 movq %rax,RAX(%rsp)
1115 xorl %edi,%edi
1116
1117 /*
1118 * It isn't worth to check for reschedule here,
1119 * so internally to the x86_64 port you can rely on kernel_thread()
1120 * not to reschedule the child before returning, this avoids the need
1121 * of hacks for example to fork off the per-CPU idle tasks.
1122 * [Hopefully no generic code relies on the reschedule -AK]
1123 */
1124 RESTORE_ALL
1125 UNFAKE_STACK_FRAME
1126 ret
1127 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001128ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +02001131 pushq $0 # fake return address
1132 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 /*
1134 * Here we are in the child and the registers are set as they were
1135 * at kernel_thread() invocation in the parent.
1136 */
1137 movq %rdi, %rax
1138 movq %rsi, %rdi
1139 call *%rax
1140 # exit
Andrey Mirkin1c5b5cf2007-10-17 18:04:33 +02001141 mov %eax, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +02001143 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001144ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146/*
1147 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1148 *
1149 * C extern interface:
1150 * extern long execve(char *name, char **argv, char **envp)
1151 *
1152 * asm input arguments:
1153 * rdi: name, rsi: argv, rdx: envp
1154 *
1155 * We want to fallback into:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001156 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 *
1158 * do_sys_execve asm fallback arguments:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001159 * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 */
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001161ENTRY(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 CFI_STARTPROC
1163 FAKE_STACK_FRAME $0
1164 SAVE_ALL
Ingo Molnar5d119b22008-02-26 12:55:57 +01001165 movq %rsp,%rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 call sys_execve
1167 movq %rax, RAX(%rsp)
1168 RESTORE_REST
1169 testq %rax,%rax
1170 je int_ret_from_sys_call
1171 RESTORE_ARGS
1172 UNFAKE_STACK_FRAME
1173 ret
1174 CFI_ENDPROC
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001175ENDPROC(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001177KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001179KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181ENTRY(coprocessor_error)
1182 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001183END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
1185ENTRY(simd_coprocessor_error)
1186 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001187END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189ENTRY(device_not_available)
1190 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001191END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001194KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001195 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 pushq $0
1197 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001198 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001199 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001200KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
1202 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001203KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001204 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001206 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001207 paranoidentry do_nmi, 0, 0
1208#ifdef CONFIG_TRACE_IRQFLAGS
1209 paranoidexit 0
1210#else
1211 jmp paranoid_exit1
1212 CFI_ENDPROC
1213#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001214KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001215
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001216KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001217 INTR_FRAME
1218 pushq $0
1219 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001220 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001221 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001222 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001223KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225ENTRY(overflow)
1226 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001227END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229ENTRY(bounds)
1230 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001231END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233ENTRY(invalid_op)
1234 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001235END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237ENTRY(coprocessor_segment_overrun)
1238 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001239END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 /* runs on exception stack */
1242ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001243 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001245 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001247END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249ENTRY(invalid_TSS)
1250 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001251END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253ENTRY(segment_not_present)
1254 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001255END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 /* runs on exception stack */
1258ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001259 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001261 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001263END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001265KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001267KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269ENTRY(alignment_check)
1270 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001271END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273ENTRY(divide_error)
1274 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001275END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277ENTRY(spurious_interrupt_bug)
1278 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001279END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281#ifdef CONFIG_X86_MCE
1282 /* runs on exception stack */
1283ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001284 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 pushq $0
1286 CFI_ADJUST_CFA_OFFSET 8
1287 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001288 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001290END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291#endif
1292
Andi Kleen26995002006-08-02 22:37:28 +02001293/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001294ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001295 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001296 push %rbp
1297 CFI_ADJUST_CFA_OFFSET 8
1298 CFI_REL_OFFSET rbp,0
1299 mov %rsp,%rbp
1300 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001301 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001302 cmove %gs:pda_irqstackptr,%rsp
1303 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001304 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001305 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001306 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001307 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001308 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001309 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001310 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001311ENDPROC(call_softirq)
Andi Kleen75154f42007-06-23 02:29:25 +02001312
1313KPROBE_ENTRY(ignore_sysret)
1314 CFI_STARTPROC
1315 mov $-ENOSYS,%eax
1316 sysret
1317 CFI_ENDPROC
1318ENDPROC(ignore_sysret)