blob: be51dbe1f75ec1a91765e8a4735a052ae144c6e1 [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>
39#include <asm/offset.h>
40#include <asm/msr.h>
41#include <asm/unistd.h>
42#include <asm/thread_info.h>
43#include <asm/hw_irq.h>
44
45 .code64
46
Andi Kleendc37db42005-04-16 15:25:05 -070047#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#define retint_kernel retint_restore_args
49#endif
50
51/*
52 * C code is not supposed to know about undefined top of stack. Every time
53 * a C function with an pt_regs argument is called from the SYSCALL based
54 * fast path FIXUP_TOP_OF_STACK is needed.
55 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
56 * manipulation.
57 */
58
59 /* %rsp:at FRAMEEND */
60 .macro FIXUP_TOP_OF_STACK tmp
61 movq %gs:pda_oldrsp,\tmp
62 movq \tmp,RSP(%rsp)
63 movq $__USER_DS,SS(%rsp)
64 movq $__USER_CS,CS(%rsp)
65 movq $-1,RCX(%rsp)
66 movq R11(%rsp),\tmp /* get eflags */
67 movq \tmp,EFLAGS(%rsp)
68 .endm
69
70 .macro RESTORE_TOP_OF_STACK tmp,offset=0
71 movq RSP-\offset(%rsp),\tmp
72 movq \tmp,%gs:pda_oldrsp
73 movq EFLAGS-\offset(%rsp),\tmp
74 movq \tmp,R11-\offset(%rsp)
75 .endm
76
77 .macro FAKE_STACK_FRAME child_rip
78 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -070079 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 pushq %rax /* ss */
81 CFI_ADJUST_CFA_OFFSET 8
82 pushq %rax /* rsp */
83 CFI_ADJUST_CFA_OFFSET 8
84 CFI_OFFSET rip,0
85 pushq $(1<<9) /* eflags - interrupts on */
86 CFI_ADJUST_CFA_OFFSET 8
87 pushq $__KERNEL_CS /* cs */
88 CFI_ADJUST_CFA_OFFSET 8
89 pushq \child_rip /* rip */
90 CFI_ADJUST_CFA_OFFSET 8
91 CFI_OFFSET rip,0
92 pushq %rax /* orig rax */
93 CFI_ADJUST_CFA_OFFSET 8
94 .endm
95
96 .macro UNFAKE_STACK_FRAME
97 addq $8*6, %rsp
98 CFI_ADJUST_CFA_OFFSET -(6*8)
99 .endm
100
101 .macro CFI_DEFAULT_STACK
102 CFI_ADJUST_CFA_OFFSET (SS)
103 CFI_OFFSET r15,R15-SS
104 CFI_OFFSET r14,R14-SS
105 CFI_OFFSET r13,R13-SS
106 CFI_OFFSET r12,R12-SS
107 CFI_OFFSET rbp,RBP-SS
108 CFI_OFFSET rbx,RBX-SS
109 CFI_OFFSET r11,R11-SS
110 CFI_OFFSET r10,R10-SS
111 CFI_OFFSET r9,R9-SS
112 CFI_OFFSET r8,R8-SS
113 CFI_OFFSET rax,RAX-SS
114 CFI_OFFSET rcx,RCX-SS
115 CFI_OFFSET rdx,RDX-SS
116 CFI_OFFSET rsi,RSI-SS
117 CFI_OFFSET rdi,RDI-SS
118 CFI_OFFSET rsp,RSP-SS
119 CFI_OFFSET rip,RIP-SS
120 .endm
121/*
122 * A newly forked process directly context switches into this.
123 */
124/* rdi: prev */
125ENTRY(ret_from_fork)
126 CFI_STARTPROC
127 CFI_DEFAULT_STACK
128 call schedule_tail
129 GET_THREAD_INFO(%rcx)
130 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
131 jnz rff_trace
132rff_action:
133 RESTORE_REST
134 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
135 je int_ret_from_sys_call
136 testl $_TIF_IA32,threadinfo_flags(%rcx)
137 jnz int_ret_from_sys_call
138 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
139 jmp ret_from_sys_call
140rff_trace:
141 movq %rsp,%rdi
142 call syscall_trace_leave
143 GET_THREAD_INFO(%rcx)
144 jmp rff_action
145 CFI_ENDPROC
146
147/*
148 * System call entry. Upto 6 arguments in registers are supported.
149 *
150 * SYSCALL does not save anything on the stack and does not change the
151 * stack pointer.
152 */
153
154/*
155 * Register setup:
156 * rax system call number
157 * rdi arg0
158 * rcx return address for syscall/sysret, C arg3
159 * rsi arg1
160 * rdx arg2
161 * r10 arg3 (--> moved to rcx for C)
162 * r8 arg4
163 * r9 arg5
164 * r11 eflags for syscall/sysret, temporary for C
165 * r12-r15,rbp,rbx saved by C code, not touched.
166 *
167 * Interrupts are off on entry.
168 * Only called from user space.
169 *
170 * XXX if we had a free scratch register we could save the RSP into the stack frame
171 * and report it properly in ps. Unfortunately we haven't.
172 */
173
174ENTRY(system_call)
175 CFI_STARTPROC
176 swapgs
177 movq %rsp,%gs:pda_oldrsp
178 movq %gs:pda_kernelstack,%rsp
179 sti
180 SAVE_ARGS 8,1
181 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
182 movq %rcx,RIP-ARGOFFSET(%rsp)
183 GET_THREAD_INFO(%rcx)
184 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
185 jnz tracesys
186 cmpq $__NR_syscall_max,%rax
187 ja badsys
188 movq %r10,%rcx
189 call *sys_call_table(,%rax,8) # XXX: rip relative
190 movq %rax,RAX-ARGOFFSET(%rsp)
191/*
192 * Syscall return path ending with SYSRET (fast path)
193 * Has incomplete stack frame and undefined top of stack.
194 */
195 .globl ret_from_sys_call
196ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700197 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 /* edi: flagmask */
199sysret_check:
200 GET_THREAD_INFO(%rcx)
201 cli
202 movl threadinfo_flags(%rcx),%edx
203 andl %edi,%edx
204 jnz sysret_careful
205 movq RIP-ARGOFFSET(%rsp),%rcx
206 RESTORE_ARGS 0,-ARG_SKIP,1
207 movq %gs:pda_oldrsp,%rsp
208 swapgs
209 sysretq
210
211 /* Handle reschedules */
212 /* edx: work, edi: workmask */
213sysret_careful:
214 bt $TIF_NEED_RESCHED,%edx
215 jnc sysret_signal
216 sti
217 pushq %rdi
218 call schedule
219 popq %rdi
220 jmp sysret_check
221
222 /* Handle a signal */
223sysret_signal:
224 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700225 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
226 jz 1f
227
228 /* Really a signal */
229 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 leaq do_notify_resume(%rip),%rax
231 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
232 xorl %esi,%esi # oldset -> arg2
233 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002341: movl $_TIF_NEED_RESCHED,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 jmp sysret_check
236
237 /* Do syscall tracing */
238tracesys:
239 SAVE_REST
240 movq $-ENOSYS,RAX(%rsp)
241 FIXUP_TOP_OF_STACK %rdi
242 movq %rsp,%rdi
243 call syscall_trace_enter
244 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
245 RESTORE_REST
246 cmpq $__NR_syscall_max,%rax
247 ja 1f
248 movq %r10,%rcx /* fixup for C */
249 call *sys_call_table(,%rax,8)
250 movq %rax,RAX-ARGOFFSET(%rsp)
2511: SAVE_REST
252 movq %rsp,%rdi
253 call syscall_trace_leave
254 RESTORE_TOP_OF_STACK %rbx
255 RESTORE_REST
256 jmp ret_from_sys_call
257
258badsys:
259 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
260 jmp ret_from_sys_call
261
262/*
263 * Syscall return path ending with IRET.
264 * Has correct top of stack, but partial stack frame.
265 */
266ENTRY(int_ret_from_sys_call)
267 cli
268 testl $3,CS-ARGOFFSET(%rsp)
269 je retint_restore_args
270 movl $_TIF_ALLWORK_MASK,%edi
271 /* edi: mask to check */
272int_with_check:
273 GET_THREAD_INFO(%rcx)
274 movl threadinfo_flags(%rcx),%edx
275 andl %edi,%edx
276 jnz int_careful
277 jmp retint_swapgs
278
279 /* Either reschedule or signal or syscall exit tracking needed. */
280 /* First do a reschedule test. */
281 /* edx: work, edi: workmask */
282int_careful:
283 bt $TIF_NEED_RESCHED,%edx
284 jnc int_very_careful
285 sti
286 pushq %rdi
287 call schedule
288 popq %rdi
Andi Kleencdd219c2005-04-16 15:25:04 -0700289 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 jmp int_with_check
291
292 /* handle signals and tracing -- both require a full stack frame */
293int_very_careful:
294 sti
295 SAVE_REST
296 /* Check for syscall exit trace */
297 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
298 jz int_signal
299 pushq %rdi
300 leaq 8(%rsp),%rdi # &ptregs -> arg1
301 call syscall_trace_leave
302 popq %rdi
Andi Kleen36c11042005-04-16 15:25:01 -0700303 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700304 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 jmp int_restore_rest
306
307int_signal:
308 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
309 jz 1f
310 movq %rsp,%rdi # &ptregs -> arg1
311 xorl %esi,%esi # oldset -> arg2
312 call do_notify_resume
3131: movl $_TIF_NEED_RESCHED,%edi
314int_restore_rest:
315 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700316 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 jmp int_with_check
318 CFI_ENDPROC
319
320/*
321 * Certain special system calls that need to save a complete full stack frame.
322 */
323
324 .macro PTREGSCALL label,func,arg
325 .globl \label
326\label:
327 leaq \func(%rip),%rax
328 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
329 jmp ptregscall_common
330 .endm
331
332 PTREGSCALL stub_clone, sys_clone, %r8
333 PTREGSCALL stub_fork, sys_fork, %rdi
334 PTREGSCALL stub_vfork, sys_vfork, %rdi
335 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
336 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
337 PTREGSCALL stub_iopl, sys_iopl, %rsi
338
339ENTRY(ptregscall_common)
340 CFI_STARTPROC
341 popq %r11
342 CFI_ADJUST_CFA_OFFSET -8
343 SAVE_REST
344 movq %r11, %r15
345 FIXUP_TOP_OF_STACK %r11
346 call *%rax
347 RESTORE_TOP_OF_STACK %r11
348 movq %r15, %r11
349 RESTORE_REST
350 pushq %r11
351 CFI_ADJUST_CFA_OFFSET 8
352 ret
353 CFI_ENDPROC
354
355ENTRY(stub_execve)
356 CFI_STARTPROC
357 popq %r11
358 CFI_ADJUST_CFA_OFFSET -8
359 SAVE_REST
360 movq %r11, %r15
361 FIXUP_TOP_OF_STACK %r11
362 call sys_execve
363 GET_THREAD_INFO(%rcx)
364 bt $TIF_IA32,threadinfo_flags(%rcx)
365 jc exec_32bit
366 RESTORE_TOP_OF_STACK %r11
367 movq %r15, %r11
368 RESTORE_REST
369 push %r11
370 ret
371
372exec_32bit:
373 CFI_ADJUST_CFA_OFFSET REST_SKIP
374 movq %rax,RAX(%rsp)
375 RESTORE_REST
376 jmp int_ret_from_sys_call
377 CFI_ENDPROC
378
379/*
380 * sigreturn is special because it needs to restore all registers on return.
381 * This cannot be done with SYSRET, so use the IRET return path instead.
382 */
383ENTRY(stub_rt_sigreturn)
384 CFI_STARTPROC
385 addq $8, %rsp
386 SAVE_REST
387 movq %rsp,%rdi
388 FIXUP_TOP_OF_STACK %r11
389 call sys_rt_sigreturn
390 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
391 RESTORE_REST
392 jmp int_ret_from_sys_call
393 CFI_ENDPROC
394
395/*
396 * Interrupt entry/exit.
397 *
398 * Interrupt entry points save only callee clobbered registers in fast path.
399 *
400 * Entry runs with interrupts off.
401 */
402
403/* 0(%rsp): interrupt number */
404 .macro interrupt func
405 CFI_STARTPROC simple
406 CFI_DEF_CFA rsp,(SS-RDI)
407 CFI_REL_OFFSET rsp,(RSP-ORIG_RAX)
408 CFI_REL_OFFSET rip,(RIP-ORIG_RAX)
409 cld
410#ifdef CONFIG_DEBUG_INFO
411 SAVE_ALL
412 movq %rsp,%rdi
413 /*
414 * Setup a stack frame pointer. This allows gdb to trace
415 * back to the original stack.
416 */
417 movq %rsp,%rbp
418 CFI_DEF_CFA_REGISTER rbp
419#else
420 SAVE_ARGS
421 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
422#endif
423 testl $3,CS(%rdi)
424 je 1f
425 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07004261: incl %gs:pda_irqcount # RED-PEN should check preempt count
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 movq %gs:pda_irqstackptr,%rax
428 cmoveq %rax,%rsp
429 pushq %rdi # save old stack
430 call \func
431 .endm
432
433ENTRY(common_interrupt)
434 interrupt do_IRQ
435 /* 0(%rsp): oldrsp-ARGOFFSET */
436ret_from_intr:
437 popq %rdi
438 cli
Andi Kleen3829ee62005-07-28 21:15:48 -0700439 decl %gs:pda_irqcount
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440#ifdef CONFIG_DEBUG_INFO
441 movq RBP(%rdi),%rbp
442#endif
443 leaq ARGOFFSET(%rdi),%rsp
444exit_intr:
445 GET_THREAD_INFO(%rcx)
446 testl $3,CS-ARGOFFSET(%rsp)
447 je retint_kernel
448
449 /* Interrupt came from user space */
450 /*
451 * Has a correct top of stack, but a partial stack frame
452 * %rcx: thread info. Interrupts off.
453 */
454retint_with_reschedule:
455 movl $_TIF_WORK_MASK,%edi
456retint_check:
457 movl threadinfo_flags(%rcx),%edx
458 andl %edi,%edx
459 jnz retint_careful
460retint_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 swapgs
462retint_restore_args:
463 cli
464 RESTORE_ARGS 0,8,0
465iret_label:
466 iretq
467
468 .section __ex_table,"a"
469 .quad iret_label,bad_iret
470 .previous
471 .section .fixup,"ax"
472 /* force a signal here? this matches i386 behaviour */
473 /* running with kernel gs */
474bad_iret:
475 movq $-9999,%rdi /* better code? */
476 jmp do_exit
477 .previous
478
479 /* edi: workmask, edx: work */
480retint_careful:
481 bt $TIF_NEED_RESCHED,%edx
482 jnc retint_signal
483 sti
484 pushq %rdi
485 call schedule
486 popq %rdi
487 GET_THREAD_INFO(%rcx)
488 cli
489 jmp retint_check
490
491retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700492 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
493 jz retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 sti
495 SAVE_REST
496 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700497 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 movq %rsp,%rdi # &pt_regs
499 call do_notify_resume
500 RESTORE_REST
501 cli
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700502 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700503 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 jmp retint_check
505
506#ifdef CONFIG_PREEMPT
507 /* Returning to kernel space. Check if we need preemption */
508 /* rcx: threadinfo. interrupts off. */
509 .p2align
510retint_kernel:
511 cmpl $0,threadinfo_preempt_count(%rcx)
512 jnz retint_restore_args
513 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
514 jnc retint_restore_args
515 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
516 jnc retint_restore_args
517 call preempt_schedule_irq
518 jmp exit_intr
519#endif
520 CFI_ENDPROC
521
522/*
523 * APIC interrupts.
524 */
525 .macro apicinterrupt num,func
526 pushq $\num-256
527 interrupt \func
528 jmp ret_from_intr
529 CFI_ENDPROC
530 .endm
531
532ENTRY(thermal_interrupt)
533 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
534
535#ifdef CONFIG_SMP
536ENTRY(reschedule_interrupt)
537 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
538
539ENTRY(invalidate_interrupt)
540 apicinterrupt INVALIDATE_TLB_VECTOR,smp_invalidate_interrupt
541
542ENTRY(call_function_interrupt)
543 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
544#endif
545
546#ifdef CONFIG_X86_LOCAL_APIC
547ENTRY(apic_timer_interrupt)
548 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
549
550ENTRY(error_interrupt)
551 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
552
553ENTRY(spurious_interrupt)
554 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
555#endif
556
557/*
558 * Exception entry points.
559 */
560 .macro zeroentry sym
561 pushq $0 /* push error code/oldrax */
562 pushq %rax /* push real oldrax to the rdi slot */
563 leaq \sym(%rip),%rax
564 jmp error_entry
565 .endm
566
567 .macro errorentry sym
568 pushq %rax
569 leaq \sym(%rip),%rax
570 jmp error_entry
571 .endm
572
573 /* error code is on the stack already */
574 /* handle NMI like exceptions that can happen everywhere */
575 .macro paranoidentry sym
576 SAVE_ALL
577 cld
578 movl $1,%ebx
579 movl $MSR_GS_BASE,%ecx
580 rdmsr
581 testl %edx,%edx
582 js 1f
583 swapgs
584 xorl %ebx,%ebx
5851: movq %rsp,%rdi
586 movq ORIG_RAX(%rsp),%rsi
587 movq $-1,ORIG_RAX(%rsp)
588 call \sym
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700589 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 .endm
591
592/*
593 * Exception entry point. This expects an error code/orig_rax on the stack
594 * and the exception handler in %rax.
595 */
596ENTRY(error_entry)
597 CFI_STARTPROC simple
598 CFI_DEF_CFA rsp,(SS-RDI)
599 CFI_REL_OFFSET rsp,(RSP-RDI)
600 CFI_REL_OFFSET rip,(RIP-RDI)
601 /* rdi slot contains rax, oldrax contains error code */
602 cld
603 subq $14*8,%rsp
604 CFI_ADJUST_CFA_OFFSET (14*8)
605 movq %rsi,13*8(%rsp)
606 CFI_REL_OFFSET rsi,RSI
607 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
608 movq %rdx,12*8(%rsp)
609 CFI_REL_OFFSET rdx,RDX
610 movq %rcx,11*8(%rsp)
611 CFI_REL_OFFSET rcx,RCX
612 movq %rsi,10*8(%rsp) /* store rax */
613 CFI_REL_OFFSET rax,RAX
614 movq %r8, 9*8(%rsp)
615 CFI_REL_OFFSET r8,R8
616 movq %r9, 8*8(%rsp)
617 CFI_REL_OFFSET r9,R9
618 movq %r10,7*8(%rsp)
619 CFI_REL_OFFSET r10,R10
620 movq %r11,6*8(%rsp)
621 CFI_REL_OFFSET r11,R11
622 movq %rbx,5*8(%rsp)
623 CFI_REL_OFFSET rbx,RBX
624 movq %rbp,4*8(%rsp)
625 CFI_REL_OFFSET rbp,RBP
626 movq %r12,3*8(%rsp)
627 CFI_REL_OFFSET r12,R12
628 movq %r13,2*8(%rsp)
629 CFI_REL_OFFSET r13,R13
630 movq %r14,1*8(%rsp)
631 CFI_REL_OFFSET r14,R14
632 movq %r15,(%rsp)
633 CFI_REL_OFFSET r15,R15
634 xorl %ebx,%ebx
635 testl $3,CS(%rsp)
636 je error_kernelspace
637error_swapgs:
638 swapgs
639error_sti:
640 movq %rdi,RDI(%rsp)
641 movq %rsp,%rdi
642 movq ORIG_RAX(%rsp),%rsi /* get error code */
643 movq $-1,ORIG_RAX(%rsp)
644 call *%rax
645 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
646error_exit:
647 movl %ebx,%eax
648 RESTORE_REST
649 cli
650 GET_THREAD_INFO(%rcx)
651 testl %eax,%eax
652 jne retint_kernel
653 movl threadinfo_flags(%rcx),%edx
654 movl $_TIF_WORK_MASK,%edi
655 andl %edi,%edx
656 jnz retint_careful
657 swapgs
658 RESTORE_ARGS 0,8,0
659 iretq
660 CFI_ENDPROC
661
662error_kernelspace:
663 incl %ebx
664 /* There are two places in the kernel that can potentially fault with
665 usergs. Handle them here. The exception handlers after
666 iret run with kernel gs again, so don't set the user space flag.
667 B stepping K8s sometimes report an truncated RIP for IRET
668 exceptions returning to compat mode. Check for these here too. */
669 leaq iret_label(%rip),%rbp
670 cmpq %rbp,RIP(%rsp)
671 je error_swapgs
672 movl %ebp,%ebp /* zero extend */
673 cmpq %rbp,RIP(%rsp)
674 je error_swapgs
675 cmpq $gs_change,RIP(%rsp)
676 je error_swapgs
677 jmp error_sti
678
679 /* Reload gs selector with exception handling */
680 /* edi: new selector */
681ENTRY(load_gs_index)
682 pushf
683 cli
684 swapgs
685gs_change:
686 movl %edi,%gs
6872: mfence /* workaround */
688 swapgs
689 popf
690 ret
691
692 .section __ex_table,"a"
693 .align 8
694 .quad gs_change,bad_gs
695 .previous
696 .section .fixup,"ax"
697 /* running with kernelgs */
698bad_gs:
699 swapgs /* switch back to user gs */
700 xorl %eax,%eax
701 movl %eax,%gs
702 jmp 2b
703 .previous
704
705/*
706 * Create a kernel thread.
707 *
708 * C extern interface:
709 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
710 *
711 * asm input arguments:
712 * rdi: fn, rsi: arg, rdx: flags
713 */
714ENTRY(kernel_thread)
715 CFI_STARTPROC
716 FAKE_STACK_FRAME $child_rip
717 SAVE_ALL
718
719 # rdi: flags, rsi: usp, rdx: will be &pt_regs
720 movq %rdx,%rdi
721 orq kernel_thread_flags(%rip),%rdi
722 movq $-1, %rsi
723 movq %rsp, %rdx
724
725 xorl %r8d,%r8d
726 xorl %r9d,%r9d
727
728 # clone now
729 call do_fork
730 movq %rax,RAX(%rsp)
731 xorl %edi,%edi
732
733 /*
734 * It isn't worth to check for reschedule here,
735 * so internally to the x86_64 port you can rely on kernel_thread()
736 * not to reschedule the child before returning, this avoids the need
737 * of hacks for example to fork off the per-CPU idle tasks.
738 * [Hopefully no generic code relies on the reschedule -AK]
739 */
740 RESTORE_ALL
741 UNFAKE_STACK_FRAME
742 ret
743 CFI_ENDPROC
744
745
746child_rip:
747 /*
748 * Here we are in the child and the registers are set as they were
749 * at kernel_thread() invocation in the parent.
750 */
751 movq %rdi, %rax
752 movq %rsi, %rdi
753 call *%rax
754 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700755 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 call do_exit
757
758/*
759 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
760 *
761 * C extern interface:
762 * extern long execve(char *name, char **argv, char **envp)
763 *
764 * asm input arguments:
765 * rdi: name, rsi: argv, rdx: envp
766 *
767 * We want to fallback into:
768 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
769 *
770 * do_sys_execve asm fallback arguments:
771 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
772 */
773ENTRY(execve)
774 CFI_STARTPROC
775 FAKE_STACK_FRAME $0
776 SAVE_ALL
777 call sys_execve
778 movq %rax, RAX(%rsp)
779 RESTORE_REST
780 testq %rax,%rax
781 je int_ret_from_sys_call
782 RESTORE_ARGS
783 UNFAKE_STACK_FRAME
784 ret
785 CFI_ENDPROC
786
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700787KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 errorentry do_page_fault
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700789 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791ENTRY(coprocessor_error)
792 zeroentry do_coprocessor_error
793
794ENTRY(simd_coprocessor_error)
795 zeroentry do_simd_coprocessor_error
796
797ENTRY(device_not_available)
798 zeroentry math_state_restore
799
800 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700801KPROBE_ENTRY(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 CFI_STARTPROC
803 pushq $0
804 CFI_ADJUST_CFA_OFFSET 8
805 paranoidentry do_debug
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 jmp paranoid_exit
807 CFI_ENDPROC
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700808 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 /* runs on exception stack */
811ENTRY(nmi)
812 CFI_STARTPROC
813 pushq $-1
814 CFI_ADJUST_CFA_OFFSET 8
815 paranoidentry do_nmi
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700816 /*
817 * "Paranoid" exit path from exception stack.
818 * Paranoid because this is used by NMIs and cannot take
819 * any kernel state for granted.
820 * We don't do kernel preemption checks here, because only
821 * NMI should be common and it does not enable IRQs and
822 * cannot get reschedule ticks.
823 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 /* ebx: no swapgs flag */
825paranoid_exit:
826 testl %ebx,%ebx /* swapgs needed? */
827 jnz paranoid_restore
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700828 testl $3,CS(%rsp)
829 jnz paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830paranoid_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 swapgs
832paranoid_restore:
833 RESTORE_ALL 8
834 iretq
835paranoid_userspace:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 GET_THREAD_INFO(%rcx)
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700837 movl threadinfo_flags(%rcx),%ebx
838 andl $_TIF_WORK_MASK,%ebx
Andi Kleen11b854b2005-04-16 15:25:02 -0700839 jz paranoid_swapgs
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700840 movq %rsp,%rdi /* &pt_regs */
841 call sync_regs
842 movq %rax,%rsp /* switch stack for scheduling */
843 testl $_TIF_NEED_RESCHED,%ebx
844 jnz paranoid_schedule
845 movl %ebx,%edx /* arg3: thread flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 sti
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700847 xorl %esi,%esi /* arg2: oldset */
848 movq %rsp,%rdi /* arg1: &pt_regs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 call do_notify_resume
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700850 cli
851 jmp paranoid_userspace
852paranoid_schedule:
Andi Kleen11b854b2005-04-16 15:25:02 -0700853 sti
854 call schedule
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700855 cli
856 jmp paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 CFI_ENDPROC
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700858
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700859KPROBE_ENTRY(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 zeroentry do_int3
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700861 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863ENTRY(overflow)
864 zeroentry do_overflow
865
866ENTRY(bounds)
867 zeroentry do_bounds
868
869ENTRY(invalid_op)
870 zeroentry do_invalid_op
871
872ENTRY(coprocessor_segment_overrun)
873 zeroentry do_coprocessor_segment_overrun
874
875ENTRY(reserved)
876 zeroentry do_reserved
877
878 /* runs on exception stack */
879ENTRY(double_fault)
880 CFI_STARTPROC
881 paranoidentry do_double_fault
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 jmp paranoid_exit
883 CFI_ENDPROC
884
885ENTRY(invalid_TSS)
886 errorentry do_invalid_TSS
887
888ENTRY(segment_not_present)
889 errorentry do_segment_not_present
890
891 /* runs on exception stack */
892ENTRY(stack_segment)
893 CFI_STARTPROC
894 paranoidentry do_stack_segment
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 jmp paranoid_exit
896 CFI_ENDPROC
897
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700898KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 errorentry do_general_protection
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700900 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902ENTRY(alignment_check)
903 errorentry do_alignment_check
904
905ENTRY(divide_error)
906 zeroentry do_divide_error
907
908ENTRY(spurious_interrupt_bug)
909 zeroentry do_spurious_interrupt_bug
910
911#ifdef CONFIG_X86_MCE
912 /* runs on exception stack */
913ENTRY(machine_check)
914 CFI_STARTPROC
915 pushq $0
916 CFI_ADJUST_CFA_OFFSET 8
917 paranoidentry do_machine_check
918 jmp paranoid_exit
919 CFI_ENDPROC
920#endif
921
922ENTRY(call_debug)
923 zeroentry do_call_debug
924
Andi Kleened6b6762005-07-28 21:15:49 -0700925ENTRY(call_softirq)
926 movq %gs:pda_irqstackptr,%rax
927 pushq %r15
928 movq %rsp,%r15
929 incl %gs:pda_irqcount
930 cmove %rax,%rsp
931 call __do_softirq
932 movq %r15,%rsp
933 decl %gs:pda_irqcount
934 popq %r15
935 ret
936