blob: d464dded68c0eb363e1ca848cb5563d34a74b724 [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
Ingo Molnar2601e642006-07-03 00:24:45 -0700516 /*
517 * We entered an interrupt context - irqs are off:
518 */
519 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 call \func
521 .endm
522
523ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200524 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 interrupt do_IRQ
526 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200527ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700529 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700530 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200531 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200532 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200533 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200534exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 GET_THREAD_INFO(%rcx)
536 testl $3,CS-ARGOFFSET(%rsp)
537 je retint_kernel
538
539 /* Interrupt came from user space */
540 /*
541 * Has a correct top of stack, but a partial stack frame
542 * %rcx: thread info. Interrupts off.
543 */
544retint_with_reschedule:
545 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200546retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 movl threadinfo_flags(%rcx),%edx
548 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200549 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 jnz retint_careful
551retint_swapgs:
Ingo Molnar2601e642006-07-03 00:24:45 -0700552 /*
553 * The iretq could re-enable interrupts:
554 */
555 cli
556 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700558 jmp restore_args
559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560retint_restore_args:
561 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700562 /*
563 * The iretq could re-enable interrupts:
564 */
565 TRACE_IRQS_IRETQ
566restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 RESTORE_ARGS 0,8,0
568iret_label:
569 iretq
570
571 .section __ex_table,"a"
572 .quad iret_label,bad_iret
573 .previous
574 .section .fixup,"ax"
575 /* force a signal here? this matches i386 behaviour */
576 /* running with kernel gs */
577bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100578 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700579 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100580 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 jmp do_exit
582 .previous
583
Jan Beulich7effaa82005-09-12 18:49:24 +0200584 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200586 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 bt $TIF_NEED_RESCHED,%edx
588 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700589 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 sti
591 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200592 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 call schedule
594 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200595 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 GET_THREAD_INFO(%rcx)
597 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700598 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 jmp retint_check
600
601retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700602 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
603 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700604 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 sti
606 SAVE_REST
607 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700608 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 movq %rsp,%rdi # &pt_regs
610 call do_notify_resume
611 RESTORE_REST
612 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700613 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700614 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700615 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 jmp retint_check
617
618#ifdef CONFIG_PREEMPT
619 /* Returning to kernel space. Check if we need preemption */
620 /* rcx: threadinfo. interrupts off. */
621 .p2align
622retint_kernel:
623 cmpl $0,threadinfo_preempt_count(%rcx)
624 jnz retint_restore_args
625 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
626 jnc retint_restore_args
627 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
628 jnc retint_restore_args
629 call preempt_schedule_irq
630 jmp exit_intr
631#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200634END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636/*
637 * APIC interrupts.
638 */
639 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200640 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700641 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200642 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 interrupt \func
644 jmp ret_from_intr
645 CFI_ENDPROC
646 .endm
647
648ENTRY(thermal_interrupt)
649 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200650END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Jacob Shin89b831e2005-11-05 17:25:53 +0100652ENTRY(threshold_interrupt)
653 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200654END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656#ifdef CONFIG_SMP
657ENTRY(reschedule_interrupt)
658 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200659END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Andi Kleene5bc8b62005-09-12 18:49:24 +0200661 .macro INVALIDATE_ENTRY num
662ENTRY(invalidate_interrupt\num)
663 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200664END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200665 .endm
666
667 INVALIDATE_ENTRY 0
668 INVALIDATE_ENTRY 1
669 INVALIDATE_ENTRY 2
670 INVALIDATE_ENTRY 3
671 INVALIDATE_ENTRY 4
672 INVALIDATE_ENTRY 5
673 INVALIDATE_ENTRY 6
674 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676ENTRY(call_function_interrupt)
677 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200678END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679#endif
680
681#ifdef CONFIG_X86_LOCAL_APIC
682ENTRY(apic_timer_interrupt)
683 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200684END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686ENTRY(error_interrupt)
687 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200688END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690ENTRY(spurious_interrupt)
691 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200692END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693#endif
694
695/*
696 * Exception entry points.
697 */
698 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200699 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200701 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200703 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 leaq \sym(%rip),%rax
705 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200706 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 .endm
708
709 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200710 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200712 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 leaq \sym(%rip),%rax
714 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200715 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 .endm
717
718 /* error code is on the stack already */
719 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700720 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 SAVE_ALL
722 cld
723 movl $1,%ebx
724 movl $MSR_GS_BASE,%ecx
725 rdmsr
726 testl %edx,%edx
727 js 1f
728 swapgs
729 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01007301:
731 .if \ist
732 movq %gs:pda_data_offset, %rbp
733 .endif
734 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 movq ORIG_RAX(%rsp),%rsi
736 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100737 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100738 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100739 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100741 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100742 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100743 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700744 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700745 .if \irqtrace
746 TRACE_IRQS_OFF
747 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700749
750 /*
751 * "Paranoid" exit path from exception stack.
752 * Paranoid because this is used by NMIs and cannot take
753 * any kernel state for granted.
754 * We don't do kernel preemption checks here, because only
755 * NMI should be common and it does not enable IRQs and
756 * cannot get reschedule ticks.
757 *
758 * "trace" is 0 for the NMI handler only, because irq-tracing
759 * is fundamentally NMI-unsafe. (we cannot change the soft and
760 * hard flags at once, atomically)
761 */
762 .macro paranoidexit trace=1
763 /* ebx: no swapgs flag */
764paranoid_exit\trace:
765 testl %ebx,%ebx /* swapgs needed? */
766 jnz paranoid_restore\trace
767 testl $3,CS(%rsp)
768 jnz paranoid_userspace\trace
769paranoid_swapgs\trace:
770 TRACE_IRQS_IRETQ 0
771 swapgs
772paranoid_restore\trace:
773 RESTORE_ALL 8
774 iretq
775paranoid_userspace\trace:
776 GET_THREAD_INFO(%rcx)
777 movl threadinfo_flags(%rcx),%ebx
778 andl $_TIF_WORK_MASK,%ebx
779 jz paranoid_swapgs\trace
780 movq %rsp,%rdi /* &pt_regs */
781 call sync_regs
782 movq %rax,%rsp /* switch stack for scheduling */
783 testl $_TIF_NEED_RESCHED,%ebx
784 jnz paranoid_schedule\trace
785 movl %ebx,%edx /* arg3: thread flags */
786 .if \trace
787 TRACE_IRQS_ON
788 .endif
789 sti
790 xorl %esi,%esi /* arg2: oldset */
791 movq %rsp,%rdi /* arg1: &pt_regs */
792 call do_notify_resume
793 cli
794 .if \trace
795 TRACE_IRQS_OFF
796 .endif
797 jmp paranoid_userspace\trace
798paranoid_schedule\trace:
799 .if \trace
800 TRACE_IRQS_ON
801 .endif
802 sti
803 call schedule
804 cli
805 .if \trace
806 TRACE_IRQS_OFF
807 .endif
808 jmp paranoid_userspace\trace
809 CFI_ENDPROC
810 .endm
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812/*
813 * Exception entry point. This expects an error code/orig_rax on the stack
814 * and the exception handler in %rax.
815 */
816ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200817 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 /* rdi slot contains rax, oldrax contains error code */
819 cld
820 subq $14*8,%rsp
821 CFI_ADJUST_CFA_OFFSET (14*8)
822 movq %rsi,13*8(%rsp)
823 CFI_REL_OFFSET rsi,RSI
824 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
825 movq %rdx,12*8(%rsp)
826 CFI_REL_OFFSET rdx,RDX
827 movq %rcx,11*8(%rsp)
828 CFI_REL_OFFSET rcx,RCX
829 movq %rsi,10*8(%rsp) /* store rax */
830 CFI_REL_OFFSET rax,RAX
831 movq %r8, 9*8(%rsp)
832 CFI_REL_OFFSET r8,R8
833 movq %r9, 8*8(%rsp)
834 CFI_REL_OFFSET r9,R9
835 movq %r10,7*8(%rsp)
836 CFI_REL_OFFSET r10,R10
837 movq %r11,6*8(%rsp)
838 CFI_REL_OFFSET r11,R11
839 movq %rbx,5*8(%rsp)
840 CFI_REL_OFFSET rbx,RBX
841 movq %rbp,4*8(%rsp)
842 CFI_REL_OFFSET rbp,RBP
843 movq %r12,3*8(%rsp)
844 CFI_REL_OFFSET r12,R12
845 movq %r13,2*8(%rsp)
846 CFI_REL_OFFSET r13,R13
847 movq %r14,1*8(%rsp)
848 CFI_REL_OFFSET r14,R14
849 movq %r15,(%rsp)
850 CFI_REL_OFFSET r15,R15
851 xorl %ebx,%ebx
852 testl $3,CS(%rsp)
853 je error_kernelspace
854error_swapgs:
855 swapgs
856error_sti:
857 movq %rdi,RDI(%rsp)
858 movq %rsp,%rdi
859 movq ORIG_RAX(%rsp),%rsi /* get error code */
860 movq $-1,ORIG_RAX(%rsp)
861 call *%rax
862 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
863error_exit:
864 movl %ebx,%eax
865 RESTORE_REST
866 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700867 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 GET_THREAD_INFO(%rcx)
869 testl %eax,%eax
870 jne retint_kernel
871 movl threadinfo_flags(%rcx),%edx
872 movl $_TIF_WORK_MASK,%edi
873 andl %edi,%edx
874 jnz retint_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700875 /*
876 * The iret might restore flags:
877 */
878 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 swapgs
880 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100881 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 CFI_ENDPROC
883
884error_kernelspace:
885 incl %ebx
886 /* There are two places in the kernel that can potentially fault with
887 usergs. Handle them here. The exception handlers after
888 iret run with kernel gs again, so don't set the user space flag.
889 B stepping K8s sometimes report an truncated RIP for IRET
890 exceptions returning to compat mode. Check for these here too. */
891 leaq iret_label(%rip),%rbp
892 cmpq %rbp,RIP(%rsp)
893 je error_swapgs
894 movl %ebp,%ebp /* zero extend */
895 cmpq %rbp,RIP(%rsp)
896 je error_swapgs
897 cmpq $gs_change,RIP(%rsp)
898 je error_swapgs
899 jmp error_sti
Jan Beulich4b787e02006-06-26 13:56:55 +0200900END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 /* Reload gs selector with exception handling */
903 /* edi: new selector */
904ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200905 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200907 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 cli
909 swapgs
910gs_change:
911 movl %edi,%gs
9122: mfence /* workaround */
913 swapgs
914 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200915 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200917 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200918ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 .section __ex_table,"a"
921 .align 8
922 .quad gs_change,bad_gs
923 .previous
924 .section .fixup,"ax"
925 /* running with kernelgs */
926bad_gs:
927 swapgs /* switch back to user gs */
928 xorl %eax,%eax
929 movl %eax,%gs
930 jmp 2b
931 .previous
932
933/*
934 * Create a kernel thread.
935 *
936 * C extern interface:
937 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
938 *
939 * asm input arguments:
940 * rdi: fn, rsi: arg, rdx: flags
941 */
942ENTRY(kernel_thread)
943 CFI_STARTPROC
944 FAKE_STACK_FRAME $child_rip
945 SAVE_ALL
946
947 # rdi: flags, rsi: usp, rdx: will be &pt_regs
948 movq %rdx,%rdi
949 orq kernel_thread_flags(%rip),%rdi
950 movq $-1, %rsi
951 movq %rsp, %rdx
952
953 xorl %r8d,%r8d
954 xorl %r9d,%r9d
955
956 # clone now
957 call do_fork
958 movq %rax,RAX(%rsp)
959 xorl %edi,%edi
960
961 /*
962 * It isn't worth to check for reschedule here,
963 * so internally to the x86_64 port you can rely on kernel_thread()
964 * not to reschedule the child before returning, this avoids the need
965 * of hacks for example to fork off the per-CPU idle tasks.
966 * [Hopefully no generic code relies on the reschedule -AK]
967 */
968 RESTORE_ALL
969 UNFAKE_STACK_FRAME
970 ret
971 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200972ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974child_rip:
975 /*
976 * Here we are in the child and the registers are set as they were
977 * at kernel_thread() invocation in the parent.
978 */
979 movq %rdi, %rax
980 movq %rsi, %rdi
981 call *%rax
982 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700983 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 call do_exit
Jan Beulich4b787e02006-06-26 13:56:55 +0200985ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987/*
988 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
989 *
990 * C extern interface:
991 * extern long execve(char *name, char **argv, char **envp)
992 *
993 * asm input arguments:
994 * rdi: name, rsi: argv, rdx: envp
995 *
996 * We want to fallback into:
997 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
998 *
999 * do_sys_execve asm fallback arguments:
1000 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1001 */
1002ENTRY(execve)
1003 CFI_STARTPROC
1004 FAKE_STACK_FRAME $0
1005 SAVE_ALL
1006 call sys_execve
1007 movq %rax, RAX(%rsp)
1008 RESTORE_REST
1009 testq %rax,%rax
1010 je int_ret_from_sys_call
1011 RESTORE_ARGS
1012 UNFAKE_STACK_FRAME
1013 ret
1014 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001015ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001017KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 errorentry do_page_fault
Jan Beulich4b787e02006-06-26 13:56:55 +02001019END(page_fault)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001020 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022ENTRY(coprocessor_error)
1023 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001024END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026ENTRY(simd_coprocessor_error)
1027 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001028END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030ENTRY(device_not_available)
1031 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001032END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001035KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001036 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 pushq $0
1038 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001039 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001040 paranoidexit
Jan Beulich4b787e02006-06-26 13:56:55 +02001041END(debug)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001042 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001045KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001046 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001048 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001049 paranoidentry do_nmi, 0, 0
1050#ifdef CONFIG_TRACE_IRQFLAGS
1051 paranoidexit 0
1052#else
1053 jmp paranoid_exit1
1054 CFI_ENDPROC
1055#endif
Jan Beulich4b787e02006-06-26 13:56:55 +02001056END(nmi)
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001057 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001058
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001059KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001060 INTR_FRAME
1061 pushq $0
1062 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001063 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001064 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001065 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001066END(int3)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001067 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069ENTRY(overflow)
1070 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001071END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073ENTRY(bounds)
1074 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001075END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077ENTRY(invalid_op)
1078 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001079END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
1081ENTRY(coprocessor_segment_overrun)
1082 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001083END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085ENTRY(reserved)
1086 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001087END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 /* runs on exception stack */
1090ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001091 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001093 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001095END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097ENTRY(invalid_TSS)
1098 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001099END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101ENTRY(segment_not_present)
1102 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001103END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 /* runs on exception stack */
1106ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001107 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001109 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001111END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001113KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 errorentry do_general_protection
Jan Beulich4b787e02006-06-26 13:56:55 +02001115END(general_protection)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001116 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118ENTRY(alignment_check)
1119 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001120END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122ENTRY(divide_error)
1123 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001124END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126ENTRY(spurious_interrupt_bug)
1127 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001128END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130#ifdef CONFIG_X86_MCE
1131 /* runs on exception stack */
1132ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001133 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 pushq $0
1135 CFI_ADJUST_CFA_OFFSET 8
1136 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001137 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001139END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140#endif
1141
Andi Kleened6b6762005-07-28 21:15:49 -07001142ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001143 CFI_STARTPROC
Andi Kleened6b6762005-07-28 21:15:49 -07001144 movq %gs:pda_irqstackptr,%rax
Jan Beulichbd9cb642006-01-11 22:43:21 +01001145 movq %rsp,%rdx
1146 CFI_DEF_CFA_REGISTER rdx
Andi Kleened6b6762005-07-28 21:15:49 -07001147 incl %gs:pda_irqcount
1148 cmove %rax,%rsp
Jan Beulichbd9cb642006-01-11 22:43:21 +01001149 pushq %rdx
1150 /*todo CFI_DEF_CFA_EXPRESSION ...*/
Andi Kleened6b6762005-07-28 21:15:49 -07001151 call __do_softirq
Jan Beulichbd9cb642006-01-11 22:43:21 +01001152 popq %rsp
Jan Beulich7effaa82005-09-12 18:49:24 +02001153 CFI_DEF_CFA_REGISTER rsp
Andi Kleened6b6762005-07-28 21:15:49 -07001154 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001155 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001156 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001157ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001158
1159#ifdef CONFIG_STACK_UNWIND
1160ENTRY(arch_unwind_init_running)
1161 CFI_STARTPROC
1162 movq %r15, R15(%rdi)
1163 movq %r14, R14(%rdi)
1164 xchgq %rsi, %rdx
1165 movq %r13, R13(%rdi)
1166 movq %r12, R12(%rdi)
1167 xorl %eax, %eax
1168 movq %rbp, RBP(%rdi)
1169 movq %rbx, RBX(%rdi)
1170 movq (%rsp), %rcx
1171 movq %rax, R11(%rdi)
1172 movq %rax, R10(%rdi)
1173 movq %rax, R9(%rdi)
1174 movq %rax, R8(%rdi)
1175 movq %rax, RAX(%rdi)
1176 movq %rax, RCX(%rdi)
1177 movq %rax, RDX(%rdi)
1178 movq %rax, RSI(%rdi)
1179 movq %rax, RDI(%rdi)
1180 movq %rax, ORIG_RAX(%rdi)
1181 movq %rcx, RIP(%rdi)
1182 leaq 8(%rsp), %rcx
1183 movq $__KERNEL_CS, CS(%rdi)
1184 movq %rax, EFLAGS(%rdi)
1185 movq %rcx, RSP(%rdi)
1186 movq $__KERNEL_DS, SS(%rdi)
1187 jmpq *%rdx
1188 CFI_ENDPROC
1189ENDPROC(arch_unwind_init_running)
1190#endif