blob: f046e0c6488391416f28e6a747893c85d76d5e10 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/entry.S
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
6 * Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9/*
10 * entry.S contains the system-call and fault low-level handling routines.
11 *
12 * NOTE: This code handles signal-recognition, which happens every time
13 * after an interrupt and after each system call.
14 *
15 * Normal syscalls and interrupts don't save a full stack frame, this is
16 * only done for syscall tracing, signals or fork/exec et.al.
17 *
18 * A note on terminology:
19 * - top of stack: Architecture defined interrupt frame from SS to RIP
20 * at the top of the kernel process stack.
21 * - partial stack frame: partially saved registers upto R11.
22 * - full stack frame: Like partial stack frame, but all register saved.
Andi Kleen2e91a172006-09-26 10:52:29 +020023 *
24 * Some macro usage:
25 * - CFI macros are used to generate dwarf2 unwind information for better
26 * backtraces. They don't change any code.
27 * - SAVE_ALL/RESTORE_ALL - Save/restore all registers
28 * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify.
29 * There are unfortunately lots of special cases where some registers
30 * not touched. The macro is a big mess that should be cleaned up.
31 * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS.
32 * Gives a full stack frame.
33 * - ENTRY/END Define functions in the symbol table.
34 * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack
35 * frame that is otherwise undefined after a SYSCALL
36 * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
37 * - errorentry/paranoidentry/zeroentry - Define exception entry points.
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 */
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/linkage.h>
41#include <asm/segment.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/cache.h>
43#include <asm/errno.h>
44#include <asm/dwarf2.h>
45#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020046#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/msr.h>
48#include <asm/unistd.h>
49#include <asm/thread_info.h>
50#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010051#include <asm/page.h>
Ingo Molnar2601e642006-07-03 00:24:45 -070052#include <asm/irqflags.h>
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +010053#include <asm/paravirt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55 .code64
56
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020057#ifdef CONFIG_FTRACE
58ENTRY(mcount)
59 cmpq $ftrace_stub, ftrace_trace_function
60 jnz trace
61.globl ftrace_stub
62ftrace_stub:
63 retq
64
65trace:
66 /* taken from glibc */
67 subq $0x38, %rsp
68 movq %rax, (%rsp)
69 movq %rcx, 8(%rsp)
70 movq %rdx, 16(%rsp)
71 movq %rsi, 24(%rsp)
72 movq %rdi, 32(%rsp)
73 movq %r8, 40(%rsp)
74 movq %r9, 48(%rsp)
75
76 movq 0x38(%rsp), %rdi
77 movq 8(%rbp), %rsi
78
79 call *ftrace_trace_function
80
81 movq 48(%rsp), %r9
82 movq 40(%rsp), %r8
83 movq 32(%rsp), %rdi
84 movq 24(%rsp), %rsi
85 movq 16(%rsp), %rdx
86 movq 8(%rsp), %rcx
87 movq (%rsp), %rax
88 addq $0x38, %rsp
89
90 jmp ftrace_stub
91END(mcount)
92#endif
93
Andi Kleendc37db42005-04-16 15:25:05 -070094#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070095#define retint_kernel retint_restore_args
96#endif
Ingo Molnar2601e642006-07-03 00:24:45 -070097
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +010098#ifdef CONFIG_PARAVIRT
99ENTRY(native_irq_enable_syscall_ret)
100 movq %gs:pda_oldrsp,%rsp
101 swapgs
102 sysretq
103#endif /* CONFIG_PARAVIRT */
104
Ingo Molnar2601e642006-07-03 00:24:45 -0700105
106.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
107#ifdef CONFIG_TRACE_IRQFLAGS
108 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
109 jnc 1f
110 TRACE_IRQS_ON
1111:
112#endif
113.endm
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/*
116 * C code is not supposed to know about undefined top of stack. Every time
117 * a C function with an pt_regs argument is called from the SYSCALL based
118 * fast path FIXUP_TOP_OF_STACK is needed.
119 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
120 * manipulation.
121 */
122
123 /* %rsp:at FRAMEEND */
124 .macro FIXUP_TOP_OF_STACK tmp
125 movq %gs:pda_oldrsp,\tmp
126 movq \tmp,RSP(%rsp)
127 movq $__USER_DS,SS(%rsp)
128 movq $__USER_CS,CS(%rsp)
129 movq $-1,RCX(%rsp)
130 movq R11(%rsp),\tmp /* get eflags */
131 movq \tmp,EFLAGS(%rsp)
132 .endm
133
134 .macro RESTORE_TOP_OF_STACK tmp,offset=0
135 movq RSP-\offset(%rsp),\tmp
136 movq \tmp,%gs:pda_oldrsp
137 movq EFLAGS-\offset(%rsp),\tmp
138 movq \tmp,R11-\offset(%rsp)
139 .endm
140
141 .macro FAKE_STACK_FRAME child_rip
142 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -0700143 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 pushq %rax /* ss */
145 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200146 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 pushq %rax /* rsp */
148 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200149 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 pushq $(1<<9) /* eflags - interrupts on */
151 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200152 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 pushq $__KERNEL_CS /* cs */
154 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200155 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 pushq \child_rip /* rip */
157 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200158 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 pushq %rax /* orig rax */
160 CFI_ADJUST_CFA_OFFSET 8
161 .endm
162
163 .macro UNFAKE_STACK_FRAME
164 addq $8*6, %rsp
165 CFI_ADJUST_CFA_OFFSET -(6*8)
166 .endm
167
Jan Beulich7effaa82005-09-12 18:49:24 +0200168 .macro CFI_DEFAULT_STACK start=1
169 .if \start
170 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200171 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200172 CFI_DEF_CFA rsp,SS+8
173 .else
174 CFI_DEF_CFA_OFFSET SS+8
175 .endif
176 CFI_REL_OFFSET r15,R15
177 CFI_REL_OFFSET r14,R14
178 CFI_REL_OFFSET r13,R13
179 CFI_REL_OFFSET r12,R12
180 CFI_REL_OFFSET rbp,RBP
181 CFI_REL_OFFSET rbx,RBX
182 CFI_REL_OFFSET r11,R11
183 CFI_REL_OFFSET r10,R10
184 CFI_REL_OFFSET r9,R9
185 CFI_REL_OFFSET r8,R8
186 CFI_REL_OFFSET rax,RAX
187 CFI_REL_OFFSET rcx,RCX
188 CFI_REL_OFFSET rdx,RDX
189 CFI_REL_OFFSET rsi,RSI
190 CFI_REL_OFFSET rdi,RDI
191 CFI_REL_OFFSET rip,RIP
192 /*CFI_REL_OFFSET cs,CS*/
193 /*CFI_REL_OFFSET rflags,EFLAGS*/
194 CFI_REL_OFFSET rsp,RSP
195 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 .endm
197/*
198 * A newly forked process directly context switches into this.
199 */
200/* rdi: prev */
201ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 CFI_DEFAULT_STACK
Andi Kleen658fdbe2006-09-26 10:52:41 +0200203 push kernel_eflags(%rip)
204 CFI_ADJUST_CFA_OFFSET 4
205 popf # reset kernel eflags
206 CFI_ADJUST_CFA_OFFSET -4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 call schedule_tail
208 GET_THREAD_INFO(%rcx)
209 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
210 jnz rff_trace
211rff_action:
212 RESTORE_REST
213 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
214 je int_ret_from_sys_call
215 testl $_TIF_IA32,threadinfo_flags(%rcx)
216 jnz int_ret_from_sys_call
217 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
218 jmp ret_from_sys_call
219rff_trace:
220 movq %rsp,%rdi
221 call syscall_trace_leave
222 GET_THREAD_INFO(%rcx)
223 jmp rff_action
224 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200225END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
227/*
228 * System call entry. Upto 6 arguments in registers are supported.
229 *
230 * SYSCALL does not save anything on the stack and does not change the
231 * stack pointer.
232 */
233
234/*
235 * Register setup:
236 * rax system call number
237 * rdi arg0
238 * rcx return address for syscall/sysret, C arg3
239 * rsi arg1
240 * rdx arg2
241 * r10 arg3 (--> moved to rcx for C)
242 * r8 arg4
243 * r9 arg5
244 * r11 eflags for syscall/sysret, temporary for C
245 * r12-r15,rbp,rbx saved by C code, not touched.
246 *
247 * Interrupts are off on entry.
248 * Only called from user space.
249 *
250 * XXX if we had a free scratch register we could save the RSP into the stack frame
251 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200252 *
253 * When user can change the frames always force IRET. That is because
254 * it deals with uncanonical addresses better. SYSRET has trouble
255 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 */
257
258ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200259 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200260 CFI_SIGNAL_FRAME
Jan Beulichdffead42006-06-26 13:57:38 +0200261 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200262 CFI_REGISTER rip,rcx
263 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100264 SWAPGS_UNSAFE_STACK
265 /*
266 * A hypervisor implementation might want to use a label
267 * after the swapgs, so that it can do the swapgs
268 * for the guest and jump here on syscall.
269 */
270ENTRY(system_call_after_swapgs)
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 movq %rsp,%gs:pda_oldrsp
273 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700274 /*
275 * No need to follow this irqs off/on section - it's straight
276 * and short:
277 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100278 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 SAVE_ARGS 8,1
280 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200281 movq %rcx,RIP-ARGOFFSET(%rsp)
282 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 GET_THREAD_INFO(%rcx)
284 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
285 jnz tracesys
286 cmpq $__NR_syscall_max,%rax
287 ja badsys
288 movq %r10,%rcx
289 call *sys_call_table(,%rax,8) # XXX: rip relative
290 movq %rax,RAX-ARGOFFSET(%rsp)
291/*
292 * Syscall return path ending with SYSRET (fast path)
293 * Has incomplete stack frame and undefined top of stack.
294 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700296 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 /* edi: flagmask */
298sysret_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200299 LOCKDEP_SYS_EXIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100301 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700302 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 movl threadinfo_flags(%rcx),%edx
304 andl %edi,%edx
305 jnz sysret_careful
Jan Beulichbcddc012006-12-07 02:14:02 +0100306 CFI_REMEMBER_STATE
Ingo Molnar2601e642006-07-03 00:24:45 -0700307 /*
308 * sysretq will re-enable interrupts:
309 */
310 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200312 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200314 /*CFI_REGISTER rflags,r11*/
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100315 ENABLE_INTERRUPTS_SYSCALL_RET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Jan Beulichbcddc012006-12-07 02:14:02 +0100317 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 /* Handle reschedules */
319 /* edx: work, edi: workmask */
320sysret_careful:
321 bt $TIF_NEED_RESCHED,%edx
322 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700323 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100324 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200326 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 call schedule
328 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200329 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 jmp sysret_check
331
332 /* Handle a signal */
333sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700334 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100335 ENABLE_INTERRUPTS(CLBR_NONE)
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100336 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700337 jz 1f
338
339 /* Really a signal */
340 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 leaq do_notify_resume(%rip),%rax
342 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
343 xorl %esi,%esi # oldset -> arg2
344 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07003451: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200346 /* Use IRET because user could have changed frame. This
347 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100348 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700349 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200350 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Jan Beulich7effaa82005-09-12 18:49:24 +0200352badsys:
353 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
354 jmp ret_from_sys_call
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 /* Do syscall tracing */
357tracesys:
358 SAVE_REST
Roland McGratha31f8dd2008-03-16 21:59:11 -0700359 movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 FIXUP_TOP_OF_STACK %rdi
361 movq %rsp,%rdi
362 call syscall_trace_enter
363 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
364 RESTORE_REST
365 cmpq $__NR_syscall_max,%rax
Roland McGratha31f8dd2008-03-16 21:59:11 -0700366 ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 movq %r10,%rcx /* fixup for C */
368 call *sys_call_table(,%rax,8)
Roland McGratha31f8dd2008-03-16 21:59:11 -0700369 movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200370 /* Use IRET because user could have changed frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372/*
373 * Syscall return path ending with IRET.
374 * Has correct top of stack, but partial stack frame.
Jan Beulichbcddc012006-12-07 02:14:02 +0100375 */
376 .globl int_ret_from_sys_call
377int_ret_from_sys_call:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100378 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700379 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 testl $3,CS-ARGOFFSET(%rsp)
381 je retint_restore_args
382 movl $_TIF_ALLWORK_MASK,%edi
383 /* edi: mask to check */
384int_with_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200385 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 GET_THREAD_INFO(%rcx)
387 movl threadinfo_flags(%rcx),%edx
388 andl %edi,%edx
389 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100390 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 jmp retint_swapgs
392
393 /* Either reschedule or signal or syscall exit tracking needed. */
394 /* First do a reschedule test. */
395 /* edx: work, edi: workmask */
396int_careful:
397 bt $TIF_NEED_RESCHED,%edx
398 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700399 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100400 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200402 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 call schedule
404 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200405 CFI_ADJUST_CFA_OFFSET -8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100406 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700407 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 jmp int_with_check
409
410 /* handle signals and tracing -- both require a full stack frame */
411int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700412 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100413 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 SAVE_REST
415 /* Check for syscall exit trace */
416 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
417 jz int_signal
418 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200419 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 leaq 8(%rsp),%rdi # &ptregs -> arg1
421 call syscall_trace_leave
422 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200423 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700424 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 jmp int_restore_rest
426
427int_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100428 testl $_TIF_DO_NOTIFY_MASK,%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 jz 1f
430 movq %rsp,%rdi # &ptregs -> arg1
431 xorl %esi,%esi # oldset -> arg2
432 call do_notify_resume
4331: movl $_TIF_NEED_RESCHED,%edi
434int_restore_rest:
435 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100436 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700437 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 jmp int_with_check
439 CFI_ENDPROC
Jan Beulichbcddc012006-12-07 02:14:02 +0100440END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442/*
443 * Certain special system calls that need to save a complete full stack frame.
444 */
445
446 .macro PTREGSCALL label,func,arg
447 .globl \label
448\label:
449 leaq \func(%rip),%rax
450 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
451 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200452END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 .endm
454
Jan Beulich7effaa82005-09-12 18:49:24 +0200455 CFI_STARTPROC
456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 PTREGSCALL stub_clone, sys_clone, %r8
458 PTREGSCALL stub_fork, sys_fork, %rdi
459 PTREGSCALL stub_vfork, sys_vfork, %rdi
460 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
461 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
462 PTREGSCALL stub_iopl, sys_iopl, %rsi
463
464ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200466 CFI_ADJUST_CFA_OFFSET -8
467 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 SAVE_REST
469 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200470 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 FIXUP_TOP_OF_STACK %r11
472 call *%rax
473 RESTORE_TOP_OF_STACK %r11
474 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200475 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 RESTORE_REST
477 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200478 CFI_ADJUST_CFA_OFFSET 8
479 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 ret
481 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200482END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484ENTRY(stub_execve)
485 CFI_STARTPROC
486 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200487 CFI_ADJUST_CFA_OFFSET -8
488 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 FIXUP_TOP_OF_STACK %r11
Ingo Molnar5d119b22008-02-26 12:55:57 +0100491 movq %rsp, %rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 movq %rax,RAX(%rsp)
495 RESTORE_REST
496 jmp int_ret_from_sys_call
497 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200498END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
500/*
501 * sigreturn is special because it needs to restore all registers on return.
502 * This cannot be done with SYSRET, so use the IRET return path instead.
503 */
504ENTRY(stub_rt_sigreturn)
505 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200506 addq $8, %rsp
507 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 SAVE_REST
509 movq %rsp,%rdi
510 FIXUP_TOP_OF_STACK %r11
511 call sys_rt_sigreturn
512 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
513 RESTORE_REST
514 jmp int_ret_from_sys_call
515 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200516END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Jan Beulich7effaa82005-09-12 18:49:24 +0200518/*
519 * initial frame state for interrupts and exceptions
520 */
521 .macro _frame ref
522 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200523 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200524 CFI_DEF_CFA rsp,SS+8-\ref
525 /*CFI_REL_OFFSET ss,SS-\ref*/
526 CFI_REL_OFFSET rsp,RSP-\ref
527 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
528 /*CFI_REL_OFFSET cs,CS-\ref*/
529 CFI_REL_OFFSET rip,RIP-\ref
530 .endm
531
532/* initial frame state for interrupts (and exceptions without error code) */
533#define INTR_FRAME _frame RIP
534/* initial frame state for exceptions with error code (and interrupts with
535 vector already pushed) */
536#define XCPT_FRAME _frame ORIG_RAX
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538/*
539 * Interrupt entry/exit.
540 *
541 * Interrupt entry points save only callee clobbered registers in fast path.
542 *
543 * Entry runs with interrupts off.
544 */
545
546/* 0(%rsp): interrupt number */
547 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 SAVE_ARGS
550 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200551 pushq %rbp
552 CFI_ADJUST_CFA_OFFSET 8
553 CFI_REL_OFFSET rbp, 0
554 movq %rsp,%rbp
555 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 testl $3,CS(%rdi)
557 je 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100558 SWAPGS
Andi Kleen96e54042006-09-26 10:52:39 +0200559 /* irqcount is used to check if a CPU is already on an interrupt
560 stack or not. While this is essentially redundant with preempt_count
561 it is a little cheaper to use a separate counter in the PDA
562 (short of moving irq_enter into assembly, which would be too
563 much work) */
5641: incl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200565 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200566 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700567 /*
568 * We entered an interrupt context - irqs are off:
569 */
570 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 call \func
572 .endm
573
574ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200575 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 interrupt do_IRQ
577 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200578ret_from_intr:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100579 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700580 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700581 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200582 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200583 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200584 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200585exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 GET_THREAD_INFO(%rcx)
587 testl $3,CS-ARGOFFSET(%rsp)
588 je retint_kernel
589
590 /* Interrupt came from user space */
591 /*
592 * Has a correct top of stack, but a partial stack frame
593 * %rcx: thread info. Interrupts off.
594 */
595retint_with_reschedule:
596 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200597retint_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200598 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 movl threadinfo_flags(%rcx),%edx
600 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200601 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200603
604retint_swapgs: /* return to user-space */
Ingo Molnar2601e642006-07-03 00:24:45 -0700605 /*
606 * The iretq could re-enable interrupts:
607 */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100608 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700609 TRACE_IRQS_IRETQ
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100610 SWAPGS
Ingo Molnar2601e642006-07-03 00:24:45 -0700611 jmp restore_args
612
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200613retint_restore_args: /* return to kernel space */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100614 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700615 /*
616 * The iretq could re-enable interrupts:
617 */
618 TRACE_IRQS_IRETQ
619restore_args:
Ingo Molnar3701d8632008-02-09 23:24:08 +0100620 RESTORE_ARGS 0,8,0
621
Adrian Bunkf7f3d792008-02-13 23:29:53 +0200622irq_return:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100623 INTERRUPT_RETURN
Ingo Molnar3701d8632008-02-09 23:24:08 +0100624
625 .section __ex_table, "a"
626 .quad irq_return, bad_iret
627 .previous
628
629#ifdef CONFIG_PARAVIRT
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100630ENTRY(native_iret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 iretq
632
633 .section __ex_table,"a"
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100634 .quad native_iret, bad_iret
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 .previous
Ingo Molnar3701d8632008-02-09 23:24:08 +0100636#endif
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 .section .fixup,"ax"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639bad_iret:
Roland McGrath3aa4b372008-02-06 22:39:43 +0100640 /*
641 * The iret traps when the %cs or %ss being restored is bogus.
642 * We've lost the original trap vector and error code.
643 * #GPF is the most likely one to get for an invalid selector.
644 * So pretend we completed the iret and took the #GPF in user mode.
645 *
646 * We are now running with the kernel GS after exception recovery.
647 * But error_entry expects us to have user GS to match the user %cs,
648 * so swap back.
649 */
650 pushq $0
651
652 SWAPGS
653 jmp general_protection
654
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100655 .previous
656
Jan Beulich7effaa82005-09-12 18:49:24 +0200657 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200659 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 bt $TIF_NEED_RESCHED,%edx
661 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700662 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100663 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200665 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 call schedule
667 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200668 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 GET_THREAD_INFO(%rcx)
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100670 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700671 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 jmp retint_check
673
674retint_signal:
Peter Zijlstra8f4d37e2008-01-25 21:08:29 +0100675 testl $_TIF_DO_NOTIFY_MASK,%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700676 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700677 TRACE_IRQS_ON
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100678 ENABLE_INTERRUPTS(CLBR_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 SAVE_REST
680 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700681 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 movq %rsp,%rdi # &pt_regs
683 call do_notify_resume
684 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100685 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700686 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700687 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700688 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 jmp retint_check
690
691#ifdef CONFIG_PREEMPT
692 /* Returning to kernel space. Check if we need preemption */
693 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200694ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 cmpl $0,threadinfo_preempt_count(%rcx)
696 jnz retint_restore_args
697 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
698 jnc retint_restore_args
699 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
700 jnc retint_restore_args
701 call preempt_schedule_irq
702 jmp exit_intr
703#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200706END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708/*
709 * APIC interrupts.
710 */
711 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200712 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700713 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200714 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 interrupt \func
716 jmp ret_from_intr
717 CFI_ENDPROC
718 .endm
719
720ENTRY(thermal_interrupt)
721 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200722END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Jacob Shin89b831e2005-11-05 17:25:53 +0100724ENTRY(threshold_interrupt)
725 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200726END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728#ifdef CONFIG_SMP
729ENTRY(reschedule_interrupt)
730 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200731END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Andi Kleene5bc8b62005-09-12 18:49:24 +0200733 .macro INVALIDATE_ENTRY num
734ENTRY(invalidate_interrupt\num)
735 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200736END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200737 .endm
738
739 INVALIDATE_ENTRY 0
740 INVALIDATE_ENTRY 1
741 INVALIDATE_ENTRY 2
742 INVALIDATE_ENTRY 3
743 INVALIDATE_ENTRY 4
744 INVALIDATE_ENTRY 5
745 INVALIDATE_ENTRY 6
746 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748ENTRY(call_function_interrupt)
749 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200750END(call_function_interrupt)
Eric W. Biederman61014292007-02-23 04:40:58 -0700751ENTRY(irq_move_cleanup_interrupt)
752 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
753END(irq_move_cleanup_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754#endif
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756ENTRY(apic_timer_interrupt)
757 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200758END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760ENTRY(error_interrupt)
761 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200762END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764ENTRY(spurious_interrupt)
765 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200766END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768/*
769 * Exception entry points.
770 */
771 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200772 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200774 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200776 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200777 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 leaq \sym(%rip),%rax
779 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200780 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 .endm
782
783 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200784 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200786 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200787 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 leaq \sym(%rip),%rax
789 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200790 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 .endm
792
793 /* error code is on the stack already */
794 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700795 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 SAVE_ALL
797 cld
798 movl $1,%ebx
799 movl $MSR_GS_BASE,%ecx
800 rdmsr
801 testl %edx,%edx
802 js 1f
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100803 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01008051:
806 .if \ist
807 movq %gs:pda_data_offset, %rbp
808 .endif
809 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 movq ORIG_RAX(%rsp),%rsi
811 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100812 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100813 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100814 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100816 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100817 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100818 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100819 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700820 .if \irqtrace
821 TRACE_IRQS_OFF
822 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700824
825 /*
826 * "Paranoid" exit path from exception stack.
827 * Paranoid because this is used by NMIs and cannot take
828 * any kernel state for granted.
829 * We don't do kernel preemption checks here, because only
830 * NMI should be common and it does not enable IRQs and
831 * cannot get reschedule ticks.
832 *
833 * "trace" is 0 for the NMI handler only, because irq-tracing
834 * is fundamentally NMI-unsafe. (we cannot change the soft and
835 * hard flags at once, atomically)
836 */
837 .macro paranoidexit trace=1
838 /* ebx: no swapgs flag */
839paranoid_exit\trace:
840 testl %ebx,%ebx /* swapgs needed? */
841 jnz paranoid_restore\trace
842 testl $3,CS(%rsp)
843 jnz paranoid_userspace\trace
844paranoid_swapgs\trace:
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200845 .if \trace
Ingo Molnar2601e642006-07-03 00:24:45 -0700846 TRACE_IRQS_IRETQ 0
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200847 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100848 SWAPGS_UNSAFE_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -0700849paranoid_restore\trace:
850 RESTORE_ALL 8
Ingo Molnar3701d8632008-02-09 23:24:08 +0100851 jmp irq_return
Ingo Molnar2601e642006-07-03 00:24:45 -0700852paranoid_userspace\trace:
853 GET_THREAD_INFO(%rcx)
854 movl threadinfo_flags(%rcx),%ebx
855 andl $_TIF_WORK_MASK,%ebx
856 jz paranoid_swapgs\trace
857 movq %rsp,%rdi /* &pt_regs */
858 call sync_regs
859 movq %rax,%rsp /* switch stack for scheduling */
860 testl $_TIF_NEED_RESCHED,%ebx
861 jnz paranoid_schedule\trace
862 movl %ebx,%edx /* arg3: thread flags */
863 .if \trace
864 TRACE_IRQS_ON
865 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100866 ENABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700867 xorl %esi,%esi /* arg2: oldset */
868 movq %rsp,%rdi /* arg1: &pt_regs */
869 call do_notify_resume
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100870 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700871 .if \trace
872 TRACE_IRQS_OFF
873 .endif
874 jmp paranoid_userspace\trace
875paranoid_schedule\trace:
876 .if \trace
877 TRACE_IRQS_ON
878 .endif
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100879 ENABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700880 call schedule
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100881 DISABLE_INTERRUPTS(CLBR_ANY)
Ingo Molnar2601e642006-07-03 00:24:45 -0700882 .if \trace
883 TRACE_IRQS_OFF
884 .endif
885 jmp paranoid_userspace\trace
886 CFI_ENDPROC
887 .endm
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889/*
890 * Exception entry point. This expects an error code/orig_rax on the stack
891 * and the exception handler in %rax.
892 */
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200893KPROBE_ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200894 _frame RDI
Jan Beulich37550902007-05-02 19:27:05 +0200895 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 /* rdi slot contains rax, oldrax contains error code */
897 cld
898 subq $14*8,%rsp
899 CFI_ADJUST_CFA_OFFSET (14*8)
900 movq %rsi,13*8(%rsp)
901 CFI_REL_OFFSET rsi,RSI
902 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
Jan Beulich37550902007-05-02 19:27:05 +0200903 CFI_REGISTER rax,rsi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 movq %rdx,12*8(%rsp)
905 CFI_REL_OFFSET rdx,RDX
906 movq %rcx,11*8(%rsp)
907 CFI_REL_OFFSET rcx,RCX
908 movq %rsi,10*8(%rsp) /* store rax */
909 CFI_REL_OFFSET rax,RAX
910 movq %r8, 9*8(%rsp)
911 CFI_REL_OFFSET r8,R8
912 movq %r9, 8*8(%rsp)
913 CFI_REL_OFFSET r9,R9
914 movq %r10,7*8(%rsp)
915 CFI_REL_OFFSET r10,R10
916 movq %r11,6*8(%rsp)
917 CFI_REL_OFFSET r11,R11
918 movq %rbx,5*8(%rsp)
919 CFI_REL_OFFSET rbx,RBX
920 movq %rbp,4*8(%rsp)
921 CFI_REL_OFFSET rbp,RBP
922 movq %r12,3*8(%rsp)
923 CFI_REL_OFFSET r12,R12
924 movq %r13,2*8(%rsp)
925 CFI_REL_OFFSET r13,R13
926 movq %r14,1*8(%rsp)
927 CFI_REL_OFFSET r14,R14
928 movq %r15,(%rsp)
929 CFI_REL_OFFSET r15,R15
930 xorl %ebx,%ebx
931 testl $3,CS(%rsp)
932 je error_kernelspace
933error_swapgs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100934 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935error_sti:
936 movq %rdi,RDI(%rsp)
Jan Beulich37550902007-05-02 19:27:05 +0200937 CFI_REL_OFFSET rdi,RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 movq %rsp,%rdi
939 movq ORIG_RAX(%rsp),%rsi /* get error code */
940 movq $-1,ORIG_RAX(%rsp)
941 call *%rax
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200942 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
943error_exit:
944 movl %ebx,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 RESTORE_REST
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100946 DISABLE_INTERRUPTS(CLBR_NONE)
Ingo Molnar2601e642006-07-03 00:24:45 -0700947 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 GET_THREAD_INFO(%rcx)
949 testl %eax,%eax
950 jne retint_kernel
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200951 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 movl threadinfo_flags(%rcx),%edx
953 movl $_TIF_WORK_MASK,%edi
954 andl %edi,%edx
955 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200956 jmp retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 CFI_ENDPROC
958
959error_kernelspace:
960 incl %ebx
961 /* There are two places in the kernel that can potentially fault with
962 usergs. Handle them here. The exception handlers after
963 iret run with kernel gs again, so don't set the user space flag.
964 B stepping K8s sometimes report an truncated RIP for IRET
965 exceptions returning to compat mode. Check for these here too. */
Ingo Molnar3701d8632008-02-09 23:24:08 +0100966 leaq irq_return(%rip),%rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 cmpq %rbp,RIP(%rsp)
968 je error_swapgs
969 movl %ebp,%ebp /* zero extend */
970 cmpq %rbp,RIP(%rsp)
971 je error_swapgs
972 cmpq $gs_change,RIP(%rsp)
973 je error_swapgs
974 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200975KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 /* Reload gs selector with exception handling */
978 /* edi: new selector */
979ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200980 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200982 CFI_ADJUST_CFA_OFFSET 8
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100983 DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
984 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985gs_change:
986 movl %edi,%gs
9872: mfence /* workaround */
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +0100988 SWAPGS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200990 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200992 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200993ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 .section __ex_table,"a"
996 .align 8
997 .quad gs_change,bad_gs
998 .previous
999 .section .fixup,"ax"
1000 /* running with kernelgs */
1001bad_gs:
Glauber de Oliveira Costa72fe4852008-01-30 13:32:08 +01001002 SWAPGS /* switch back to user gs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 xorl %eax,%eax
1004 movl %eax,%gs
1005 jmp 2b
1006 .previous
1007
1008/*
1009 * Create a kernel thread.
1010 *
1011 * C extern interface:
1012 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
1013 *
1014 * asm input arguments:
1015 * rdi: fn, rsi: arg, rdx: flags
1016 */
1017ENTRY(kernel_thread)
1018 CFI_STARTPROC
1019 FAKE_STACK_FRAME $child_rip
1020 SAVE_ALL
1021
1022 # rdi: flags, rsi: usp, rdx: will be &pt_regs
1023 movq %rdx,%rdi
1024 orq kernel_thread_flags(%rip),%rdi
1025 movq $-1, %rsi
1026 movq %rsp, %rdx
1027
1028 xorl %r8d,%r8d
1029 xorl %r9d,%r9d
1030
1031 # clone now
1032 call do_fork
1033 movq %rax,RAX(%rsp)
1034 xorl %edi,%edi
1035
1036 /*
1037 * It isn't worth to check for reschedule here,
1038 * so internally to the x86_64 port you can rely on kernel_thread()
1039 * not to reschedule the child before returning, this avoids the need
1040 * of hacks for example to fork off the per-CPU idle tasks.
1041 * [Hopefully no generic code relies on the reschedule -AK]
1042 */
1043 RESTORE_ALL
1044 UNFAKE_STACK_FRAME
1045 ret
1046 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001047ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
1049child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +02001050 pushq $0 # fake return address
1051 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 /*
1053 * Here we are in the child and the registers are set as they were
1054 * at kernel_thread() invocation in the parent.
1055 */
1056 movq %rdi, %rax
1057 movq %rsi, %rdi
1058 call *%rax
1059 # exit
Andrey Mirkin1c5b5cf2007-10-17 18:04:33 +02001060 mov %eax, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +02001062 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001063ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065/*
1066 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1067 *
1068 * C extern interface:
1069 * extern long execve(char *name, char **argv, char **envp)
1070 *
1071 * asm input arguments:
1072 * rdi: name, rsi: argv, rdx: envp
1073 *
1074 * We want to fallback into:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001075 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 *
1077 * do_sys_execve asm fallback arguments:
Ingo Molnar5d119b22008-02-26 12:55:57 +01001078 * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 */
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001080ENTRY(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 CFI_STARTPROC
1082 FAKE_STACK_FRAME $0
1083 SAVE_ALL
Ingo Molnar5d119b22008-02-26 12:55:57 +01001084 movq %rsp,%rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 call sys_execve
1086 movq %rax, RAX(%rsp)
1087 RESTORE_REST
1088 testq %rax,%rax
1089 je int_ret_from_sys_call
1090 RESTORE_ARGS
1091 UNFAKE_STACK_FRAME
1092 ret
1093 CFI_ENDPROC
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001094ENDPROC(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001096KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001098KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100ENTRY(coprocessor_error)
1101 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001102END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104ENTRY(simd_coprocessor_error)
1105 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001106END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108ENTRY(device_not_available)
1109 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001110END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001113KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001114 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 pushq $0
1116 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001117 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001118 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001119KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
1121 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001122KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001123 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001125 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001126 paranoidentry do_nmi, 0, 0
1127#ifdef CONFIG_TRACE_IRQFLAGS
1128 paranoidexit 0
1129#else
1130 jmp paranoid_exit1
1131 CFI_ENDPROC
1132#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001133KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001134
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001135KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001136 INTR_FRAME
1137 pushq $0
1138 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001139 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001140 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001141 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001142KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144ENTRY(overflow)
1145 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001146END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
1148ENTRY(bounds)
1149 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001150END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152ENTRY(invalid_op)
1153 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001154END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156ENTRY(coprocessor_segment_overrun)
1157 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001158END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160ENTRY(reserved)
1161 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001162END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 /* runs on exception stack */
1165ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001166 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001168 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001170END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172ENTRY(invalid_TSS)
1173 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001174END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176ENTRY(segment_not_present)
1177 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001178END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180 /* runs on exception stack */
1181ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001182 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001184 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001186END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001188KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001190KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192ENTRY(alignment_check)
1193 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001194END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196ENTRY(divide_error)
1197 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001198END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200ENTRY(spurious_interrupt_bug)
1201 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001202END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204#ifdef CONFIG_X86_MCE
1205 /* runs on exception stack */
1206ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001207 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 pushq $0
1209 CFI_ADJUST_CFA_OFFSET 8
1210 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001211 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001213END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214#endif
1215
Andi Kleen26995002006-08-02 22:37:28 +02001216/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001217ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001218 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001219 push %rbp
1220 CFI_ADJUST_CFA_OFFSET 8
1221 CFI_REL_OFFSET rbp,0
1222 mov %rsp,%rbp
1223 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001224 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001225 cmove %gs:pda_irqstackptr,%rsp
1226 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001227 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001228 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001229 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001230 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001231 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001232 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001233 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001234ENDPROC(call_softirq)
Andi Kleen75154f42007-06-23 02:29:25 +02001235
1236KPROBE_ENTRY(ignore_sysret)
1237 CFI_STARTPROC
1238 mov $-ENOSYS,%eax
1239 sysret
1240 CFI_ENDPROC
1241ENDPROC(ignore_sysret)