blob: 873c39d8f8184ae4d06fdb2025229c94d16af459 [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>
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
Andi Kleene5bc8b62005-09-12 18:49:24 +0200539 .macro INVALIDATE_ENTRY num
540ENTRY(invalidate_interrupt\num)
541 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
542 .endm
543
544 INVALIDATE_ENTRY 0
545 INVALIDATE_ENTRY 1
546 INVALIDATE_ENTRY 2
547 INVALIDATE_ENTRY 3
548 INVALIDATE_ENTRY 4
549 INVALIDATE_ENTRY 5
550 INVALIDATE_ENTRY 6
551 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553ENTRY(call_function_interrupt)
554 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
555#endif
556
557#ifdef CONFIG_X86_LOCAL_APIC
558ENTRY(apic_timer_interrupt)
559 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
560
561ENTRY(error_interrupt)
562 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
563
564ENTRY(spurious_interrupt)
565 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
566#endif
567
568/*
569 * Exception entry points.
570 */
571 .macro zeroentry sym
572 pushq $0 /* push error code/oldrax */
573 pushq %rax /* push real oldrax to the rdi slot */
574 leaq \sym(%rip),%rax
575 jmp error_entry
576 .endm
577
578 .macro errorentry sym
579 pushq %rax
580 leaq \sym(%rip),%rax
581 jmp error_entry
582 .endm
583
584 /* error code is on the stack already */
585 /* handle NMI like exceptions that can happen everywhere */
586 .macro paranoidentry sym
587 SAVE_ALL
588 cld
589 movl $1,%ebx
590 movl $MSR_GS_BASE,%ecx
591 rdmsr
592 testl %edx,%edx
593 js 1f
594 swapgs
595 xorl %ebx,%ebx
5961: movq %rsp,%rdi
597 movq ORIG_RAX(%rsp),%rsi
598 movq $-1,ORIG_RAX(%rsp)
599 call \sym
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700600 cli
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 .endm
602
603/*
604 * Exception entry point. This expects an error code/orig_rax on the stack
605 * and the exception handler in %rax.
606 */
607ENTRY(error_entry)
608 CFI_STARTPROC simple
609 CFI_DEF_CFA rsp,(SS-RDI)
610 CFI_REL_OFFSET rsp,(RSP-RDI)
611 CFI_REL_OFFSET rip,(RIP-RDI)
612 /* rdi slot contains rax, oldrax contains error code */
613 cld
614 subq $14*8,%rsp
615 CFI_ADJUST_CFA_OFFSET (14*8)
616 movq %rsi,13*8(%rsp)
617 CFI_REL_OFFSET rsi,RSI
618 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
619 movq %rdx,12*8(%rsp)
620 CFI_REL_OFFSET rdx,RDX
621 movq %rcx,11*8(%rsp)
622 CFI_REL_OFFSET rcx,RCX
623 movq %rsi,10*8(%rsp) /* store rax */
624 CFI_REL_OFFSET rax,RAX
625 movq %r8, 9*8(%rsp)
626 CFI_REL_OFFSET r8,R8
627 movq %r9, 8*8(%rsp)
628 CFI_REL_OFFSET r9,R9
629 movq %r10,7*8(%rsp)
630 CFI_REL_OFFSET r10,R10
631 movq %r11,6*8(%rsp)
632 CFI_REL_OFFSET r11,R11
633 movq %rbx,5*8(%rsp)
634 CFI_REL_OFFSET rbx,RBX
635 movq %rbp,4*8(%rsp)
636 CFI_REL_OFFSET rbp,RBP
637 movq %r12,3*8(%rsp)
638 CFI_REL_OFFSET r12,R12
639 movq %r13,2*8(%rsp)
640 CFI_REL_OFFSET r13,R13
641 movq %r14,1*8(%rsp)
642 CFI_REL_OFFSET r14,R14
643 movq %r15,(%rsp)
644 CFI_REL_OFFSET r15,R15
645 xorl %ebx,%ebx
646 testl $3,CS(%rsp)
647 je error_kernelspace
648error_swapgs:
649 swapgs
650error_sti:
651 movq %rdi,RDI(%rsp)
652 movq %rsp,%rdi
653 movq ORIG_RAX(%rsp),%rsi /* get error code */
654 movq $-1,ORIG_RAX(%rsp)
655 call *%rax
656 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
657error_exit:
658 movl %ebx,%eax
659 RESTORE_REST
660 cli
661 GET_THREAD_INFO(%rcx)
662 testl %eax,%eax
663 jne retint_kernel
664 movl threadinfo_flags(%rcx),%edx
665 movl $_TIF_WORK_MASK,%edi
666 andl %edi,%edx
667 jnz retint_careful
668 swapgs
669 RESTORE_ARGS 0,8,0
670 iretq
671 CFI_ENDPROC
672
673error_kernelspace:
674 incl %ebx
675 /* There are two places in the kernel that can potentially fault with
676 usergs. Handle them here. The exception handlers after
677 iret run with kernel gs again, so don't set the user space flag.
678 B stepping K8s sometimes report an truncated RIP for IRET
679 exceptions returning to compat mode. Check for these here too. */
680 leaq iret_label(%rip),%rbp
681 cmpq %rbp,RIP(%rsp)
682 je error_swapgs
683 movl %ebp,%ebp /* zero extend */
684 cmpq %rbp,RIP(%rsp)
685 je error_swapgs
686 cmpq $gs_change,RIP(%rsp)
687 je error_swapgs
688 jmp error_sti
689
690 /* Reload gs selector with exception handling */
691 /* edi: new selector */
692ENTRY(load_gs_index)
693 pushf
694 cli
695 swapgs
696gs_change:
697 movl %edi,%gs
6982: mfence /* workaround */
699 swapgs
700 popf
701 ret
702
703 .section __ex_table,"a"
704 .align 8
705 .quad gs_change,bad_gs
706 .previous
707 .section .fixup,"ax"
708 /* running with kernelgs */
709bad_gs:
710 swapgs /* switch back to user gs */
711 xorl %eax,%eax
712 movl %eax,%gs
713 jmp 2b
714 .previous
715
716/*
717 * Create a kernel thread.
718 *
719 * C extern interface:
720 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
721 *
722 * asm input arguments:
723 * rdi: fn, rsi: arg, rdx: flags
724 */
725ENTRY(kernel_thread)
726 CFI_STARTPROC
727 FAKE_STACK_FRAME $child_rip
728 SAVE_ALL
729
730 # rdi: flags, rsi: usp, rdx: will be &pt_regs
731 movq %rdx,%rdi
732 orq kernel_thread_flags(%rip),%rdi
733 movq $-1, %rsi
734 movq %rsp, %rdx
735
736 xorl %r8d,%r8d
737 xorl %r9d,%r9d
738
739 # clone now
740 call do_fork
741 movq %rax,RAX(%rsp)
742 xorl %edi,%edi
743
744 /*
745 * It isn't worth to check for reschedule here,
746 * so internally to the x86_64 port you can rely on kernel_thread()
747 * not to reschedule the child before returning, this avoids the need
748 * of hacks for example to fork off the per-CPU idle tasks.
749 * [Hopefully no generic code relies on the reschedule -AK]
750 */
751 RESTORE_ALL
752 UNFAKE_STACK_FRAME
753 ret
754 CFI_ENDPROC
755
756
757child_rip:
758 /*
759 * Here we are in the child and the registers are set as they were
760 * at kernel_thread() invocation in the parent.
761 */
762 movq %rdi, %rax
763 movq %rsi, %rdi
764 call *%rax
765 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700766 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 call do_exit
768
769/*
770 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
771 *
772 * C extern interface:
773 * extern long execve(char *name, char **argv, char **envp)
774 *
775 * asm input arguments:
776 * rdi: name, rsi: argv, rdx: envp
777 *
778 * We want to fallback into:
779 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
780 *
781 * do_sys_execve asm fallback arguments:
782 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
783 */
784ENTRY(execve)
785 CFI_STARTPROC
786 FAKE_STACK_FRAME $0
787 SAVE_ALL
788 call sys_execve
789 movq %rax, RAX(%rsp)
790 RESTORE_REST
791 testq %rax,%rax
792 je int_ret_from_sys_call
793 RESTORE_ARGS
794 UNFAKE_STACK_FRAME
795 ret
796 CFI_ENDPROC
797
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700798KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 errorentry do_page_fault
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700800 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802ENTRY(coprocessor_error)
803 zeroentry do_coprocessor_error
804
805ENTRY(simd_coprocessor_error)
806 zeroentry do_simd_coprocessor_error
807
808ENTRY(device_not_available)
809 zeroentry math_state_restore
810
811 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700812KPROBE_ENTRY(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 CFI_STARTPROC
814 pushq $0
815 CFI_ADJUST_CFA_OFFSET 8
816 paranoidentry do_debug
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 jmp paranoid_exit
818 CFI_ENDPROC
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700819 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 /* runs on exception stack */
822ENTRY(nmi)
823 CFI_STARTPROC
824 pushq $-1
825 CFI_ADJUST_CFA_OFFSET 8
826 paranoidentry do_nmi
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700827 /*
828 * "Paranoid" exit path from exception stack.
829 * Paranoid because this is used by NMIs and cannot take
830 * any kernel state for granted.
831 * We don't do kernel preemption checks here, because only
832 * NMI should be common and it does not enable IRQs and
833 * cannot get reschedule ticks.
834 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 /* ebx: no swapgs flag */
836paranoid_exit:
837 testl %ebx,%ebx /* swapgs needed? */
838 jnz paranoid_restore
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700839 testl $3,CS(%rsp)
840 jnz paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841paranoid_swapgs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 swapgs
843paranoid_restore:
844 RESTORE_ALL 8
845 iretq
846paranoid_userspace:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 GET_THREAD_INFO(%rcx)
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700848 movl threadinfo_flags(%rcx),%ebx
849 andl $_TIF_WORK_MASK,%ebx
Andi Kleen11b854b2005-04-16 15:25:02 -0700850 jz paranoid_swapgs
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700851 movq %rsp,%rdi /* &pt_regs */
852 call sync_regs
853 movq %rax,%rsp /* switch stack for scheduling */
854 testl $_TIF_NEED_RESCHED,%ebx
855 jnz paranoid_schedule
856 movl %ebx,%edx /* arg3: thread flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 sti
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700858 xorl %esi,%esi /* arg2: oldset */
859 movq %rsp,%rdi /* arg1: &pt_regs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 call do_notify_resume
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700861 cli
862 jmp paranoid_userspace
863paranoid_schedule:
Andi Kleen11b854b2005-04-16 15:25:02 -0700864 sti
865 call schedule
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700866 cli
867 jmp paranoid_userspace
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 CFI_ENDPROC
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700869
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700870KPROBE_ENTRY(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 zeroentry do_int3
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700872 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
874ENTRY(overflow)
875 zeroentry do_overflow
876
877ENTRY(bounds)
878 zeroentry do_bounds
879
880ENTRY(invalid_op)
881 zeroentry do_invalid_op
882
883ENTRY(coprocessor_segment_overrun)
884 zeroentry do_coprocessor_segment_overrun
885
886ENTRY(reserved)
887 zeroentry do_reserved
888
889 /* runs on exception stack */
890ENTRY(double_fault)
891 CFI_STARTPROC
892 paranoidentry do_double_fault
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 jmp paranoid_exit
894 CFI_ENDPROC
895
896ENTRY(invalid_TSS)
897 errorentry do_invalid_TSS
898
899ENTRY(segment_not_present)
900 errorentry do_segment_not_present
901
902 /* runs on exception stack */
903ENTRY(stack_segment)
904 CFI_STARTPROC
905 paranoidentry do_stack_segment
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 jmp paranoid_exit
907 CFI_ENDPROC
908
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700909KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 errorentry do_general_protection
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -0700911 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913ENTRY(alignment_check)
914 errorentry do_alignment_check
915
916ENTRY(divide_error)
917 zeroentry do_divide_error
918
919ENTRY(spurious_interrupt_bug)
920 zeroentry do_spurious_interrupt_bug
921
922#ifdef CONFIG_X86_MCE
923 /* runs on exception stack */
924ENTRY(machine_check)
925 CFI_STARTPROC
926 pushq $0
927 CFI_ADJUST_CFA_OFFSET 8
928 paranoidentry do_machine_check
929 jmp paranoid_exit
930 CFI_ENDPROC
931#endif
932
933ENTRY(call_debug)
934 zeroentry do_call_debug
935
Andi Kleened6b6762005-07-28 21:15:49 -0700936ENTRY(call_softirq)
937 movq %gs:pda_irqstackptr,%rax
938 pushq %r15
939 movq %rsp,%r15
940 incl %gs:pda_irqcount
941 cmove %rax,%rsp
942 call __do_softirq
943 movq %r15,%rsp
944 decl %gs:pda_irqcount
945 popq %r15
946 ret
947