blob: f1cacd4897f74892eea1e8c4399b1891c6b523ad [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9/*
10 * entry.S contains the system-call and fault low-level handling routines.
11 *
12 * NOTE: This code handles signal-recognition, which happens every time
13 * after an interrupt and after each system call.
14 *
15 * Normal syscalls and interrupts don't save a full stack frame, this is
16 * only done for syscall tracing, signals or fork/exec et.al.
17 *
18 * A note on terminology:
19 * - top of stack: Architecture defined interrupt frame from SS to RIP
20 * at the top of the kernel process stack.
21 * - partial stack frame: partially saved registers upto R11.
22 * - full stack frame: Like partial stack frame, but all register saved.
Andi Kleen2e91a172006-09-26 10:52:29 +020023 *
24 * Some macro usage:
25 * - CFI macros are used to generate dwarf2 unwind information for better
26 * backtraces. They don't change any code.
27 * - SAVE_ALL/RESTORE_ALL - Save/restore all registers
28 * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify.
29 * There are unfortunately lots of special cases where some registers
30 * not touched. The macro is a big mess that should be cleaned up.
31 * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS.
32 * Gives a full stack frame.
33 * - ENTRY/END Define functions in the symbol table.
34 * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack
35 * frame that is otherwise undefined after a SYSCALL
36 * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
37 * - errorentry/paranoidentry/zeroentry - Define exception entry points.
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 */
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/linkage.h>
41#include <asm/segment.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/cache.h>
43#include <asm/errno.h>
44#include <asm/dwarf2.h>
45#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020046#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/msr.h>
48#include <asm/unistd.h>
49#include <asm/thread_info.h>
50#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010051#include <asm/page.h>
Ingo Molnar2601e642006-07-03 00:24:45 -070052#include <asm/irqflags.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54 .code64
55
Andi Kleendc37db42005-04-16 15:25:05 -070056#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#define retint_kernel retint_restore_args
58#endif
Ingo Molnar2601e642006-07-03 00:24:45 -070059
60
61.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
62#ifdef CONFIG_TRACE_IRQFLAGS
63 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
64 jnc 1f
65 TRACE_IRQS_ON
661:
67#endif
68.endm
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/*
71 * C code is not supposed to know about undefined top of stack. Every time
72 * a C function with an pt_regs argument is called from the SYSCALL based
73 * fast path FIXUP_TOP_OF_STACK is needed.
74 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
75 * manipulation.
76 */
77
78 /* %rsp:at FRAMEEND */
79 .macro FIXUP_TOP_OF_STACK tmp
80 movq %gs:pda_oldrsp,\tmp
81 movq \tmp,RSP(%rsp)
82 movq $__USER_DS,SS(%rsp)
83 movq $__USER_CS,CS(%rsp)
84 movq $-1,RCX(%rsp)
85 movq R11(%rsp),\tmp /* get eflags */
86 movq \tmp,EFLAGS(%rsp)
87 .endm
88
89 .macro RESTORE_TOP_OF_STACK tmp,offset=0
90 movq RSP-\offset(%rsp),\tmp
91 movq \tmp,%gs:pda_oldrsp
92 movq EFLAGS-\offset(%rsp),\tmp
93 movq \tmp,R11-\offset(%rsp)
94 .endm
95
96 .macro FAKE_STACK_FRAME child_rip
97 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -070098 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 pushq %rax /* ss */
100 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200101 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 pushq %rax /* rsp */
103 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200104 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 pushq $(1<<9) /* eflags - interrupts on */
106 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200107 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 pushq $__KERNEL_CS /* cs */
109 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200110 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 pushq \child_rip /* rip */
112 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200113 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 pushq %rax /* orig rax */
115 CFI_ADJUST_CFA_OFFSET 8
116 .endm
117
118 .macro UNFAKE_STACK_FRAME
119 addq $8*6, %rsp
120 CFI_ADJUST_CFA_OFFSET -(6*8)
121 .endm
122
Jan Beulich7effaa82005-09-12 18:49:24 +0200123 .macro CFI_DEFAULT_STACK start=1
124 .if \start
125 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200126 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200127 CFI_DEF_CFA rsp,SS+8
128 .else
129 CFI_DEF_CFA_OFFSET SS+8
130 .endif
131 CFI_REL_OFFSET r15,R15
132 CFI_REL_OFFSET r14,R14
133 CFI_REL_OFFSET r13,R13
134 CFI_REL_OFFSET r12,R12
135 CFI_REL_OFFSET rbp,RBP
136 CFI_REL_OFFSET rbx,RBX
137 CFI_REL_OFFSET r11,R11
138 CFI_REL_OFFSET r10,R10
139 CFI_REL_OFFSET r9,R9
140 CFI_REL_OFFSET r8,R8
141 CFI_REL_OFFSET rax,RAX
142 CFI_REL_OFFSET rcx,RCX
143 CFI_REL_OFFSET rdx,RDX
144 CFI_REL_OFFSET rsi,RSI
145 CFI_REL_OFFSET rdi,RDI
146 CFI_REL_OFFSET rip,RIP
147 /*CFI_REL_OFFSET cs,CS*/
148 /*CFI_REL_OFFSET rflags,EFLAGS*/
149 CFI_REL_OFFSET rsp,RSP
150 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 .endm
152/*
153 * A newly forked process directly context switches into this.
154 */
155/* rdi: prev */
156ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 CFI_DEFAULT_STACK
Andi Kleen658fdbe2006-09-26 10:52:41 +0200158 push kernel_eflags(%rip)
159 CFI_ADJUST_CFA_OFFSET 4
160 popf # reset kernel eflags
161 CFI_ADJUST_CFA_OFFSET -4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 call schedule_tail
163 GET_THREAD_INFO(%rcx)
164 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
165 jnz rff_trace
166rff_action:
167 RESTORE_REST
168 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
169 je int_ret_from_sys_call
170 testl $_TIF_IA32,threadinfo_flags(%rcx)
171 jnz int_ret_from_sys_call
172 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
173 jmp ret_from_sys_call
174rff_trace:
175 movq %rsp,%rdi
176 call syscall_trace_leave
177 GET_THREAD_INFO(%rcx)
178 jmp rff_action
179 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200180END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182/*
183 * System call entry. Upto 6 arguments in registers are supported.
184 *
185 * SYSCALL does not save anything on the stack and does not change the
186 * stack pointer.
187 */
188
189/*
190 * Register setup:
191 * rax system call number
192 * rdi arg0
193 * rcx return address for syscall/sysret, C arg3
194 * rsi arg1
195 * rdx arg2
196 * r10 arg3 (--> moved to rcx for C)
197 * r8 arg4
198 * r9 arg5
199 * r11 eflags for syscall/sysret, temporary for C
200 * r12-r15,rbp,rbx saved by C code, not touched.
201 *
202 * Interrupts are off on entry.
203 * Only called from user space.
204 *
205 * XXX if we had a free scratch register we could save the RSP into the stack frame
206 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200207 *
208 * When user can change the frames always force IRET. That is because
209 * it deals with uncanonical addresses better. SYSRET has trouble
210 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 */
212
213ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200214 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200215 CFI_SIGNAL_FRAME
Jan Beulichdffead42006-06-26 13:57:38 +0200216 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200217 CFI_REGISTER rip,rcx
218 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 swapgs
220 movq %rsp,%gs:pda_oldrsp
221 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700222 /*
223 * No need to follow this irqs off/on section - it's straight
224 * and short:
225 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 sti
227 SAVE_ARGS 8,1
228 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200229 movq %rcx,RIP-ARGOFFSET(%rsp)
230 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 GET_THREAD_INFO(%rcx)
232 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
233 jnz tracesys
234 cmpq $__NR_syscall_max,%rax
235 ja badsys
236 movq %r10,%rcx
237 call *sys_call_table(,%rax,8) # XXX: rip relative
238 movq %rax,RAX-ARGOFFSET(%rsp)
239/*
240 * Syscall return path ending with SYSRET (fast path)
241 * Has incomplete stack frame and undefined top of stack.
242 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700244 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 /* edi: flagmask */
246sysret_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200247 LOCKDEP_SYS_EXIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 GET_THREAD_INFO(%rcx)
249 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700250 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 movl threadinfo_flags(%rcx),%edx
252 andl %edi,%edx
253 jnz sysret_careful
Jan Beulichbcddc012006-12-07 02:14:02 +0100254 CFI_REMEMBER_STATE
Ingo Molnar2601e642006-07-03 00:24:45 -0700255 /*
256 * sysretq will re-enable interrupts:
257 */
258 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200260 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200262 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 movq %gs:pda_oldrsp,%rsp
264 swapgs
265 sysretq
266
Jan Beulichbcddc012006-12-07 02:14:02 +0100267 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 /* Handle reschedules */
269 /* edx: work, edi: workmask */
270sysret_careful:
271 bt $TIF_NEED_RESCHED,%edx
272 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700273 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 sti
275 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200276 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 call schedule
278 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200279 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 jmp sysret_check
281
282 /* Handle a signal */
283sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700284 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 sti
Stephane Eraniana583f1b2007-07-31 00:38:00 -0700286 testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700287 jz 1f
288
289 /* Really a signal */
290 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 leaq do_notify_resume(%rip),%rax
292 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
293 xorl %esi,%esi # oldset -> arg2
294 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002951: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200296 /* Use IRET because user could have changed frame. This
297 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
298 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700299 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200300 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Jan Beulich7effaa82005-09-12 18:49:24 +0200302badsys:
303 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
304 jmp ret_from_sys_call
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 /* Do syscall tracing */
307tracesys:
308 SAVE_REST
309 movq $-ENOSYS,RAX(%rsp)
310 FIXUP_TOP_OF_STACK %rdi
311 movq %rsp,%rdi
312 call syscall_trace_enter
313 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
314 RESTORE_REST
315 cmpq $__NR_syscall_max,%rax
Jan Beulichcc7d4792006-10-21 18:37:02 +0200316 movq $-ENOSYS,%rcx
317 cmova %rcx,%rax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 ja 1f
319 movq %r10,%rcx /* fixup for C */
320 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02003211: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200322 /* Use IRET because user could have changed frame */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324/*
325 * Syscall return path ending with IRET.
326 * Has correct top of stack, but partial stack frame.
Jan Beulichbcddc012006-12-07 02:14:02 +0100327 */
328 .globl int_ret_from_sys_call
329int_ret_from_sys_call:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700331 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 testl $3,CS-ARGOFFSET(%rsp)
333 je retint_restore_args
334 movl $_TIF_ALLWORK_MASK,%edi
335 /* edi: mask to check */
336int_with_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200337 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 GET_THREAD_INFO(%rcx)
339 movl threadinfo_flags(%rcx),%edx
340 andl %edi,%edx
341 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100342 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 jmp retint_swapgs
344
345 /* Either reschedule or signal or syscall exit tracking needed. */
346 /* First do a reschedule test. */
347 /* edx: work, edi: workmask */
348int_careful:
349 bt $TIF_NEED_RESCHED,%edx
350 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700351 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 sti
353 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200354 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 call schedule
356 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200357 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700358 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700359 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 jmp int_with_check
361
362 /* handle signals and tracing -- both require a full stack frame */
363int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700364 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 sti
366 SAVE_REST
367 /* Check for syscall exit trace */
368 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
369 jz int_signal
370 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200371 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 leaq 8(%rsp),%rdi # &ptregs -> arg1
373 call syscall_trace_leave
374 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200375 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700376 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 jmp int_restore_rest
378
379int_signal:
Stephane Eraniana583f1b2007-07-31 00:38:00 -0700380 testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 jz 1f
382 movq %rsp,%rdi # &ptregs -> arg1
383 xorl %esi,%esi # oldset -> arg2
384 call do_notify_resume
3851: movl $_TIF_NEED_RESCHED,%edi
386int_restore_rest:
387 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700388 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700389 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 jmp int_with_check
391 CFI_ENDPROC
Jan Beulichbcddc012006-12-07 02:14:02 +0100392END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394/*
395 * Certain special system calls that need to save a complete full stack frame.
396 */
397
398 .macro PTREGSCALL label,func,arg
399 .globl \label
400\label:
401 leaq \func(%rip),%rax
402 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
403 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200404END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 .endm
406
Jan Beulich7effaa82005-09-12 18:49:24 +0200407 CFI_STARTPROC
408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 PTREGSCALL stub_clone, sys_clone, %r8
410 PTREGSCALL stub_fork, sys_fork, %rdi
411 PTREGSCALL stub_vfork, sys_vfork, %rdi
412 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
413 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
414 PTREGSCALL stub_iopl, sys_iopl, %rsi
415
416ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200418 CFI_ADJUST_CFA_OFFSET -8
419 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 SAVE_REST
421 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200422 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 FIXUP_TOP_OF_STACK %r11
424 call *%rax
425 RESTORE_TOP_OF_STACK %r11
426 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200427 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 RESTORE_REST
429 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200430 CFI_ADJUST_CFA_OFFSET 8
431 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 ret
433 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200434END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436ENTRY(stub_execve)
437 CFI_STARTPROC
438 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200439 CFI_ADJUST_CFA_OFFSET -8
440 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 FIXUP_TOP_OF_STACK %r11
443 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 movq %rax,RAX(%rsp)
446 RESTORE_REST
447 jmp int_ret_from_sys_call
448 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200449END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451/*
452 * sigreturn is special because it needs to restore all registers on return.
453 * This cannot be done with SYSRET, so use the IRET return path instead.
454 */
455ENTRY(stub_rt_sigreturn)
456 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200457 addq $8, %rsp
458 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 SAVE_REST
460 movq %rsp,%rdi
461 FIXUP_TOP_OF_STACK %r11
462 call sys_rt_sigreturn
463 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
464 RESTORE_REST
465 jmp int_ret_from_sys_call
466 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200467END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Jan Beulich7effaa82005-09-12 18:49:24 +0200469/*
470 * initial frame state for interrupts and exceptions
471 */
472 .macro _frame ref
473 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200474 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200475 CFI_DEF_CFA rsp,SS+8-\ref
476 /*CFI_REL_OFFSET ss,SS-\ref*/
477 CFI_REL_OFFSET rsp,RSP-\ref
478 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
479 /*CFI_REL_OFFSET cs,CS-\ref*/
480 CFI_REL_OFFSET rip,RIP-\ref
481 .endm
482
483/* initial frame state for interrupts (and exceptions without error code) */
484#define INTR_FRAME _frame RIP
485/* initial frame state for exceptions with error code (and interrupts with
486 vector already pushed) */
487#define XCPT_FRAME _frame ORIG_RAX
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489/*
490 * Interrupt entry/exit.
491 *
492 * Interrupt entry points save only callee clobbered registers in fast path.
493 *
494 * Entry runs with interrupts off.
495 */
496
497/* 0(%rsp): interrupt number */
498 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 SAVE_ARGS
501 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200502 pushq %rbp
503 CFI_ADJUST_CFA_OFFSET 8
504 CFI_REL_OFFSET rbp, 0
505 movq %rsp,%rbp
506 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 testl $3,CS(%rdi)
508 je 1f
509 swapgs
Andi Kleen96e54042006-09-26 10:52:39 +0200510 /* irqcount is used to check if a CPU is already on an interrupt
511 stack or not. While this is essentially redundant with preempt_count
512 it is a little cheaper to use a separate counter in the PDA
513 (short of moving irq_enter into assembly, which would be too
514 much work) */
5151: incl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200516 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200517 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700518 /*
519 * We entered an interrupt context - irqs are off:
520 */
521 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 call \func
523 .endm
524
525ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200526 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 interrupt do_IRQ
528 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200529ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700531 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700532 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200533 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200534 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200535 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200536exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 GET_THREAD_INFO(%rcx)
538 testl $3,CS-ARGOFFSET(%rsp)
539 je retint_kernel
540
541 /* Interrupt came from user space */
542 /*
543 * Has a correct top of stack, but a partial stack frame
544 * %rcx: thread info. Interrupts off.
545 */
546retint_with_reschedule:
547 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200548retint_check:
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200549 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 movl threadinfo_flags(%rcx),%edx
551 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200552 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200554
555retint_swapgs: /* return to user-space */
Ingo Molnar2601e642006-07-03 00:24:45 -0700556 /*
557 * The iretq could re-enable interrupts:
558 */
559 cli
560 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700562 jmp restore_args
563
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200564retint_restore_args: /* return to kernel space */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700566 /*
567 * The iretq could re-enable interrupts:
568 */
569 TRACE_IRQS_IRETQ
570restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 RESTORE_ARGS 0,8,0
572iret_label:
573 iretq
574
575 .section __ex_table,"a"
576 .quad iret_label,bad_iret
577 .previous
578 .section .fixup,"ax"
579 /* force a signal here? this matches i386 behaviour */
580 /* running with kernel gs */
581bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100582 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700583 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100584 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 jmp do_exit
586 .previous
587
Jan Beulich7effaa82005-09-12 18:49:24 +0200588 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200590 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 bt $TIF_NEED_RESCHED,%edx
592 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700593 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 sti
595 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200596 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 call schedule
598 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200599 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 GET_THREAD_INFO(%rcx)
601 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700602 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 jmp retint_check
604
605retint_signal:
Stephane Eraniana583f1b2007-07-31 00:38:00 -0700606 testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700607 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700608 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 sti
610 SAVE_REST
611 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700612 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 movq %rsp,%rdi # &pt_regs
614 call do_notify_resume
615 RESTORE_REST
616 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700617 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700618 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700619 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 jmp retint_check
621
622#ifdef CONFIG_PREEMPT
623 /* Returning to kernel space. Check if we need preemption */
624 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200625ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 cmpl $0,threadinfo_preempt_count(%rcx)
627 jnz retint_restore_args
628 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
629 jnc retint_restore_args
630 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
631 jnc retint_restore_args
632 call preempt_schedule_irq
633 jmp exit_intr
634#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200637END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639/*
640 * APIC interrupts.
641 */
642 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200643 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700644 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200645 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 interrupt \func
647 jmp ret_from_intr
648 CFI_ENDPROC
649 .endm
650
651ENTRY(thermal_interrupt)
652 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200653END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Jacob Shin89b831e2005-11-05 17:25:53 +0100655ENTRY(threshold_interrupt)
656 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200657END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659#ifdef CONFIG_SMP
660ENTRY(reschedule_interrupt)
661 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200662END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Andi Kleene5bc8b62005-09-12 18:49:24 +0200664 .macro INVALIDATE_ENTRY num
665ENTRY(invalidate_interrupt\num)
666 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200667END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200668 .endm
669
670 INVALIDATE_ENTRY 0
671 INVALIDATE_ENTRY 1
672 INVALIDATE_ENTRY 2
673 INVALIDATE_ENTRY 3
674 INVALIDATE_ENTRY 4
675 INVALIDATE_ENTRY 5
676 INVALIDATE_ENTRY 6
677 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679ENTRY(call_function_interrupt)
680 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200681END(call_function_interrupt)
Eric W. Biederman61014292007-02-23 04:40:58 -0700682ENTRY(irq_move_cleanup_interrupt)
683 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
684END(irq_move_cleanup_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685#endif
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687ENTRY(apic_timer_interrupt)
688 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200689END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691ENTRY(error_interrupt)
692 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200693END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695ENTRY(spurious_interrupt)
696 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200697END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699/*
700 * Exception entry points.
701 */
702 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200703 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200705 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200707 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200708 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 leaq \sym(%rip),%rax
710 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200711 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 .endm
713
714 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200715 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200717 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich37550902007-05-02 19:27:05 +0200718 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 leaq \sym(%rip),%rax
720 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200721 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 .endm
723
724 /* error code is on the stack already */
725 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700726 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 SAVE_ALL
728 cld
729 movl $1,%ebx
730 movl $MSR_GS_BASE,%ecx
731 rdmsr
732 testl %edx,%edx
733 js 1f
734 swapgs
735 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01007361:
737 .if \ist
738 movq %gs:pda_data_offset, %rbp
739 .endif
740 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 movq ORIG_RAX(%rsp),%rsi
742 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100743 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100744 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100745 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100747 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100748 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100749 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700750 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700751 .if \irqtrace
752 TRACE_IRQS_OFF
753 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700755
756 /*
757 * "Paranoid" exit path from exception stack.
758 * Paranoid because this is used by NMIs and cannot take
759 * any kernel state for granted.
760 * We don't do kernel preemption checks here, because only
761 * NMI should be common and it does not enable IRQs and
762 * cannot get reschedule ticks.
763 *
764 * "trace" is 0 for the NMI handler only, because irq-tracing
765 * is fundamentally NMI-unsafe. (we cannot change the soft and
766 * hard flags at once, atomically)
767 */
768 .macro paranoidexit trace=1
769 /* ebx: no swapgs flag */
770paranoid_exit\trace:
771 testl %ebx,%ebx /* swapgs needed? */
772 jnz paranoid_restore\trace
773 testl $3,CS(%rsp)
774 jnz paranoid_userspace\trace
775paranoid_swapgs\trace:
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200776 .if \trace
Ingo Molnar2601e642006-07-03 00:24:45 -0700777 TRACE_IRQS_IRETQ 0
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200778 .endif
Ingo Molnar2601e642006-07-03 00:24:45 -0700779 swapgs
780paranoid_restore\trace:
781 RESTORE_ALL 8
782 iretq
783paranoid_userspace\trace:
784 GET_THREAD_INFO(%rcx)
785 movl threadinfo_flags(%rcx),%ebx
786 andl $_TIF_WORK_MASK,%ebx
787 jz paranoid_swapgs\trace
788 movq %rsp,%rdi /* &pt_regs */
789 call sync_regs
790 movq %rax,%rsp /* switch stack for scheduling */
791 testl $_TIF_NEED_RESCHED,%ebx
792 jnz paranoid_schedule\trace
793 movl %ebx,%edx /* arg3: thread flags */
794 .if \trace
795 TRACE_IRQS_ON
796 .endif
797 sti
798 xorl %esi,%esi /* arg2: oldset */
799 movq %rsp,%rdi /* arg1: &pt_regs */
800 call do_notify_resume
801 cli
802 .if \trace
803 TRACE_IRQS_OFF
804 .endif
805 jmp paranoid_userspace\trace
806paranoid_schedule\trace:
807 .if \trace
808 TRACE_IRQS_ON
809 .endif
810 sti
811 call schedule
812 cli
813 .if \trace
814 TRACE_IRQS_OFF
815 .endif
816 jmp paranoid_userspace\trace
817 CFI_ENDPROC
818 .endm
819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820/*
821 * Exception entry point. This expects an error code/orig_rax on the stack
822 * and the exception handler in %rax.
823 */
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200824KPROBE_ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200825 _frame RDI
Jan Beulich37550902007-05-02 19:27:05 +0200826 CFI_REL_OFFSET rax,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 /* rdi slot contains rax, oldrax contains error code */
828 cld
829 subq $14*8,%rsp
830 CFI_ADJUST_CFA_OFFSET (14*8)
831 movq %rsi,13*8(%rsp)
832 CFI_REL_OFFSET rsi,RSI
833 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
Jan Beulich37550902007-05-02 19:27:05 +0200834 CFI_REGISTER rax,rsi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 movq %rdx,12*8(%rsp)
836 CFI_REL_OFFSET rdx,RDX
837 movq %rcx,11*8(%rsp)
838 CFI_REL_OFFSET rcx,RCX
839 movq %rsi,10*8(%rsp) /* store rax */
840 CFI_REL_OFFSET rax,RAX
841 movq %r8, 9*8(%rsp)
842 CFI_REL_OFFSET r8,R8
843 movq %r9, 8*8(%rsp)
844 CFI_REL_OFFSET r9,R9
845 movq %r10,7*8(%rsp)
846 CFI_REL_OFFSET r10,R10
847 movq %r11,6*8(%rsp)
848 CFI_REL_OFFSET r11,R11
849 movq %rbx,5*8(%rsp)
850 CFI_REL_OFFSET rbx,RBX
851 movq %rbp,4*8(%rsp)
852 CFI_REL_OFFSET rbp,RBP
853 movq %r12,3*8(%rsp)
854 CFI_REL_OFFSET r12,R12
855 movq %r13,2*8(%rsp)
856 CFI_REL_OFFSET r13,R13
857 movq %r14,1*8(%rsp)
858 CFI_REL_OFFSET r14,R14
859 movq %r15,(%rsp)
860 CFI_REL_OFFSET r15,R15
861 xorl %ebx,%ebx
862 testl $3,CS(%rsp)
863 je error_kernelspace
864error_swapgs:
865 swapgs
866error_sti:
867 movq %rdi,RDI(%rsp)
Jan Beulich37550902007-05-02 19:27:05 +0200868 CFI_REL_OFFSET rdi,RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 movq %rsp,%rdi
870 movq ORIG_RAX(%rsp),%rsi /* get error code */
871 movq $-1,ORIG_RAX(%rsp)
872 call *%rax
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200873 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
874error_exit:
875 movl %ebx,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 RESTORE_REST
877 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700878 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 GET_THREAD_INFO(%rcx)
880 testl %eax,%eax
881 jne retint_kernel
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200882 LOCKDEP_SYS_EXIT_IRQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 movl threadinfo_flags(%rcx),%edx
884 movl $_TIF_WORK_MASK,%edi
885 andl %edi,%edx
886 jnz retint_careful
Peter Zijlstra10cd7062007-10-11 22:11:12 +0200887 jmp retint_swapgs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 CFI_ENDPROC
889
890error_kernelspace:
891 incl %ebx
892 /* There are two places in the kernel that can potentially fault with
893 usergs. Handle them here. The exception handlers after
894 iret run with kernel gs again, so don't set the user space flag.
895 B stepping K8s sometimes report an truncated RIP for IRET
896 exceptions returning to compat mode. Check for these here too. */
897 leaq iret_label(%rip),%rbp
898 cmpq %rbp,RIP(%rsp)
899 je error_swapgs
900 movl %ebp,%ebp /* zero extend */
901 cmpq %rbp,RIP(%rsp)
902 je error_swapgs
903 cmpq $gs_change,RIP(%rsp)
904 je error_swapgs
905 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200906KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 /* Reload gs selector with exception handling */
909 /* edi: new selector */
910ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200911 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200913 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 cli
915 swapgs
916gs_change:
917 movl %edi,%gs
9182: mfence /* workaround */
919 swapgs
920 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200921 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200923 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200924ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 .section __ex_table,"a"
927 .align 8
928 .quad gs_change,bad_gs
929 .previous
930 .section .fixup,"ax"
931 /* running with kernelgs */
932bad_gs:
933 swapgs /* switch back to user gs */
934 xorl %eax,%eax
935 movl %eax,%gs
936 jmp 2b
937 .previous
938
939/*
940 * Create a kernel thread.
941 *
942 * C extern interface:
943 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
944 *
945 * asm input arguments:
946 * rdi: fn, rsi: arg, rdx: flags
947 */
948ENTRY(kernel_thread)
949 CFI_STARTPROC
950 FAKE_STACK_FRAME $child_rip
951 SAVE_ALL
952
953 # rdi: flags, rsi: usp, rdx: will be &pt_regs
954 movq %rdx,%rdi
955 orq kernel_thread_flags(%rip),%rdi
956 movq $-1, %rsi
957 movq %rsp, %rdx
958
959 xorl %r8d,%r8d
960 xorl %r9d,%r9d
961
962 # clone now
963 call do_fork
964 movq %rax,RAX(%rsp)
965 xorl %edi,%edi
966
967 /*
968 * It isn't worth to check for reschedule here,
969 * so internally to the x86_64 port you can rely on kernel_thread()
970 * not to reschedule the child before returning, this avoids the need
971 * of hacks for example to fork off the per-CPU idle tasks.
972 * [Hopefully no generic code relies on the reschedule -AK]
973 */
974 RESTORE_ALL
975 UNFAKE_STACK_FRAME
976 ret
977 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200978ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +0200981 pushq $0 # fake return address
982 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /*
984 * Here we are in the child and the registers are set as they were
985 * at kernel_thread() invocation in the parent.
986 */
987 movq %rdi, %rax
988 movq %rsi, %rdi
989 call *%rax
990 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700991 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +0200993 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200994ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996/*
997 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
998 *
999 * C extern interface:
1000 * extern long execve(char *name, char **argv, char **envp)
1001 *
1002 * asm input arguments:
1003 * rdi: name, rsi: argv, rdx: envp
1004 *
1005 * We want to fallback into:
1006 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
1007 *
1008 * do_sys_execve asm fallback arguments:
1009 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1010 */
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001011ENTRY(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 CFI_STARTPROC
1013 FAKE_STACK_FRAME $0
1014 SAVE_ALL
1015 call sys_execve
1016 movq %rax, RAX(%rsp)
1017 RESTORE_REST
1018 testq %rax,%rax
1019 je int_ret_from_sys_call
1020 RESTORE_ARGS
1021 UNFAKE_STACK_FRAME
1022 ret
1023 CFI_ENDPROC
Arnd Bergmann3db03b42006-10-02 02:18:31 -07001024ENDPROC(kernel_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001026KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001028KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030ENTRY(coprocessor_error)
1031 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001032END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034ENTRY(simd_coprocessor_error)
1035 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001036END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038ENTRY(device_not_available)
1039 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001040END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001043KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001044 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 pushq $0
1046 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001047 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001048 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001049KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001052KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001053 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001055 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001056 paranoidentry do_nmi, 0, 0
1057#ifdef CONFIG_TRACE_IRQFLAGS
1058 paranoidexit 0
1059#else
1060 jmp paranoid_exit1
1061 CFI_ENDPROC
1062#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001063KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001064
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001065KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001066 INTR_FRAME
1067 pushq $0
1068 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001069 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001070 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001071 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001072KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
1074ENTRY(overflow)
1075 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001076END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078ENTRY(bounds)
1079 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001080END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082ENTRY(invalid_op)
1083 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001084END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086ENTRY(coprocessor_segment_overrun)
1087 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001088END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090ENTRY(reserved)
1091 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001092END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094 /* runs on exception stack */
1095ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001096 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001098 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001100END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
1102ENTRY(invalid_TSS)
1103 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001104END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106ENTRY(segment_not_present)
1107 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001108END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
1110 /* runs on exception stack */
1111ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001112 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001114 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001116END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001118KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001120KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122ENTRY(alignment_check)
1123 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001124END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126ENTRY(divide_error)
1127 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001128END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130ENTRY(spurious_interrupt_bug)
1131 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001132END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134#ifdef CONFIG_X86_MCE
1135 /* runs on exception stack */
1136ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001137 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 pushq $0
1139 CFI_ADJUST_CFA_OFFSET 8
1140 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001141 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001143END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144#endif
1145
Andi Kleen26995002006-08-02 22:37:28 +02001146/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001147ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001148 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001149 push %rbp
1150 CFI_ADJUST_CFA_OFFSET 8
1151 CFI_REL_OFFSET rbp,0
1152 mov %rsp,%rbp
1153 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001154 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001155 cmove %gs:pda_irqstackptr,%rsp
1156 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001157 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001158 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001159 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001160 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001161 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001162 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001163 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001164ENDPROC(call_softirq)
Andi Kleen75154f42007-06-23 02:29:25 +02001165
1166KPROBE_ENTRY(ignore_sysret)
1167 CFI_STARTPROC
1168 mov $-ENOSYS,%eax
1169 sysret
1170 CFI_ENDPROC
1171ENDPROC(ignore_sysret)