blob: 6c68beec51b395cb8fe7f5b01a5f01762fb3e9c7 [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
192 CFI_DEF_CFA rsp,0
193 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
476#ifdef CONFIG_DEBUG_INFO
477 SAVE_ALL
478 movq %rsp,%rdi
479 /*
480 * Setup a stack frame pointer. This allows gdb to trace
481 * back to the original stack.
482 */
483 movq %rsp,%rbp
484 CFI_DEF_CFA_REGISTER rbp
485#else
486 SAVE_ARGS
487 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
488#endif
489 testl $3,CS(%rdi)
490 je 1f
491 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07004921: incl %gs:pda_irqcount # RED-PEN should check preempt count
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 movq %gs:pda_irqstackptr,%rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200494 cmoveq %rax,%rsp /*todo This needs CFI annotation! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 pushq %rdi # save old stack
Jan Beulich91522a92006-02-03 21:51:44 +0100496#ifndef CONFIG_DEBUG_INFO
Jan Beulich7effaa82005-09-12 18:49:24 +0200497 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich91522a92006-02-03 21:51:44 +0100498#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 call \func
500 .endm
501
502ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200503 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 interrupt do_IRQ
505 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200506ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 popq %rdi
Jan Beulich91522a92006-02-03 21:51:44 +0100508#ifndef CONFIG_DEBUG_INFO
Jan Beulich7effaa82005-09-12 18:49:24 +0200509 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich91522a92006-02-03 21:51:44 +0100510#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 cli
Andi Kleen3829ee62005-07-28 21:15:48 -0700512 decl %gs:pda_irqcount
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513#ifdef CONFIG_DEBUG_INFO
514 movq RBP(%rdi),%rbp
Jan Beulich7effaa82005-09-12 18:49:24 +0200515 CFI_DEF_CFA_REGISTER rsp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516#endif
Jan Beulich7effaa82005-09-12 18:49:24 +0200517 leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */
518exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 GET_THREAD_INFO(%rcx)
520 testl $3,CS-ARGOFFSET(%rsp)
521 je retint_kernel
522
523 /* Interrupt came from user space */
524 /*
525 * Has a correct top of stack, but a partial stack frame
526 * %rcx: thread info. Interrupts off.
527 */
528retint_with_reschedule:
529 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200530retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 movl threadinfo_flags(%rcx),%edx
532 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200533 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 jnz retint_careful
535retint_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 swapgs
537retint_restore_args:
538 cli
539 RESTORE_ARGS 0,8,0
540iret_label:
541 iretq
542
543 .section __ex_table,"a"
544 .quad iret_label,bad_iret
545 .previous
546 .section .fixup,"ax"
547 /* force a signal here? this matches i386 behaviour */
548 /* running with kernel gs */
549bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100550 movq $11,%rdi /* SIGSEGV */
Andi Kleen2391c4b2006-02-16 23:42:01 +0100551 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 jmp do_exit
553 .previous
554
Jan Beulich7effaa82005-09-12 18:49:24 +0200555 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200557 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 bt $TIF_NEED_RESCHED,%edx
559 jnc retint_signal
560 sti
561 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200562 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 call schedule
564 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200565 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 GET_THREAD_INFO(%rcx)
567 cli
568 jmp retint_check
569
570retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700571 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
572 jz retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 sti
574 SAVE_REST
575 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700576 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 movq %rsp,%rdi # &pt_regs
578 call do_notify_resume
579 RESTORE_REST
580 cli
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700581 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700582 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 jmp retint_check
584
585#ifdef CONFIG_PREEMPT
586 /* Returning to kernel space. Check if we need preemption */
587 /* rcx: threadinfo. interrupts off. */
588 .p2align
589retint_kernel:
590 cmpl $0,threadinfo_preempt_count(%rcx)
591 jnz retint_restore_args
592 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
593 jnc retint_restore_args
594 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
595 jnc retint_restore_args
596 call preempt_schedule_irq
597 jmp exit_intr
598#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200601END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603/*
604 * APIC interrupts.
605 */
606 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200607 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 pushq $\num-256
Jan Beulich7effaa82005-09-12 18:49:24 +0200609 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 interrupt \func
611 jmp ret_from_intr
612 CFI_ENDPROC
613 .endm
614
615ENTRY(thermal_interrupt)
616 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200617END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Jacob Shin89b831e2005-11-05 17:25:53 +0100619ENTRY(threshold_interrupt)
620 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200621END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623#ifdef CONFIG_SMP
624ENTRY(reschedule_interrupt)
625 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200626END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Andi Kleene5bc8b62005-09-12 18:49:24 +0200628 .macro INVALIDATE_ENTRY num
629ENTRY(invalidate_interrupt\num)
630 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200631END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200632 .endm
633
634 INVALIDATE_ENTRY 0
635 INVALIDATE_ENTRY 1
636 INVALIDATE_ENTRY 2
637 INVALIDATE_ENTRY 3
638 INVALIDATE_ENTRY 4
639 INVALIDATE_ENTRY 5
640 INVALIDATE_ENTRY 6
641 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643ENTRY(call_function_interrupt)
644 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200645END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646#endif
647
648#ifdef CONFIG_X86_LOCAL_APIC
649ENTRY(apic_timer_interrupt)
650 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200651END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653ENTRY(error_interrupt)
654 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200655END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657ENTRY(spurious_interrupt)
658 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200659END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660#endif
661
662/*
663 * Exception entry points.
664 */
665 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200666 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200668 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200670 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 leaq \sym(%rip),%rax
672 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200673 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 .endm
675
676 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200677 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200679 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 leaq \sym(%rip),%rax
681 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200682 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 .endm
684
685 /* error code is on the stack already */
686 /* handle NMI like exceptions that can happen everywhere */
Jan Beulichb556b352006-01-11 22:43:00 +0100687 .macro paranoidentry sym, ist=0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 SAVE_ALL
689 cld
690 movl $1,%ebx
691 movl $MSR_GS_BASE,%ecx
692 rdmsr
693 testl %edx,%edx
694 js 1f
695 swapgs
696 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01006971:
698 .if \ist
699 movq %gs:pda_data_offset, %rbp
700 .endif
701 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 movq ORIG_RAX(%rsp),%rsi
703 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100704 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100705 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100706 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100708 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100709 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100710 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700711 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 .endm
713
714/*
715 * Exception entry point. This expects an error code/orig_rax on the stack
716 * and the exception handler in %rax.
717 */
718ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200719 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 /* rdi slot contains rax, oldrax contains error code */
721 cld
722 subq $14*8,%rsp
723 CFI_ADJUST_CFA_OFFSET (14*8)
724 movq %rsi,13*8(%rsp)
725 CFI_REL_OFFSET rsi,RSI
726 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
727 movq %rdx,12*8(%rsp)
728 CFI_REL_OFFSET rdx,RDX
729 movq %rcx,11*8(%rsp)
730 CFI_REL_OFFSET rcx,RCX
731 movq %rsi,10*8(%rsp) /* store rax */
732 CFI_REL_OFFSET rax,RAX
733 movq %r8, 9*8(%rsp)
734 CFI_REL_OFFSET r8,R8
735 movq %r9, 8*8(%rsp)
736 CFI_REL_OFFSET r9,R9
737 movq %r10,7*8(%rsp)
738 CFI_REL_OFFSET r10,R10
739 movq %r11,6*8(%rsp)
740 CFI_REL_OFFSET r11,R11
741 movq %rbx,5*8(%rsp)
742 CFI_REL_OFFSET rbx,RBX
743 movq %rbp,4*8(%rsp)
744 CFI_REL_OFFSET rbp,RBP
745 movq %r12,3*8(%rsp)
746 CFI_REL_OFFSET r12,R12
747 movq %r13,2*8(%rsp)
748 CFI_REL_OFFSET r13,R13
749 movq %r14,1*8(%rsp)
750 CFI_REL_OFFSET r14,R14
751 movq %r15,(%rsp)
752 CFI_REL_OFFSET r15,R15
753 xorl %ebx,%ebx
754 testl $3,CS(%rsp)
755 je error_kernelspace
756error_swapgs:
757 swapgs
758error_sti:
759 movq %rdi,RDI(%rsp)
760 movq %rsp,%rdi
761 movq ORIG_RAX(%rsp),%rsi /* get error code */
762 movq $-1,ORIG_RAX(%rsp)
763 call *%rax
764 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
765error_exit:
766 movl %ebx,%eax
767 RESTORE_REST
768 cli
769 GET_THREAD_INFO(%rcx)
770 testl %eax,%eax
771 jne retint_kernel
772 movl threadinfo_flags(%rcx),%edx
773 movl $_TIF_WORK_MASK,%edi
774 andl %edi,%edx
775 jnz retint_careful
776 swapgs
777 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100778 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 CFI_ENDPROC
780
781error_kernelspace:
782 incl %ebx
783 /* There are two places in the kernel that can potentially fault with
784 usergs. Handle them here. The exception handlers after
785 iret run with kernel gs again, so don't set the user space flag.
786 B stepping K8s sometimes report an truncated RIP for IRET
787 exceptions returning to compat mode. Check for these here too. */
788 leaq iret_label(%rip),%rbp
789 cmpq %rbp,RIP(%rsp)
790 je error_swapgs
791 movl %ebp,%ebp /* zero extend */
792 cmpq %rbp,RIP(%rsp)
793 je error_swapgs
794 cmpq $gs_change,RIP(%rsp)
795 je error_swapgs
796 jmp error_sti
Jan Beulich4b787e02006-06-26 13:56:55 +0200797END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 /* Reload gs selector with exception handling */
800 /* edi: new selector */
801ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200802 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200804 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 cli
806 swapgs
807gs_change:
808 movl %edi,%gs
8092: mfence /* workaround */
810 swapgs
811 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200812 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200814 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200815ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 .section __ex_table,"a"
818 .align 8
819 .quad gs_change,bad_gs
820 .previous
821 .section .fixup,"ax"
822 /* running with kernelgs */
823bad_gs:
824 swapgs /* switch back to user gs */
825 xorl %eax,%eax
826 movl %eax,%gs
827 jmp 2b
828 .previous
829
830/*
831 * Create a kernel thread.
832 *
833 * C extern interface:
834 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
835 *
836 * asm input arguments:
837 * rdi: fn, rsi: arg, rdx: flags
838 */
839ENTRY(kernel_thread)
840 CFI_STARTPROC
841 FAKE_STACK_FRAME $child_rip
842 SAVE_ALL
843
844 # rdi: flags, rsi: usp, rdx: will be &pt_regs
845 movq %rdx,%rdi
846 orq kernel_thread_flags(%rip),%rdi
847 movq $-1, %rsi
848 movq %rsp, %rdx
849
850 xorl %r8d,%r8d
851 xorl %r9d,%r9d
852
853 # clone now
854 call do_fork
855 movq %rax,RAX(%rsp)
856 xorl %edi,%edi
857
858 /*
859 * It isn't worth to check for reschedule here,
860 * so internally to the x86_64 port you can rely on kernel_thread()
861 * not to reschedule the child before returning, this avoids the need
862 * of hacks for example to fork off the per-CPU idle tasks.
863 * [Hopefully no generic code relies on the reschedule -AK]
864 */
865 RESTORE_ALL
866 UNFAKE_STACK_FRAME
867 ret
868 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200869ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
871child_rip:
872 /*
873 * Here we are in the child and the registers are set as they were
874 * at kernel_thread() invocation in the parent.
875 */
876 movq %rdi, %rax
877 movq %rsi, %rdi
878 call *%rax
879 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700880 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 call do_exit
Jan Beulich4b787e02006-06-26 13:56:55 +0200882ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884/*
885 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
886 *
887 * C extern interface:
888 * extern long execve(char *name, char **argv, char **envp)
889 *
890 * asm input arguments:
891 * rdi: name, rsi: argv, rdx: envp
892 *
893 * We want to fallback into:
894 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
895 *
896 * do_sys_execve asm fallback arguments:
897 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
898 */
899ENTRY(execve)
900 CFI_STARTPROC
901 FAKE_STACK_FRAME $0
902 SAVE_ALL
903 call sys_execve
904 movq %rax, RAX(%rsp)
905 RESTORE_REST
906 testq %rax,%rax
907 je int_ret_from_sys_call
908 RESTORE_ARGS
909 UNFAKE_STACK_FRAME
910 ret
911 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200912ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700914KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 errorentry do_page_fault
Jan Beulich4b787e02006-06-26 13:56:55 +0200916END(page_fault)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700917 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919ENTRY(coprocessor_error)
920 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +0200921END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923ENTRY(simd_coprocessor_error)
924 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +0200925END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927ENTRY(device_not_available)
928 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +0200929END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700932KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +0200933 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 pushq $0
935 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100936 paranoidentry do_debug, DEBUG_STACK
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 jmp paranoid_exit
938 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200939END(debug)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700940 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +0100943KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +0200944 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +0200946 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 paranoidentry do_nmi
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700948 /*
949 * "Paranoid" exit path from exception stack.
950 * Paranoid because this is used by NMIs and cannot take
951 * any kernel state for granted.
952 * We don't do kernel preemption checks here, because only
953 * NMI should be common and it does not enable IRQs and
954 * cannot get reschedule ticks.
955 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 /* ebx: no swapgs flag */
957paranoid_exit:
958 testl %ebx,%ebx /* swapgs needed? */
959 jnz paranoid_restore
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700960 testl $3,CS(%rsp)
961 jnz paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962paranoid_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 swapgs
964paranoid_restore:
965 RESTORE_ALL 8
966 iretq
967paranoid_userspace:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 GET_THREAD_INFO(%rcx)
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700969 movl threadinfo_flags(%rcx),%ebx
970 andl $_TIF_WORK_MASK,%ebx
Andi Kleen11b854b2005-04-16 15:25:02 -0700971 jz paranoid_swapgs
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700972 movq %rsp,%rdi /* &pt_regs */
973 call sync_regs
974 movq %rax,%rsp /* switch stack for scheduling */
975 testl $_TIF_NEED_RESCHED,%ebx
976 jnz paranoid_schedule
977 movl %ebx,%edx /* arg3: thread flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 sti
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700979 xorl %esi,%esi /* arg2: oldset */
980 movq %rsp,%rdi /* arg1: &pt_regs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 call do_notify_resume
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700982 cli
983 jmp paranoid_userspace
984paranoid_schedule:
Andi Kleen11b854b2005-04-16 15:25:02 -0700985 sti
986 call schedule
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700987 cli
988 jmp paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200990END(nmi)
Andi Kleeneddb6fb2006-02-03 21:50:41 +0100991 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700992
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700993KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +0100994 INTR_FRAME
995 pushq $0
996 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100997 paranoidentry do_int3, DEBUG_STACK
Jan Beulichb556b352006-01-11 22:43:00 +0100998 jmp paranoid_exit
999 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001000END(int3)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001001 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003ENTRY(overflow)
1004 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001005END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007ENTRY(bounds)
1008 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001009END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011ENTRY(invalid_op)
1012 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001013END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015ENTRY(coprocessor_segment_overrun)
1016 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001017END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019ENTRY(reserved)
1020 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001021END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 /* runs on exception stack */
1024ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001025 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 paranoidentry do_double_fault
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 jmp paranoid_exit
1028 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001029END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031ENTRY(invalid_TSS)
1032 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001033END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035ENTRY(segment_not_present)
1036 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001037END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 /* runs on exception stack */
1040ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001041 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 paranoidentry do_stack_segment
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 jmp paranoid_exit
1044 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001045END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001047KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 errorentry do_general_protection
Jan Beulich4b787e02006-06-26 13:56:55 +02001049END(general_protection)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001050 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052ENTRY(alignment_check)
1053 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001054END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056ENTRY(divide_error)
1057 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001058END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060ENTRY(spurious_interrupt_bug)
1061 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001062END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064#ifdef CONFIG_X86_MCE
1065 /* runs on exception stack */
1066ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001067 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 pushq $0
1069 CFI_ADJUST_CFA_OFFSET 8
1070 paranoidentry do_machine_check
1071 jmp paranoid_exit
1072 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001073END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074#endif
1075
Andi Kleened6b6762005-07-28 21:15:49 -07001076ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001077 CFI_STARTPROC
Andi Kleened6b6762005-07-28 21:15:49 -07001078 movq %gs:pda_irqstackptr,%rax
Jan Beulichbd9cb642006-01-11 22:43:21 +01001079 movq %rsp,%rdx
1080 CFI_DEF_CFA_REGISTER rdx
Andi Kleened6b6762005-07-28 21:15:49 -07001081 incl %gs:pda_irqcount
1082 cmove %rax,%rsp
Jan Beulichbd9cb642006-01-11 22:43:21 +01001083 pushq %rdx
1084 /*todo CFI_DEF_CFA_EXPRESSION ...*/
Andi Kleened6b6762005-07-28 21:15:49 -07001085 call __do_softirq
Jan Beulichbd9cb642006-01-11 22:43:21 +01001086 popq %rsp
Jan Beulich7effaa82005-09-12 18:49:24 +02001087 CFI_DEF_CFA_REGISTER rsp
Andi Kleened6b6762005-07-28 21:15:49 -07001088 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001089 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001090 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001091ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001092
1093#ifdef CONFIG_STACK_UNWIND
1094ENTRY(arch_unwind_init_running)
1095 CFI_STARTPROC
1096 movq %r15, R15(%rdi)
1097 movq %r14, R14(%rdi)
1098 xchgq %rsi, %rdx
1099 movq %r13, R13(%rdi)
1100 movq %r12, R12(%rdi)
1101 xorl %eax, %eax
1102 movq %rbp, RBP(%rdi)
1103 movq %rbx, RBX(%rdi)
1104 movq (%rsp), %rcx
1105 movq %rax, R11(%rdi)
1106 movq %rax, R10(%rdi)
1107 movq %rax, R9(%rdi)
1108 movq %rax, R8(%rdi)
1109 movq %rax, RAX(%rdi)
1110 movq %rax, RCX(%rdi)
1111 movq %rax, RDX(%rdi)
1112 movq %rax, RSI(%rdi)
1113 movq %rax, RDI(%rdi)
1114 movq %rax, ORIG_RAX(%rdi)
1115 movq %rcx, RIP(%rdi)
1116 leaq 8(%rsp), %rcx
1117 movq $__KERNEL_CS, CS(%rdi)
1118 movq %rax, EFLAGS(%rdi)
1119 movq %rcx, RSP(%rdi)
1120 movq $__KERNEL_DS, SS(%rdi)
1121 jmpq *%rdx
1122 CFI_ENDPROC
1123ENDPROC(arch_unwind_init_running)
1124#endif