blob: 4fcc0ad8bbeb3630117375e478f143f648a97b4f [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
126 CFI_DEF_CFA rsp,SS+8
127 .else
128 CFI_DEF_CFA_OFFSET SS+8
129 .endif
130 CFI_REL_OFFSET r15,R15
131 CFI_REL_OFFSET r14,R14
132 CFI_REL_OFFSET r13,R13
133 CFI_REL_OFFSET r12,R12
134 CFI_REL_OFFSET rbp,RBP
135 CFI_REL_OFFSET rbx,RBX
136 CFI_REL_OFFSET r11,R11
137 CFI_REL_OFFSET r10,R10
138 CFI_REL_OFFSET r9,R9
139 CFI_REL_OFFSET r8,R8
140 CFI_REL_OFFSET rax,RAX
141 CFI_REL_OFFSET rcx,RCX
142 CFI_REL_OFFSET rdx,RDX
143 CFI_REL_OFFSET rsi,RSI
144 CFI_REL_OFFSET rdi,RDI
145 CFI_REL_OFFSET rip,RIP
146 /*CFI_REL_OFFSET cs,CS*/
147 /*CFI_REL_OFFSET rflags,EFLAGS*/
148 CFI_REL_OFFSET rsp,RSP
149 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 .endm
151/*
152 * A newly forked process directly context switches into this.
153 */
154/* rdi: prev */
155ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 CFI_DEFAULT_STACK
157 call schedule_tail
158 GET_THREAD_INFO(%rcx)
159 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
160 jnz rff_trace
161rff_action:
162 RESTORE_REST
163 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
164 je int_ret_from_sys_call
165 testl $_TIF_IA32,threadinfo_flags(%rcx)
166 jnz int_ret_from_sys_call
167 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
168 jmp ret_from_sys_call
169rff_trace:
170 movq %rsp,%rdi
171 call syscall_trace_leave
172 GET_THREAD_INFO(%rcx)
173 jmp rff_action
174 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200175END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177/*
178 * System call entry. Upto 6 arguments in registers are supported.
179 *
180 * SYSCALL does not save anything on the stack and does not change the
181 * stack pointer.
182 */
183
184/*
185 * Register setup:
186 * rax system call number
187 * rdi arg0
188 * rcx return address for syscall/sysret, C arg3
189 * rsi arg1
190 * rdx arg2
191 * r10 arg3 (--> moved to rcx for C)
192 * r8 arg4
193 * r9 arg5
194 * r11 eflags for syscall/sysret, temporary for C
195 * r12-r15,rbp,rbx saved by C code, not touched.
196 *
197 * Interrupts are off on entry.
198 * Only called from user space.
199 *
200 * XXX if we had a free scratch register we could save the RSP into the stack frame
201 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200202 *
203 * When user can change the frames always force IRET. That is because
204 * it deals with uncanonical addresses better. SYSRET has trouble
205 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 */
207
208ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200209 CFI_STARTPROC simple
Jan Beulichdffead42006-06-26 13:57:38 +0200210 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200211 CFI_REGISTER rip,rcx
212 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 swapgs
214 movq %rsp,%gs:pda_oldrsp
215 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700216 /*
217 * No need to follow this irqs off/on section - it's straight
218 * and short:
219 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 sti
221 SAVE_ARGS 8,1
222 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200223 movq %rcx,RIP-ARGOFFSET(%rsp)
224 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 GET_THREAD_INFO(%rcx)
226 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200227 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 jnz tracesys
229 cmpq $__NR_syscall_max,%rax
230 ja badsys
231 movq %r10,%rcx
232 call *sys_call_table(,%rax,8) # XXX: rip relative
233 movq %rax,RAX-ARGOFFSET(%rsp)
234/*
235 * Syscall return path ending with SYSRET (fast path)
236 * Has incomplete stack frame and undefined top of stack.
237 */
238 .globl ret_from_sys_call
239ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700240 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 /* edi: flagmask */
242sysret_check:
243 GET_THREAD_INFO(%rcx)
244 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700245 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 movl threadinfo_flags(%rcx),%edx
247 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200248 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 jnz sysret_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700250 /*
251 * sysretq will re-enable interrupts:
252 */
253 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200255 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200257 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 movq %gs:pda_oldrsp,%rsp
259 swapgs
260 sysretq
261
262 /* Handle reschedules */
263 /* edx: work, edi: workmask */
264sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200265 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 bt $TIF_NEED_RESCHED,%edx
267 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700268 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sti
270 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200271 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 call schedule
273 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200274 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 jmp sysret_check
276
277 /* Handle a signal */
278sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700279 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700281 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
282 jz 1f
283
284 /* Really a signal */
285 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 leaq do_notify_resume(%rip),%rax
287 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
288 xorl %esi,%esi # oldset -> arg2
289 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002901: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200291 /* Use IRET because user could have changed frame. This
292 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
293 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700294 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200295 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Jan Beulich7effaa82005-09-12 18:49:24 +0200297badsys:
298 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
299 jmp ret_from_sys_call
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 /* Do syscall tracing */
302tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200303 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 SAVE_REST
305 movq $-ENOSYS,RAX(%rsp)
306 FIXUP_TOP_OF_STACK %rdi
307 movq %rsp,%rdi
308 call syscall_trace_enter
309 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
310 RESTORE_REST
311 cmpq $__NR_syscall_max,%rax
312 ja 1f
313 movq %r10,%rcx /* fixup for C */
314 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02003151: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200316 /* Use IRET because user could have changed frame */
317 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200318 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200319END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321/*
322 * Syscall return path ending with IRET.
323 * Has correct top of stack, but partial stack frame.
324 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200325ENTRY(int_ret_from_sys_call)
326 CFI_STARTPROC simple
327 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
328 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
329 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
330 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
331 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
332 CFI_REL_OFFSET rip,RIP-ARGOFFSET
333 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
334 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
335 CFI_REL_OFFSET rax,RAX-ARGOFFSET
336 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
337 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
338 CFI_REL_OFFSET r8,R8-ARGOFFSET
339 CFI_REL_OFFSET r9,R9-ARGOFFSET
340 CFI_REL_OFFSET r10,R10-ARGOFFSET
341 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700343 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 testl $3,CS-ARGOFFSET(%rsp)
345 je retint_restore_args
346 movl $_TIF_ALLWORK_MASK,%edi
347 /* edi: mask to check */
348int_with_check:
349 GET_THREAD_INFO(%rcx)
350 movl threadinfo_flags(%rcx),%edx
351 andl %edi,%edx
352 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100353 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 jmp retint_swapgs
355
356 /* Either reschedule or signal or syscall exit tracking needed. */
357 /* First do a reschedule test. */
358 /* edx: work, edi: workmask */
359int_careful:
360 bt $TIF_NEED_RESCHED,%edx
361 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700362 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 sti
364 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200365 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 call schedule
367 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200368 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700369 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700370 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 jmp int_with_check
372
373 /* handle signals and tracing -- both require a full stack frame */
374int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700375 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 sti
377 SAVE_REST
378 /* Check for syscall exit trace */
379 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
380 jz int_signal
381 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200382 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 leaq 8(%rsp),%rdi # &ptregs -> arg1
384 call syscall_trace_leave
385 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200386 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700387 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
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_restore_rest
391
392int_signal:
393 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
394 jz 1f
395 movq %rsp,%rdi # &ptregs -> arg1
396 xorl %esi,%esi # oldset -> arg2
397 call do_notify_resume
3981: movl $_TIF_NEED_RESCHED,%edi
399int_restore_rest:
400 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700401 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700402 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 jmp int_with_check
404 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200405END(int_ret_from_sys_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407/*
408 * Certain special system calls that need to save a complete full stack frame.
409 */
410
411 .macro PTREGSCALL label,func,arg
412 .globl \label
413\label:
414 leaq \func(%rip),%rax
415 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
416 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200417END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 .endm
419
Jan Beulich7effaa82005-09-12 18:49:24 +0200420 CFI_STARTPROC
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 PTREGSCALL stub_clone, sys_clone, %r8
423 PTREGSCALL stub_fork, sys_fork, %rdi
424 PTREGSCALL stub_vfork, sys_vfork, %rdi
425 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
426 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
427 PTREGSCALL stub_iopl, sys_iopl, %rsi
428
429ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200431 CFI_ADJUST_CFA_OFFSET -8
432 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 SAVE_REST
434 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200435 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 FIXUP_TOP_OF_STACK %r11
437 call *%rax
438 RESTORE_TOP_OF_STACK %r11
439 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200440 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 RESTORE_REST
442 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200443 CFI_ADJUST_CFA_OFFSET 8
444 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 ret
446 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200447END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449ENTRY(stub_execve)
450 CFI_STARTPROC
451 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200452 CFI_ADJUST_CFA_OFFSET -8
453 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 FIXUP_TOP_OF_STACK %r11
456 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 movq %rax,RAX(%rsp)
459 RESTORE_REST
460 jmp int_ret_from_sys_call
461 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200462END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464/*
465 * sigreturn is special because it needs to restore all registers on return.
466 * This cannot be done with SYSRET, so use the IRET return path instead.
467 */
468ENTRY(stub_rt_sigreturn)
469 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200470 addq $8, %rsp
471 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 SAVE_REST
473 movq %rsp,%rdi
474 FIXUP_TOP_OF_STACK %r11
475 call sys_rt_sigreturn
476 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
477 RESTORE_REST
478 jmp int_ret_from_sys_call
479 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200480END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Jan Beulich7effaa82005-09-12 18:49:24 +0200482/*
483 * initial frame state for interrupts and exceptions
484 */
485 .macro _frame ref
486 CFI_STARTPROC simple
487 CFI_DEF_CFA rsp,SS+8-\ref
488 /*CFI_REL_OFFSET ss,SS-\ref*/
489 CFI_REL_OFFSET rsp,RSP-\ref
490 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
491 /*CFI_REL_OFFSET cs,CS-\ref*/
492 CFI_REL_OFFSET rip,RIP-\ref
493 .endm
494
495/* initial frame state for interrupts (and exceptions without error code) */
496#define INTR_FRAME _frame RIP
497/* initial frame state for exceptions with error code (and interrupts with
498 vector already pushed) */
499#define XCPT_FRAME _frame ORIG_RAX
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
502 * Interrupt entry/exit.
503 *
504 * Interrupt entry points save only callee clobbered registers in fast path.
505 *
506 * Entry runs with interrupts off.
507 */
508
509/* 0(%rsp): interrupt number */
510 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 SAVE_ARGS
513 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200514 pushq %rbp
515 CFI_ADJUST_CFA_OFFSET 8
516 CFI_REL_OFFSET rbp, 0
517 movq %rsp,%rbp
518 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 testl $3,CS(%rdi)
520 je 1f
521 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07005221: incl %gs:pda_irqcount # RED-PEN should check preempt count
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200523 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200524 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700525 /*
526 * We entered an interrupt context - irqs are off:
527 */
528 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 call \func
530 .endm
531
532ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200533 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 interrupt do_IRQ
535 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200536ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700538 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700539 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200540 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200541 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200542 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200543exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 GET_THREAD_INFO(%rcx)
545 testl $3,CS-ARGOFFSET(%rsp)
546 je retint_kernel
547
548 /* Interrupt came from user space */
549 /*
550 * Has a correct top of stack, but a partial stack frame
551 * %rcx: thread info. Interrupts off.
552 */
553retint_with_reschedule:
554 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200555retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 movl threadinfo_flags(%rcx),%edx
557 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200558 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 jnz retint_careful
560retint_swapgs:
Ingo Molnar2601e642006-07-03 00:24:45 -0700561 /*
562 * The iretq could re-enable interrupts:
563 */
564 cli
565 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700567 jmp restore_args
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569retint_restore_args:
570 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700571 /*
572 * The iretq could re-enable interrupts:
573 */
574 TRACE_IRQS_IRETQ
575restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 RESTORE_ARGS 0,8,0
577iret_label:
578 iretq
579
580 .section __ex_table,"a"
581 .quad iret_label,bad_iret
582 .previous
583 .section .fixup,"ax"
584 /* force a signal here? this matches i386 behaviour */
585 /* running with kernel gs */
586bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100587 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700588 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100589 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 jmp do_exit
591 .previous
592
Jan Beulich7effaa82005-09-12 18:49:24 +0200593 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200595 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 bt $TIF_NEED_RESCHED,%edx
597 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700598 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 sti
600 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200601 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 call schedule
603 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200604 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 GET_THREAD_INFO(%rcx)
606 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700607 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 jmp retint_check
609
610retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700611 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
612 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700613 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 sti
615 SAVE_REST
616 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700617 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 movq %rsp,%rdi # &pt_regs
619 call do_notify_resume
620 RESTORE_REST
621 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700622 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700623 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700624 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 jmp retint_check
626
627#ifdef CONFIG_PREEMPT
628 /* Returning to kernel space. Check if we need preemption */
629 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200630ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 cmpl $0,threadinfo_preempt_count(%rcx)
632 jnz retint_restore_args
633 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
634 jnc retint_restore_args
635 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
636 jnc retint_restore_args
637 call preempt_schedule_irq
638 jmp exit_intr
639#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200642END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644/*
645 * APIC interrupts.
646 */
647 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200648 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700649 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200650 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 interrupt \func
652 jmp ret_from_intr
653 CFI_ENDPROC
654 .endm
655
656ENTRY(thermal_interrupt)
657 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200658END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Jacob Shin89b831e2005-11-05 17:25:53 +0100660ENTRY(threshold_interrupt)
661 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200662END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664#ifdef CONFIG_SMP
665ENTRY(reschedule_interrupt)
666 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200667END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Andi Kleene5bc8b62005-09-12 18:49:24 +0200669 .macro INVALIDATE_ENTRY num
670ENTRY(invalidate_interrupt\num)
671 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200672END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200673 .endm
674
675 INVALIDATE_ENTRY 0
676 INVALIDATE_ENTRY 1
677 INVALIDATE_ENTRY 2
678 INVALIDATE_ENTRY 3
679 INVALIDATE_ENTRY 4
680 INVALIDATE_ENTRY 5
681 INVALIDATE_ENTRY 6
682 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684ENTRY(call_function_interrupt)
685 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200686END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687#endif
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689ENTRY(apic_timer_interrupt)
690 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200691END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693ENTRY(error_interrupt)
694 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200695END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697ENTRY(spurious_interrupt)
698 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200699END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701/*
702 * Exception entry points.
703 */
704 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200705 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200707 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200709 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 leaq \sym(%rip),%rax
711 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200712 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 .endm
714
715 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200716 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 pushq %rax
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 /* 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 /* rdi slot contains rax, oldrax contains error code */
827 cld
828 subq $14*8,%rsp
829 CFI_ADJUST_CFA_OFFSET (14*8)
830 movq %rsi,13*8(%rsp)
831 CFI_REL_OFFSET rsi,RSI
832 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
833 movq %rdx,12*8(%rsp)
834 CFI_REL_OFFSET rdx,RDX
835 movq %rcx,11*8(%rsp)
836 CFI_REL_OFFSET rcx,RCX
837 movq %rsi,10*8(%rsp) /* store rax */
838 CFI_REL_OFFSET rax,RAX
839 movq %r8, 9*8(%rsp)
840 CFI_REL_OFFSET r8,R8
841 movq %r9, 8*8(%rsp)
842 CFI_REL_OFFSET r9,R9
843 movq %r10,7*8(%rsp)
844 CFI_REL_OFFSET r10,R10
845 movq %r11,6*8(%rsp)
846 CFI_REL_OFFSET r11,R11
847 movq %rbx,5*8(%rsp)
848 CFI_REL_OFFSET rbx,RBX
849 movq %rbp,4*8(%rsp)
850 CFI_REL_OFFSET rbp,RBP
851 movq %r12,3*8(%rsp)
852 CFI_REL_OFFSET r12,R12
853 movq %r13,2*8(%rsp)
854 CFI_REL_OFFSET r13,R13
855 movq %r14,1*8(%rsp)
856 CFI_REL_OFFSET r14,R14
857 movq %r15,(%rsp)
858 CFI_REL_OFFSET r15,R15
859 xorl %ebx,%ebx
860 testl $3,CS(%rsp)
861 je error_kernelspace
862error_swapgs:
863 swapgs
864error_sti:
865 movq %rdi,RDI(%rsp)
866 movq %rsp,%rdi
867 movq ORIG_RAX(%rsp),%rsi /* get error code */
868 movq $-1,ORIG_RAX(%rsp)
869 call *%rax
870 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
871error_exit:
872 movl %ebx,%eax
873 RESTORE_REST
874 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700875 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 GET_THREAD_INFO(%rcx)
877 testl %eax,%eax
878 jne retint_kernel
879 movl threadinfo_flags(%rcx),%edx
880 movl $_TIF_WORK_MASK,%edi
881 andl %edi,%edx
882 jnz retint_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700883 /*
884 * The iret might restore flags:
885 */
886 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 swapgs
888 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100889 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 CFI_ENDPROC
891
892error_kernelspace:
893 incl %ebx
894 /* There are two places in the kernel that can potentially fault with
895 usergs. Handle them here. The exception handlers after
896 iret run with kernel gs again, so don't set the user space flag.
897 B stepping K8s sometimes report an truncated RIP for IRET
898 exceptions returning to compat mode. Check for these here too. */
899 leaq iret_label(%rip),%rbp
900 cmpq %rbp,RIP(%rsp)
901 je error_swapgs
902 movl %ebp,%ebp /* zero extend */
903 cmpq %rbp,RIP(%rsp)
904 je error_swapgs
905 cmpq $gs_change,RIP(%rsp)
906 je error_swapgs
907 jmp error_sti
Prasanna S.Pd28c4392006-09-26 10:52:34 +0200908KPROBE_END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 /* Reload gs selector with exception handling */
911 /* edi: new selector */
912ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200913 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200915 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 cli
917 swapgs
918gs_change:
919 movl %edi,%gs
9202: mfence /* workaround */
921 swapgs
922 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200923 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200925 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200926ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 .section __ex_table,"a"
929 .align 8
930 .quad gs_change,bad_gs
931 .previous
932 .section .fixup,"ax"
933 /* running with kernelgs */
934bad_gs:
935 swapgs /* switch back to user gs */
936 xorl %eax,%eax
937 movl %eax,%gs
938 jmp 2b
939 .previous
940
941/*
942 * Create a kernel thread.
943 *
944 * C extern interface:
945 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
946 *
947 * asm input arguments:
948 * rdi: fn, rsi: arg, rdx: flags
949 */
950ENTRY(kernel_thread)
951 CFI_STARTPROC
952 FAKE_STACK_FRAME $child_rip
953 SAVE_ALL
954
955 # rdi: flags, rsi: usp, rdx: will be &pt_regs
956 movq %rdx,%rdi
957 orq kernel_thread_flags(%rip),%rdi
958 movq $-1, %rsi
959 movq %rsp, %rdx
960
961 xorl %r8d,%r8d
962 xorl %r9d,%r9d
963
964 # clone now
965 call do_fork
966 movq %rax,RAX(%rsp)
967 xorl %edi,%edi
968
969 /*
970 * It isn't worth to check for reschedule here,
971 * so internally to the x86_64 port you can rely on kernel_thread()
972 * not to reschedule the child before returning, this avoids the need
973 * of hacks for example to fork off the per-CPU idle tasks.
974 * [Hopefully no generic code relies on the reschedule -AK]
975 */
976 RESTORE_ALL
977 UNFAKE_STACK_FRAME
978 ret
979 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200980ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +0200983 pushq $0 # fake return address
984 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 /*
986 * Here we are in the child and the registers are set as they were
987 * at kernel_thread() invocation in the parent.
988 */
989 movq %rdi, %rax
990 movq %rsi, %rdi
991 call *%rax
992 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700993 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +0200995 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200996ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998/*
999 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1000 *
1001 * C extern interface:
1002 * extern long execve(char *name, char **argv, char **envp)
1003 *
1004 * asm input arguments:
1005 * rdi: name, rsi: argv, rdx: envp
1006 *
1007 * We want to fallback into:
1008 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
1009 *
1010 * do_sys_execve asm fallback arguments:
1011 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1012 */
1013ENTRY(execve)
1014 CFI_STARTPROC
1015 FAKE_STACK_FRAME $0
1016 SAVE_ALL
1017 call sys_execve
1018 movq %rax, RAX(%rsp)
1019 RESTORE_REST
1020 testq %rax,%rax
1021 je int_ret_from_sys_call
1022 RESTORE_ARGS
1023 UNFAKE_STACK_FRAME
1024 ret
1025 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001026ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001028KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 errorentry do_page_fault
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001030KPROBE_END(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032ENTRY(coprocessor_error)
1033 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001034END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
1036ENTRY(simd_coprocessor_error)
1037 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001038END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
1040ENTRY(device_not_available)
1041 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001042END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001045KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001046 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 pushq $0
1048 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001049 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001050 paranoidexit
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001051KPROBE_END(debug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001054KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001055 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001057 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001058 paranoidentry do_nmi, 0, 0
1059#ifdef CONFIG_TRACE_IRQFLAGS
1060 paranoidexit 0
1061#else
1062 jmp paranoid_exit1
1063 CFI_ENDPROC
1064#endif
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001065KPROBE_END(nmi)
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001066
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001067KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001068 INTR_FRAME
1069 pushq $0
1070 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001071 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001072 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001073 CFI_ENDPROC
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001074KPROBE_END(int3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076ENTRY(overflow)
1077 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001078END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080ENTRY(bounds)
1081 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001082END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084ENTRY(invalid_op)
1085 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001086END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088ENTRY(coprocessor_segment_overrun)
1089 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001090END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092ENTRY(reserved)
1093 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001094END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096 /* runs on exception stack */
1097ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001098 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001100 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001102END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104ENTRY(invalid_TSS)
1105 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001106END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108ENTRY(segment_not_present)
1109 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001110END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 /* runs on exception stack */
1113ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001114 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001116 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001118END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001120KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 errorentry do_general_protection
Prasanna S.Pd28c4392006-09-26 10:52:34 +02001122KPROBE_END(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124ENTRY(alignment_check)
1125 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001126END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128ENTRY(divide_error)
1129 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001130END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132ENTRY(spurious_interrupt_bug)
1133 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001134END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136#ifdef CONFIG_X86_MCE
1137 /* runs on exception stack */
1138ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001139 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 pushq $0
1141 CFI_ADJUST_CFA_OFFSET 8
1142 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001143 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001145END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146#endif
1147
Andi Kleen26995002006-08-02 22:37:28 +02001148/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001149ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001150 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001151 push %rbp
1152 CFI_ADJUST_CFA_OFFSET 8
1153 CFI_REL_OFFSET rbp,0
1154 mov %rsp,%rbp
1155 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001156 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001157 cmove %gs:pda_irqstackptr,%rsp
1158 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001159 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001160 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001161 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001162 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001163 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001164 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001165 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001166ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001167
1168#ifdef CONFIG_STACK_UNWIND
1169ENTRY(arch_unwind_init_running)
1170 CFI_STARTPROC
1171 movq %r15, R15(%rdi)
1172 movq %r14, R14(%rdi)
1173 xchgq %rsi, %rdx
1174 movq %r13, R13(%rdi)
1175 movq %r12, R12(%rdi)
1176 xorl %eax, %eax
1177 movq %rbp, RBP(%rdi)
1178 movq %rbx, RBX(%rdi)
1179 movq (%rsp), %rcx
1180 movq %rax, R11(%rdi)
1181 movq %rax, R10(%rdi)
1182 movq %rax, R9(%rdi)
1183 movq %rax, R8(%rdi)
1184 movq %rax, RAX(%rdi)
1185 movq %rax, RCX(%rdi)
1186 movq %rax, RDX(%rdi)
1187 movq %rax, RSI(%rdi)
1188 movq %rax, RDI(%rdi)
1189 movq %rax, ORIG_RAX(%rdi)
1190 movq %rcx, RIP(%rdi)
1191 leaq 8(%rsp), %rcx
1192 movq $__KERNEL_CS, CS(%rdi)
1193 movq %rax, EFLAGS(%rdi)
1194 movq %rcx, RSP(%rdi)
1195 movq $__KERNEL_DS, SS(%rdi)
1196 jmpq *%rdx
1197 CFI_ENDPROC
1198ENDPROC(arch_unwind_init_running)
1199#endif