[PATCH] x86_64: reliable stack trace support
[deliverable/linux.git] / arch / x86_64 / kernel / entry.S
CommitLineData
1da177e4
LT
1/*
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>
e2d5df93 39#include <asm/asm-offsets.h>
1da177e4
LT
40#include <asm/msr.h>
41#include <asm/unistd.h>
42#include <asm/thread_info.h>
43#include <asm/hw_irq.h>
5f8efbb9 44#include <asm/page.h>
1da177e4
LT
45
46 .code64
47
dc37db4d 48#ifndef CONFIG_PREEMPT
1da177e4
LT
49#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 */
3829ee6b 80 xorl %eax, %eax
1da177e4
LT
81 pushq %rax /* ss */
82 CFI_ADJUST_CFA_OFFSET 8
7effaa88 83 /*CFI_REL_OFFSET ss,0*/
1da177e4
LT
84 pushq %rax /* rsp */
85 CFI_ADJUST_CFA_OFFSET 8
7effaa88 86 CFI_REL_OFFSET rsp,0
1da177e4
LT
87 pushq $(1<<9) /* eflags - interrupts on */
88 CFI_ADJUST_CFA_OFFSET 8
7effaa88 89 /*CFI_REL_OFFSET rflags,0*/
1da177e4
LT
90 pushq $__KERNEL_CS /* cs */
91 CFI_ADJUST_CFA_OFFSET 8
7effaa88 92 /*CFI_REL_OFFSET cs,0*/
1da177e4
LT
93 pushq \child_rip /* rip */
94 CFI_ADJUST_CFA_OFFSET 8
7effaa88 95 CFI_REL_OFFSET rip,0
1da177e4
LT
96 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
7effaa88
JB
105 .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*/
1da177e4
LT
132 .endm
133/*
134 * A newly forked process directly context switches into this.
135 */
136/* rdi: prev */
137ENTRY(ret_from_fork)
1da177e4
LT
138 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
4b787e0b 157END(ret_from_fork)
1da177e4
LT
158
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.
7bf36bbc
AK
184 *
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.
1da177e4
LT
188 */
189
190ENTRY(system_call)
7effaa88
JB
191 CFI_STARTPROC simple
192 CFI_DEF_CFA rsp,0
193 CFI_REGISTER rip,rcx
194 /*CFI_REGISTER rflags,r11*/
1da177e4
LT
195 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)
7effaa88
JB
201 movq %rcx,RIP-ARGOFFSET(%rsp)
202 CFI_REL_OFFSET rip,RIP-ARGOFFSET
1da177e4
LT
203 GET_THREAD_INFO(%rcx)
204 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
7effaa88 205 CFI_REMEMBER_STATE
1da177e4
LT
206 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:
11b854b2 218 movl $_TIF_ALLWORK_MASK,%edi
1da177e4
LT
219 /* edi: flagmask */
220sysret_check:
221 GET_THREAD_INFO(%rcx)
222 cli
223 movl threadinfo_flags(%rcx),%edx
224 andl %edi,%edx
7effaa88 225 CFI_REMEMBER_STATE
1da177e4
LT
226 jnz sysret_careful
227 movq RIP-ARGOFFSET(%rsp),%rcx
7effaa88 228 CFI_REGISTER rip,rcx
1da177e4 229 RESTORE_ARGS 0,-ARG_SKIP,1
7effaa88 230 /*CFI_REGISTER rflags,r11*/
1da177e4
LT
231 movq %gs:pda_oldrsp,%rsp
232 swapgs
233 sysretq
234
235 /* Handle reschedules */
236 /* edx: work, edi: workmask */
237sysret_careful:
7effaa88 238 CFI_RESTORE_STATE
1da177e4
LT
239 bt $TIF_NEED_RESCHED,%edx
240 jnc sysret_signal
241 sti
242 pushq %rdi
7effaa88 243 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
244 call schedule
245 popq %rdi
7effaa88 246 CFI_ADJUST_CFA_OFFSET -8
1da177e4
LT
247 jmp sysret_check
248
249 /* Handle a signal */
250sysret_signal:
251 sti
10ffdbb8
AK
252 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
253 jz 1f
254
255 /* Really a signal */
256 /* edx: work flags (arg3) */
1da177e4
LT
257 leaq do_notify_resume(%rip),%rax
258 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
259 xorl %esi,%esi # oldset -> arg2
260 call ptregscall_common
10ffdbb8 2611: movl $_TIF_NEED_RESCHED,%edi
7bf36bbc
AK
262 /* 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
1da177e4 266
7effaa88
JB
267badsys:
268 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
269 jmp ret_from_sys_call
270
1da177e4
LT
271 /* Do syscall tracing */
272tracesys:
7effaa88 273 CFI_RESTORE_STATE
1da177e4
LT
274 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)
822ff019 2851: movq %rax,RAX-ARGOFFSET(%rsp)
7bf36bbc
AK
286 /* Use IRET because user could have changed frame */
287 jmp int_ret_from_sys_call
7effaa88 288 CFI_ENDPROC
4b787e0b 289END(system_call)
1da177e4 290
1da177e4
LT
291/*
292 * Syscall return path ending with IRET.
293 * Has correct top of stack, but partial stack frame.
294 */
7effaa88
JB
295ENTRY(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
1da177e4
LT
312 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
bf2fcc6f 322 andl $~TS_COMPAT,threadinfo_status(%rcx)
1da177e4
LT
323 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
7effaa88 333 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
334 call schedule
335 popq %rdi
7effaa88 336 CFI_ADJUST_CFA_OFFSET -8
cdd219cd 337 cli
1da177e4
LT
338 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
7effaa88 348 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
349 leaq 8(%rsp),%rdi # &ptregs -> arg1
350 call syscall_trace_leave
351 popq %rdi
7effaa88 352 CFI_ADJUST_CFA_OFFSET -8
36c1104e 353 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
be9e6870 354 cli
1da177e4
LT
355 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
be9e6870 366 cli
1da177e4
LT
367 jmp int_with_check
368 CFI_ENDPROC
4b787e0b 369END(int_ret_from_sys_call)
1da177e4
LT
370
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
4b787e0b 381END(\label)
1da177e4
LT
382 .endm
383
7effaa88
JB
384 CFI_STARTPROC
385
1da177e4
LT
386 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)
1da177e4 394 popq %r11
7effaa88
JB
395 CFI_ADJUST_CFA_OFFSET -8
396 CFI_REGISTER rip, r11
1da177e4
LT
397 SAVE_REST
398 movq %r11, %r15
7effaa88 399 CFI_REGISTER rip, r15
1da177e4
LT
400 FIXUP_TOP_OF_STACK %r11
401 call *%rax
402 RESTORE_TOP_OF_STACK %r11
403 movq %r15, %r11
7effaa88 404 CFI_REGISTER rip, r11
1da177e4
LT
405 RESTORE_REST
406 pushq %r11
7effaa88
JB
407 CFI_ADJUST_CFA_OFFSET 8
408 CFI_REL_OFFSET rip, 0
1da177e4
LT
409 ret
410 CFI_ENDPROC
4b787e0b 411END(ptregscall_common)
1da177e4
LT
412
413ENTRY(stub_execve)
414 CFI_STARTPROC
415 popq %r11
7effaa88
JB
416 CFI_ADJUST_CFA_OFFSET -8
417 CFI_REGISTER rip, r11
1da177e4 418 SAVE_REST
1da177e4
LT
419 FIXUP_TOP_OF_STACK %r11
420 call sys_execve
1da177e4 421 RESTORE_TOP_OF_STACK %r11
1da177e4
LT
422 movq %rax,RAX(%rsp)
423 RESTORE_REST
424 jmp int_ret_from_sys_call
425 CFI_ENDPROC
4b787e0b 426END(stub_execve)
1da177e4
LT
427
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
7effaa88
JB
434 addq $8, %rsp
435 CFI_ADJUST_CFA_OFFSET -8
1da177e4
LT
436 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
4b787e0b 444END(stub_rt_sigreturn)
1da177e4 445
7effaa88
JB
446/*
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
1da177e4
LT
465/*
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
1da177e4
LT
475 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
3829ee6b 4921: incl %gs:pda_irqcount # RED-PEN should check preempt count
1da177e4 493 movq %gs:pda_irqstackptr,%rax
7effaa88 494 cmoveq %rax,%rsp /*todo This needs CFI annotation! */
1da177e4 495 pushq %rdi # save old stack
91522a96 496#ifndef CONFIG_DEBUG_INFO
7effaa88 497 CFI_ADJUST_CFA_OFFSET 8
91522a96 498#endif
1da177e4
LT
499 call \func
500 .endm
501
502ENTRY(common_interrupt)
7effaa88 503 XCPT_FRAME
1da177e4
LT
504 interrupt do_IRQ
505 /* 0(%rsp): oldrsp-ARGOFFSET */
7effaa88 506ret_from_intr:
1da177e4 507 popq %rdi
91522a96 508#ifndef CONFIG_DEBUG_INFO
7effaa88 509 CFI_ADJUST_CFA_OFFSET -8
91522a96 510#endif
1da177e4 511 cli
3829ee6b 512 decl %gs:pda_irqcount
1da177e4
LT
513#ifdef CONFIG_DEBUG_INFO
514 movq RBP(%rdi),%rbp
7effaa88 515 CFI_DEF_CFA_REGISTER rsp
1da177e4 516#endif
7effaa88
JB
517 leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */
518exit_intr:
1da177e4
LT
519 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
7effaa88 530retint_check:
1da177e4
LT
531 movl threadinfo_flags(%rcx),%edx
532 andl %edi,%edx
7effaa88 533 CFI_REMEMBER_STATE
1da177e4
LT
534 jnz retint_careful
535retint_swapgs:
1da177e4
LT
536 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:
3076a492 550 movq $11,%rdi /* SIGSEGV */
2391c4b5 551 sti
1da177e4
LT
552 jmp do_exit
553 .previous
554
7effaa88 555 /* edi: workmask, edx: work */
1da177e4 556retint_careful:
7effaa88 557 CFI_RESTORE_STATE
1da177e4
LT
558 bt $TIF_NEED_RESCHED,%edx
559 jnc retint_signal
560 sti
561 pushq %rdi
7effaa88 562 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
563 call schedule
564 popq %rdi
7effaa88 565 CFI_ADJUST_CFA_OFFSET -8
1da177e4
LT
566 GET_THREAD_INFO(%rcx)
567 cli
568 jmp retint_check
569
570retint_signal:
10ffdbb8
AK
571 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
572 jz retint_swapgs
1da177e4
LT
573 sti
574 SAVE_REST
575 movq $-1,ORIG_RAX(%rsp)
3829ee6b 576 xorl %esi,%esi # oldset
1da177e4
LT
577 movq %rsp,%rdi # &pt_regs
578 call do_notify_resume
579 RESTORE_REST
580 cli
10ffdbb8 581 movl $_TIF_NEED_RESCHED,%edi
be9e6870 582 GET_THREAD_INFO(%rcx)
1da177e4
LT
583 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
4b787e0b 599
1da177e4 600 CFI_ENDPROC
4b787e0b 601END(common_interrupt)
1da177e4
LT
602
603/*
604 * APIC interrupts.
605 */
606 .macro apicinterrupt num,func
7effaa88 607 INTR_FRAME
1da177e4 608 pushq $\num-256
7effaa88 609 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
610 interrupt \func
611 jmp ret_from_intr
612 CFI_ENDPROC
613 .endm
614
615ENTRY(thermal_interrupt)
616 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
4b787e0b 617END(thermal_interrupt)
1da177e4 618
89b831ef
JS
619ENTRY(threshold_interrupt)
620 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
4b787e0b 621END(threshold_interrupt)
89b831ef 622
1da177e4
LT
623#ifdef CONFIG_SMP
624ENTRY(reschedule_interrupt)
625 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
4b787e0b 626END(reschedule_interrupt)
1da177e4 627
e5bc8b6b
AK
628 .macro INVALIDATE_ENTRY num
629ENTRY(invalidate_interrupt\num)
630 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
4b787e0b 631END(invalidate_interrupt\num)
e5bc8b6b
AK
632 .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
1da177e4
LT
642
643ENTRY(call_function_interrupt)
644 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
4b787e0b 645END(call_function_interrupt)
1da177e4
LT
646#endif
647
648#ifdef CONFIG_X86_LOCAL_APIC
649ENTRY(apic_timer_interrupt)
650 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
4b787e0b 651END(apic_timer_interrupt)
1da177e4
LT
652
653ENTRY(error_interrupt)
654 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
4b787e0b 655END(error_interrupt)
1da177e4
LT
656
657ENTRY(spurious_interrupt)
658 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
4b787e0b 659END(spurious_interrupt)
1da177e4
LT
660#endif
661
662/*
663 * Exception entry points.
664 */
665 .macro zeroentry sym
7effaa88 666 INTR_FRAME
1da177e4 667 pushq $0 /* push error code/oldrax */
7effaa88 668 CFI_ADJUST_CFA_OFFSET 8
1da177e4 669 pushq %rax /* push real oldrax to the rdi slot */
7effaa88 670 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
671 leaq \sym(%rip),%rax
672 jmp error_entry
7effaa88 673 CFI_ENDPROC
1da177e4
LT
674 .endm
675
676 .macro errorentry sym
7effaa88 677 XCPT_FRAME
1da177e4 678 pushq %rax
7effaa88 679 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
680 leaq \sym(%rip),%rax
681 jmp error_entry
7effaa88 682 CFI_ENDPROC
1da177e4
LT
683 .endm
684
685 /* error code is on the stack already */
686 /* handle NMI like exceptions that can happen everywhere */
b556b35e 687 .macro paranoidentry sym, ist=0
1da177e4
LT
688 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
b556b35e
JB
6971:
698 .if \ist
699 movq %gs:pda_data_offset, %rbp
700 .endif
701 movq %rsp,%rdi
1da177e4
LT
702 movq ORIG_RAX(%rsp),%rsi
703 movq $-1,ORIG_RAX(%rsp)
b556b35e 704 .if \ist
5f8efbb9 705 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
b556b35e 706 .endif
1da177e4 707 call \sym
b556b35e 708 .if \ist
5f8efbb9 709 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
b556b35e 710 .endif
6fefb0d1 711 cli
1da177e4
LT
712 .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)
7effaa88 719 _frame RDI
1da177e4
LT
720 /* 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
505cc4e1 778 jmp iret_label
1da177e4
LT
779 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
4b787e0b 797END(error_entry)
1da177e4
LT
798
799 /* Reload gs selector with exception handling */
800 /* edi: new selector */
801ENTRY(load_gs_index)
7effaa88 802 CFI_STARTPROC
1da177e4 803 pushf
7effaa88 804 CFI_ADJUST_CFA_OFFSET 8
1da177e4
LT
805 cli
806 swapgs
807gs_change:
808 movl %edi,%gs
8092: mfence /* workaround */
810 swapgs
811 popf
7effaa88 812 CFI_ADJUST_CFA_OFFSET -8
1da177e4 813 ret
7effaa88 814 CFI_ENDPROC
4b787e0b 815ENDPROC(load_gs_index)
1da177e4
LT
816
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
4b787e0b 869ENDPROC(kernel_thread)
1da177e4
LT
870
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
3829ee6b 880 xorl %edi, %edi
1da177e4 881 call do_exit
4b787e0b 882ENDPROC(child_rip)
1da177e4
LT
883
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
4b787e0b 912ENDPROC(execve)
1da177e4 913
0f2fbdcb 914KPROBE_ENTRY(page_fault)
1da177e4 915 errorentry do_page_fault
4b787e0b 916END(page_fault)
0f2fbdcb 917 .previous .text
1da177e4
LT
918
919ENTRY(coprocessor_error)
920 zeroentry do_coprocessor_error
4b787e0b 921END(coprocessor_error)
1da177e4
LT
922
923ENTRY(simd_coprocessor_error)
924 zeroentry do_simd_coprocessor_error
4b787e0b 925END(simd_coprocessor_error)
1da177e4
LT
926
927ENTRY(device_not_available)
928 zeroentry math_state_restore
4b787e0b 929END(device_not_available)
1da177e4
LT
930
931 /* runs on exception stack */
0f2fbdcb 932KPROBE_ENTRY(debug)
7effaa88 933 INTR_FRAME
1da177e4
LT
934 pushq $0
935 CFI_ADJUST_CFA_OFFSET 8
5f8efbb9 936 paranoidentry do_debug, DEBUG_STACK
1da177e4
LT
937 jmp paranoid_exit
938 CFI_ENDPROC
4b787e0b 939END(debug)
0f2fbdcb 940 .previous .text
1da177e4
LT
941
942 /* runs on exception stack */
eddb6fb9 943KPROBE_ENTRY(nmi)
7effaa88 944 INTR_FRAME
1da177e4 945 pushq $-1
7effaa88 946 CFI_ADJUST_CFA_OFFSET 8
1da177e4 947 paranoidentry do_nmi
6fefb0d1
AK
948 /*
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 */
1da177e4
LT
956 /* ebx: no swapgs flag */
957paranoid_exit:
958 testl %ebx,%ebx /* swapgs needed? */
959 jnz paranoid_restore
6fefb0d1
AK
960 testl $3,CS(%rsp)
961 jnz paranoid_userspace
1da177e4 962paranoid_swapgs:
1da177e4
LT
963 swapgs
964paranoid_restore:
965 RESTORE_ALL 8
966 iretq
967paranoid_userspace:
1da177e4 968 GET_THREAD_INFO(%rcx)
6fefb0d1
AK
969 movl threadinfo_flags(%rcx),%ebx
970 andl $_TIF_WORK_MASK,%ebx
11b854b2 971 jz paranoid_swapgs
6fefb0d1
AK
972 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 */
1da177e4 978 sti
6fefb0d1
AK
979 xorl %esi,%esi /* arg2: oldset */
980 movq %rsp,%rdi /* arg1: &pt_regs */
1da177e4 981 call do_notify_resume
6fefb0d1
AK
982 cli
983 jmp paranoid_userspace
984paranoid_schedule:
11b854b2
AK
985 sti
986 call schedule
6fefb0d1
AK
987 cli
988 jmp paranoid_userspace
1da177e4 989 CFI_ENDPROC
4b787e0b 990END(nmi)
eddb6fb9 991 .previous .text
6fefb0d1 992
0f2fbdcb 993KPROBE_ENTRY(int3)
b556b35e
JB
994 INTR_FRAME
995 pushq $0
996 CFI_ADJUST_CFA_OFFSET 8
5f8efbb9 997 paranoidentry do_int3, DEBUG_STACK
b556b35e
JB
998 jmp paranoid_exit
999 CFI_ENDPROC
4b787e0b 1000END(int3)
0f2fbdcb 1001 .previous .text
1da177e4
LT
1002
1003ENTRY(overflow)
1004 zeroentry do_overflow
4b787e0b 1005END(overflow)
1da177e4
LT
1006
1007ENTRY(bounds)
1008 zeroentry do_bounds
4b787e0b 1009END(bounds)
1da177e4
LT
1010
1011ENTRY(invalid_op)
1012 zeroentry do_invalid_op
4b787e0b 1013END(invalid_op)
1da177e4
LT
1014
1015ENTRY(coprocessor_segment_overrun)
1016 zeroentry do_coprocessor_segment_overrun
4b787e0b 1017END(coprocessor_segment_overrun)
1da177e4
LT
1018
1019ENTRY(reserved)
1020 zeroentry do_reserved
4b787e0b 1021END(reserved)
1da177e4
LT
1022
1023 /* runs on exception stack */
1024ENTRY(double_fault)
7effaa88 1025 XCPT_FRAME
1da177e4 1026 paranoidentry do_double_fault
1da177e4
LT
1027 jmp paranoid_exit
1028 CFI_ENDPROC
4b787e0b 1029END(double_fault)
1da177e4
LT
1030
1031ENTRY(invalid_TSS)
1032 errorentry do_invalid_TSS
4b787e0b 1033END(invalid_TSS)
1da177e4
LT
1034
1035ENTRY(segment_not_present)
1036 errorentry do_segment_not_present
4b787e0b 1037END(segment_not_present)
1da177e4
LT
1038
1039 /* runs on exception stack */
1040ENTRY(stack_segment)
7effaa88 1041 XCPT_FRAME
1da177e4 1042 paranoidentry do_stack_segment
1da177e4
LT
1043 jmp paranoid_exit
1044 CFI_ENDPROC
4b787e0b 1045END(stack_segment)
1da177e4 1046
0f2fbdcb 1047KPROBE_ENTRY(general_protection)
1da177e4 1048 errorentry do_general_protection
4b787e0b 1049END(general_protection)
0f2fbdcb 1050 .previous .text
1da177e4
LT
1051
1052ENTRY(alignment_check)
1053 errorentry do_alignment_check
4b787e0b 1054END(alignment_check)
1da177e4
LT
1055
1056ENTRY(divide_error)
1057 zeroentry do_divide_error
4b787e0b 1058END(divide_error)
1da177e4
LT
1059
1060ENTRY(spurious_interrupt_bug)
1061 zeroentry do_spurious_interrupt_bug
4b787e0b 1062END(spurious_interrupt_bug)
1da177e4
LT
1063
1064#ifdef CONFIG_X86_MCE
1065 /* runs on exception stack */
1066ENTRY(machine_check)
7effaa88 1067 INTR_FRAME
1da177e4
LT
1068 pushq $0
1069 CFI_ADJUST_CFA_OFFSET 8
1070 paranoidentry do_machine_check
1071 jmp paranoid_exit
1072 CFI_ENDPROC
4b787e0b 1073END(machine_check)
1da177e4
LT
1074#endif
1075
ed6b676c 1076ENTRY(call_softirq)
7effaa88 1077 CFI_STARTPROC
ed6b676c 1078 movq %gs:pda_irqstackptr,%rax
bd9cb64d
JB
1079 movq %rsp,%rdx
1080 CFI_DEF_CFA_REGISTER rdx
ed6b676c
AK
1081 incl %gs:pda_irqcount
1082 cmove %rax,%rsp
bd9cb64d
JB
1083 pushq %rdx
1084 /*todo CFI_DEF_CFA_EXPRESSION ...*/
ed6b676c 1085 call __do_softirq
bd9cb64d 1086 popq %rsp
7effaa88 1087 CFI_DEF_CFA_REGISTER rsp
ed6b676c 1088 decl %gs:pda_irqcount
ed6b676c 1089 ret
7effaa88 1090 CFI_ENDPROC
4b787e0b 1091ENDPROC(call_softirq)
This page took 0.20054 seconds and 5 git commands to generate.