blob: 4cbc65290ae7599ed0dfa54d33b186f51182b756 [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
158 call schedule_tail
159 GET_THREAD_INFO(%rcx)
160 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
161 jnz rff_trace
162rff_action:
163 RESTORE_REST
164 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
165 je int_ret_from_sys_call
166 testl $_TIF_IA32,threadinfo_flags(%rcx)
167 jnz int_ret_from_sys_call
168 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
169 jmp ret_from_sys_call
170rff_trace:
171 movq %rsp,%rdi
172 call syscall_trace_leave
173 GET_THREAD_INFO(%rcx)
174 jmp rff_action
175 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200176END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178/*
179 * System call entry. Upto 6 arguments in registers are supported.
180 *
181 * SYSCALL does not save anything on the stack and does not change the
182 * stack pointer.
183 */
184
185/*
186 * Register setup:
187 * rax system call number
188 * rdi arg0
189 * rcx return address for syscall/sysret, C arg3
190 * rsi arg1
191 * rdx arg2
192 * r10 arg3 (--> moved to rcx for C)
193 * r8 arg4
194 * r9 arg5
195 * r11 eflags for syscall/sysret, temporary for C
196 * r12-r15,rbp,rbx saved by C code, not touched.
197 *
198 * Interrupts are off on entry.
199 * Only called from user space.
200 *
201 * XXX if we had a free scratch register we could save the RSP into the stack frame
202 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200203 *
204 * When user can change the frames always force IRET. That is because
205 * it deals with uncanonical addresses better. SYSRET has trouble
206 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 */
208
209ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200210 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200211 CFI_SIGNAL_FRAME
Jan Beulichdffead42006-06-26 13:57:38 +0200212 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200213 CFI_REGISTER rip,rcx
214 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 swapgs
216 movq %rsp,%gs:pda_oldrsp
217 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700218 /*
219 * No need to follow this irqs off/on section - it's straight
220 * and short:
221 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 sti
223 SAVE_ARGS 8,1
224 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200225 movq %rcx,RIP-ARGOFFSET(%rsp)
226 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 GET_THREAD_INFO(%rcx)
228 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200229 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 jnz tracesys
231 cmpq $__NR_syscall_max,%rax
232 ja badsys
233 movq %r10,%rcx
234 call *sys_call_table(,%rax,8) # XXX: rip relative
235 movq %rax,RAX-ARGOFFSET(%rsp)
236/*
237 * Syscall return path ending with SYSRET (fast path)
238 * Has incomplete stack frame and undefined top of stack.
239 */
240 .globl ret_from_sys_call
241ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700242 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 /* edi: flagmask */
244sysret_check:
245 GET_THREAD_INFO(%rcx)
246 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700247 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 movl threadinfo_flags(%rcx),%edx
249 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200250 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 jnz sysret_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700252 /*
253 * sysretq will re-enable interrupts:
254 */
255 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200257 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200259 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 movq %gs:pda_oldrsp,%rsp
261 swapgs
262 sysretq
263
264 /* Handle reschedules */
265 /* edx: work, edi: workmask */
266sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200267 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 bt $TIF_NEED_RESCHED,%edx
269 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700270 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sti
272 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200273 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 call schedule
275 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200276 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 jmp sysret_check
278
279 /* Handle a signal */
280sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700281 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700283 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
284 jz 1f
285
286 /* Really a signal */
287 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 leaq do_notify_resume(%rip),%rax
289 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
290 xorl %esi,%esi # oldset -> arg2
291 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002921: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200293 /* Use IRET because user could have changed frame. This
294 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
295 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700296 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200297 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Jan Beulich7effaa82005-09-12 18:49:24 +0200299badsys:
300 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
301 jmp ret_from_sys_call
302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 /* Do syscall tracing */
304tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200305 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 SAVE_REST
307 movq $-ENOSYS,RAX(%rsp)
308 FIXUP_TOP_OF_STACK %rdi
309 movq %rsp,%rdi
310 call syscall_trace_enter
311 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
312 RESTORE_REST
313 cmpq $__NR_syscall_max,%rax
314 ja 1f
315 movq %r10,%rcx /* fixup for C */
316 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02003171: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200318 /* Use IRET because user could have changed frame */
319 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200320 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200321END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323/*
324 * Syscall return path ending with IRET.
325 * Has correct top of stack, but partial stack frame.
326 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200327ENTRY(int_ret_from_sys_call)
328 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200329 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200330 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
331 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
332 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
333 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
334 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
335 CFI_REL_OFFSET rip,RIP-ARGOFFSET
336 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
337 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
338 CFI_REL_OFFSET rax,RAX-ARGOFFSET
339 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
340 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
341 CFI_REL_OFFSET r8,R8-ARGOFFSET
342 CFI_REL_OFFSET r9,R9-ARGOFFSET
343 CFI_REL_OFFSET r10,R10-ARGOFFSET
344 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700346 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 testl $3,CS-ARGOFFSET(%rsp)
348 je retint_restore_args
349 movl $_TIF_ALLWORK_MASK,%edi
350 /* edi: mask to check */
351int_with_check:
352 GET_THREAD_INFO(%rcx)
353 movl threadinfo_flags(%rcx),%edx
354 andl %edi,%edx
355 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100356 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 jmp retint_swapgs
358
359 /* Either reschedule or signal or syscall exit tracking needed. */
360 /* First do a reschedule test. */
361 /* edx: work, edi: workmask */
362int_careful:
363 bt $TIF_NEED_RESCHED,%edx
364 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700365 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sti
367 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200368 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 call schedule
370 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200371 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700372 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700373 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 jmp int_with_check
375
376 /* handle signals and tracing -- both require a full stack frame */
377int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700378 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 sti
380 SAVE_REST
381 /* Check for syscall exit trace */
382 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
383 jz int_signal
384 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200385 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 leaq 8(%rsp),%rdi # &ptregs -> arg1
387 call syscall_trace_leave
388 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200389 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700390 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700391 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700392 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 jmp int_restore_rest
394
395int_signal:
396 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
397 jz 1f
398 movq %rsp,%rdi # &ptregs -> arg1
399 xorl %esi,%esi # oldset -> arg2
400 call do_notify_resume
4011: movl $_TIF_NEED_RESCHED,%edi
402int_restore_rest:
403 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700404 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700405 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 jmp int_with_check
407 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200408END(int_ret_from_sys_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
410/*
411 * Certain special system calls that need to save a complete full stack frame.
412 */
413
414 .macro PTREGSCALL label,func,arg
415 .globl \label
416\label:
417 leaq \func(%rip),%rax
418 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
419 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200420END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 .endm
422
Jan Beulich7effaa82005-09-12 18:49:24 +0200423 CFI_STARTPROC
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 PTREGSCALL stub_clone, sys_clone, %r8
426 PTREGSCALL stub_fork, sys_fork, %rdi
427 PTREGSCALL stub_vfork, sys_vfork, %rdi
428 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
429 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
430 PTREGSCALL stub_iopl, sys_iopl, %rsi
431
432ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200434 CFI_ADJUST_CFA_OFFSET -8
435 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 SAVE_REST
437 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200438 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 FIXUP_TOP_OF_STACK %r11
440 call *%rax
441 RESTORE_TOP_OF_STACK %r11
442 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200443 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 RESTORE_REST
445 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200446 CFI_ADJUST_CFA_OFFSET 8
447 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 ret
449 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200450END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452ENTRY(stub_execve)
453 CFI_STARTPROC
454 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200455 CFI_ADJUST_CFA_OFFSET -8
456 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 FIXUP_TOP_OF_STACK %r11
459 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 movq %rax,RAX(%rsp)
462 RESTORE_REST
463 jmp int_ret_from_sys_call
464 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200465END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467/*
468 * sigreturn is special because it needs to restore all registers on return.
469 * This cannot be done with SYSRET, so use the IRET return path instead.
470 */
471ENTRY(stub_rt_sigreturn)
472 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200473 addq $8, %rsp
474 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 SAVE_REST
476 movq %rsp,%rdi
477 FIXUP_TOP_OF_STACK %r11
478 call sys_rt_sigreturn
479 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
480 RESTORE_REST
481 jmp int_ret_from_sys_call
482 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200483END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Jan Beulich7effaa82005-09-12 18:49:24 +0200485/*
486 * initial frame state for interrupts and exceptions
487 */
488 .macro _frame ref
489 CFI_STARTPROC simple
Jan Beulichadf14232006-09-26 10:52:41 +0200490 CFI_SIGNAL_FRAME
Jan Beulich7effaa82005-09-12 18:49:24 +0200491 CFI_DEF_CFA rsp,SS+8-\ref
492 /*CFI_REL_OFFSET ss,SS-\ref*/
493 CFI_REL_OFFSET rsp,RSP-\ref
494 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
495 /*CFI_REL_OFFSET cs,CS-\ref*/
496 CFI_REL_OFFSET rip,RIP-\ref
497 .endm
498
499/* initial frame state for interrupts (and exceptions without error code) */
500#define INTR_FRAME _frame RIP
501/* initial frame state for exceptions with error code (and interrupts with
502 vector already pushed) */
503#define XCPT_FRAME _frame ORIG_RAX
504
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505/*
506 * Interrupt entry/exit.
507 *
508 * Interrupt entry points save only callee clobbered registers in fast path.
509 *
510 * Entry runs with interrupts off.
511 */
512
513/* 0(%rsp): interrupt number */
514 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 SAVE_ARGS
517 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200518 pushq %rbp
519 CFI_ADJUST_CFA_OFFSET 8
520 CFI_REL_OFFSET rbp, 0
521 movq %rsp,%rbp
522 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 testl $3,CS(%rdi)
524 je 1f
525 swapgs
Andi Kleen96e54042006-09-26 10:52:39 +0200526 /* irqcount is used to check if a CPU is already on an interrupt
527 stack or not. While this is essentially redundant with preempt_count
528 it is a little cheaper to use a separate counter in the PDA
529 (short of moving irq_enter into assembly, which would be too
530 much work) */
5311: incl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200532 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200533 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700534 /*
535 * We entered an interrupt context - irqs are off:
536 */
537 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 call \func
539 .endm
540
541ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200542 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 interrupt do_IRQ
544 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200545ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700547 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700548 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200549 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200550 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200551 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200552exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 GET_THREAD_INFO(%rcx)
554 testl $3,CS-ARGOFFSET(%rsp)
555 je retint_kernel
556
557 /* Interrupt came from user space */
558 /*
559 * Has a correct top of stack, but a partial stack frame
560 * %rcx: thread info. Interrupts off.
561 */
562retint_with_reschedule:
563 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200564retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 movl threadinfo_flags(%rcx),%edx
566 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200567 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 jnz retint_careful
569retint_swapgs:
Ingo Molnar2601e642006-07-03 00:24:45 -0700570 /*
571 * The iretq could re-enable interrupts:
572 */
573 cli
574 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700576 jmp restore_args
577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578retint_restore_args:
579 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700580 /*
581 * The iretq could re-enable interrupts:
582 */
583 TRACE_IRQS_IRETQ
584restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 RESTORE_ARGS 0,8,0
586iret_label:
587 iretq
588
589 .section __ex_table,"a"
590 .quad iret_label,bad_iret
591 .previous
592 .section .fixup,"ax"
593 /* force a signal here? this matches i386 behaviour */
594 /* running with kernel gs */
595bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100596 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700597 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100598 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 jmp do_exit
600 .previous
601
Jan Beulich7effaa82005-09-12 18:49:24 +0200602 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200604 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 bt $TIF_NEED_RESCHED,%edx
606 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700607 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 sti
609 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200610 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 call schedule
612 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200613 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 GET_THREAD_INFO(%rcx)
615 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700616 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 jmp retint_check
618
619retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700620 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
621 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700622 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 sti
624 SAVE_REST
625 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700626 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 movq %rsp,%rdi # &pt_regs
628 call do_notify_resume
629 RESTORE_REST
630 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700631 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700632 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700633 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 jmp retint_check
635
636#ifdef CONFIG_PREEMPT
637 /* Returning to kernel space. Check if we need preemption */
638 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200639ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 cmpl $0,threadinfo_preempt_count(%rcx)
641 jnz retint_restore_args
642 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
643 jnc retint_restore_args
644 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
645 jnc retint_restore_args
646 call preempt_schedule_irq
647 jmp exit_intr
648#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200651END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653/*
654 * APIC interrupts.
655 */
656 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200657 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700658 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200659 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 interrupt \func
661 jmp ret_from_intr
662 CFI_ENDPROC
663 .endm
664
665ENTRY(thermal_interrupt)
666 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200667END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Jacob Shin89b831e2005-11-05 17:25:53 +0100669ENTRY(threshold_interrupt)
670 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200671END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673#ifdef CONFIG_SMP
674ENTRY(reschedule_interrupt)
675 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200676END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Andi Kleene5bc8b62005-09-12 18:49:24 +0200678 .macro INVALIDATE_ENTRY num
679ENTRY(invalidate_interrupt\num)
680 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200681END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200682 .endm
683
684 INVALIDATE_ENTRY 0
685 INVALIDATE_ENTRY 1
686 INVALIDATE_ENTRY 2
687 INVALIDATE_ENTRY 3
688 INVALIDATE_ENTRY 4
689 INVALIDATE_ENTRY 5
690 INVALIDATE_ENTRY 6
691 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693ENTRY(call_function_interrupt)
694 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200695END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696#endif
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698ENTRY(apic_timer_interrupt)
699 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200700END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702ENTRY(error_interrupt)
703 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200704END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706ENTRY(spurious_interrupt)
707 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200708END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710/*
711 * Exception entry points.
712 */
713 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200714 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200716 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200718 CFI_ADJUST_CFA_OFFSET 8
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 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200725 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200727 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 leaq \sym(%rip),%rax
729 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200730 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 .endm
732
733 /* error code is on the stack already */
734 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700735 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 SAVE_ALL
737 cld
738 movl $1,%ebx
739 movl $MSR_GS_BASE,%ecx
740 rdmsr
741 testl %edx,%edx
742 js 1f
743 swapgs
744 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01007451:
746 .if \ist
747 movq %gs:pda_data_offset, %rbp
748 .endif
749 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 movq ORIG_RAX(%rsp),%rsi
751 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100752 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100753 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100754 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100756 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100757 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100758 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700759 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700760 .if \irqtrace
761 TRACE_IRQS_OFF
762 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700764
765 /*
766 * "Paranoid" exit path from exception stack.
767 * Paranoid because this is used by NMIs and cannot take
768 * any kernel state for granted.
769 * We don't do kernel preemption checks here, because only
770 * NMI should be common and it does not enable IRQs and
771 * cannot get reschedule ticks.
772 *
773 * "trace" is 0 for the NMI handler only, because irq-tracing
774 * is fundamentally NMI-unsafe. (we cannot change the soft and
775 * hard flags at once, atomically)
776 */
777 .macro paranoidexit trace=1
778 /* ebx: no swapgs flag */
779paranoid_exit\trace:
780 testl %ebx,%ebx /* swapgs needed? */
781 jnz paranoid_restore\trace
782 testl $3,CS(%rsp)
783 jnz paranoid_userspace\trace
784paranoid_swapgs\trace:
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200785 .if \trace
Ingo Molnar2601e642006-07-03 00:24:45 -0700786 TRACE_IRQS_IRETQ 0
Andi Kleen7a0a2df2006-09-26 10:52:37 +0200787 .endif
Ingo Molnar2601e642006-07-03 00:24:45 -0700788 swapgs
789paranoid_restore\trace:
790 RESTORE_ALL 8
791 iretq
792paranoid_userspace\trace:
793 GET_THREAD_INFO(%rcx)
794 movl threadinfo_flags(%rcx),%ebx
795 andl $_TIF_WORK_MASK,%ebx
796 jz paranoid_swapgs\trace
797 movq %rsp,%rdi /* &pt_regs */
798 call sync_regs
799 movq %rax,%rsp /* switch stack for scheduling */
800 testl $_TIF_NEED_RESCHED,%ebx
801 jnz paranoid_schedule\trace
802 movl %ebx,%edx /* arg3: thread flags */
803 .if \trace
804 TRACE_IRQS_ON
805 .endif
806 sti
807 xorl %esi,%esi /* arg2: oldset */
808 movq %rsp,%rdi /* arg1: &pt_regs */
809 call do_notify_resume
810 cli
811 .if \trace
812 TRACE_IRQS_OFF
813 .endif
814 jmp paranoid_userspace\trace
815paranoid_schedule\trace:
816 .if \trace
817 TRACE_IRQS_ON
818 .endif
819 sti
820 call schedule
821 cli
822 .if \trace
823 TRACE_IRQS_OFF
824 .endif
825 jmp paranoid_userspace\trace
826 CFI_ENDPROC
827 .endm
828
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829/*
830 * Exception entry point. This expects an error code/orig_rax on the stack
831 * and the exception handler in %rax.
832 */
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200833KPROBE_ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200834 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 /* rdi slot contains rax, oldrax contains error code */
836 cld
837 subq $14*8,%rsp
838 CFI_ADJUST_CFA_OFFSET (14*8)
839 movq %rsi,13*8(%rsp)
840 CFI_REL_OFFSET rsi,RSI
841 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
842 movq %rdx,12*8(%rsp)
843 CFI_REL_OFFSET rdx,RDX
844 movq %rcx,11*8(%rsp)
845 CFI_REL_OFFSET rcx,RCX
846 movq %rsi,10*8(%rsp) /* store rax */
847 CFI_REL_OFFSET rax,RAX
848 movq %r8, 9*8(%rsp)
849 CFI_REL_OFFSET r8,R8
850 movq %r9, 8*8(%rsp)
851 CFI_REL_OFFSET r9,R9
852 movq %r10,7*8(%rsp)
853 CFI_REL_OFFSET r10,R10
854 movq %r11,6*8(%rsp)
855 CFI_REL_OFFSET r11,R11
856 movq %rbx,5*8(%rsp)
857 CFI_REL_OFFSET rbx,RBX
858 movq %rbp,4*8(%rsp)
859 CFI_REL_OFFSET rbp,RBP
860 movq %r12,3*8(%rsp)
861 CFI_REL_OFFSET r12,R12
862 movq %r13,2*8(%rsp)
863 CFI_REL_OFFSET r13,R13
864 movq %r14,1*8(%rsp)
865 CFI_REL_OFFSET r14,R14
866 movq %r15,(%rsp)
867 CFI_REL_OFFSET r15,R15
868 xorl %ebx,%ebx
869 testl $3,CS(%rsp)
870 je error_kernelspace
871error_swapgs:
872 swapgs
873error_sti:
874 movq %rdi,RDI(%rsp)
875 movq %rsp,%rdi
876 movq ORIG_RAX(%rsp),%rsi /* get error code */
877 movq $-1,ORIG_RAX(%rsp)
878 call *%rax
879 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
880error_exit:
881 movl %ebx,%eax
882 RESTORE_REST
883 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700884 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 GET_THREAD_INFO(%rcx)
886 testl %eax,%eax
887 jne retint_kernel
888 movl threadinfo_flags(%rcx),%edx
889 movl $_TIF_WORK_MASK,%edi
890 andl %edi,%edx
891 jnz retint_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700892 /*
893 * The iret might restore flags:
894 */
895 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 swapgs
897 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100898 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 CFI_ENDPROC
900
901error_kernelspace:
902 incl %ebx
903 /* There are two places in the kernel that can potentially fault with
904 usergs. Handle them here. The exception handlers after
905 iret run with kernel gs again, so don't set the user space flag.
906 B stepping K8s sometimes report an truncated RIP for IRET
907 exceptions returning to compat mode. Check for these here too. */
908 leaq iret_label(%rip),%rbp
909 cmpq %rbp,RIP(%rsp)
910 je error_swapgs
911 movl %ebp,%ebp /* zero extend */
912 cmpq %rbp,RIP(%rsp)
913 je error_swapgs
914 cmpq $gs_change,RIP(%rsp)
915 je error_swapgs
916 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200917KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 /* Reload gs selector with exception handling */
920 /* edi: new selector */
921ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200922 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200924 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 cli
926 swapgs
927gs_change:
928 movl %edi,%gs
9292: mfence /* workaround */
930 swapgs
931 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200932 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200934 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200935ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 .section __ex_table,"a"
938 .align 8
939 .quad gs_change,bad_gs
940 .previous
941 .section .fixup,"ax"
942 /* running with kernelgs */
943bad_gs:
944 swapgs /* switch back to user gs */
945 xorl %eax,%eax
946 movl %eax,%gs
947 jmp 2b
948 .previous
949
950/*
951 * Create a kernel thread.
952 *
953 * C extern interface:
954 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
955 *
956 * asm input arguments:
957 * rdi: fn, rsi: arg, rdx: flags
958 */
959ENTRY(kernel_thread)
960 CFI_STARTPROC
961 FAKE_STACK_FRAME $child_rip
962 SAVE_ALL
963
964 # rdi: flags, rsi: usp, rdx: will be &pt_regs
965 movq %rdx,%rdi
966 orq kernel_thread_flags(%rip),%rdi
967 movq $-1, %rsi
968 movq %rsp, %rdx
969
970 xorl %r8d,%r8d
971 xorl %r9d,%r9d
972
973 # clone now
974 call do_fork
975 movq %rax,RAX(%rsp)
976 xorl %edi,%edi
977
978 /*
979 * It isn't worth to check for reschedule here,
980 * so internally to the x86_64 port you can rely on kernel_thread()
981 * not to reschedule the child before returning, this avoids the need
982 * of hacks for example to fork off the per-CPU idle tasks.
983 * [Hopefully no generic code relies on the reschedule -AK]
984 */
985 RESTORE_ALL
986 UNFAKE_STACK_FRAME
987 ret
988 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200989ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +0200992 pushq $0 # fake return address
993 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 /*
995 * Here we are in the child and the registers are set as they were
996 * at kernel_thread() invocation in the parent.
997 */
998 movq %rdi, %rax
999 movq %rsi, %rdi
1000 call *%rax
1001 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -07001002 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +02001004 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001005ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007/*
1008 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1009 *
1010 * C extern interface:
1011 * extern long execve(char *name, char **argv, char **envp)
1012 *
1013 * asm input arguments:
1014 * rdi: name, rsi: argv, rdx: envp
1015 *
1016 * We want to fallback into:
1017 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
1018 *
1019 * do_sys_execve asm fallback arguments:
1020 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1021 */
1022ENTRY(execve)
1023 CFI_STARTPROC
1024 FAKE_STACK_FRAME $0
1025 SAVE_ALL
1026 call sys_execve
1027 movq %rax, RAX(%rsp)
1028 RESTORE_REST
1029 testq %rax,%rax
1030 je int_ret_from_sys_call
1031 RESTORE_ARGS
1032 UNFAKE_STACK_FRAME
1033 ret
1034 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001035ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001037KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001039KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041ENTRY(coprocessor_error)
1042 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001043END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045ENTRY(simd_coprocessor_error)
1046 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001047END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
1049ENTRY(device_not_available)
1050 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001051END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001054KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001055 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 pushq $0
1057 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001058 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001059 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001060KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001063KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001064 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001066 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001067 paranoidentry do_nmi, 0, 0
1068#ifdef CONFIG_TRACE_IRQFLAGS
1069 paranoidexit 0
1070#else
1071 jmp paranoid_exit1
1072 CFI_ENDPROC
1073#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001074KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001075
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001076KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001077 INTR_FRAME
1078 pushq $0
1079 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001080 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001081 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001082 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001083KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085ENTRY(overflow)
1086 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001087END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089ENTRY(bounds)
1090 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001091END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093ENTRY(invalid_op)
1094 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001095END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097ENTRY(coprocessor_segment_overrun)
1098 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001099END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101ENTRY(reserved)
1102 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001103END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 /* runs on exception stack */
1106ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001107 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001109 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001111END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113ENTRY(invalid_TSS)
1114 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001115END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117ENTRY(segment_not_present)
1118 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001119END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
1121 /* runs on exception stack */
1122ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001123 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001125 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001127END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001129KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001131KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133ENTRY(alignment_check)
1134 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001135END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137ENTRY(divide_error)
1138 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001139END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141ENTRY(spurious_interrupt_bug)
1142 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001143END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145#ifdef CONFIG_X86_MCE
1146 /* runs on exception stack */
1147ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001148 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 pushq $0
1150 CFI_ADJUST_CFA_OFFSET 8
1151 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001152 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001154END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155#endif
1156
Andi Kleen26995002006-08-02 22:37:28 +02001157/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001158ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001159 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001160 push %rbp
1161 CFI_ADJUST_CFA_OFFSET 8
1162 CFI_REL_OFFSET rbp,0
1163 mov %rsp,%rbp
1164 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001165 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001166 cmove %gs:pda_irqstackptr,%rsp
1167 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001168 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001169 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001170 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001171 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001172 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001173 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001174 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001175ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001176
1177#ifdef CONFIG_STACK_UNWIND
1178ENTRY(arch_unwind_init_running)
1179 CFI_STARTPROC
1180 movq %r15, R15(%rdi)
1181 movq %r14, R14(%rdi)
1182 xchgq %rsi, %rdx
1183 movq %r13, R13(%rdi)
1184 movq %r12, R12(%rdi)
1185 xorl %eax, %eax
1186 movq %rbp, RBP(%rdi)
1187 movq %rbx, RBX(%rdi)
1188 movq (%rsp), %rcx
1189 movq %rax, R11(%rdi)
1190 movq %rax, R10(%rdi)
1191 movq %rax, R9(%rdi)
1192 movq %rax, R8(%rdi)
1193 movq %rax, RAX(%rdi)
1194 movq %rax, RCX(%rdi)
1195 movq %rax, RDX(%rdi)
1196 movq %rax, RSI(%rdi)
1197 movq %rax, RDI(%rdi)
1198 movq %rax, ORIG_RAX(%rdi)
1199 movq %rcx, RIP(%rdi)
1200 leaq 8(%rsp), %rcx
1201 movq $__KERNEL_CS, CS(%rdi)
1202 movq %rax, EFLAGS(%rdi)
1203 movq %rcx, RSP(%rdi)
1204 movq $__KERNEL_DS, SS(%rdi)
1205 jmpq *%rdx
1206 CFI_ENDPROC
1207ENDPROC(arch_unwind_init_running)
1208#endif