blob: c946e4fe67a7937ab15eba697246602c7dc67dbd [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
157
158/*
159 * System call entry. Upto 6 arguments in registers are supported.
160 *
161 * SYSCALL does not save anything on the stack and does not change the
162 * stack pointer.
163 */
164
165/*
166 * Register setup:
167 * rax system call number
168 * rdi arg0
169 * rcx return address for syscall/sysret, C arg3
170 * rsi arg1
171 * rdx arg2
172 * r10 arg3 (--> moved to rcx for C)
173 * r8 arg4
174 * r9 arg5
175 * r11 eflags for syscall/sysret, temporary for C
176 * r12-r15,rbp,rbx saved by C code, not touched.
177 *
178 * Interrupts are off on entry.
179 * Only called from user space.
180 *
181 * XXX if we had a free scratch register we could save the RSP into the stack frame
182 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200183 *
184 * When user can change the frames always force IRET. That is because
185 * it deals with uncanonical addresses better. SYSRET has trouble
186 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 */
188
189ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200190 CFI_STARTPROC simple
191 CFI_DEF_CFA rsp,0
192 CFI_REGISTER rip,rcx
193 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 swapgs
195 movq %rsp,%gs:pda_oldrsp
196 movq %gs:pda_kernelstack,%rsp
197 sti
198 SAVE_ARGS 8,1
199 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200200 movq %rcx,RIP-ARGOFFSET(%rsp)
201 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 GET_THREAD_INFO(%rcx)
203 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200204 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 jnz tracesys
206 cmpq $__NR_syscall_max,%rax
207 ja badsys
208 movq %r10,%rcx
209 call *sys_call_table(,%rax,8) # XXX: rip relative
210 movq %rax,RAX-ARGOFFSET(%rsp)
211/*
212 * Syscall return path ending with SYSRET (fast path)
213 * Has incomplete stack frame and undefined top of stack.
214 */
215 .globl ret_from_sys_call
216ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700217 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 /* edi: flagmask */
219sysret_check:
220 GET_THREAD_INFO(%rcx)
221 cli
222 movl threadinfo_flags(%rcx),%edx
223 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200224 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 jnz sysret_careful
226 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200227 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200229 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 movq %gs:pda_oldrsp,%rsp
231 swapgs
232 sysretq
233
234 /* Handle reschedules */
235 /* edx: work, edi: workmask */
236sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200237 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 bt $TIF_NEED_RESCHED,%edx
239 jnc sysret_signal
240 sti
241 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200242 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 call schedule
244 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200245 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 jmp sysret_check
247
248 /* Handle a signal */
249sysret_signal:
250 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700251 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
252 jz 1f
253
254 /* Really a signal */
255 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 leaq do_notify_resume(%rip),%rax
257 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
258 xorl %esi,%esi # oldset -> arg2
259 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002601: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200261 /* Use IRET because user could have changed frame. This
262 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
263 cli
264 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Jan Beulich7effaa82005-09-12 18:49:24 +0200266badsys:
267 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
268 jmp ret_from_sys_call
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 /* Do syscall tracing */
271tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200272 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 SAVE_REST
274 movq $-ENOSYS,RAX(%rsp)
275 FIXUP_TOP_OF_STACK %rdi
276 movq %rsp,%rdi
277 call syscall_trace_enter
278 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
279 RESTORE_REST
280 cmpq $__NR_syscall_max,%rax
281 ja 1f
282 movq %r10,%rcx /* fixup for C */
283 call *sys_call_table(,%rax,8)
284 movq %rax,RAX-ARGOFFSET(%rsp)
2851: SAVE_REST
286 movq %rsp,%rdi
287 call syscall_trace_leave
288 RESTORE_TOP_OF_STACK %rbx
289 RESTORE_REST
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200290 /* Use IRET because user could have changed frame */
291 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200292 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294/*
295 * Syscall return path ending with IRET.
296 * Has correct top of stack, but partial stack frame.
297 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200298ENTRY(int_ret_from_sys_call)
299 CFI_STARTPROC simple
300 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
301 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
302 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
303 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
304 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
305 CFI_REL_OFFSET rip,RIP-ARGOFFSET
306 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
307 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
308 CFI_REL_OFFSET rax,RAX-ARGOFFSET
309 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
310 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
311 CFI_REL_OFFSET r8,R8-ARGOFFSET
312 CFI_REL_OFFSET r9,R9-ARGOFFSET
313 CFI_REL_OFFSET r10,R10-ARGOFFSET
314 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 cli
316 testl $3,CS-ARGOFFSET(%rsp)
317 je retint_restore_args
318 movl $_TIF_ALLWORK_MASK,%edi
319 /* edi: mask to check */
320int_with_check:
321 GET_THREAD_INFO(%rcx)
322 movl threadinfo_flags(%rcx),%edx
323 andl %edi,%edx
324 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100325 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 jmp retint_swapgs
327
328 /* Either reschedule or signal or syscall exit tracking needed. */
329 /* First do a reschedule test. */
330 /* edx: work, edi: workmask */
331int_careful:
332 bt $TIF_NEED_RESCHED,%edx
333 jnc int_very_careful
334 sti
335 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200336 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 call schedule
338 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200339 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700340 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 jmp int_with_check
342
343 /* handle signals and tracing -- both require a full stack frame */
344int_very_careful:
345 sti
346 SAVE_REST
347 /* Check for syscall exit trace */
348 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
349 jz int_signal
350 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200351 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 leaq 8(%rsp),%rdi # &ptregs -> arg1
353 call syscall_trace_leave
354 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200355 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700356 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700357 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 jmp int_restore_rest
359
360int_signal:
361 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
362 jz 1f
363 movq %rsp,%rdi # &ptregs -> arg1
364 xorl %esi,%esi # oldset -> arg2
365 call do_notify_resume
3661: movl $_TIF_NEED_RESCHED,%edi
367int_restore_rest:
368 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700369 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 jmp int_with_check
371 CFI_ENDPROC
372
373/*
374 * Certain special system calls that need to save a complete full stack frame.
375 */
376
377 .macro PTREGSCALL label,func,arg
378 .globl \label
379\label:
380 leaq \func(%rip),%rax
381 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
382 jmp ptregscall_common
383 .endm
384
Jan Beulich7effaa82005-09-12 18:49:24 +0200385 CFI_STARTPROC
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 PTREGSCALL stub_clone, sys_clone, %r8
388 PTREGSCALL stub_fork, sys_fork, %rdi
389 PTREGSCALL stub_vfork, sys_vfork, %rdi
390 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
391 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
392 PTREGSCALL stub_iopl, sys_iopl, %rsi
393
394ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200396 CFI_ADJUST_CFA_OFFSET -8
397 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 SAVE_REST
399 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200400 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 FIXUP_TOP_OF_STACK %r11
402 call *%rax
403 RESTORE_TOP_OF_STACK %r11
404 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200405 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 RESTORE_REST
407 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200408 CFI_ADJUST_CFA_OFFSET 8
409 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 ret
411 CFI_ENDPROC
412
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
426
427/*
428 * sigreturn is special because it needs to restore all registers on return.
429 * This cannot be done with SYSRET, so use the IRET return path instead.
430 */
431ENTRY(stub_rt_sigreturn)
432 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200433 addq $8, %rsp
434 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 SAVE_REST
436 movq %rsp,%rdi
437 FIXUP_TOP_OF_STACK %r11
438 call sys_rt_sigreturn
439 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
440 RESTORE_REST
441 jmp int_ret_from_sys_call
442 CFI_ENDPROC
443
Jan Beulich7effaa82005-09-12 18:49:24 +0200444/*
445 * initial frame state for interrupts and exceptions
446 */
447 .macro _frame ref
448 CFI_STARTPROC simple
449 CFI_DEF_CFA rsp,SS+8-\ref
450 /*CFI_REL_OFFSET ss,SS-\ref*/
451 CFI_REL_OFFSET rsp,RSP-\ref
452 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
453 /*CFI_REL_OFFSET cs,CS-\ref*/
454 CFI_REL_OFFSET rip,RIP-\ref
455 .endm
456
457/* initial frame state for interrupts (and exceptions without error code) */
458#define INTR_FRAME _frame RIP
459/* initial frame state for exceptions with error code (and interrupts with
460 vector already pushed) */
461#define XCPT_FRAME _frame ORIG_RAX
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463/*
464 * Interrupt entry/exit.
465 *
466 * Interrupt entry points save only callee clobbered registers in fast path.
467 *
468 * Entry runs with interrupts off.
469 */
470
471/* 0(%rsp): interrupt number */
472 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 cld
474#ifdef CONFIG_DEBUG_INFO
475 SAVE_ALL
476 movq %rsp,%rdi
477 /*
478 * Setup a stack frame pointer. This allows gdb to trace
479 * back to the original stack.
480 */
481 movq %rsp,%rbp
482 CFI_DEF_CFA_REGISTER rbp
483#else
484 SAVE_ARGS
485 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
486#endif
487 testl $3,CS(%rdi)
488 je 1f
489 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07004901: incl %gs:pda_irqcount # RED-PEN should check preempt count
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 movq %gs:pda_irqstackptr,%rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200492 cmoveq %rax,%rsp /*todo This needs CFI annotation! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 pushq %rdi # save old stack
Jan Beulich91522a92006-02-03 21:51:44 +0100494#ifndef CONFIG_DEBUG_INFO
Jan Beulich7effaa82005-09-12 18:49:24 +0200495 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich91522a92006-02-03 21:51:44 +0100496#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 call \func
498 .endm
499
500ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200501 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 interrupt do_IRQ
503 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200504ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 popq %rdi
Jan Beulich91522a92006-02-03 21:51:44 +0100506#ifndef CONFIG_DEBUG_INFO
Jan Beulich7effaa82005-09-12 18:49:24 +0200507 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich91522a92006-02-03 21:51:44 +0100508#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 cli
Andi Kleen3829ee62005-07-28 21:15:48 -0700510 decl %gs:pda_irqcount
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511#ifdef CONFIG_DEBUG_INFO
512 movq RBP(%rdi),%rbp
Jan Beulich7effaa82005-09-12 18:49:24 +0200513 CFI_DEF_CFA_REGISTER rsp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514#endif
Jan Beulich7effaa82005-09-12 18:49:24 +0200515 leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */
516exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 GET_THREAD_INFO(%rcx)
518 testl $3,CS-ARGOFFSET(%rsp)
519 je retint_kernel
520
521 /* Interrupt came from user space */
522 /*
523 * Has a correct top of stack, but a partial stack frame
524 * %rcx: thread info. Interrupts off.
525 */
526retint_with_reschedule:
527 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200528retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 movl threadinfo_flags(%rcx),%edx
530 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200531 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 jnz retint_careful
533retint_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 swapgs
535retint_restore_args:
536 cli
537 RESTORE_ARGS 0,8,0
538iret_label:
539 iretq
540
541 .section __ex_table,"a"
542 .quad iret_label,bad_iret
543 .previous
544 .section .fixup,"ax"
545 /* force a signal here? this matches i386 behaviour */
546 /* running with kernel gs */
547bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100548 movq $11,%rdi /* SIGSEGV */
Andi Kleen2391c4b2006-02-16 23:42:01 +0100549 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 jmp do_exit
551 .previous
552
Jan Beulich7effaa82005-09-12 18:49:24 +0200553 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200555 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 bt $TIF_NEED_RESCHED,%edx
557 jnc retint_signal
558 sti
559 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200560 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 call schedule
562 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200563 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 GET_THREAD_INFO(%rcx)
565 cli
566 jmp retint_check
567
568retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700569 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
570 jz retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 sti
572 SAVE_REST
573 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700574 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 movq %rsp,%rdi # &pt_regs
576 call do_notify_resume
577 RESTORE_REST
578 cli
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700579 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700580 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 jmp retint_check
582
583#ifdef CONFIG_PREEMPT
584 /* Returning to kernel space. Check if we need preemption */
585 /* rcx: threadinfo. interrupts off. */
586 .p2align
587retint_kernel:
588 cmpl $0,threadinfo_preempt_count(%rcx)
589 jnz retint_restore_args
590 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
591 jnc retint_restore_args
592 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
593 jnc retint_restore_args
594 call preempt_schedule_irq
595 jmp exit_intr
596#endif
597 CFI_ENDPROC
598
599/*
600 * APIC interrupts.
601 */
602 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200603 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 pushq $\num-256
Jan Beulich7effaa82005-09-12 18:49:24 +0200605 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 interrupt \func
607 jmp ret_from_intr
608 CFI_ENDPROC
609 .endm
610
611ENTRY(thermal_interrupt)
612 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
613
Jacob Shin89b831e2005-11-05 17:25:53 +0100614ENTRY(threshold_interrupt)
615 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617#ifdef CONFIG_SMP
618ENTRY(reschedule_interrupt)
619 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
620
Andi Kleene5bc8b62005-09-12 18:49:24 +0200621 .macro INVALIDATE_ENTRY num
622ENTRY(invalidate_interrupt\num)
623 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
624 .endm
625
626 INVALIDATE_ENTRY 0
627 INVALIDATE_ENTRY 1
628 INVALIDATE_ENTRY 2
629 INVALIDATE_ENTRY 3
630 INVALIDATE_ENTRY 4
631 INVALIDATE_ENTRY 5
632 INVALIDATE_ENTRY 6
633 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635ENTRY(call_function_interrupt)
636 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
637#endif
638
639#ifdef CONFIG_X86_LOCAL_APIC
640ENTRY(apic_timer_interrupt)
641 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
642
643ENTRY(error_interrupt)
644 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
645
646ENTRY(spurious_interrupt)
647 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
648#endif
649
650/*
651 * Exception entry points.
652 */
653 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200654 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200656 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200658 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 leaq \sym(%rip),%rax
660 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200661 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 .endm
663
664 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200665 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200667 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 leaq \sym(%rip),%rax
669 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200670 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 .endm
672
673 /* error code is on the stack already */
674 /* handle NMI like exceptions that can happen everywhere */
Jan Beulichb556b352006-01-11 22:43:00 +0100675 .macro paranoidentry sym, ist=0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 SAVE_ALL
677 cld
678 movl $1,%ebx
679 movl $MSR_GS_BASE,%ecx
680 rdmsr
681 testl %edx,%edx
682 js 1f
683 swapgs
684 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01006851:
686 .if \ist
687 movq %gs:pda_data_offset, %rbp
688 .endif
689 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 movq ORIG_RAX(%rsp),%rsi
691 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100692 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100693 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100694 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100696 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100697 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100698 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700699 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 .endm
701
702/*
703 * Exception entry point. This expects an error code/orig_rax on the stack
704 * and the exception handler in %rax.
705 */
706ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200707 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /* rdi slot contains rax, oldrax contains error code */
709 cld
710 subq $14*8,%rsp
711 CFI_ADJUST_CFA_OFFSET (14*8)
712 movq %rsi,13*8(%rsp)
713 CFI_REL_OFFSET rsi,RSI
714 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
715 movq %rdx,12*8(%rsp)
716 CFI_REL_OFFSET rdx,RDX
717 movq %rcx,11*8(%rsp)
718 CFI_REL_OFFSET rcx,RCX
719 movq %rsi,10*8(%rsp) /* store rax */
720 CFI_REL_OFFSET rax,RAX
721 movq %r8, 9*8(%rsp)
722 CFI_REL_OFFSET r8,R8
723 movq %r9, 8*8(%rsp)
724 CFI_REL_OFFSET r9,R9
725 movq %r10,7*8(%rsp)
726 CFI_REL_OFFSET r10,R10
727 movq %r11,6*8(%rsp)
728 CFI_REL_OFFSET r11,R11
729 movq %rbx,5*8(%rsp)
730 CFI_REL_OFFSET rbx,RBX
731 movq %rbp,4*8(%rsp)
732 CFI_REL_OFFSET rbp,RBP
733 movq %r12,3*8(%rsp)
734 CFI_REL_OFFSET r12,R12
735 movq %r13,2*8(%rsp)
736 CFI_REL_OFFSET r13,R13
737 movq %r14,1*8(%rsp)
738 CFI_REL_OFFSET r14,R14
739 movq %r15,(%rsp)
740 CFI_REL_OFFSET r15,R15
741 xorl %ebx,%ebx
742 testl $3,CS(%rsp)
743 je error_kernelspace
744error_swapgs:
745 swapgs
746error_sti:
747 movq %rdi,RDI(%rsp)
748 movq %rsp,%rdi
749 movq ORIG_RAX(%rsp),%rsi /* get error code */
750 movq $-1,ORIG_RAX(%rsp)
751 call *%rax
752 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
753error_exit:
754 movl %ebx,%eax
755 RESTORE_REST
756 cli
757 GET_THREAD_INFO(%rcx)
758 testl %eax,%eax
759 jne retint_kernel
760 movl threadinfo_flags(%rcx),%edx
761 movl $_TIF_WORK_MASK,%edi
762 andl %edi,%edx
763 jnz retint_careful
764 swapgs
765 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100766 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 CFI_ENDPROC
768
769error_kernelspace:
770 incl %ebx
771 /* There are two places in the kernel that can potentially fault with
772 usergs. Handle them here. The exception handlers after
773 iret run with kernel gs again, so don't set the user space flag.
774 B stepping K8s sometimes report an truncated RIP for IRET
775 exceptions returning to compat mode. Check for these here too. */
776 leaq iret_label(%rip),%rbp
777 cmpq %rbp,RIP(%rsp)
778 je error_swapgs
779 movl %ebp,%ebp /* zero extend */
780 cmpq %rbp,RIP(%rsp)
781 je error_swapgs
782 cmpq $gs_change,RIP(%rsp)
783 je error_swapgs
784 jmp error_sti
785
786 /* Reload gs selector with exception handling */
787 /* edi: new selector */
788ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200789 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200791 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 cli
793 swapgs
794gs_change:
795 movl %edi,%gs
7962: mfence /* workaround */
797 swapgs
798 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200799 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200801 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
803 .section __ex_table,"a"
804 .align 8
805 .quad gs_change,bad_gs
806 .previous
807 .section .fixup,"ax"
808 /* running with kernelgs */
809bad_gs:
810 swapgs /* switch back to user gs */
811 xorl %eax,%eax
812 movl %eax,%gs
813 jmp 2b
814 .previous
815
816/*
817 * Create a kernel thread.
818 *
819 * C extern interface:
820 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
821 *
822 * asm input arguments:
823 * rdi: fn, rsi: arg, rdx: flags
824 */
825ENTRY(kernel_thread)
826 CFI_STARTPROC
827 FAKE_STACK_FRAME $child_rip
828 SAVE_ALL
829
830 # rdi: flags, rsi: usp, rdx: will be &pt_regs
831 movq %rdx,%rdi
832 orq kernel_thread_flags(%rip),%rdi
833 movq $-1, %rsi
834 movq %rsp, %rdx
835
836 xorl %r8d,%r8d
837 xorl %r9d,%r9d
838
839 # clone now
840 call do_fork
841 movq %rax,RAX(%rsp)
842 xorl %edi,%edi
843
844 /*
845 * It isn't worth to check for reschedule here,
846 * so internally to the x86_64 port you can rely on kernel_thread()
847 * not to reschedule the child before returning, this avoids the need
848 * of hacks for example to fork off the per-CPU idle tasks.
849 * [Hopefully no generic code relies on the reschedule -AK]
850 */
851 RESTORE_ALL
852 UNFAKE_STACK_FRAME
853 ret
854 CFI_ENDPROC
855
856
857child_rip:
858 /*
859 * Here we are in the child and the registers are set as they were
860 * at kernel_thread() invocation in the parent.
861 */
862 movq %rdi, %rax
863 movq %rsi, %rdi
864 call *%rax
865 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700866 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 call do_exit
868
869/*
870 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
871 *
872 * C extern interface:
873 * extern long execve(char *name, char **argv, char **envp)
874 *
875 * asm input arguments:
876 * rdi: name, rsi: argv, rdx: envp
877 *
878 * We want to fallback into:
879 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
880 *
881 * do_sys_execve asm fallback arguments:
882 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
883 */
884ENTRY(execve)
885 CFI_STARTPROC
886 FAKE_STACK_FRAME $0
887 SAVE_ALL
888 call sys_execve
889 movq %rax, RAX(%rsp)
890 RESTORE_REST
891 testq %rax,%rax
892 je int_ret_from_sys_call
893 RESTORE_ARGS
894 UNFAKE_STACK_FRAME
895 ret
896 CFI_ENDPROC
897
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700898KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 errorentry do_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
904
905ENTRY(simd_coprocessor_error)
906 zeroentry do_simd_coprocessor_error
907
908ENTRY(device_not_available)
909 zeroentry math_state_restore
910
911 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700912KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +0200913 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 pushq $0
915 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100916 paranoidentry do_debug, DEBUG_STACK
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 jmp paranoid_exit
918 CFI_ENDPROC
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700919 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +0100922KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +0200923 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +0200925 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 paranoidentry do_nmi
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700927 /*
928 * "Paranoid" exit path from exception stack.
929 * Paranoid because this is used by NMIs and cannot take
930 * any kernel state for granted.
931 * We don't do kernel preemption checks here, because only
932 * NMI should be common and it does not enable IRQs and
933 * cannot get reschedule ticks.
934 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 /* ebx: no swapgs flag */
936paranoid_exit:
937 testl %ebx,%ebx /* swapgs needed? */
938 jnz paranoid_restore
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700939 testl $3,CS(%rsp)
940 jnz paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941paranoid_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 swapgs
943paranoid_restore:
944 RESTORE_ALL 8
945 iretq
946paranoid_userspace:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 GET_THREAD_INFO(%rcx)
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700948 movl threadinfo_flags(%rcx),%ebx
949 andl $_TIF_WORK_MASK,%ebx
Andi Kleen11b854b2005-04-16 15:25:02 -0700950 jz paranoid_swapgs
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700951 movq %rsp,%rdi /* &pt_regs */
952 call sync_regs
953 movq %rax,%rsp /* switch stack for scheduling */
954 testl $_TIF_NEED_RESCHED,%ebx
955 jnz paranoid_schedule
956 movl %ebx,%edx /* arg3: thread flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 sti
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700958 xorl %esi,%esi /* arg2: oldset */
959 movq %rsp,%rdi /* arg1: &pt_regs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 call do_notify_resume
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700961 cli
962 jmp paranoid_userspace
963paranoid_schedule:
Andi Kleen11b854b2005-04-16 15:25:02 -0700964 sti
965 call schedule
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700966 cli
967 jmp paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 CFI_ENDPROC
Andi Kleeneddb6fb2006-02-03 21:50:41 +0100969 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700970
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700971KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +0100972 INTR_FRAME
973 pushq $0
974 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100975 paranoidentry do_int3, DEBUG_STACK
Jan Beulichb556b352006-01-11 22:43:00 +0100976 jmp paranoid_exit
977 CFI_ENDPROC
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700978 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980ENTRY(overflow)
981 zeroentry do_overflow
982
983ENTRY(bounds)
984 zeroentry do_bounds
985
986ENTRY(invalid_op)
987 zeroentry do_invalid_op
988
989ENTRY(coprocessor_segment_overrun)
990 zeroentry do_coprocessor_segment_overrun
991
992ENTRY(reserved)
993 zeroentry do_reserved
994
995 /* runs on exception stack */
996ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +0200997 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 paranoidentry do_double_fault
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 jmp paranoid_exit
1000 CFI_ENDPROC
1001
1002ENTRY(invalid_TSS)
1003 errorentry do_invalid_TSS
1004
1005ENTRY(segment_not_present)
1006 errorentry do_segment_not_present
1007
1008 /* runs on exception stack */
1009ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001010 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 paranoidentry do_stack_segment
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 jmp paranoid_exit
1013 CFI_ENDPROC
1014
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001015KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 errorentry do_general_protection
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001017 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019ENTRY(alignment_check)
1020 errorentry do_alignment_check
1021
1022ENTRY(divide_error)
1023 zeroentry do_divide_error
1024
1025ENTRY(spurious_interrupt_bug)
1026 zeroentry do_spurious_interrupt_bug
1027
1028#ifdef CONFIG_X86_MCE
1029 /* runs on exception stack */
1030ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001031 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 pushq $0
1033 CFI_ADJUST_CFA_OFFSET 8
1034 paranoidentry do_machine_check
1035 jmp paranoid_exit
1036 CFI_ENDPROC
1037#endif
1038
Andi Kleened6b6762005-07-28 21:15:49 -07001039ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001040 CFI_STARTPROC
Andi Kleened6b6762005-07-28 21:15:49 -07001041 movq %gs:pda_irqstackptr,%rax
Jan Beulichbd9cb642006-01-11 22:43:21 +01001042 movq %rsp,%rdx
1043 CFI_DEF_CFA_REGISTER rdx
Andi Kleened6b6762005-07-28 21:15:49 -07001044 incl %gs:pda_irqcount
1045 cmove %rax,%rsp
Jan Beulichbd9cb642006-01-11 22:43:21 +01001046 pushq %rdx
1047 /*todo CFI_DEF_CFA_EXPRESSION ...*/
Andi Kleened6b6762005-07-28 21:15:49 -07001048 call __do_softirq
Jan Beulichbd9cb642006-01-11 22:43:21 +01001049 popq %rsp
Jan Beulich7effaa82005-09-12 18:49:24 +02001050 CFI_DEF_CFA_REGISTER rsp
Andi Kleened6b6762005-07-28 21:15:49 -07001051 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001052 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001053 CFI_ENDPROC