blob: aa8d8939abc1692df22e7000c226095a44167678 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/entry.S
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
6 * Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
7 *
8 * $Id$
9 */
10
11/*
12 * entry.S contains the system-call and fault low-level handling routines.
13 *
14 * NOTE: This code handles signal-recognition, which happens every time
15 * after an interrupt and after each system call.
16 *
17 * Normal syscalls and interrupts don't save a full stack frame, this is
18 * only done for syscall tracing, signals or fork/exec et.al.
19 *
20 * A note on terminology:
21 * - top of stack: Architecture defined interrupt frame from SS to RIP
22 * at the top of the kernel process stack.
23 * - partial stack frame: partially saved registers upto R11.
24 * - full stack frame: Like partial stack frame, but all register saved.
25 *
26 * TODO:
27 * - schedule it carefully for the final hardware.
28 */
29
30#define ASSEMBLY 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/linkage.h>
32#include <asm/segment.h>
33#include <asm/smp.h>
34#include <asm/cache.h>
35#include <asm/errno.h>
36#include <asm/dwarf2.h>
37#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020038#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/msr.h>
40#include <asm/unistd.h>
41#include <asm/thread_info.h>
42#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010043#include <asm/page.h>
Ingo Molnar2601e642006-07-03 00:24:45 -070044#include <asm/irqflags.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 .code64
47
Andi Kleendc37db42005-04-16 15:25:05 -070048#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#define retint_kernel retint_restore_args
50#endif
Ingo Molnar2601e642006-07-03 00:24:45 -070051
52
53.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
54#ifdef CONFIG_TRACE_IRQFLAGS
55 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
56 jnc 1f
57 TRACE_IRQS_ON
581:
59#endif
60.endm
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062/*
63 * C code is not supposed to know about undefined top of stack. Every time
64 * a C function with an pt_regs argument is called from the SYSCALL based
65 * fast path FIXUP_TOP_OF_STACK is needed.
66 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
67 * manipulation.
68 */
69
70 /* %rsp:at FRAMEEND */
71 .macro FIXUP_TOP_OF_STACK tmp
72 movq %gs:pda_oldrsp,\tmp
73 movq \tmp,RSP(%rsp)
74 movq $__USER_DS,SS(%rsp)
75 movq $__USER_CS,CS(%rsp)
76 movq $-1,RCX(%rsp)
77 movq R11(%rsp),\tmp /* get eflags */
78 movq \tmp,EFLAGS(%rsp)
79 .endm
80
81 .macro RESTORE_TOP_OF_STACK tmp,offset=0
82 movq RSP-\offset(%rsp),\tmp
83 movq \tmp,%gs:pda_oldrsp
84 movq EFLAGS-\offset(%rsp),\tmp
85 movq \tmp,R11-\offset(%rsp)
86 .endm
87
88 .macro FAKE_STACK_FRAME child_rip
89 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -070090 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 pushq %rax /* ss */
92 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020093 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 pushq %rax /* rsp */
95 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020096 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 pushq $(1<<9) /* eflags - interrupts on */
98 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +020099 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 pushq $__KERNEL_CS /* cs */
101 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200102 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 pushq \child_rip /* rip */
104 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200105 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 pushq %rax /* orig rax */
107 CFI_ADJUST_CFA_OFFSET 8
108 .endm
109
110 .macro UNFAKE_STACK_FRAME
111 addq $8*6, %rsp
112 CFI_ADJUST_CFA_OFFSET -(6*8)
113 .endm
114
Jan Beulich7effaa82005-09-12 18:49:24 +0200115 .macro CFI_DEFAULT_STACK start=1
116 .if \start
117 CFI_STARTPROC simple
118 CFI_DEF_CFA rsp,SS+8
119 .else
120 CFI_DEF_CFA_OFFSET SS+8
121 .endif
122 CFI_REL_OFFSET r15,R15
123 CFI_REL_OFFSET r14,R14
124 CFI_REL_OFFSET r13,R13
125 CFI_REL_OFFSET r12,R12
126 CFI_REL_OFFSET rbp,RBP
127 CFI_REL_OFFSET rbx,RBX
128 CFI_REL_OFFSET r11,R11
129 CFI_REL_OFFSET r10,R10
130 CFI_REL_OFFSET r9,R9
131 CFI_REL_OFFSET r8,R8
132 CFI_REL_OFFSET rax,RAX
133 CFI_REL_OFFSET rcx,RCX
134 CFI_REL_OFFSET rdx,RDX
135 CFI_REL_OFFSET rsi,RSI
136 CFI_REL_OFFSET rdi,RDI
137 CFI_REL_OFFSET rip,RIP
138 /*CFI_REL_OFFSET cs,CS*/
139 /*CFI_REL_OFFSET rflags,EFLAGS*/
140 CFI_REL_OFFSET rsp,RSP
141 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 .endm
143/*
144 * A newly forked process directly context switches into this.
145 */
146/* rdi: prev */
147ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 CFI_DEFAULT_STACK
149 call schedule_tail
150 GET_THREAD_INFO(%rcx)
151 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
152 jnz rff_trace
153rff_action:
154 RESTORE_REST
155 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
156 je int_ret_from_sys_call
157 testl $_TIF_IA32,threadinfo_flags(%rcx)
158 jnz int_ret_from_sys_call
159 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
160 jmp ret_from_sys_call
161rff_trace:
162 movq %rsp,%rdi
163 call syscall_trace_leave
164 GET_THREAD_INFO(%rcx)
165 jmp rff_action
166 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200167END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169/*
170 * System call entry. Upto 6 arguments in registers are supported.
171 *
172 * SYSCALL does not save anything on the stack and does not change the
173 * stack pointer.
174 */
175
176/*
177 * Register setup:
178 * rax system call number
179 * rdi arg0
180 * rcx return address for syscall/sysret, C arg3
181 * rsi arg1
182 * rdx arg2
183 * r10 arg3 (--> moved to rcx for C)
184 * r8 arg4
185 * r9 arg5
186 * r11 eflags for syscall/sysret, temporary for C
187 * r12-r15,rbp,rbx saved by C code, not touched.
188 *
189 * Interrupts are off on entry.
190 * Only called from user space.
191 *
192 * XXX if we had a free scratch register we could save the RSP into the stack frame
193 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200194 *
195 * When user can change the frames always force IRET. That is because
196 * it deals with uncanonical addresses better. SYSRET has trouble
197 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 */
199
200ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200201 CFI_STARTPROC simple
Jan Beulichdffead42006-06-26 13:57:38 +0200202 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200203 CFI_REGISTER rip,rcx
204 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 swapgs
206 movq %rsp,%gs:pda_oldrsp
207 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700208 /*
209 * No need to follow this irqs off/on section - it's straight
210 * and short:
211 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 sti
213 SAVE_ARGS 8,1
214 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200215 movq %rcx,RIP-ARGOFFSET(%rsp)
216 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 GET_THREAD_INFO(%rcx)
218 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200219 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 jnz tracesys
221 cmpq $__NR_syscall_max,%rax
222 ja badsys
223 movq %r10,%rcx
224 call *sys_call_table(,%rax,8) # XXX: rip relative
225 movq %rax,RAX-ARGOFFSET(%rsp)
226/*
227 * Syscall return path ending with SYSRET (fast path)
228 * Has incomplete stack frame and undefined top of stack.
229 */
230 .globl ret_from_sys_call
231ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700232 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 /* edi: flagmask */
234sysret_check:
235 GET_THREAD_INFO(%rcx)
236 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700237 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 movl threadinfo_flags(%rcx),%edx
239 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200240 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 jnz sysret_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700242 /*
243 * sysretq will re-enable interrupts:
244 */
245 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200247 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200249 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 movq %gs:pda_oldrsp,%rsp
251 swapgs
252 sysretq
253
254 /* Handle reschedules */
255 /* edx: work, edi: workmask */
256sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200257 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 bt $TIF_NEED_RESCHED,%edx
259 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700260 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 sti
262 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200263 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 call schedule
265 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200266 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 jmp sysret_check
268
269 /* Handle a signal */
270sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700271 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700273 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
274 jz 1f
275
276 /* Really a signal */
277 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 leaq do_notify_resume(%rip),%rax
279 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
280 xorl %esi,%esi # oldset -> arg2
281 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002821: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200283 /* Use IRET because user could have changed frame. This
284 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
285 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700286 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200287 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Jan Beulich7effaa82005-09-12 18:49:24 +0200289badsys:
290 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
291 jmp ret_from_sys_call
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* Do syscall tracing */
294tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200295 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 SAVE_REST
297 movq $-ENOSYS,RAX(%rsp)
298 FIXUP_TOP_OF_STACK %rdi
299 movq %rsp,%rdi
300 call syscall_trace_enter
301 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
302 RESTORE_REST
303 cmpq $__NR_syscall_max,%rax
304 ja 1f
305 movq %r10,%rcx /* fixup for C */
306 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02003071: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200308 /* Use IRET because user could have changed frame */
309 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200310 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200311END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313/*
314 * Syscall return path ending with IRET.
315 * Has correct top of stack, but partial stack frame.
316 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200317ENTRY(int_ret_from_sys_call)
318 CFI_STARTPROC simple
319 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
320 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
321 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
322 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
323 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
324 CFI_REL_OFFSET rip,RIP-ARGOFFSET
325 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
326 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
327 CFI_REL_OFFSET rax,RAX-ARGOFFSET
328 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
329 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
330 CFI_REL_OFFSET r8,R8-ARGOFFSET
331 CFI_REL_OFFSET r9,R9-ARGOFFSET
332 CFI_REL_OFFSET r10,R10-ARGOFFSET
333 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700335 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 testl $3,CS-ARGOFFSET(%rsp)
337 je retint_restore_args
338 movl $_TIF_ALLWORK_MASK,%edi
339 /* edi: mask to check */
340int_with_check:
341 GET_THREAD_INFO(%rcx)
342 movl threadinfo_flags(%rcx),%edx
343 andl %edi,%edx
344 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100345 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 jmp retint_swapgs
347
348 /* Either reschedule or signal or syscall exit tracking needed. */
349 /* First do a reschedule test. */
350 /* edx: work, edi: workmask */
351int_careful:
352 bt $TIF_NEED_RESCHED,%edx
353 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700354 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 sti
356 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200357 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 call schedule
359 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200360 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700361 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700362 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 jmp int_with_check
364
365 /* handle signals and tracing -- both require a full stack frame */
366int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700367 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 sti
369 SAVE_REST
370 /* Check for syscall exit trace */
371 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
372 jz int_signal
373 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200374 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 leaq 8(%rsp),%rdi # &ptregs -> arg1
376 call syscall_trace_leave
377 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200378 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700379 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700380 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700381 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 jmp int_restore_rest
383
384int_signal:
385 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
386 jz 1f
387 movq %rsp,%rdi # &ptregs -> arg1
388 xorl %esi,%esi # oldset -> arg2
389 call do_notify_resume
3901: movl $_TIF_NEED_RESCHED,%edi
391int_restore_rest:
392 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700393 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700394 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 jmp int_with_check
396 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200397END(int_ret_from_sys_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399/*
400 * Certain special system calls that need to save a complete full stack frame.
401 */
402
403 .macro PTREGSCALL label,func,arg
404 .globl \label
405\label:
406 leaq \func(%rip),%rax
407 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
408 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200409END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 .endm
411
Jan Beulich7effaa82005-09-12 18:49:24 +0200412 CFI_STARTPROC
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 PTREGSCALL stub_clone, sys_clone, %r8
415 PTREGSCALL stub_fork, sys_fork, %rdi
416 PTREGSCALL stub_vfork, sys_vfork, %rdi
417 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
418 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
419 PTREGSCALL stub_iopl, sys_iopl, %rsi
420
421ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200423 CFI_ADJUST_CFA_OFFSET -8
424 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 SAVE_REST
426 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200427 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 FIXUP_TOP_OF_STACK %r11
429 call *%rax
430 RESTORE_TOP_OF_STACK %r11
431 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200432 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 RESTORE_REST
434 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200435 CFI_ADJUST_CFA_OFFSET 8
436 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 ret
438 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200439END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441ENTRY(stub_execve)
442 CFI_STARTPROC
443 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200444 CFI_ADJUST_CFA_OFFSET -8
445 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 FIXUP_TOP_OF_STACK %r11
448 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 movq %rax,RAX(%rsp)
451 RESTORE_REST
452 jmp int_ret_from_sys_call
453 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200454END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456/*
457 * sigreturn is special because it needs to restore all registers on return.
458 * This cannot be done with SYSRET, so use the IRET return path instead.
459 */
460ENTRY(stub_rt_sigreturn)
461 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200462 addq $8, %rsp
463 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 SAVE_REST
465 movq %rsp,%rdi
466 FIXUP_TOP_OF_STACK %r11
467 call sys_rt_sigreturn
468 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
469 RESTORE_REST
470 jmp int_ret_from_sys_call
471 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200472END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Jan Beulich7effaa82005-09-12 18:49:24 +0200474/*
475 * initial frame state for interrupts and exceptions
476 */
477 .macro _frame ref
478 CFI_STARTPROC simple
479 CFI_DEF_CFA rsp,SS+8-\ref
480 /*CFI_REL_OFFSET ss,SS-\ref*/
481 CFI_REL_OFFSET rsp,RSP-\ref
482 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
483 /*CFI_REL_OFFSET cs,CS-\ref*/
484 CFI_REL_OFFSET rip,RIP-\ref
485 .endm
486
487/* initial frame state for interrupts (and exceptions without error code) */
488#define INTR_FRAME _frame RIP
489/* initial frame state for exceptions with error code (and interrupts with
490 vector already pushed) */
491#define XCPT_FRAME _frame ORIG_RAX
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493/*
494 * Interrupt entry/exit.
495 *
496 * Interrupt entry points save only callee clobbered registers in fast path.
497 *
498 * Entry runs with interrupts off.
499 */
500
501/* 0(%rsp): interrupt number */
502 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 SAVE_ARGS
505 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200506 pushq %rbp
507 CFI_ADJUST_CFA_OFFSET 8
508 CFI_REL_OFFSET rbp, 0
509 movq %rsp,%rbp
510 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 testl $3,CS(%rdi)
512 je 1f
513 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07005141: incl %gs:pda_irqcount # RED-PEN should check preempt count
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200515 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200516 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700517 /*
518 * We entered an interrupt context - irqs are off:
519 */
520 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 call \func
522 .endm
523
524ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200525 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 interrupt do_IRQ
527 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200528ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700530 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700531 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200532 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200533 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200534 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200535exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 GET_THREAD_INFO(%rcx)
537 testl $3,CS-ARGOFFSET(%rsp)
538 je retint_kernel
539
540 /* Interrupt came from user space */
541 /*
542 * Has a correct top of stack, but a partial stack frame
543 * %rcx: thread info. Interrupts off.
544 */
545retint_with_reschedule:
546 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200547retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 movl threadinfo_flags(%rcx),%edx
549 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200550 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 jnz retint_careful
552retint_swapgs:
Ingo Molnar2601e642006-07-03 00:24:45 -0700553 /*
554 * The iretq could re-enable interrupts:
555 */
556 cli
557 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700559 jmp restore_args
560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561retint_restore_args:
562 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700563 /*
564 * The iretq could re-enable interrupts:
565 */
566 TRACE_IRQS_IRETQ
567restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 RESTORE_ARGS 0,8,0
569iret_label:
570 iretq
571
572 .section __ex_table,"a"
573 .quad iret_label,bad_iret
574 .previous
575 .section .fixup,"ax"
576 /* force a signal here? this matches i386 behaviour */
577 /* running with kernel gs */
578bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100579 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700580 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100581 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 jmp do_exit
583 .previous
584
Jan Beulich7effaa82005-09-12 18:49:24 +0200585 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200587 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 bt $TIF_NEED_RESCHED,%edx
589 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700590 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 sti
592 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200593 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 call schedule
595 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200596 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 GET_THREAD_INFO(%rcx)
598 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700599 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 jmp retint_check
601
602retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700603 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
604 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700605 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 sti
607 SAVE_REST
608 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700609 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 movq %rsp,%rdi # &pt_regs
611 call do_notify_resume
612 RESTORE_REST
613 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700614 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700615 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700616 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 jmp retint_check
618
619#ifdef CONFIG_PREEMPT
620 /* Returning to kernel space. Check if we need preemption */
621 /* rcx: threadinfo. interrupts off. */
622 .p2align
623retint_kernel:
624 cmpl $0,threadinfo_preempt_count(%rcx)
625 jnz retint_restore_args
626 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
627 jnc retint_restore_args
628 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
629 jnc retint_restore_args
630 call preempt_schedule_irq
631 jmp exit_intr
632#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200635END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637/*
638 * APIC interrupts.
639 */
640 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200641 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700642 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200643 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 interrupt \func
645 jmp ret_from_intr
646 CFI_ENDPROC
647 .endm
648
649ENTRY(thermal_interrupt)
650 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200651END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Jacob Shin89b831e2005-11-05 17:25:53 +0100653ENTRY(threshold_interrupt)
654 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200655END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657#ifdef CONFIG_SMP
658ENTRY(reschedule_interrupt)
659 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200660END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Andi Kleene5bc8b62005-09-12 18:49:24 +0200662 .macro INVALIDATE_ENTRY num
663ENTRY(invalidate_interrupt\num)
664 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200665END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200666 .endm
667
668 INVALIDATE_ENTRY 0
669 INVALIDATE_ENTRY 1
670 INVALIDATE_ENTRY 2
671 INVALIDATE_ENTRY 3
672 INVALIDATE_ENTRY 4
673 INVALIDATE_ENTRY 5
674 INVALIDATE_ENTRY 6
675 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677ENTRY(call_function_interrupt)
678 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200679END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680#endif
681
682#ifdef CONFIG_X86_LOCAL_APIC
683ENTRY(apic_timer_interrupt)
684 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200685END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687ENTRY(error_interrupt)
688 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200689END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691ENTRY(spurious_interrupt)
692 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200693END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694#endif
695
696/*
697 * Exception entry points.
698 */
699 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200700 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200702 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200704 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 leaq \sym(%rip),%rax
706 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200707 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 .endm
709
710 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200711 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200713 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 leaq \sym(%rip),%rax
715 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200716 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 .endm
718
719 /* error code is on the stack already */
720 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700721 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 SAVE_ALL
723 cld
724 movl $1,%ebx
725 movl $MSR_GS_BASE,%ecx
726 rdmsr
727 testl %edx,%edx
728 js 1f
729 swapgs
730 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01007311:
732 .if \ist
733 movq %gs:pda_data_offset, %rbp
734 .endif
735 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 movq ORIG_RAX(%rsp),%rsi
737 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100738 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100739 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100740 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100742 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100743 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100744 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700745 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700746 .if \irqtrace
747 TRACE_IRQS_OFF
748 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700750
751 /*
752 * "Paranoid" exit path from exception stack.
753 * Paranoid because this is used by NMIs and cannot take
754 * any kernel state for granted.
755 * We don't do kernel preemption checks here, because only
756 * NMI should be common and it does not enable IRQs and
757 * cannot get reschedule ticks.
758 *
759 * "trace" is 0 for the NMI handler only, because irq-tracing
760 * is fundamentally NMI-unsafe. (we cannot change the soft and
761 * hard flags at once, atomically)
762 */
763 .macro paranoidexit trace=1
764 /* ebx: no swapgs flag */
765paranoid_exit\trace:
766 testl %ebx,%ebx /* swapgs needed? */
767 jnz paranoid_restore\trace
768 testl $3,CS(%rsp)
769 jnz paranoid_userspace\trace
770paranoid_swapgs\trace:
771 TRACE_IRQS_IRETQ 0
772 swapgs
773paranoid_restore\trace:
774 RESTORE_ALL 8
775 iretq
776paranoid_userspace\trace:
777 GET_THREAD_INFO(%rcx)
778 movl threadinfo_flags(%rcx),%ebx
779 andl $_TIF_WORK_MASK,%ebx
780 jz paranoid_swapgs\trace
781 movq %rsp,%rdi /* &pt_regs */
782 call sync_regs
783 movq %rax,%rsp /* switch stack for scheduling */
784 testl $_TIF_NEED_RESCHED,%ebx
785 jnz paranoid_schedule\trace
786 movl %ebx,%edx /* arg3: thread flags */
787 .if \trace
788 TRACE_IRQS_ON
789 .endif
790 sti
791 xorl %esi,%esi /* arg2: oldset */
792 movq %rsp,%rdi /* arg1: &pt_regs */
793 call do_notify_resume
794 cli
795 .if \trace
796 TRACE_IRQS_OFF
797 .endif
798 jmp paranoid_userspace\trace
799paranoid_schedule\trace:
800 .if \trace
801 TRACE_IRQS_ON
802 .endif
803 sti
804 call schedule
805 cli
806 .if \trace
807 TRACE_IRQS_OFF
808 .endif
809 jmp paranoid_userspace\trace
810 CFI_ENDPROC
811 .endm
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813/*
814 * Exception entry point. This expects an error code/orig_rax on the stack
815 * and the exception handler in %rax.
816 */
817ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200818 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 /* rdi slot contains rax, oldrax contains error code */
820 cld
821 subq $14*8,%rsp
822 CFI_ADJUST_CFA_OFFSET (14*8)
823 movq %rsi,13*8(%rsp)
824 CFI_REL_OFFSET rsi,RSI
825 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
826 movq %rdx,12*8(%rsp)
827 CFI_REL_OFFSET rdx,RDX
828 movq %rcx,11*8(%rsp)
829 CFI_REL_OFFSET rcx,RCX
830 movq %rsi,10*8(%rsp) /* store rax */
831 CFI_REL_OFFSET rax,RAX
832 movq %r8, 9*8(%rsp)
833 CFI_REL_OFFSET r8,R8
834 movq %r9, 8*8(%rsp)
835 CFI_REL_OFFSET r9,R9
836 movq %r10,7*8(%rsp)
837 CFI_REL_OFFSET r10,R10
838 movq %r11,6*8(%rsp)
839 CFI_REL_OFFSET r11,R11
840 movq %rbx,5*8(%rsp)
841 CFI_REL_OFFSET rbx,RBX
842 movq %rbp,4*8(%rsp)
843 CFI_REL_OFFSET rbp,RBP
844 movq %r12,3*8(%rsp)
845 CFI_REL_OFFSET r12,R12
846 movq %r13,2*8(%rsp)
847 CFI_REL_OFFSET r13,R13
848 movq %r14,1*8(%rsp)
849 CFI_REL_OFFSET r14,R14
850 movq %r15,(%rsp)
851 CFI_REL_OFFSET r15,R15
852 xorl %ebx,%ebx
853 testl $3,CS(%rsp)
854 je error_kernelspace
855error_swapgs:
856 swapgs
857error_sti:
858 movq %rdi,RDI(%rsp)
859 movq %rsp,%rdi
860 movq ORIG_RAX(%rsp),%rsi /* get error code */
861 movq $-1,ORIG_RAX(%rsp)
862 call *%rax
863 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
864error_exit:
865 movl %ebx,%eax
866 RESTORE_REST
867 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700868 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 GET_THREAD_INFO(%rcx)
870 testl %eax,%eax
871 jne retint_kernel
872 movl threadinfo_flags(%rcx),%edx
873 movl $_TIF_WORK_MASK,%edi
874 andl %edi,%edx
875 jnz retint_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700876 /*
877 * The iret might restore flags:
878 */
879 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 swapgs
881 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100882 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 CFI_ENDPROC
884
885error_kernelspace:
886 incl %ebx
887 /* There are two places in the kernel that can potentially fault with
888 usergs. Handle them here. The exception handlers after
889 iret run with kernel gs again, so don't set the user space flag.
890 B stepping K8s sometimes report an truncated RIP for IRET
891 exceptions returning to compat mode. Check for these here too. */
892 leaq iret_label(%rip),%rbp
893 cmpq %rbp,RIP(%rsp)
894 je error_swapgs
895 movl %ebp,%ebp /* zero extend */
896 cmpq %rbp,RIP(%rsp)
897 je error_swapgs
898 cmpq $gs_change,RIP(%rsp)
899 je error_swapgs
900 jmp error_sti
Jan Beulich4b787e02006-06-26 13:56:55 +0200901END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903 /* Reload gs selector with exception handling */
904 /* edi: new selector */
905ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200906 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200908 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 cli
910 swapgs
911gs_change:
912 movl %edi,%gs
9132: mfence /* workaround */
914 swapgs
915 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200916 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200918 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200919ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 .section __ex_table,"a"
922 .align 8
923 .quad gs_change,bad_gs
924 .previous
925 .section .fixup,"ax"
926 /* running with kernelgs */
927bad_gs:
928 swapgs /* switch back to user gs */
929 xorl %eax,%eax
930 movl %eax,%gs
931 jmp 2b
932 .previous
933
934/*
935 * Create a kernel thread.
936 *
937 * C extern interface:
938 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
939 *
940 * asm input arguments:
941 * rdi: fn, rsi: arg, rdx: flags
942 */
943ENTRY(kernel_thread)
944 CFI_STARTPROC
945 FAKE_STACK_FRAME $child_rip
946 SAVE_ALL
947
948 # rdi: flags, rsi: usp, rdx: will be &pt_regs
949 movq %rdx,%rdi
950 orq kernel_thread_flags(%rip),%rdi
951 movq $-1, %rsi
952 movq %rsp, %rdx
953
954 xorl %r8d,%r8d
955 xorl %r9d,%r9d
956
957 # clone now
958 call do_fork
959 movq %rax,RAX(%rsp)
960 xorl %edi,%edi
961
962 /*
963 * It isn't worth to check for reschedule here,
964 * so internally to the x86_64 port you can rely on kernel_thread()
965 * not to reschedule the child before returning, this avoids the need
966 * of hacks for example to fork off the per-CPU idle tasks.
967 * [Hopefully no generic code relies on the reschedule -AK]
968 */
969 RESTORE_ALL
970 UNFAKE_STACK_FRAME
971 ret
972 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200973ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +0200976 pushq $0 # fake return address
977 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 /*
979 * Here we are in the child and the registers are set as they were
980 * at kernel_thread() invocation in the parent.
981 */
982 movq %rdi, %rax
983 movq %rsi, %rdi
984 call *%rax
985 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700986 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +0200988 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200989ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991/*
992 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
993 *
994 * C extern interface:
995 * extern long execve(char *name, char **argv, char **envp)
996 *
997 * asm input arguments:
998 * rdi: name, rsi: argv, rdx: envp
999 *
1000 * We want to fallback into:
1001 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
1002 *
1003 * do_sys_execve asm fallback arguments:
1004 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1005 */
1006ENTRY(execve)
1007 CFI_STARTPROC
1008 FAKE_STACK_FRAME $0
1009 SAVE_ALL
1010 call sys_execve
1011 movq %rax, RAX(%rsp)
1012 RESTORE_REST
1013 testq %rax,%rax
1014 je int_ret_from_sys_call
1015 RESTORE_ARGS
1016 UNFAKE_STACK_FRAME
1017 ret
1018 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001019ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001021KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 errorentry do_page_fault
Jan Beulich4b787e02006-06-26 13:56:55 +02001023END(page_fault)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001024 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026ENTRY(coprocessor_error)
1027 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001028END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030ENTRY(simd_coprocessor_error)
1031 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001032END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034ENTRY(device_not_available)
1035 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001036END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001039KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001040 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 pushq $0
1042 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001043 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001044 paranoidexit
Jan Beulich4b787e02006-06-26 13:56:55 +02001045END(debug)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001046 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
1048 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001049KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001050 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001052 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001053 paranoidentry do_nmi, 0, 0
1054#ifdef CONFIG_TRACE_IRQFLAGS
1055 paranoidexit 0
1056#else
1057 jmp paranoid_exit1
1058 CFI_ENDPROC
1059#endif
Jan Beulich4b787e02006-06-26 13:56:55 +02001060END(nmi)
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001061 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001062
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001063KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001064 INTR_FRAME
1065 pushq $0
1066 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001067 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001068 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001069 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001070END(int3)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001071 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073ENTRY(overflow)
1074 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001075END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077ENTRY(bounds)
1078 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001079END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
1081ENTRY(invalid_op)
1082 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001083END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085ENTRY(coprocessor_segment_overrun)
1086 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001087END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089ENTRY(reserved)
1090 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001091END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093 /* runs on exception stack */
1094ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001095 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001097 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001099END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101ENTRY(invalid_TSS)
1102 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001103END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105ENTRY(segment_not_present)
1106 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001107END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 /* runs on exception stack */
1110ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001111 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001113 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001115END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001117KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 errorentry do_general_protection
Jan Beulich4b787e02006-06-26 13:56:55 +02001119END(general_protection)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001120 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122ENTRY(alignment_check)
1123 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001124END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126ENTRY(divide_error)
1127 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001128END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130ENTRY(spurious_interrupt_bug)
1131 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001132END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134#ifdef CONFIG_X86_MCE
1135 /* runs on exception stack */
1136ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001137 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 pushq $0
1139 CFI_ADJUST_CFA_OFFSET 8
1140 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001141 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001143END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144#endif
1145
Andi Kleen26995002006-08-02 22:37:28 +02001146/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001147ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001148 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001149 push %rbp
1150 CFI_ADJUST_CFA_OFFSET 8
1151 CFI_REL_OFFSET rbp,0
1152 mov %rsp,%rbp
1153 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001154 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001155 cmove %gs:pda_irqstackptr,%rsp
1156 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001157 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001158 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001159 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001160 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001161 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001162 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001163 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001164ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001165
1166#ifdef CONFIG_STACK_UNWIND
1167ENTRY(arch_unwind_init_running)
1168 CFI_STARTPROC
1169 movq %r15, R15(%rdi)
1170 movq %r14, R14(%rdi)
1171 xchgq %rsi, %rdx
1172 movq %r13, R13(%rdi)
1173 movq %r12, R12(%rdi)
1174 xorl %eax, %eax
1175 movq %rbp, RBP(%rdi)
1176 movq %rbx, RBX(%rdi)
1177 movq (%rsp), %rcx
1178 movq %rax, R11(%rdi)
1179 movq %rax, R10(%rdi)
1180 movq %rax, R9(%rdi)
1181 movq %rax, R8(%rdi)
1182 movq %rax, RAX(%rdi)
1183 movq %rax, RCX(%rdi)
1184 movq %rax, RDX(%rdi)
1185 movq %rax, RSI(%rdi)
1186 movq %rax, RDI(%rdi)
1187 movq %rax, ORIG_RAX(%rdi)
1188 movq %rcx, RIP(%rdi)
1189 leaq 8(%rsp), %rcx
1190 movq $__KERNEL_CS, CS(%rdi)
1191 movq %rax, EFLAGS(%rdi)
1192 movq %rcx, RSP(%rdi)
1193 movq $__KERNEL_DS, SS(%rdi)
1194 jmpq *%rdx
1195 CFI_ENDPROC
1196ENDPROC(arch_unwind_init_running)
1197#endif