blob: 22cac4487b57fd1e9aef98769071a8e4f02f0d81 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/entry.S
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
6 * Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
7 *
8 * $Id$
9 */
10
11/*
12 * entry.S contains the system-call and fault low-level handling routines.
13 *
14 * NOTE: This code handles signal-recognition, which happens every time
15 * after an interrupt and after each system call.
16 *
17 * Normal syscalls and interrupts don't save a full stack frame, this is
18 * only done for syscall tracing, signals or fork/exec et.al.
19 *
20 * A note on terminology:
21 * - top of stack: Architecture defined interrupt frame from SS to RIP
22 * at the top of the kernel process stack.
23 * - partial stack frame: partially saved registers upto R11.
24 * - full stack frame: Like partial stack frame, but all register saved.
25 *
26 * TODO:
27 * - schedule it carefully for the final hardware.
28 */
29
30#define ASSEMBLY 1
31#include <linux/config.h>
32#include <linux/linkage.h>
33#include <asm/segment.h>
34#include <asm/smp.h>
35#include <asm/cache.h>
36#include <asm/errno.h>
37#include <asm/dwarf2.h>
38#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020039#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <asm/msr.h>
41#include <asm/unistd.h>
42#include <asm/thread_info.h>
43#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010044#include <asm/page.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 .code64
47
Andi Kleendc37db42005-04-16 15:25:05 -070048#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#define retint_kernel retint_restore_args
50#endif
51
52/*
53 * C code is not supposed to know about undefined top of stack. Every time
54 * a C function with an pt_regs argument is called from the SYSCALL based
55 * fast path FIXUP_TOP_OF_STACK is needed.
56 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
57 * manipulation.
58 */
59
60 /* %rsp:at FRAMEEND */
61 .macro FIXUP_TOP_OF_STACK tmp
62 movq %gs:pda_oldrsp,\tmp
63 movq \tmp,RSP(%rsp)
64 movq $__USER_DS,SS(%rsp)
65 movq $__USER_CS,CS(%rsp)
66 movq $-1,RCX(%rsp)
67 movq R11(%rsp),\tmp /* get eflags */
68 movq \tmp,EFLAGS(%rsp)
69 .endm
70
71 .macro RESTORE_TOP_OF_STACK tmp,offset=0
72 movq RSP-\offset(%rsp),\tmp
73 movq \tmp,%gs:pda_oldrsp
74 movq EFLAGS-\offset(%rsp),\tmp
75 movq \tmp,R11-\offset(%rsp)
76 .endm
77
78 .macro FAKE_STACK_FRAME child_rip
79 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -070080 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 pushq %rax /* ss */
82 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020083 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 pushq %rax /* rsp */
85 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020086 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 pushq $(1<<9) /* eflags - interrupts on */
88 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020089 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 pushq $__KERNEL_CS /* cs */
91 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020092 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 pushq \child_rip /* rip */
94 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020095 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 pushq %rax /* orig rax */
97 CFI_ADJUST_CFA_OFFSET 8
98 .endm
99
100 .macro UNFAKE_STACK_FRAME
101 addq $8*6, %rsp
102 CFI_ADJUST_CFA_OFFSET -(6*8)
103 .endm
104
Jan Beulich7effaa82005-09-12 18:49:24 +0200105 .macro CFI_DEFAULT_STACK start=1
106 .if \start
107 CFI_STARTPROC simple
108 CFI_DEF_CFA rsp,SS+8
109 .else
110 CFI_DEF_CFA_OFFSET SS+8
111 .endif
112 CFI_REL_OFFSET r15,R15
113 CFI_REL_OFFSET r14,R14
114 CFI_REL_OFFSET r13,R13
115 CFI_REL_OFFSET r12,R12
116 CFI_REL_OFFSET rbp,RBP
117 CFI_REL_OFFSET rbx,RBX
118 CFI_REL_OFFSET r11,R11
119 CFI_REL_OFFSET r10,R10
120 CFI_REL_OFFSET r9,R9
121 CFI_REL_OFFSET r8,R8
122 CFI_REL_OFFSET rax,RAX
123 CFI_REL_OFFSET rcx,RCX
124 CFI_REL_OFFSET rdx,RDX
125 CFI_REL_OFFSET rsi,RSI
126 CFI_REL_OFFSET rdi,RDI
127 CFI_REL_OFFSET rip,RIP
128 /*CFI_REL_OFFSET cs,CS*/
129 /*CFI_REL_OFFSET rflags,EFLAGS*/
130 CFI_REL_OFFSET rsp,RSP
131 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 .endm
133/*
134 * A newly forked process directly context switches into this.
135 */
136/* rdi: prev */
137ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 CFI_DEFAULT_STACK
139 call schedule_tail
140 GET_THREAD_INFO(%rcx)
141 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
142 jnz rff_trace
143rff_action:
144 RESTORE_REST
145 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
146 je int_ret_from_sys_call
147 testl $_TIF_IA32,threadinfo_flags(%rcx)
148 jnz int_ret_from_sys_call
149 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
150 jmp ret_from_sys_call
151rff_trace:
152 movq %rsp,%rdi
153 call syscall_trace_leave
154 GET_THREAD_INFO(%rcx)
155 jmp rff_action
156 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200157END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159/*
160 * System call entry. Upto 6 arguments in registers are supported.
161 *
162 * SYSCALL does not save anything on the stack and does not change the
163 * stack pointer.
164 */
165
166/*
167 * Register setup:
168 * rax system call number
169 * rdi arg0
170 * rcx return address for syscall/sysret, C arg3
171 * rsi arg1
172 * rdx arg2
173 * r10 arg3 (--> moved to rcx for C)
174 * r8 arg4
175 * r9 arg5
176 * r11 eflags for syscall/sysret, temporary for C
177 * r12-r15,rbp,rbx saved by C code, not touched.
178 *
179 * Interrupts are off on entry.
180 * Only called from user space.
181 *
182 * XXX if we had a free scratch register we could save the RSP into the stack frame
183 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200184 *
185 * When user can change the frames always force IRET. That is because
186 * it deals with uncanonical addresses better. SYSRET has trouble
187 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 */
189
190ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200191 CFI_STARTPROC simple
Jan Beulichdffead42006-06-26 13:57:38 +0200192 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200193 CFI_REGISTER rip,rcx
194 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 swapgs
196 movq %rsp,%gs:pda_oldrsp
197 movq %gs:pda_kernelstack,%rsp
198 sti
199 SAVE_ARGS 8,1
200 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200201 movq %rcx,RIP-ARGOFFSET(%rsp)
202 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 GET_THREAD_INFO(%rcx)
204 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200205 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 jnz tracesys
207 cmpq $__NR_syscall_max,%rax
208 ja badsys
209 movq %r10,%rcx
210 call *sys_call_table(,%rax,8) # XXX: rip relative
211 movq %rax,RAX-ARGOFFSET(%rsp)
212/*
213 * Syscall return path ending with SYSRET (fast path)
214 * Has incomplete stack frame and undefined top of stack.
215 */
216 .globl ret_from_sys_call
217ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700218 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 /* edi: flagmask */
220sysret_check:
221 GET_THREAD_INFO(%rcx)
222 cli
223 movl threadinfo_flags(%rcx),%edx
224 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200225 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 jnz sysret_careful
227 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200228 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200230 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 movq %gs:pda_oldrsp,%rsp
232 swapgs
233 sysretq
234
235 /* Handle reschedules */
236 /* edx: work, edi: workmask */
237sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200238 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 bt $TIF_NEED_RESCHED,%edx
240 jnc sysret_signal
241 sti
242 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200243 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 call schedule
245 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200246 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 jmp sysret_check
248
249 /* Handle a signal */
250sysret_signal:
251 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700252 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
253 jz 1f
254
255 /* Really a signal */
256 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 leaq do_notify_resume(%rip),%rax
258 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
259 xorl %esi,%esi # oldset -> arg2
260 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002611: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200262 /* Use IRET because user could have changed frame. This
263 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
264 cli
265 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Jan Beulich7effaa82005-09-12 18:49:24 +0200267badsys:
268 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
269 jmp ret_from_sys_call
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /* Do syscall tracing */
272tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200273 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 SAVE_REST
275 movq $-ENOSYS,RAX(%rsp)
276 FIXUP_TOP_OF_STACK %rdi
277 movq %rsp,%rdi
278 call syscall_trace_enter
279 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
280 RESTORE_REST
281 cmpq $__NR_syscall_max,%rax
282 ja 1f
283 movq %r10,%rcx /* fixup for C */
284 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02002851: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200286 /* Use IRET because user could have changed frame */
287 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200288 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200289END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291/*
292 * Syscall return path ending with IRET.
293 * Has correct top of stack, but partial stack frame.
294 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200295ENTRY(int_ret_from_sys_call)
296 CFI_STARTPROC simple
297 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
298 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
299 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
300 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
301 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
302 CFI_REL_OFFSET rip,RIP-ARGOFFSET
303 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
304 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
305 CFI_REL_OFFSET rax,RAX-ARGOFFSET
306 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
307 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
308 CFI_REL_OFFSET r8,R8-ARGOFFSET
309 CFI_REL_OFFSET r9,R9-ARGOFFSET
310 CFI_REL_OFFSET r10,R10-ARGOFFSET
311 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 cli
313 testl $3,CS-ARGOFFSET(%rsp)
314 je retint_restore_args
315 movl $_TIF_ALLWORK_MASK,%edi
316 /* edi: mask to check */
317int_with_check:
318 GET_THREAD_INFO(%rcx)
319 movl threadinfo_flags(%rcx),%edx
320 andl %edi,%edx
321 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100322 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 jmp retint_swapgs
324
325 /* Either reschedule or signal or syscall exit tracking needed. */
326 /* First do a reschedule test. */
327 /* edx: work, edi: workmask */
328int_careful:
329 bt $TIF_NEED_RESCHED,%edx
330 jnc int_very_careful
331 sti
332 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200333 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 call schedule
335 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200336 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700337 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 jmp int_with_check
339
340 /* handle signals and tracing -- both require a full stack frame */
341int_very_careful:
342 sti
343 SAVE_REST
344 /* Check for syscall exit trace */
345 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
346 jz int_signal
347 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200348 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 leaq 8(%rsp),%rdi # &ptregs -> arg1
350 call syscall_trace_leave
351 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200352 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700353 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700354 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 jmp int_restore_rest
356
357int_signal:
358 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
359 jz 1f
360 movq %rsp,%rdi # &ptregs -> arg1
361 xorl %esi,%esi # oldset -> arg2
362 call do_notify_resume
3631: movl $_TIF_NEED_RESCHED,%edi
364int_restore_rest:
365 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700366 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 jmp int_with_check
368 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200369END(int_ret_from_sys_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371/*
372 * Certain special system calls that need to save a complete full stack frame.
373 */
374
375 .macro PTREGSCALL label,func,arg
376 .globl \label
377\label:
378 leaq \func(%rip),%rax
379 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
380 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200381END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 .endm
383
Jan Beulich7effaa82005-09-12 18:49:24 +0200384 CFI_STARTPROC
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 PTREGSCALL stub_clone, sys_clone, %r8
387 PTREGSCALL stub_fork, sys_fork, %rdi
388 PTREGSCALL stub_vfork, sys_vfork, %rdi
389 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
390 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
391 PTREGSCALL stub_iopl, sys_iopl, %rsi
392
393ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200395 CFI_ADJUST_CFA_OFFSET -8
396 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 SAVE_REST
398 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200399 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 FIXUP_TOP_OF_STACK %r11
401 call *%rax
402 RESTORE_TOP_OF_STACK %r11
403 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200404 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 RESTORE_REST
406 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200407 CFI_ADJUST_CFA_OFFSET 8
408 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 ret
410 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200411END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
413ENTRY(stub_execve)
414 CFI_STARTPROC
415 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200416 CFI_ADJUST_CFA_OFFSET -8
417 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 FIXUP_TOP_OF_STACK %r11
420 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 movq %rax,RAX(%rsp)
423 RESTORE_REST
424 jmp int_ret_from_sys_call
425 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200426END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428/*
429 * sigreturn is special because it needs to restore all registers on return.
430 * This cannot be done with SYSRET, so use the IRET return path instead.
431 */
432ENTRY(stub_rt_sigreturn)
433 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200434 addq $8, %rsp
435 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 SAVE_REST
437 movq %rsp,%rdi
438 FIXUP_TOP_OF_STACK %r11
439 call sys_rt_sigreturn
440 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
441 RESTORE_REST
442 jmp int_ret_from_sys_call
443 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200444END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Jan Beulich7effaa82005-09-12 18:49:24 +0200446/*
447 * initial frame state for interrupts and exceptions
448 */
449 .macro _frame ref
450 CFI_STARTPROC simple
451 CFI_DEF_CFA rsp,SS+8-\ref
452 /*CFI_REL_OFFSET ss,SS-\ref*/
453 CFI_REL_OFFSET rsp,RSP-\ref
454 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
455 /*CFI_REL_OFFSET cs,CS-\ref*/
456 CFI_REL_OFFSET rip,RIP-\ref
457 .endm
458
459/* initial frame state for interrupts (and exceptions without error code) */
460#define INTR_FRAME _frame RIP
461/* initial frame state for exceptions with error code (and interrupts with
462 vector already pushed) */
463#define XCPT_FRAME _frame ORIG_RAX
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465/*
466 * Interrupt entry/exit.
467 *
468 * Interrupt entry points save only callee clobbered registers in fast path.
469 *
470 * Entry runs with interrupts off.
471 */
472
473/* 0(%rsp): interrupt number */
474 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 SAVE_ARGS
477 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200478 pushq %rbp
479 CFI_ADJUST_CFA_OFFSET 8
480 CFI_REL_OFFSET rbp, 0
481 movq %rsp,%rbp
482 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 testl $3,CS(%rdi)
484 je 1f
485 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07004861: incl %gs:pda_irqcount # RED-PEN should check preempt count
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200487 cmoveq %gs:pda_irqstackptr,%rsp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 call \func
489 .endm
490
491ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200492 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 interrupt do_IRQ
494 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200495ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 cli
Andi Kleen3829ee62005-07-28 21:15:48 -0700497 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200498 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200499 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200500 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200501exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 GET_THREAD_INFO(%rcx)
503 testl $3,CS-ARGOFFSET(%rsp)
504 je retint_kernel
505
506 /* Interrupt came from user space */
507 /*
508 * Has a correct top of stack, but a partial stack frame
509 * %rcx: thread info. Interrupts off.
510 */
511retint_with_reschedule:
512 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200513retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 movl threadinfo_flags(%rcx),%edx
515 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200516 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 jnz retint_careful
518retint_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 swapgs
520retint_restore_args:
521 cli
522 RESTORE_ARGS 0,8,0
523iret_label:
524 iretq
525
526 .section __ex_table,"a"
527 .quad iret_label,bad_iret
528 .previous
529 .section .fixup,"ax"
530 /* force a signal here? this matches i386 behaviour */
531 /* running with kernel gs */
532bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100533 movq $11,%rdi /* SIGSEGV */
Andi Kleen2391c4b2006-02-16 23:42:01 +0100534 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 jmp do_exit
536 .previous
537
Jan Beulich7effaa82005-09-12 18:49:24 +0200538 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200540 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 bt $TIF_NEED_RESCHED,%edx
542 jnc retint_signal
543 sti
544 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200545 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 call schedule
547 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200548 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 GET_THREAD_INFO(%rcx)
550 cli
551 jmp retint_check
552
553retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700554 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
555 jz retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 sti
557 SAVE_REST
558 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700559 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 movq %rsp,%rdi # &pt_regs
561 call do_notify_resume
562 RESTORE_REST
563 cli
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700564 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700565 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 jmp retint_check
567
568#ifdef CONFIG_PREEMPT
569 /* Returning to kernel space. Check if we need preemption */
570 /* rcx: threadinfo. interrupts off. */
571 .p2align
572retint_kernel:
573 cmpl $0,threadinfo_preempt_count(%rcx)
574 jnz retint_restore_args
575 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
576 jnc retint_restore_args
577 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
578 jnc retint_restore_args
579 call preempt_schedule_irq
580 jmp exit_intr
581#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200584END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586/*
587 * APIC interrupts.
588 */
589 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200590 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700591 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200592 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 interrupt \func
594 jmp ret_from_intr
595 CFI_ENDPROC
596 .endm
597
598ENTRY(thermal_interrupt)
599 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200600END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Jacob Shin89b831e2005-11-05 17:25:53 +0100602ENTRY(threshold_interrupt)
603 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200604END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606#ifdef CONFIG_SMP
607ENTRY(reschedule_interrupt)
608 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200609END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
Andi Kleene5bc8b62005-09-12 18:49:24 +0200611 .macro INVALIDATE_ENTRY num
612ENTRY(invalidate_interrupt\num)
613 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200614END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200615 .endm
616
617 INVALIDATE_ENTRY 0
618 INVALIDATE_ENTRY 1
619 INVALIDATE_ENTRY 2
620 INVALIDATE_ENTRY 3
621 INVALIDATE_ENTRY 4
622 INVALIDATE_ENTRY 5
623 INVALIDATE_ENTRY 6
624 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626ENTRY(call_function_interrupt)
627 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200628END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629#endif
630
631#ifdef CONFIG_X86_LOCAL_APIC
632ENTRY(apic_timer_interrupt)
633 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200634END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636ENTRY(error_interrupt)
637 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200638END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640ENTRY(spurious_interrupt)
641 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200642END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643#endif
644
645/*
646 * Exception entry points.
647 */
648 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200649 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200651 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200653 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 leaq \sym(%rip),%rax
655 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200656 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 .endm
658
659 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200660 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200662 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 leaq \sym(%rip),%rax
664 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200665 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 .endm
667
668 /* error code is on the stack already */
669 /* handle NMI like exceptions that can happen everywhere */
Jan Beulichb556b352006-01-11 22:43:00 +0100670 .macro paranoidentry sym, ist=0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 SAVE_ALL
672 cld
673 movl $1,%ebx
674 movl $MSR_GS_BASE,%ecx
675 rdmsr
676 testl %edx,%edx
677 js 1f
678 swapgs
679 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01006801:
681 .if \ist
682 movq %gs:pda_data_offset, %rbp
683 .endif
684 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 movq ORIG_RAX(%rsp),%rsi
686 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100687 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100688 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100689 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100691 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100692 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100693 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700694 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 .endm
696
697/*
698 * Exception entry point. This expects an error code/orig_rax on the stack
699 * and the exception handler in %rax.
700 */
701ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200702 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* rdi slot contains rax, oldrax contains error code */
704 cld
705 subq $14*8,%rsp
706 CFI_ADJUST_CFA_OFFSET (14*8)
707 movq %rsi,13*8(%rsp)
708 CFI_REL_OFFSET rsi,RSI
709 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
710 movq %rdx,12*8(%rsp)
711 CFI_REL_OFFSET rdx,RDX
712 movq %rcx,11*8(%rsp)
713 CFI_REL_OFFSET rcx,RCX
714 movq %rsi,10*8(%rsp) /* store rax */
715 CFI_REL_OFFSET rax,RAX
716 movq %r8, 9*8(%rsp)
717 CFI_REL_OFFSET r8,R8
718 movq %r9, 8*8(%rsp)
719 CFI_REL_OFFSET r9,R9
720 movq %r10,7*8(%rsp)
721 CFI_REL_OFFSET r10,R10
722 movq %r11,6*8(%rsp)
723 CFI_REL_OFFSET r11,R11
724 movq %rbx,5*8(%rsp)
725 CFI_REL_OFFSET rbx,RBX
726 movq %rbp,4*8(%rsp)
727 CFI_REL_OFFSET rbp,RBP
728 movq %r12,3*8(%rsp)
729 CFI_REL_OFFSET r12,R12
730 movq %r13,2*8(%rsp)
731 CFI_REL_OFFSET r13,R13
732 movq %r14,1*8(%rsp)
733 CFI_REL_OFFSET r14,R14
734 movq %r15,(%rsp)
735 CFI_REL_OFFSET r15,R15
736 xorl %ebx,%ebx
737 testl $3,CS(%rsp)
738 je error_kernelspace
739error_swapgs:
740 swapgs
741error_sti:
742 movq %rdi,RDI(%rsp)
743 movq %rsp,%rdi
744 movq ORIG_RAX(%rsp),%rsi /* get error code */
745 movq $-1,ORIG_RAX(%rsp)
746 call *%rax
747 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
748error_exit:
749 movl %ebx,%eax
750 RESTORE_REST
751 cli
752 GET_THREAD_INFO(%rcx)
753 testl %eax,%eax
754 jne retint_kernel
755 movl threadinfo_flags(%rcx),%edx
756 movl $_TIF_WORK_MASK,%edi
757 andl %edi,%edx
758 jnz retint_careful
759 swapgs
760 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100761 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 CFI_ENDPROC
763
764error_kernelspace:
765 incl %ebx
766 /* There are two places in the kernel that can potentially fault with
767 usergs. Handle them here. The exception handlers after
768 iret run with kernel gs again, so don't set the user space flag.
769 B stepping K8s sometimes report an truncated RIP for IRET
770 exceptions returning to compat mode. Check for these here too. */
771 leaq iret_label(%rip),%rbp
772 cmpq %rbp,RIP(%rsp)
773 je error_swapgs
774 movl %ebp,%ebp /* zero extend */
775 cmpq %rbp,RIP(%rsp)
776 je error_swapgs
777 cmpq $gs_change,RIP(%rsp)
778 je error_swapgs
779 jmp error_sti
Jan Beulich4b787e02006-06-26 13:56:55 +0200780END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 /* Reload gs selector with exception handling */
783 /* edi: new selector */
784ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200785 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200787 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 cli
789 swapgs
790gs_change:
791 movl %edi,%gs
7922: mfence /* workaround */
793 swapgs
794 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200795 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200797 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200798ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 .section __ex_table,"a"
801 .align 8
802 .quad gs_change,bad_gs
803 .previous
804 .section .fixup,"ax"
805 /* running with kernelgs */
806bad_gs:
807 swapgs /* switch back to user gs */
808 xorl %eax,%eax
809 movl %eax,%gs
810 jmp 2b
811 .previous
812
813/*
814 * Create a kernel thread.
815 *
816 * C extern interface:
817 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
818 *
819 * asm input arguments:
820 * rdi: fn, rsi: arg, rdx: flags
821 */
822ENTRY(kernel_thread)
823 CFI_STARTPROC
824 FAKE_STACK_FRAME $child_rip
825 SAVE_ALL
826
827 # rdi: flags, rsi: usp, rdx: will be &pt_regs
828 movq %rdx,%rdi
829 orq kernel_thread_flags(%rip),%rdi
830 movq $-1, %rsi
831 movq %rsp, %rdx
832
833 xorl %r8d,%r8d
834 xorl %r9d,%r9d
835
836 # clone now
837 call do_fork
838 movq %rax,RAX(%rsp)
839 xorl %edi,%edi
840
841 /*
842 * It isn't worth to check for reschedule here,
843 * so internally to the x86_64 port you can rely on kernel_thread()
844 * not to reschedule the child before returning, this avoids the need
845 * of hacks for example to fork off the per-CPU idle tasks.
846 * [Hopefully no generic code relies on the reschedule -AK]
847 */
848 RESTORE_ALL
849 UNFAKE_STACK_FRAME
850 ret
851 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200852ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854child_rip:
855 /*
856 * Here we are in the child and the registers are set as they were
857 * at kernel_thread() invocation in the parent.
858 */
859 movq %rdi, %rax
860 movq %rsi, %rdi
861 call *%rax
862 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700863 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 call do_exit
Jan Beulich4b787e02006-06-26 13:56:55 +0200865ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867/*
868 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
869 *
870 * C extern interface:
871 * extern long execve(char *name, char **argv, char **envp)
872 *
873 * asm input arguments:
874 * rdi: name, rsi: argv, rdx: envp
875 *
876 * We want to fallback into:
877 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
878 *
879 * do_sys_execve asm fallback arguments:
880 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
881 */
882ENTRY(execve)
883 CFI_STARTPROC
884 FAKE_STACK_FRAME $0
885 SAVE_ALL
886 call sys_execve
887 movq %rax, RAX(%rsp)
888 RESTORE_REST
889 testq %rax,%rax
890 je int_ret_from_sys_call
891 RESTORE_ARGS
892 UNFAKE_STACK_FRAME
893 ret
894 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200895ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700897KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 errorentry do_page_fault
Jan Beulich4b787e02006-06-26 13:56:55 +0200899END(page_fault)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700900 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902ENTRY(coprocessor_error)
903 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +0200904END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906ENTRY(simd_coprocessor_error)
907 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +0200908END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910ENTRY(device_not_available)
911 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +0200912END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700915KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +0200916 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 pushq $0
918 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100919 paranoidentry do_debug, DEBUG_STACK
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 jmp paranoid_exit
921 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200922END(debug)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700923 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +0100926KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +0200927 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +0200929 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 paranoidentry do_nmi
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700931 /*
932 * "Paranoid" exit path from exception stack.
933 * Paranoid because this is used by NMIs and cannot take
934 * any kernel state for granted.
935 * We don't do kernel preemption checks here, because only
936 * NMI should be common and it does not enable IRQs and
937 * cannot get reschedule ticks.
938 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /* ebx: no swapgs flag */
940paranoid_exit:
941 testl %ebx,%ebx /* swapgs needed? */
942 jnz paranoid_restore
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700943 testl $3,CS(%rsp)
944 jnz paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945paranoid_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 swapgs
947paranoid_restore:
948 RESTORE_ALL 8
949 iretq
950paranoid_userspace:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 GET_THREAD_INFO(%rcx)
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700952 movl threadinfo_flags(%rcx),%ebx
953 andl $_TIF_WORK_MASK,%ebx
Andi Kleen11b854b2005-04-16 15:25:02 -0700954 jz paranoid_swapgs
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700955 movq %rsp,%rdi /* &pt_regs */
956 call sync_regs
957 movq %rax,%rsp /* switch stack for scheduling */
958 testl $_TIF_NEED_RESCHED,%ebx
959 jnz paranoid_schedule
960 movl %ebx,%edx /* arg3: thread flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 sti
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700962 xorl %esi,%esi /* arg2: oldset */
963 movq %rsp,%rdi /* arg1: &pt_regs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 call do_notify_resume
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700965 cli
966 jmp paranoid_userspace
967paranoid_schedule:
Andi Kleen11b854b2005-04-16 15:25:02 -0700968 sti
969 call schedule
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700970 cli
971 jmp paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200973END(nmi)
Andi Kleeneddb6fb2006-02-03 21:50:41 +0100974 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700975
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700976KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +0100977 INTR_FRAME
978 pushq $0
979 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100980 paranoidentry do_int3, DEBUG_STACK
Jan Beulichb556b352006-01-11 22:43:00 +0100981 jmp paranoid_exit
982 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200983END(int3)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700984 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986ENTRY(overflow)
987 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +0200988END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990ENTRY(bounds)
991 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +0200992END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994ENTRY(invalid_op)
995 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +0200996END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998ENTRY(coprocessor_segment_overrun)
999 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001000END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002ENTRY(reserved)
1003 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001004END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006 /* runs on exception stack */
1007ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001008 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 paranoidentry do_double_fault
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 jmp paranoid_exit
1011 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001012END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014ENTRY(invalid_TSS)
1015 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001016END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018ENTRY(segment_not_present)
1019 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001020END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022 /* runs on exception stack */
1023ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001024 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 paranoidentry do_stack_segment
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 jmp paranoid_exit
1027 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001028END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001030KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 errorentry do_general_protection
Jan Beulich4b787e02006-06-26 13:56:55 +02001032END(general_protection)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001033 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035ENTRY(alignment_check)
1036 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001037END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039ENTRY(divide_error)
1040 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001041END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043ENTRY(spurious_interrupt_bug)
1044 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001045END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047#ifdef CONFIG_X86_MCE
1048 /* runs on exception stack */
1049ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001050 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 pushq $0
1052 CFI_ADJUST_CFA_OFFSET 8
1053 paranoidentry do_machine_check
1054 jmp paranoid_exit
1055 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001056END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057#endif
1058
Andi Kleened6b6762005-07-28 21:15:49 -07001059ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001060 CFI_STARTPROC
Andi Kleened6b6762005-07-28 21:15:49 -07001061 movq %gs:pda_irqstackptr,%rax
Jan Beulichbd9cb642006-01-11 22:43:21 +01001062 movq %rsp,%rdx
1063 CFI_DEF_CFA_REGISTER rdx
Andi Kleened6b6762005-07-28 21:15:49 -07001064 incl %gs:pda_irqcount
1065 cmove %rax,%rsp
Jan Beulichbd9cb642006-01-11 22:43:21 +01001066 pushq %rdx
1067 /*todo CFI_DEF_CFA_EXPRESSION ...*/
Andi Kleened6b6762005-07-28 21:15:49 -07001068 call __do_softirq
Jan Beulichbd9cb642006-01-11 22:43:21 +01001069 popq %rsp
Jan Beulich7effaa82005-09-12 18:49:24 +02001070 CFI_DEF_CFA_REGISTER rsp
Andi Kleened6b6762005-07-28 21:15:49 -07001071 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001072 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001073 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001074ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001075
1076#ifdef CONFIG_STACK_UNWIND
1077ENTRY(arch_unwind_init_running)
1078 CFI_STARTPROC
1079 movq %r15, R15(%rdi)
1080 movq %r14, R14(%rdi)
1081 xchgq %rsi, %rdx
1082 movq %r13, R13(%rdi)
1083 movq %r12, R12(%rdi)
1084 xorl %eax, %eax
1085 movq %rbp, RBP(%rdi)
1086 movq %rbx, RBX(%rdi)
1087 movq (%rsp), %rcx
1088 movq %rax, R11(%rdi)
1089 movq %rax, R10(%rdi)
1090 movq %rax, R9(%rdi)
1091 movq %rax, R8(%rdi)
1092 movq %rax, RAX(%rdi)
1093 movq %rax, RCX(%rdi)
1094 movq %rax, RDX(%rdi)
1095 movq %rax, RSI(%rdi)
1096 movq %rax, RDI(%rdi)
1097 movq %rax, ORIG_RAX(%rdi)
1098 movq %rcx, RIP(%rdi)
1099 leaq 8(%rsp), %rcx
1100 movq $__KERNEL_CS, CS(%rdi)
1101 movq %rax, EFLAGS(%rdi)
1102 movq %rcx, RSP(%rdi)
1103 movq $__KERNEL_DS, SS(%rdi)
1104 jmpq *%rdx
1105 CFI_ENDPROC
1106ENDPROC(arch_unwind_init_running)
1107#endif