blob: a04fc4108ff21a5390aa53cdf625ea775bf573e0 [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.
Andi Kleen2e91a172006-09-26 10:52:29 +020025 *
26 * Some macro usage:
27 * - CFI macros are used to generate dwarf2 unwind information for better
28 * backtraces. They don't change any code.
29 * - SAVE_ALL/RESTORE_ALL - Save/restore all registers
30 * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify.
31 * There are unfortunately lots of special cases where some registers
32 * not touched. The macro is a big mess that should be cleaned up.
33 * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS.
34 * Gives a full stack frame.
35 * - ENTRY/END Define functions in the symbol table.
36 * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack
37 * frame that is otherwise undefined after a SYSCALL
38 * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
39 * - errorentry/paranoidentry/zeroentry - Define exception entry points.
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 */
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/linkage.h>
43#include <asm/segment.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <asm/cache.h>
45#include <asm/errno.h>
46#include <asm/dwarf2.h>
47#include <asm/calling.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020048#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/msr.h>
50#include <asm/unistd.h>
51#include <asm/thread_info.h>
52#include <asm/hw_irq.h>
Andi Kleen5f8efbb2006-01-16 01:56:39 +010053#include <asm/page.h>
Ingo Molnar2601e642006-07-03 00:24:45 -070054#include <asm/irqflags.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56 .code64
57
Andi Kleendc37db42005-04-16 15:25:05 -070058#ifndef CONFIG_PREEMPT
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define retint_kernel retint_restore_args
60#endif
Ingo Molnar2601e642006-07-03 00:24:45 -070061
62
63.macro TRACE_IRQS_IRETQ offset=ARGOFFSET
64#ifdef CONFIG_TRACE_IRQFLAGS
65 bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */
66 jnc 1f
67 TRACE_IRQS_ON
681:
69#endif
70.endm
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/*
73 * C code is not supposed to know about undefined top of stack. Every time
74 * a C function with an pt_regs argument is called from the SYSCALL based
75 * fast path FIXUP_TOP_OF_STACK is needed.
76 * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
77 * manipulation.
78 */
79
80 /* %rsp:at FRAMEEND */
81 .macro FIXUP_TOP_OF_STACK tmp
82 movq %gs:pda_oldrsp,\tmp
83 movq \tmp,RSP(%rsp)
84 movq $__USER_DS,SS(%rsp)
85 movq $__USER_CS,CS(%rsp)
86 movq $-1,RCX(%rsp)
87 movq R11(%rsp),\tmp /* get eflags */
88 movq \tmp,EFLAGS(%rsp)
89 .endm
90
91 .macro RESTORE_TOP_OF_STACK tmp,offset=0
92 movq RSP-\offset(%rsp),\tmp
93 movq \tmp,%gs:pda_oldrsp
94 movq EFLAGS-\offset(%rsp),\tmp
95 movq \tmp,R11-\offset(%rsp)
96 .endm
97
98 .macro FAKE_STACK_FRAME child_rip
99 /* push in order ss, rsp, eflags, cs, rip */
Andi Kleen3829ee62005-07-28 21:15:48 -0700100 xorl %eax, %eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 pushq %rax /* ss */
102 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200103 /*CFI_REL_OFFSET ss,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 pushq %rax /* rsp */
105 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200106 CFI_REL_OFFSET rsp,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 pushq $(1<<9) /* eflags - interrupts on */
108 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200109 /*CFI_REL_OFFSET rflags,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 pushq $__KERNEL_CS /* cs */
111 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200112 /*CFI_REL_OFFSET cs,0*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 pushq \child_rip /* rip */
114 CFI_ADJUST_CFA_OFFSET 8
Jan Beulich7effaa82005-09-12 18:49:24 +0200115 CFI_REL_OFFSET rip,0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 pushq %rax /* orig rax */
117 CFI_ADJUST_CFA_OFFSET 8
118 .endm
119
120 .macro UNFAKE_STACK_FRAME
121 addq $8*6, %rsp
122 CFI_ADJUST_CFA_OFFSET -(6*8)
123 .endm
124
Jan Beulich7effaa82005-09-12 18:49:24 +0200125 .macro CFI_DEFAULT_STACK start=1
126 .if \start
127 CFI_STARTPROC simple
128 CFI_DEF_CFA rsp,SS+8
129 .else
130 CFI_DEF_CFA_OFFSET SS+8
131 .endif
132 CFI_REL_OFFSET r15,R15
133 CFI_REL_OFFSET r14,R14
134 CFI_REL_OFFSET r13,R13
135 CFI_REL_OFFSET r12,R12
136 CFI_REL_OFFSET rbp,RBP
137 CFI_REL_OFFSET rbx,RBX
138 CFI_REL_OFFSET r11,R11
139 CFI_REL_OFFSET r10,R10
140 CFI_REL_OFFSET r9,R9
141 CFI_REL_OFFSET r8,R8
142 CFI_REL_OFFSET rax,RAX
143 CFI_REL_OFFSET rcx,RCX
144 CFI_REL_OFFSET rdx,RDX
145 CFI_REL_OFFSET rsi,RSI
146 CFI_REL_OFFSET rdi,RDI
147 CFI_REL_OFFSET rip,RIP
148 /*CFI_REL_OFFSET cs,CS*/
149 /*CFI_REL_OFFSET rflags,EFLAGS*/
150 CFI_REL_OFFSET rsp,RSP
151 /*CFI_REL_OFFSET ss,SS*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 .endm
153/*
154 * A newly forked process directly context switches into this.
155 */
156/* rdi: prev */
157ENTRY(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 CFI_DEFAULT_STACK
159 call schedule_tail
160 GET_THREAD_INFO(%rcx)
161 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
162 jnz rff_trace
163rff_action:
164 RESTORE_REST
165 testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
166 je int_ret_from_sys_call
167 testl $_TIF_IA32,threadinfo_flags(%rcx)
168 jnz int_ret_from_sys_call
169 RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
170 jmp ret_from_sys_call
171rff_trace:
172 movq %rsp,%rdi
173 call syscall_trace_leave
174 GET_THREAD_INFO(%rcx)
175 jmp rff_action
176 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200177END(ret_from_fork)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179/*
180 * System call entry. Upto 6 arguments in registers are supported.
181 *
182 * SYSCALL does not save anything on the stack and does not change the
183 * stack pointer.
184 */
185
186/*
187 * Register setup:
188 * rax system call number
189 * rdi arg0
190 * rcx return address for syscall/sysret, C arg3
191 * rsi arg1
192 * rdx arg2
193 * r10 arg3 (--> moved to rcx for C)
194 * r8 arg4
195 * r9 arg5
196 * r11 eflags for syscall/sysret, temporary for C
197 * r12-r15,rbp,rbx saved by C code, not touched.
198 *
199 * Interrupts are off on entry.
200 * Only called from user space.
201 *
202 * XXX if we had a free scratch register we could save the RSP into the stack frame
203 * and report it properly in ps. Unfortunately we haven't.
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200204 *
205 * When user can change the frames always force IRET. That is because
206 * it deals with uncanonical addresses better. SYSRET has trouble
207 * with them due to bugs in both AMD and Intel CPUs.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 */
209
210ENTRY(system_call)
Jan Beulich7effaa82005-09-12 18:49:24 +0200211 CFI_STARTPROC simple
Jan Beulichdffead42006-06-26 13:57:38 +0200212 CFI_DEF_CFA rsp,PDA_STACKOFFSET
Jan Beulich7effaa82005-09-12 18:49:24 +0200213 CFI_REGISTER rip,rcx
214 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 swapgs
216 movq %rsp,%gs:pda_oldrsp
217 movq %gs:pda_kernelstack,%rsp
Ingo Molnar2601e642006-07-03 00:24:45 -0700218 /*
219 * No need to follow this irqs off/on section - it's straight
220 * and short:
221 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 sti
223 SAVE_ARGS 8,1
224 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
Jan Beulich7effaa82005-09-12 18:49:24 +0200225 movq %rcx,RIP-ARGOFFSET(%rsp)
226 CFI_REL_OFFSET rip,RIP-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 GET_THREAD_INFO(%rcx)
228 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
Jan Beulich7effaa82005-09-12 18:49:24 +0200229 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 jnz tracesys
231 cmpq $__NR_syscall_max,%rax
232 ja badsys
233 movq %r10,%rcx
234 call *sys_call_table(,%rax,8) # XXX: rip relative
235 movq %rax,RAX-ARGOFFSET(%rsp)
236/*
237 * Syscall return path ending with SYSRET (fast path)
238 * Has incomplete stack frame and undefined top of stack.
239 */
240 .globl ret_from_sys_call
241ret_from_sys_call:
Andi Kleen11b854b2005-04-16 15:25:02 -0700242 movl $_TIF_ALLWORK_MASK,%edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 /* edi: flagmask */
244sysret_check:
245 GET_THREAD_INFO(%rcx)
246 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700247 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 movl threadinfo_flags(%rcx),%edx
249 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200250 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 jnz sysret_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700252 /*
253 * sysretq will re-enable interrupts:
254 */
255 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 movq RIP-ARGOFFSET(%rsp),%rcx
Jan Beulich7effaa82005-09-12 18:49:24 +0200257 CFI_REGISTER rip,rcx
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 RESTORE_ARGS 0,-ARG_SKIP,1
Jan Beulich7effaa82005-09-12 18:49:24 +0200259 /*CFI_REGISTER rflags,r11*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 movq %gs:pda_oldrsp,%rsp
261 swapgs
262 sysretq
263
264 /* Handle reschedules */
265 /* edx: work, edi: workmask */
266sysret_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200267 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 bt $TIF_NEED_RESCHED,%edx
269 jnc sysret_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700270 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sti
272 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200273 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 call schedule
275 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200276 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 jmp sysret_check
278
279 /* Handle a signal */
280sysret_signal:
Ingo Molnar2601e642006-07-03 00:24:45 -0700281 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 sti
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700283 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
284 jz 1f
285
286 /* Really a signal */
287 /* edx: work flags (arg3) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 leaq do_notify_resume(%rip),%rax
289 leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
290 xorl %esi,%esi # oldset -> arg2
291 call ptregscall_common
Andi Kleen10ffdbb2005-05-16 21:53:19 -07002921: movl $_TIF_NEED_RESCHED,%edi
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200293 /* Use IRET because user could have changed frame. This
294 works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
295 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700296 TRACE_IRQS_OFF
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200297 jmp int_with_check
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Jan Beulich7effaa82005-09-12 18:49:24 +0200299badsys:
300 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
301 jmp ret_from_sys_call
302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 /* Do syscall tracing */
304tracesys:
Jan Beulich7effaa82005-09-12 18:49:24 +0200305 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 SAVE_REST
307 movq $-ENOSYS,RAX(%rsp)
308 FIXUP_TOP_OF_STACK %rdi
309 movq %rsp,%rdi
310 call syscall_trace_enter
311 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
312 RESTORE_REST
313 cmpq $__NR_syscall_max,%rax
314 ja 1f
315 movq %r10,%rcx /* fixup for C */
316 call *sys_call_table(,%rax,8)
Andi Kleen822ff012006-05-30 22:48:03 +02003171: movq %rax,RAX-ARGOFFSET(%rsp)
Andi Kleen7bf36bb2006-04-07 19:50:00 +0200318 /* Use IRET because user could have changed frame */
319 jmp int_ret_from_sys_call
Jan Beulich7effaa82005-09-12 18:49:24 +0200320 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200321END(system_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323/*
324 * Syscall return path ending with IRET.
325 * Has correct top of stack, but partial stack frame.
326 */
Jan Beulich7effaa82005-09-12 18:49:24 +0200327ENTRY(int_ret_from_sys_call)
328 CFI_STARTPROC simple
329 CFI_DEF_CFA rsp,SS+8-ARGOFFSET
330 /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
331 CFI_REL_OFFSET rsp,RSP-ARGOFFSET
332 /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
333 /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
334 CFI_REL_OFFSET rip,RIP-ARGOFFSET
335 CFI_REL_OFFSET rdx,RDX-ARGOFFSET
336 CFI_REL_OFFSET rcx,RCX-ARGOFFSET
337 CFI_REL_OFFSET rax,RAX-ARGOFFSET
338 CFI_REL_OFFSET rdi,RDI-ARGOFFSET
339 CFI_REL_OFFSET rsi,RSI-ARGOFFSET
340 CFI_REL_OFFSET r8,R8-ARGOFFSET
341 CFI_REL_OFFSET r9,R9-ARGOFFSET
342 CFI_REL_OFFSET r10,R10-ARGOFFSET
343 CFI_REL_OFFSET r11,R11-ARGOFFSET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700345 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 testl $3,CS-ARGOFFSET(%rsp)
347 je retint_restore_args
348 movl $_TIF_ALLWORK_MASK,%edi
349 /* edi: mask to check */
350int_with_check:
351 GET_THREAD_INFO(%rcx)
352 movl threadinfo_flags(%rcx),%edx
353 andl %edi,%edx
354 jnz int_careful
Andi Kleenbf2fcc62006-01-11 22:44:06 +0100355 andl $~TS_COMPAT,threadinfo_status(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 jmp retint_swapgs
357
358 /* Either reschedule or signal or syscall exit tracking needed. */
359 /* First do a reschedule test. */
360 /* edx: work, edi: workmask */
361int_careful:
362 bt $TIF_NEED_RESCHED,%edx
363 jnc int_very_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700364 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 sti
366 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200367 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 call schedule
369 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200370 CFI_ADJUST_CFA_OFFSET -8
Andi Kleencdd219c2005-04-16 15:25:04 -0700371 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700372 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 jmp int_with_check
374
375 /* handle signals and tracing -- both require a full stack frame */
376int_very_careful:
Ingo Molnar2601e642006-07-03 00:24:45 -0700377 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 sti
379 SAVE_REST
380 /* Check for syscall exit trace */
381 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
382 jz int_signal
383 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200384 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 leaq 8(%rsp),%rdi # &ptregs -> arg1
386 call syscall_trace_leave
387 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200388 CFI_ADJUST_CFA_OFFSET -8
Andi Kleen36c11042005-04-16 15:25:01 -0700389 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700390 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700391 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 jmp int_restore_rest
393
394int_signal:
395 testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
396 jz 1f
397 movq %rsp,%rdi # &ptregs -> arg1
398 xorl %esi,%esi # oldset -> arg2
399 call do_notify_resume
4001: movl $_TIF_NEED_RESCHED,%edi
401int_restore_rest:
402 RESTORE_REST
Andi Kleenbe9e6872005-05-01 08:58:51 -0700403 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700404 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 jmp int_with_check
406 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200407END(int_ret_from_sys_call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409/*
410 * Certain special system calls that need to save a complete full stack frame.
411 */
412
413 .macro PTREGSCALL label,func,arg
414 .globl \label
415\label:
416 leaq \func(%rip),%rax
417 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
418 jmp ptregscall_common
Jan Beulich4b787e02006-06-26 13:56:55 +0200419END(\label)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 .endm
421
Jan Beulich7effaa82005-09-12 18:49:24 +0200422 CFI_STARTPROC
423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 PTREGSCALL stub_clone, sys_clone, %r8
425 PTREGSCALL stub_fork, sys_fork, %rdi
426 PTREGSCALL stub_vfork, sys_vfork, %rdi
427 PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
428 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
429 PTREGSCALL stub_iopl, sys_iopl, %rsi
430
431ENTRY(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200433 CFI_ADJUST_CFA_OFFSET -8
434 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 SAVE_REST
436 movq %r11, %r15
Jan Beulich7effaa82005-09-12 18:49:24 +0200437 CFI_REGISTER rip, r15
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 FIXUP_TOP_OF_STACK %r11
439 call *%rax
440 RESTORE_TOP_OF_STACK %r11
441 movq %r15, %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200442 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 RESTORE_REST
444 pushq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200445 CFI_ADJUST_CFA_OFFSET 8
446 CFI_REL_OFFSET rip, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 ret
448 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200449END(ptregscall_common)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451ENTRY(stub_execve)
452 CFI_STARTPROC
453 popq %r11
Jan Beulich7effaa82005-09-12 18:49:24 +0200454 CFI_ADJUST_CFA_OFFSET -8
455 CFI_REGISTER rip, r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 SAVE_REST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 FIXUP_TOP_OF_STACK %r11
458 call sys_execve
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 RESTORE_TOP_OF_STACK %r11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 movq %rax,RAX(%rsp)
461 RESTORE_REST
462 jmp int_ret_from_sys_call
463 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200464END(stub_execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466/*
467 * sigreturn is special because it needs to restore all registers on return.
468 * This cannot be done with SYSRET, so use the IRET return path instead.
469 */
470ENTRY(stub_rt_sigreturn)
471 CFI_STARTPROC
Jan Beulich7effaa82005-09-12 18:49:24 +0200472 addq $8, %rsp
473 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 SAVE_REST
475 movq %rsp,%rdi
476 FIXUP_TOP_OF_STACK %r11
477 call sys_rt_sigreturn
478 movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
479 RESTORE_REST
480 jmp int_ret_from_sys_call
481 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200482END(stub_rt_sigreturn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Jan Beulich7effaa82005-09-12 18:49:24 +0200484/*
485 * initial frame state for interrupts and exceptions
486 */
487 .macro _frame ref
488 CFI_STARTPROC simple
489 CFI_DEF_CFA rsp,SS+8-\ref
490 /*CFI_REL_OFFSET ss,SS-\ref*/
491 CFI_REL_OFFSET rsp,RSP-\ref
492 /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
493 /*CFI_REL_OFFSET cs,CS-\ref*/
494 CFI_REL_OFFSET rip,RIP-\ref
495 .endm
496
497/* initial frame state for interrupts (and exceptions without error code) */
498#define INTR_FRAME _frame RIP
499/* initial frame state for exceptions with error code (and interrupts with
500 vector already pushed) */
501#define XCPT_FRAME _frame ORIG_RAX
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
504 * Interrupt entry/exit.
505 *
506 * Interrupt entry points save only callee clobbered registers in fast path.
507 *
508 * Entry runs with interrupts off.
509 */
510
511/* 0(%rsp): interrupt number */
512 .macro interrupt func
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 cld
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 SAVE_ARGS
515 leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200516 pushq %rbp
517 CFI_ADJUST_CFA_OFFSET 8
518 CFI_REL_OFFSET rbp, 0
519 movq %rsp,%rbp
520 CFI_DEF_CFA_REGISTER rbp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 testl $3,CS(%rdi)
522 je 1f
523 swapgs
Andi Kleen3829ee62005-07-28 21:15:48 -07005241: incl %gs:pda_irqcount # RED-PEN should check preempt count
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200525 cmoveq %gs:pda_irqstackptr,%rsp
Andi Kleen26995002006-08-02 22:37:28 +0200526 push %rbp # backlink for old unwinder
Ingo Molnar2601e642006-07-03 00:24:45 -0700527 /*
528 * We entered an interrupt context - irqs are off:
529 */
530 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 call \func
532 .endm
533
534ENTRY(common_interrupt)
Jan Beulich7effaa82005-09-12 18:49:24 +0200535 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 interrupt do_IRQ
537 /* 0(%rsp): oldrsp-ARGOFFSET */
Jan Beulich7effaa82005-09-12 18:49:24 +0200538ret_from_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700540 TRACE_IRQS_OFF
Andi Kleen3829ee62005-07-28 21:15:48 -0700541 decl %gs:pda_irqcount
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200542 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +0200543 CFI_DEF_CFA_REGISTER rsp
Jan Beulich1de9c3f2006-06-26 13:57:35 +0200544 CFI_ADJUST_CFA_OFFSET -8
Jan Beulich7effaa82005-09-12 18:49:24 +0200545exit_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 GET_THREAD_INFO(%rcx)
547 testl $3,CS-ARGOFFSET(%rsp)
548 je retint_kernel
549
550 /* Interrupt came from user space */
551 /*
552 * Has a correct top of stack, but a partial stack frame
553 * %rcx: thread info. Interrupts off.
554 */
555retint_with_reschedule:
556 movl $_TIF_WORK_MASK,%edi
Jan Beulich7effaa82005-09-12 18:49:24 +0200557retint_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 movl threadinfo_flags(%rcx),%edx
559 andl %edi,%edx
Jan Beulich7effaa82005-09-12 18:49:24 +0200560 CFI_REMEMBER_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 jnz retint_careful
562retint_swapgs:
Ingo Molnar2601e642006-07-03 00:24:45 -0700563 /*
564 * The iretq could re-enable interrupts:
565 */
566 cli
567 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700569 jmp restore_args
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571retint_restore_args:
572 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700573 /*
574 * The iretq could re-enable interrupts:
575 */
576 TRACE_IRQS_IRETQ
577restore_args:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 RESTORE_ARGS 0,8,0
579iret_label:
580 iretq
581
582 .section __ex_table,"a"
583 .quad iret_label,bad_iret
584 .previous
585 .section .fixup,"ax"
586 /* force a signal here? this matches i386 behaviour */
587 /* running with kernel gs */
588bad_iret:
Andi Kleen3076a492006-03-25 16:31:55 +0100589 movq $11,%rdi /* SIGSEGV */
Ingo Molnar2601e642006-07-03 00:24:45 -0700590 TRACE_IRQS_ON
Andi Kleen2391c4b2006-02-16 23:42:01 +0100591 sti
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 jmp do_exit
593 .previous
594
Jan Beulich7effaa82005-09-12 18:49:24 +0200595 /* edi: workmask, edx: work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596retint_careful:
Jan Beulich7effaa82005-09-12 18:49:24 +0200597 CFI_RESTORE_STATE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 bt $TIF_NEED_RESCHED,%edx
599 jnc retint_signal
Ingo Molnar2601e642006-07-03 00:24:45 -0700600 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 sti
602 pushq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200603 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 call schedule
605 popq %rdi
Jan Beulich7effaa82005-09-12 18:49:24 +0200606 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 GET_THREAD_INFO(%rcx)
608 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700609 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 jmp retint_check
611
612retint_signal:
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700613 testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
614 jz retint_swapgs
Ingo Molnar2601e642006-07-03 00:24:45 -0700615 TRACE_IRQS_ON
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 sti
617 SAVE_REST
618 movq $-1,ORIG_RAX(%rsp)
Andi Kleen3829ee62005-07-28 21:15:48 -0700619 xorl %esi,%esi # oldset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 movq %rsp,%rdi # &pt_regs
621 call do_notify_resume
622 RESTORE_REST
623 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700624 TRACE_IRQS_OFF
Andi Kleen10ffdbb2005-05-16 21:53:19 -0700625 movl $_TIF_NEED_RESCHED,%edi
Andi Kleenbe9e6872005-05-01 08:58:51 -0700626 GET_THREAD_INFO(%rcx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 jmp retint_check
628
629#ifdef CONFIG_PREEMPT
630 /* Returning to kernel space. Check if we need preemption */
631 /* rcx: threadinfo. interrupts off. */
Andi Kleenb06baba2006-09-26 10:52:29 +0200632ENTRY(retint_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 cmpl $0,threadinfo_preempt_count(%rcx)
634 jnz retint_restore_args
635 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
636 jnc retint_restore_args
637 bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
638 jnc retint_restore_args
639 call preempt_schedule_irq
640 jmp exit_intr
641#endif
Jan Beulich4b787e02006-06-26 13:56:55 +0200642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200644END(common_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646/*
647 * APIC interrupts.
648 */
649 .macro apicinterrupt num,func
Jan Beulich7effaa82005-09-12 18:49:24 +0200650 INTR_FRAME
Rusty Russell19eadf92006-06-27 02:53:44 -0700651 pushq $~(\num)
Jan Beulich7effaa82005-09-12 18:49:24 +0200652 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 interrupt \func
654 jmp ret_from_intr
655 CFI_ENDPROC
656 .endm
657
658ENTRY(thermal_interrupt)
659 apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200660END(thermal_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Jacob Shin89b831e2005-11-05 17:25:53 +0100662ENTRY(threshold_interrupt)
663 apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200664END(threshold_interrupt)
Jacob Shin89b831e2005-11-05 17:25:53 +0100665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666#ifdef CONFIG_SMP
667ENTRY(reschedule_interrupt)
668 apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200669END(reschedule_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Andi Kleene5bc8b62005-09-12 18:49:24 +0200671 .macro INVALIDATE_ENTRY num
672ENTRY(invalidate_interrupt\num)
673 apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200674END(invalidate_interrupt\num)
Andi Kleene5bc8b62005-09-12 18:49:24 +0200675 .endm
676
677 INVALIDATE_ENTRY 0
678 INVALIDATE_ENTRY 1
679 INVALIDATE_ENTRY 2
680 INVALIDATE_ENTRY 3
681 INVALIDATE_ENTRY 4
682 INVALIDATE_ENTRY 5
683 INVALIDATE_ENTRY 6
684 INVALIDATE_ENTRY 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686ENTRY(call_function_interrupt)
687 apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200688END(call_function_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689#endif
690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691ENTRY(apic_timer_interrupt)
692 apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200693END(apic_timer_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695ENTRY(error_interrupt)
696 apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200697END(error_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699ENTRY(spurious_interrupt)
700 apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
Jan Beulich4b787e02006-06-26 13:56:55 +0200701END(spurious_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703/*
704 * Exception entry points.
705 */
706 .macro zeroentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200707 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 pushq $0 /* push error code/oldrax */
Jan Beulich7effaa82005-09-12 18:49:24 +0200709 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 pushq %rax /* push real oldrax to the rdi slot */
Jan Beulich7effaa82005-09-12 18:49:24 +0200711 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 leaq \sym(%rip),%rax
713 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200714 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 .endm
716
717 .macro errorentry sym
Jan Beulich7effaa82005-09-12 18:49:24 +0200718 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 pushq %rax
Jan Beulich7effaa82005-09-12 18:49:24 +0200720 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 leaq \sym(%rip),%rax
722 jmp error_entry
Jan Beulich7effaa82005-09-12 18:49:24 +0200723 CFI_ENDPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 .endm
725
726 /* error code is on the stack already */
727 /* handle NMI like exceptions that can happen everywhere */
Ingo Molnar2601e642006-07-03 00:24:45 -0700728 .macro paranoidentry sym, ist=0, irqtrace=1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 SAVE_ALL
730 cld
731 movl $1,%ebx
732 movl $MSR_GS_BASE,%ecx
733 rdmsr
734 testl %edx,%edx
735 js 1f
736 swapgs
737 xorl %ebx,%ebx
Jan Beulichb556b352006-01-11 22:43:00 +01007381:
739 .if \ist
740 movq %gs:pda_data_offset, %rbp
741 .endif
742 movq %rsp,%rdi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 movq ORIG_RAX(%rsp),%rsi
744 movq $-1,ORIG_RAX(%rsp)
Jan Beulichb556b352006-01-11 22:43:00 +0100745 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100746 subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100747 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 call \sym
Jan Beulichb556b352006-01-11 22:43:00 +0100749 .if \ist
Andi Kleen5f8efbb2006-01-16 01:56:39 +0100750 addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
Jan Beulichb556b352006-01-11 22:43:00 +0100751 .endif
Andi Kleen6fefb0d2005-04-16 15:25:03 -0700752 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700753 .if \irqtrace
754 TRACE_IRQS_OFF
755 .endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 .endm
Ingo Molnar2601e642006-07-03 00:24:45 -0700757
758 /*
759 * "Paranoid" exit path from exception stack.
760 * Paranoid because this is used by NMIs and cannot take
761 * any kernel state for granted.
762 * We don't do kernel preemption checks here, because only
763 * NMI should be common and it does not enable IRQs and
764 * cannot get reschedule ticks.
765 *
766 * "trace" is 0 for the NMI handler only, because irq-tracing
767 * is fundamentally NMI-unsafe. (we cannot change the soft and
768 * hard flags at once, atomically)
769 */
770 .macro paranoidexit trace=1
771 /* ebx: no swapgs flag */
772paranoid_exit\trace:
773 testl %ebx,%ebx /* swapgs needed? */
774 jnz paranoid_restore\trace
775 testl $3,CS(%rsp)
776 jnz paranoid_userspace\trace
777paranoid_swapgs\trace:
778 TRACE_IRQS_IRETQ 0
779 swapgs
780paranoid_restore\trace:
781 RESTORE_ALL 8
782 iretq
783paranoid_userspace\trace:
784 GET_THREAD_INFO(%rcx)
785 movl threadinfo_flags(%rcx),%ebx
786 andl $_TIF_WORK_MASK,%ebx
787 jz paranoid_swapgs\trace
788 movq %rsp,%rdi /* &pt_regs */
789 call sync_regs
790 movq %rax,%rsp /* switch stack for scheduling */
791 testl $_TIF_NEED_RESCHED,%ebx
792 jnz paranoid_schedule\trace
793 movl %ebx,%edx /* arg3: thread flags */
794 .if \trace
795 TRACE_IRQS_ON
796 .endif
797 sti
798 xorl %esi,%esi /* arg2: oldset */
799 movq %rsp,%rdi /* arg1: &pt_regs */
800 call do_notify_resume
801 cli
802 .if \trace
803 TRACE_IRQS_OFF
804 .endif
805 jmp paranoid_userspace\trace
806paranoid_schedule\trace:
807 .if \trace
808 TRACE_IRQS_ON
809 .endif
810 sti
811 call schedule
812 cli
813 .if \trace
814 TRACE_IRQS_OFF
815 .endif
816 jmp paranoid_userspace\trace
817 CFI_ENDPROC
818 .endm
819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820/*
821 * Exception entry point. This expects an error code/orig_rax on the stack
822 * and the exception handler in %rax.
823 */
824ENTRY(error_entry)
Jan Beulich7effaa82005-09-12 18:49:24 +0200825 _frame RDI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 /* rdi slot contains rax, oldrax contains error code */
827 cld
828 subq $14*8,%rsp
829 CFI_ADJUST_CFA_OFFSET (14*8)
830 movq %rsi,13*8(%rsp)
831 CFI_REL_OFFSET rsi,RSI
832 movq 14*8(%rsp),%rsi /* load rax from rdi slot */
833 movq %rdx,12*8(%rsp)
834 CFI_REL_OFFSET rdx,RDX
835 movq %rcx,11*8(%rsp)
836 CFI_REL_OFFSET rcx,RCX
837 movq %rsi,10*8(%rsp) /* store rax */
838 CFI_REL_OFFSET rax,RAX
839 movq %r8, 9*8(%rsp)
840 CFI_REL_OFFSET r8,R8
841 movq %r9, 8*8(%rsp)
842 CFI_REL_OFFSET r9,R9
843 movq %r10,7*8(%rsp)
844 CFI_REL_OFFSET r10,R10
845 movq %r11,6*8(%rsp)
846 CFI_REL_OFFSET r11,R11
847 movq %rbx,5*8(%rsp)
848 CFI_REL_OFFSET rbx,RBX
849 movq %rbp,4*8(%rsp)
850 CFI_REL_OFFSET rbp,RBP
851 movq %r12,3*8(%rsp)
852 CFI_REL_OFFSET r12,R12
853 movq %r13,2*8(%rsp)
854 CFI_REL_OFFSET r13,R13
855 movq %r14,1*8(%rsp)
856 CFI_REL_OFFSET r14,R14
857 movq %r15,(%rsp)
858 CFI_REL_OFFSET r15,R15
859 xorl %ebx,%ebx
860 testl $3,CS(%rsp)
861 je error_kernelspace
862error_swapgs:
863 swapgs
864error_sti:
865 movq %rdi,RDI(%rsp)
866 movq %rsp,%rdi
867 movq ORIG_RAX(%rsp),%rsi /* get error code */
868 movq $-1,ORIG_RAX(%rsp)
869 call *%rax
870 /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
871error_exit:
872 movl %ebx,%eax
873 RESTORE_REST
874 cli
Ingo Molnar2601e642006-07-03 00:24:45 -0700875 TRACE_IRQS_OFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 GET_THREAD_INFO(%rcx)
877 testl %eax,%eax
878 jne retint_kernel
879 movl threadinfo_flags(%rcx),%edx
880 movl $_TIF_WORK_MASK,%edi
881 andl %edi,%edx
882 jnz retint_careful
Ingo Molnar2601e642006-07-03 00:24:45 -0700883 /*
884 * The iret might restore flags:
885 */
886 TRACE_IRQS_IRETQ
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 swapgs
888 RESTORE_ARGS 0,8,0
Jan Beulich505cc4e2006-01-11 22:42:20 +0100889 jmp iret_label
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 CFI_ENDPROC
891
892error_kernelspace:
893 incl %ebx
894 /* There are two places in the kernel that can potentially fault with
895 usergs. Handle them here. The exception handlers after
896 iret run with kernel gs again, so don't set the user space flag.
897 B stepping K8s sometimes report an truncated RIP for IRET
898 exceptions returning to compat mode. Check for these here too. */
899 leaq iret_label(%rip),%rbp
900 cmpq %rbp,RIP(%rsp)
901 je error_swapgs
902 movl %ebp,%ebp /* zero extend */
903 cmpq %rbp,RIP(%rsp)
904 je error_swapgs
905 cmpq $gs_change,RIP(%rsp)
906 je error_swapgs
907 jmp error_sti
Jan Beulich4b787e02006-06-26 13:56:55 +0200908END(error_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 /* Reload gs selector with exception handling */
911 /* edi: new selector */
912ENTRY(load_gs_index)
Jan Beulich7effaa82005-09-12 18:49:24 +0200913 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 pushf
Jan Beulich7effaa82005-09-12 18:49:24 +0200915 CFI_ADJUST_CFA_OFFSET 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 cli
917 swapgs
918gs_change:
919 movl %edi,%gs
9202: mfence /* workaround */
921 swapgs
922 popf
Jan Beulich7effaa82005-09-12 18:49:24 +0200923 CFI_ADJUST_CFA_OFFSET -8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 ret
Jan Beulich7effaa82005-09-12 18:49:24 +0200925 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200926ENDPROC(load_gs_index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 .section __ex_table,"a"
929 .align 8
930 .quad gs_change,bad_gs
931 .previous
932 .section .fixup,"ax"
933 /* running with kernelgs */
934bad_gs:
935 swapgs /* switch back to user gs */
936 xorl %eax,%eax
937 movl %eax,%gs
938 jmp 2b
939 .previous
940
941/*
942 * Create a kernel thread.
943 *
944 * C extern interface:
945 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
946 *
947 * asm input arguments:
948 * rdi: fn, rsi: arg, rdx: flags
949 */
950ENTRY(kernel_thread)
951 CFI_STARTPROC
952 FAKE_STACK_FRAME $child_rip
953 SAVE_ALL
954
955 # rdi: flags, rsi: usp, rdx: will be &pt_regs
956 movq %rdx,%rdi
957 orq kernel_thread_flags(%rip),%rdi
958 movq $-1, %rsi
959 movq %rsp, %rdx
960
961 xorl %r8d,%r8d
962 xorl %r9d,%r9d
963
964 # clone now
965 call do_fork
966 movq %rax,RAX(%rsp)
967 xorl %edi,%edi
968
969 /*
970 * It isn't worth to check for reschedule here,
971 * so internally to the x86_64 port you can rely on kernel_thread()
972 * not to reschedule the child before returning, this avoids the need
973 * of hacks for example to fork off the per-CPU idle tasks.
974 * [Hopefully no generic code relies on the reschedule -AK]
975 */
976 RESTORE_ALL
977 UNFAKE_STACK_FRAME
978 ret
979 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200980ENDPROC(kernel_thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982child_rip:
Andi Kleenc05991e2006-08-30 19:37:08 +0200983 pushq $0 # fake return address
984 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 /*
986 * Here we are in the child and the registers are set as they were
987 * at kernel_thread() invocation in the parent.
988 */
989 movq %rdi, %rax
990 movq %rsi, %rdi
991 call *%rax
992 # exit
Andi Kleen3829ee62005-07-28 21:15:48 -0700993 xorl %edi, %edi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 call do_exit
Andi Kleenc05991e2006-08-30 19:37:08 +0200995 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +0200996ENDPROC(child_rip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998/*
999 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
1000 *
1001 * C extern interface:
1002 * extern long execve(char *name, char **argv, char **envp)
1003 *
1004 * asm input arguments:
1005 * rdi: name, rsi: argv, rdx: envp
1006 *
1007 * We want to fallback into:
1008 * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
1009 *
1010 * do_sys_execve asm fallback arguments:
1011 * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
1012 */
1013ENTRY(execve)
1014 CFI_STARTPROC
1015 FAKE_STACK_FRAME $0
1016 SAVE_ALL
1017 call sys_execve
1018 movq %rax, RAX(%rsp)
1019 RESTORE_REST
1020 testq %rax,%rax
1021 je int_ret_from_sys_call
1022 RESTORE_ARGS
1023 UNFAKE_STACK_FRAME
1024 ret
1025 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001026ENDPROC(execve)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001028KPROBE_ENTRY(page_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 errorentry do_page_fault
Jan Beulich4b787e02006-06-26 13:56:55 +02001030END(page_fault)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001031 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033ENTRY(coprocessor_error)
1034 zeroentry do_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001035END(coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037ENTRY(simd_coprocessor_error)
1038 zeroentry do_simd_coprocessor_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001039END(simd_coprocessor_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041ENTRY(device_not_available)
1042 zeroentry math_state_restore
Jan Beulich4b787e02006-06-26 13:56:55 +02001043END(device_not_available)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 /* runs on exception stack */
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001046KPROBE_ENTRY(debug)
Jan Beulich7effaa82005-09-12 18:49:24 +02001047 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 pushq $0
1049 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001050 paranoidentry do_debug, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001051 paranoidexit
Jan Beulich4b787e02006-06-26 13:56:55 +02001052END(debug)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001053 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
1055 /* runs on exception stack */
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001056KPROBE_ENTRY(nmi)
Jan Beulich7effaa82005-09-12 18:49:24 +02001057 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 pushq $-1
Jan Beulich7effaa82005-09-12 18:49:24 +02001059 CFI_ADJUST_CFA_OFFSET 8
Ingo Molnar2601e642006-07-03 00:24:45 -07001060 paranoidentry do_nmi, 0, 0
1061#ifdef CONFIG_TRACE_IRQFLAGS
1062 paranoidexit 0
1063#else
1064 jmp paranoid_exit1
1065 CFI_ENDPROC
1066#endif
Jan Beulich4b787e02006-06-26 13:56:55 +02001067END(nmi)
Andi Kleeneddb6fb2006-02-03 21:50:41 +01001068 .previous .text
Andi Kleen6fefb0d2005-04-16 15:25:03 -07001069
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001070KPROBE_ENTRY(int3)
Jan Beulichb556b352006-01-11 22:43:00 +01001071 INTR_FRAME
1072 pushq $0
1073 CFI_ADJUST_CFA_OFFSET 8
Andi Kleen5f8efbb2006-01-16 01:56:39 +01001074 paranoidentry do_int3, DEBUG_STACK
Ingo Molnar2601e642006-07-03 00:24:45 -07001075 jmp paranoid_exit1
Jan Beulichb556b352006-01-11 22:43:00 +01001076 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001077END(int3)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001078 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080ENTRY(overflow)
1081 zeroentry do_overflow
Jan Beulich4b787e02006-06-26 13:56:55 +02001082END(overflow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084ENTRY(bounds)
1085 zeroentry do_bounds
Jan Beulich4b787e02006-06-26 13:56:55 +02001086END(bounds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088ENTRY(invalid_op)
1089 zeroentry do_invalid_op
Jan Beulich4b787e02006-06-26 13:56:55 +02001090END(invalid_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092ENTRY(coprocessor_segment_overrun)
1093 zeroentry do_coprocessor_segment_overrun
Jan Beulich4b787e02006-06-26 13:56:55 +02001094END(coprocessor_segment_overrun)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096ENTRY(reserved)
1097 zeroentry do_reserved
Jan Beulich4b787e02006-06-26 13:56:55 +02001098END(reserved)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 /* runs on exception stack */
1101ENTRY(double_fault)
Jan Beulich7effaa82005-09-12 18:49:24 +02001102 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 paranoidentry do_double_fault
Ingo Molnar2601e642006-07-03 00:24:45 -07001104 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001106END(double_fault)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108ENTRY(invalid_TSS)
1109 errorentry do_invalid_TSS
Jan Beulich4b787e02006-06-26 13:56:55 +02001110END(invalid_TSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112ENTRY(segment_not_present)
1113 errorentry do_segment_not_present
Jan Beulich4b787e02006-06-26 13:56:55 +02001114END(segment_not_present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 /* runs on exception stack */
1117ENTRY(stack_segment)
Jan Beulich7effaa82005-09-12 18:49:24 +02001118 XCPT_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 paranoidentry do_stack_segment
Ingo Molnar2601e642006-07-03 00:24:45 -07001120 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001122END(stack_segment)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001124KPROBE_ENTRY(general_protection)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 errorentry do_general_protection
Jan Beulich4b787e02006-06-26 13:56:55 +02001126END(general_protection)
Prasanna S Panchamukhi0f2fbdc2005-09-06 15:19:28 -07001127 .previous .text
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129ENTRY(alignment_check)
1130 errorentry do_alignment_check
Jan Beulich4b787e02006-06-26 13:56:55 +02001131END(alignment_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133ENTRY(divide_error)
1134 zeroentry do_divide_error
Jan Beulich4b787e02006-06-26 13:56:55 +02001135END(divide_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137ENTRY(spurious_interrupt_bug)
1138 zeroentry do_spurious_interrupt_bug
Jan Beulich4b787e02006-06-26 13:56:55 +02001139END(spurious_interrupt_bug)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141#ifdef CONFIG_X86_MCE
1142 /* runs on exception stack */
1143ENTRY(machine_check)
Jan Beulich7effaa82005-09-12 18:49:24 +02001144 INTR_FRAME
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 pushq $0
1146 CFI_ADJUST_CFA_OFFSET 8
1147 paranoidentry do_machine_check
Ingo Molnar2601e642006-07-03 00:24:45 -07001148 jmp paranoid_exit1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001150END(machine_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151#endif
1152
Andi Kleen26995002006-08-02 22:37:28 +02001153/* Call softirq on interrupt stack. Interrupts are off. */
Andi Kleened6b6762005-07-28 21:15:49 -07001154ENTRY(call_softirq)
Jan Beulich7effaa82005-09-12 18:49:24 +02001155 CFI_STARTPROC
Andi Kleen26995002006-08-02 22:37:28 +02001156 push %rbp
1157 CFI_ADJUST_CFA_OFFSET 8
1158 CFI_REL_OFFSET rbp,0
1159 mov %rsp,%rbp
1160 CFI_DEF_CFA_REGISTER rbp
Andi Kleened6b6762005-07-28 21:15:49 -07001161 incl %gs:pda_irqcount
Andi Kleen26995002006-08-02 22:37:28 +02001162 cmove %gs:pda_irqstackptr,%rsp
1163 push %rbp # backlink for old unwinder
Andi Kleened6b6762005-07-28 21:15:49 -07001164 call __do_softirq
Andi Kleen26995002006-08-02 22:37:28 +02001165 leaveq
Jan Beulich7effaa82005-09-12 18:49:24 +02001166 CFI_DEF_CFA_REGISTER rsp
Andi Kleen26995002006-08-02 22:37:28 +02001167 CFI_ADJUST_CFA_OFFSET -8
Andi Kleened6b6762005-07-28 21:15:49 -07001168 decl %gs:pda_irqcount
Andi Kleened6b6762005-07-28 21:15:49 -07001169 ret
Jan Beulich7effaa82005-09-12 18:49:24 +02001170 CFI_ENDPROC
Jan Beulich4b787e02006-06-26 13:56:55 +02001171ENDPROC(call_softirq)
Jan Beulichb538ed22006-06-26 13:57:32 +02001172
1173#ifdef CONFIG_STACK_UNWIND
1174ENTRY(arch_unwind_init_running)
1175 CFI_STARTPROC
1176 movq %r15, R15(%rdi)
1177 movq %r14, R14(%rdi)
1178 xchgq %rsi, %rdx
1179 movq %r13, R13(%rdi)
1180 movq %r12, R12(%rdi)
1181 xorl %eax, %eax
1182 movq %rbp, RBP(%rdi)
1183 movq %rbx, RBX(%rdi)
1184 movq (%rsp), %rcx
1185 movq %rax, R11(%rdi)
1186 movq %rax, R10(%rdi)
1187 movq %rax, R9(%rdi)
1188 movq %rax, R8(%rdi)
1189 movq %rax, RAX(%rdi)
1190 movq %rax, RCX(%rdi)
1191 movq %rax, RDX(%rdi)
1192 movq %rax, RSI(%rdi)
1193 movq %rax, RDI(%rdi)
1194 movq %rax, ORIG_RAX(%rdi)
1195 movq %rcx, RIP(%rdi)
1196 leaq 8(%rsp), %rcx
1197 movq $__KERNEL_CS, CS(%rdi)
1198 movq %rax, EFLAGS(%rdi)
1199 movq %rcx, RSP(%rdi)
1200 movq $__KERNEL_DS, SS(%rdi)
1201 jmpq *%rdx
1202 CFI_ENDPROC
1203ENDPROC(arch_unwind_init_running)
1204#endif