entry_32.S 28.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

/*
 * entry.S contains the system-call and fault low-level handling routines.
 * This also contains the timer-interrupt handler, as well as all interrupts
 * and faults that can result in a task-switch.
 *
 * NOTE: This code handles signal-recognition, which happens every time
 * after a timer-interrupt and after each system call.
 *
 * I changed all the .align's to 4 (16 byte alignment), as that's faster
 * on a 486.
 *
17
 * Stack layout in 'syscall_exit':
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * 	ptrace needs to have all regs on the stack.
 *	if the order here is changed, it needs to be
 *	updated in fork.c:copy_process, signal.c:do_signal,
 *	ptrace.c and ptrace.h
 *
 *	 0(%esp) - %ebx
 *	 4(%esp) - %ecx
 *	 8(%esp) - %edx
 *       C(%esp) - %esi
 *	10(%esp) - %edi
 *	14(%esp) - %ebp
 *	18(%esp) - %eax
 *	1C(%esp) - %ds
 *	20(%esp) - %es
32
 *	24(%esp) - %fs
33 34 35 36 37 38 39
 *	28(%esp) - %gs		saved iff !CONFIG_X86_32_LAZY_GS
 *	2C(%esp) - orig_eax
 *	30(%esp) - %eip
 *	34(%esp) - %cs
 *	38(%esp) - %eflags
 *	3C(%esp) - %oldesp
 *	40(%esp) - %oldss
L
Linus Torvalds 已提交
40 41 42 43 44
 *
 * "current" is in register %ebx during any slow entries.
 */

#include <linux/linkage.h>
45
#include <linux/err.h>
L
Linus Torvalds 已提交
46
#include <asm/thread_info.h>
47
#include <asm/irqflags.h>
L
Linus Torvalds 已提交
48 49 50
#include <asm/errno.h>
#include <asm/segment.h>
#include <asm/smp.h>
51
#include <asm/page_types.h>
S
Stas Sergeev 已提交
52
#include <asm/percpu.h>
53
#include <asm/processor-flags.h>
54
#include <asm/ftrace.h>
55
#include <asm/irq_vectors.h>
56
#include <asm/cpufeature.h>
57
#include <asm/alternative-asm.h>
58
#include <asm/asm.h>
59
#include <asm/smap.h>
L
Linus Torvalds 已提交
60

R
Roland McGrath 已提交
61 62 63 64 65 66 67 68 69 70
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
#include <linux/elf-em.h>
#define AUDIT_ARCH_I386		(EM_386|__AUDIT_ARCH_LE)
#define __AUDIT_ARCH_LE	   0x40000000

#ifndef CONFIG_AUDITSYSCALL
#define sysenter_audit	syscall_trace_entry
#define sysexit_audit	syscall_exit_work
#endif

J
Jiri Olsa 已提交
71 72
	.section .entry.text, "ax"

73 74 75 76 77
/*
 * We use macros for low-level operations which need to be overridden
 * for paravirtualization.  The following will never clobber any registers:
 *   INTERRUPT_RETURN (aka. "iret")
 *   GET_CR0_INTO_EAX (aka. "movl %cr0, %eax")
78
 *   ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit").
79 80 81 82 83 84 85
 *
 * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must
 * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY).
 * Allowing a register to be clobbered can shrink the paravirt replacement
 * enough to patch inline, increasing performance.
 */

L
Linus Torvalds 已提交
86
#ifdef CONFIG_PREEMPT
87
#define preempt_stop(clobbers)	DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF
L
Linus Torvalds 已提交
88
#else
89
#define preempt_stop(clobbers)
90
#define resume_kernel		restore_all
L
Linus Torvalds 已提交
91 92
#endif

93 94
.macro TRACE_IRQS_IRET
#ifdef CONFIG_TRACE_IRQFLAGS
95
	testl $X86_EFLAGS_IF,PT_EFLAGS(%esp)     # interrupts off?
96 97 98 99 100 101
	jz 1f
	TRACE_IRQS_ON
1:
#endif
.endm

102 103 104 105 106 107 108 109 110 111 112 113 114
/*
 * User gs save/restore
 *
 * %gs is used for userland TLS and kernel only uses it for stack
 * canary which is required to be at %gs:20 by gcc.  Read the comment
 * at the top of stackprotector.h for more info.
 *
 * Local labels 98 and 99 are used.
 */
#ifdef CONFIG_X86_32_LAZY_GS

 /* unfortunately push/pop can't be no-op */
.macro PUSH_GS
115
	pushl $0
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
.endm
.macro POP_GS pop=0
	addl $(4 + \pop), %esp
.endm
.macro POP_GS_EX
.endm

 /* all the rest are no-op */
.macro PTGS_TO_GS
.endm
.macro PTGS_TO_GS_EX
.endm
.macro GS_TO_REG reg
.endm
.macro REG_TO_PTGS reg
.endm
.macro SET_KERNEL_GS reg
.endm

#else	/* CONFIG_X86_32_LAZY_GS */

.macro PUSH_GS
138
	pushl %gs
139 140 141
.endm

.macro POP_GS pop=0
142
98:	popl %gs
143 144 145 146 147 148 149 150 151
  .if \pop <> 0
	add $\pop, %esp
  .endif
.endm
.macro POP_GS_EX
.pushsection .fixup, "ax"
99:	movl $0, (%esp)
	jmp 98b
.popsection
152
	_ASM_EXTABLE(98b,99b)
153 154 155 156 157 158 159 160 161 162
.endm

.macro PTGS_TO_GS
98:	mov PT_GS(%esp), %gs
.endm
.macro PTGS_TO_GS_EX
.pushsection .fixup, "ax"
99:	movl $0, PT_GS(%esp)
	jmp 98b
.popsection
163
	_ASM_EXTABLE(98b,99b)
164 165 166 167 168 169 170 171 172
.endm

.macro GS_TO_REG reg
	movl %gs, \reg
.endm
.macro REG_TO_PTGS reg
	movl \reg, PT_GS(%esp)
.endm
.macro SET_KERNEL_GS reg
173
	movl $(__KERNEL_STACK_CANARY), \reg
174 175 176 177 178
	movl \reg, %gs
.endm

#endif	/* CONFIG_X86_32_LAZY_GS */

179 180
.macro SAVE_ALL
	cld
181
	PUSH_GS
182 183 184 185 186 187 188 189 190 191
	pushl %fs
	pushl %es
	pushl %ds
	pushl %eax
	pushl %ebp
	pushl %edi
	pushl %esi
	pushl %edx
	pushl %ecx
	pushl %ebx
192 193 194 195
	movl $(__USER_DS), %edx
	movl %edx, %ds
	movl %edx, %es
	movl $(__KERNEL_PERCPU), %edx
196
	movl %edx, %fs
197
	SET_KERNEL_GS %edx
198
.endm
L
Linus Torvalds 已提交
199

200
.macro RESTORE_INT_REGS
201 202 203 204 205 206 207
	popl %ebx
	popl %ecx
	popl %edx
	popl %esi
	popl %edi
	popl %ebp
	popl %eax
208
.endm
L
Linus Torvalds 已提交
209

210
.macro RESTORE_REGS pop=0
211
	RESTORE_INT_REGS
212 213 214
1:	popl %ds
2:	popl %es
3:	popl %fs
215
	POP_GS \pop
216 217 218 219 220 221 222
.pushsection .fixup, "ax"
4:	movl $0, (%esp)
	jmp 1b
5:	movl $0, (%esp)
	jmp 2b
6:	movl $0, (%esp)
	jmp 3b
223
.popsection
224 225 226
	_ASM_EXTABLE(1b,4b)
	_ASM_EXTABLE(2b,5b)
	_ASM_EXTABLE(3b,6b)
227
	POP_GS_EX
228
.endm
L
Linus Torvalds 已提交
229 230

ENTRY(ret_from_fork)
231
	pushl %eax
L
Linus Torvalds 已提交
232 233
	call schedule_tail
	GET_THREAD_INFO(%ebp)
234 235 236
	popl %eax
	pushl $0x0202		# Reset kernel eflags
	popfl
L
Linus Torvalds 已提交
237
	jmp syscall_exit
238
END(ret_from_fork)
L
Linus Torvalds 已提交
239

240
ENTRY(ret_from_kernel_thread)
241
	pushl %eax
242
	call schedule_tail
243
	GET_THREAD_INFO(%ebp)
244 245 246
	popl %eax
	pushl $0x0202		# Reset kernel eflags
	popfl
247 248 249
	movl PT_EBP(%esp),%eax
	call *PT_EBX(%esp)
	movl $0,PT_EAX(%esp)
250
	jmp syscall_exit
251
ENDPROC(ret_from_kernel_thread)
252

L
Linus Torvalds 已提交
253 254 255 256 257 258 259 260 261 262
/*
 * Return to user mode is not as complex as all this looks,
 * but we want the default path for a system call return to
 * go as quickly as possible which is why some of this is
 * less clear than it otherwise should be.
 */

	# userspace resumption stub bypassing syscall exit tracing
	ALIGN
ret_from_exception:
263
	preempt_stop(CLBR_ANY)
L
Linus Torvalds 已提交
264 265
ret_from_intr:
	GET_THREAD_INFO(%ebp)
266
#ifdef CONFIG_VM86
267 268
	movl PT_EFLAGS(%esp), %eax	# mix EFLAGS and CS
	movb PT_CS(%esp), %al
269
	andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
270 271
#else
	/*
272
	 * We can be coming here from child spawned by kernel_thread().
273 274 275 276
	 */
	movl PT_CS(%esp), %eax
	andl $SEGMENT_RPL_MASK, %eax
#endif
277 278
	cmpl $USER_RPL, %eax
	jb resume_kernel		# not returning to v8086 or userspace
279

L
Linus Torvalds 已提交
280
ENTRY(resume_userspace)
281
	LOCKDEP_SYS_EXIT
282
 	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
L
Linus Torvalds 已提交
283 284
					# setting need_resched or sigpending
					# between sampling and the iret
285
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
286 287 288 289 290
	movl TI_flags(%ebp), %ecx
	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done on
					# int/exception return?
	jne work_pending
	jmp restore_all
291
END(ret_from_exception)
L
Linus Torvalds 已提交
292 293 294

#ifdef CONFIG_PREEMPT
ENTRY(resume_kernel)
295
	DISABLE_INTERRUPTS(CLBR_ANY)
L
Linus Torvalds 已提交
296
need_resched:
297 298
	cmpl $0,PER_CPU_VAR(__preempt_count)
	jnz restore_all
299
	testl $X86_EFLAGS_IF,PT_EFLAGS(%esp)	# interrupts off (exception path) ?
L
Linus Torvalds 已提交
300 301 302
	jz restore_all
	call preempt_schedule_irq
	jmp need_resched
303
END(resume_kernel)
L
Linus Torvalds 已提交
304 305 306 307 308 309
#endif

/* SYSENTER_RETURN points to after the "sysenter" instruction in
   the vsyscall page.  See vsyscall-sysentry.S, which defines the symbol.  */

	# sysenter call handler stub
310
ENTRY(entry_SYSENTER_32)
311
	movl TSS_sysenter_sp0(%esp),%esp
L
Linus Torvalds 已提交
312
sysenter_past_esp:
313
	/*
314 315 316
	 * Interrupts are disabled here, but we can't trace it until
	 * enough kernel state to call TRACE_IRQS_OFF can be called - but
	 * we immediately enable interrupts at that point anyway.
317
	 */
318 319 320
	pushl $__USER_DS
	pushl %ebp
	pushfl
321
	orl $X86_EFLAGS_IF, (%esp)
322
	pushl $__USER_CS
323 324
	/*
	 * Push current_thread_info()->sysenter_return to the stack.
325 326 327 328 329
	 * A tiny bit of offset fixup is necessary: TI_sysenter_return
	 * is relative to thread_info, which is at the bottom of the
	 * kernel stack page.  4*4 means the 4 words pushed above;
	 * TOP_OF_KERNEL_STACK_PADDING takes us to the top of the stack;
	 * and THREAD_SIZE takes us to the bottom.
330
	 */
331
	pushl ((TI_sysenter_return) - THREAD_SIZE + TOP_OF_KERNEL_STACK_PADDING + 4*4)(%esp)
L
Linus Torvalds 已提交
332

333
	pushl %eax
334 335 336
	SAVE_ALL
	ENABLE_INTERRUPTS(CLBR_NONE)

L
Linus Torvalds 已提交
337 338 339 340 341 342
/*
 * Load the potential sixth argument from user stack.
 * Careful about security.
 */
	cmpl $__PAGE_OFFSET-3,%ebp
	jae syscall_fault
343
	ASM_STAC
L
Linus Torvalds 已提交
344
1:	movl (%ebp),%ebp
345
	ASM_CLAC
346
	movl %ebp,PT_EBP(%esp)
347
	_ASM_EXTABLE(1b,syscall_fault)
L
Linus Torvalds 已提交
348 349 350

	GET_THREAD_INFO(%ebp)

351
	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
R
Roland McGrath 已提交
352 353
	jnz sysenter_audit
sysenter_do_call:
354
	cmpl $(NR_syscalls), %eax
355
	jae sysenter_badsys
L
Linus Torvalds 已提交
356
	call *sys_call_table(,%eax,4)
357
sysenter_after_call:
358
	movl %eax,PT_EAX(%esp)
359
	LOCKDEP_SYS_EXIT
360
	DISABLE_INTERRUPTS(CLBR_ANY)
361
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
362
	movl TI_flags(%ebp), %ecx
363
	testl $_TIF_ALLWORK_MASK, %ecx
364
	jnz sysexit_audit
R
Roland McGrath 已提交
365
sysenter_exit:
L
Linus Torvalds 已提交
366
/* if something modifies registers it must also disable sysexit */
367 368
	movl PT_EIP(%esp), %edx
	movl PT_OLDESP(%esp), %ecx
L
Linus Torvalds 已提交
369
	xorl %ebp,%ebp
370
	TRACE_IRQS_ON
371
1:	mov  PT_FS(%esp), %fs
372
	PTGS_TO_GS
373
	ENABLE_INTERRUPTS_SYSEXIT
R
Roland McGrath 已提交
374 375 376

#ifdef CONFIG_AUDITSYSCALL
sysenter_audit:
377
	testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
R
Roland McGrath 已提交
378
	jnz syscall_trace_entry
379 380 381
	/* movl PT_EAX(%esp), %eax	already set, syscall number: 1st arg to audit */
	movl PT_EBX(%esp), %edx		/* ebx/a0: 2nd arg to audit */
	/* movl PT_ECX(%esp), %ecx	already set, a1: 3nd arg to audit */
382 383
	pushl PT_ESI(%esp)		/* a3: 5th arg */
	pushl PT_EDX+4(%esp)	/* a2: 4th arg */
384
	call __audit_syscall_entry
385 386
	popl %ecx /* get that remapped edx off the stack */
	popl %ecx /* get that remapped esi off the stack */
R
Roland McGrath 已提交
387 388 389 390
	movl PT_EAX(%esp),%eax		/* reload syscall number */
	jmp sysenter_do_call

sysexit_audit:
391
	testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
392
	jnz syscall_exit_work
R
Roland McGrath 已提交
393 394 395
	TRACE_IRQS_ON
	ENABLE_INTERRUPTS(CLBR_ANY)
	movl %eax,%edx		/* second arg, syscall return value */
396 397
	cmpl $-MAX_ERRNO,%eax	/* is it an error ? */
	setbe %al		/* 1 if so, 0 if not */
R
Roland McGrath 已提交
398
	movzbl %al,%eax		/* zero-extend that */
399
	call __audit_syscall_exit
R
Roland McGrath 已提交
400 401 402
	DISABLE_INTERRUPTS(CLBR_ANY)
	TRACE_IRQS_OFF
	movl TI_flags(%ebp), %ecx
403
	testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
404
	jnz syscall_exit_work
R
Roland McGrath 已提交
405 406 407 408
	movl PT_EAX(%esp),%eax	/* reload syscall return value */
	jmp sysenter_exit
#endif

409
.pushsection .fixup,"ax"
410
2:	movl $0,PT_FS(%esp)
411 412
	jmp 1b
.popsection
413
	_ASM_EXTABLE(1b,2b)
414
	PTGS_TO_GS_EX
415
ENDPROC(entry_SYSENTER_32)
L
Linus Torvalds 已提交
416 417 418

	# system call handler stub
ENTRY(system_call)
419
	ASM_CLAC
420
	pushl %eax			# save orig_eax
L
Linus Torvalds 已提交
421 422
	SAVE_ALL
	GET_THREAD_INFO(%ebp)
423
					# system call tracing in operation / emulation
424
	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
L
Linus Torvalds 已提交
425
	jnz syscall_trace_entry
426
	cmpl $(NR_syscalls), %eax
L
Linus Torvalds 已提交
427 428 429
	jae syscall_badsys
syscall_call:
	call *sys_call_table(,%eax,4)
430
syscall_after_call:
431
	movl %eax,PT_EAX(%esp)		# store the return value
L
Linus Torvalds 已提交
432
syscall_exit:
433
	LOCKDEP_SYS_EXIT
434
	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
L
Linus Torvalds 已提交
435 436
					# setting need_resched or sigpending
					# between sampling and the iret
437
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
438
	movl TI_flags(%ebp), %ecx
439
	testl $_TIF_ALLWORK_MASK, %ecx	# current->work
440
	jnz syscall_exit_work
L
Linus Torvalds 已提交
441 442

restore_all:
443 444
	TRACE_IRQS_IRET
restore_all_notrace:
445
#ifdef CONFIG_X86_ESPFIX32
446 447
	movl PT_EFLAGS(%esp), %eax	# mix EFLAGS, SS and CS
	# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
448 449
	# are returning to the kernel.
	# See comments in process.c:copy_thread() for details.
450 451
	movb PT_OLDSS(%esp), %ah
	movb PT_CS(%esp), %al
452
	andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
453
	cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
L
Linus Torvalds 已提交
454
	je ldt_ss			# returning to user-space with LDT SS
455
#endif
L
Linus Torvalds 已提交
456
restore_nocheck:
457
	RESTORE_REGS 4			# skip orig_eax/error_code
A
Adrian Bunk 已提交
458
irq_return:
I
Ingo Molnar 已提交
459
	INTERRUPT_RETURN
L
Linus Torvalds 已提交
460
.section .fixup,"ax"
461
ENTRY(iret_exc)
462 463 464
	pushl $0			# no error code
	pushl $do_iret_error
	jmp error_code
L
Linus Torvalds 已提交
465
.previous
466
	_ASM_EXTABLE(irq_return,iret_exc)
L
Linus Torvalds 已提交
467

468
#ifdef CONFIG_X86_ESPFIX32
L
Linus Torvalds 已提交
469
ldt_ss:
470 471 472 473 474 475 476 477 478
#ifdef CONFIG_PARAVIRT
	/*
	 * The kernel can't run on a non-flat stack if paravirt mode
	 * is active.  Rather than try to fixup the high bits of
	 * ESP, bypass this code entirely.  This may break DOSemu
	 * and/or Wine support in a paravirt VM, although the option
	 * is still available to implement the setting of the high
	 * 16-bits in the INTERRUPT_RETURN paravirt-op.
	 */
479
	cmpl $0, pv_info+PARAVIRT_enabled
480 481 482
	jne restore_nocheck
#endif

483 484 485 486 487 488 489 490 491 492 493
/*
 * Setup and switch to ESPFIX stack
 *
 * We're returning to userspace with a 16 bit stack. The CPU will not
 * restore the high word of ESP for us on executing iret... This is an
 * "official" bug of all the x86-compatible CPUs, which we can work
 * around to make dosemu and wine happy. We do this by preloading the
 * high word of ESP with the high word of the userspace ESP while
 * compensating for the offset by changing to the ESPFIX segment with
 * a base address that matches for the difference.
 */
494
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
495 496 497 498 499
	mov %esp, %edx			/* load kernel esp */
	mov PT_OLDESP(%esp), %eax	/* load userspace esp */
	mov %dx, %ax			/* eax: new kernel esp */
	sub %eax, %edx			/* offset (low word is 0) */
	shr $16, %edx
500 501
	mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
	mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
502 503
	pushl $__ESPFIX_SS
	pushl %eax			/* new kernel esp */
504 505 506
	/* Disable interrupts, but do not irqtrace this section: we
	 * will soon execute iret and the tracer was already set to
	 * the irqstate after the iret */
507
	DISABLE_INTERRUPTS(CLBR_EAX)
508
	lss (%esp), %esp		/* switch to espfix segment */
S
Stas Sergeev 已提交
509
	jmp restore_nocheck
510
#endif
511
ENDPROC(system_call)
L
Linus Torvalds 已提交
512 513 514 515 516 517 518 519

	# perform work that needs to be done immediately before resumption
	ALIGN
work_pending:
	testb $_TIF_NEED_RESCHED, %cl
	jz work_notifysig
work_resched:
	call schedule
520
	LOCKDEP_SYS_EXIT
521
	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
L
Linus Torvalds 已提交
522 523
					# setting need_resched or sigpending
					# between sampling and the iret
524
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
525 526 527 528 529 530 531 532 533
	movl TI_flags(%ebp), %ecx
	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done other
					# than syscall tracing?
	jz restore_all
	testb $_TIF_NEED_RESCHED, %cl
	jnz work_resched

work_notifysig:				# deal with pending signals and
					# notify-resume requests
534
#ifdef CONFIG_VM86
535
	testl $X86_EFLAGS_VM, PT_EFLAGS(%esp)
L
Linus Torvalds 已提交
536
	movl %esp, %eax
537
	jnz work_notifysig_v86		# returning to kernel-space or
L
Linus Torvalds 已提交
538
					# vm86-space
539 540 541 542
1:
#else
	movl %esp, %eax
#endif
543 544
	TRACE_IRQS_ON
	ENABLE_INTERRUPTS(CLBR_NONE)
545 546 547 548
	movb PT_CS(%esp), %bl
	andb $SEGMENT_RPL_MASK, %bl
	cmpb $USER_RPL, %bl
	jb resume_kernel
L
Linus Torvalds 已提交
549 550
	xorl %edx, %edx
	call do_notify_resume
551
	jmp resume_userspace
L
Linus Torvalds 已提交
552

553
#ifdef CONFIG_VM86
L
Linus Torvalds 已提交
554 555
	ALIGN
work_notifysig_v86:
556
	pushl %ecx			# save ti_flags for do_notify_resume
L
Linus Torvalds 已提交
557
	call save_v86_state		# %eax contains pt_regs pointer
558
	popl %ecx
L
Linus Torvalds 已提交
559
	movl %eax, %esp
560
	jmp 1b
561
#endif
562
END(work_pending)
L
Linus Torvalds 已提交
563 564 565 566

	# perform syscall exit tracing
	ALIGN
syscall_trace_entry:
567
	movl $-ENOSYS,PT_EAX(%esp)
L
Linus Torvalds 已提交
568
	movl %esp, %eax
569 570
	call syscall_trace_enter
	/* What it returned is what we'll actually use.  */
571
	cmpl $(NR_syscalls), %eax
L
Linus Torvalds 已提交
572 573
	jnae syscall_call
	jmp syscall_exit
574
END(syscall_trace_entry)
L
Linus Torvalds 已提交
575 576 577 578

	# perform syscall exit tracing
	ALIGN
syscall_exit_work:
579
	testl $_TIF_WORK_SYSCALL_EXIT, %ecx
L
Linus Torvalds 已提交
580
	jz work_pending
581
	TRACE_IRQS_ON
582
	ENABLE_INTERRUPTS(CLBR_ANY)	# could let syscall_trace_leave() call
L
Linus Torvalds 已提交
583 584
					# schedule() instead
	movl %esp, %eax
585
	call syscall_trace_leave
L
Linus Torvalds 已提交
586
	jmp resume_userspace
587
END(syscall_exit_work)
L
Linus Torvalds 已提交
588 589

syscall_fault:
590
	ASM_CLAC
L
Linus Torvalds 已提交
591
	GET_THREAD_INFO(%ebp)
592
	movl $-EFAULT,PT_EAX(%esp)
L
Linus Torvalds 已提交
593
	jmp resume_userspace
594
END(syscall_fault)
L
Linus Torvalds 已提交
595 596

syscall_badsys:
597 598
	movl $-ENOSYS,%eax
	jmp syscall_after_call
599 600 601
END(syscall_badsys)

sysenter_badsys:
602
	movl $-ENOSYS,%eax
603
	jmp sysenter_after_call
604
END(sysenter_badsys)
L
Linus Torvalds 已提交
605

606
.macro FIXUP_ESPFIX_STACK
607 608 609 610 611 612 613
/*
 * Switch back for ESPFIX stack to the normal zerobased stack
 *
 * We can't call C functions using the ESPFIX stack. This code reads
 * the high word of the segment base from the GDT and swiches to the
 * normal stack and adjusts ESP with the matching offset.
 */
614
#ifdef CONFIG_X86_ESPFIX32
615
	/* fixup the stack */
616 617
	mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
	mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
618 619
	shl $16, %eax
	addl %esp, %eax			/* the adjusted stack pointer */
620 621
	pushl $__KERNEL_DS
	pushl %eax
622
	lss (%esp), %esp		/* switch to the normal stack segment */
623
#endif
624 625
.endm
.macro UNWIND_ESPFIX_STACK
626
#ifdef CONFIG_X86_ESPFIX32
627 628 629 630 631 632 633 634 635 636
	movl %ss, %eax
	/* see if on espfix stack */
	cmpw $__ESPFIX_SS, %ax
	jne 27f
	movl $__KERNEL_DS, %eax
	movl %eax, %ds
	movl %eax, %es
	/* switch to normal stack */
	FIXUP_ESPFIX_STACK
27:
637
#endif
638
.endm
L
Linus Torvalds 已提交
639 640

/*
641 642
 * Build the entry stubs with some assembler magic.
 * We pack 1 stub into every 8-byte block.
L
Linus Torvalds 已提交
643
 */
644
	.align 8
L
Linus Torvalds 已提交
645
ENTRY(irq_entries_start)
646 647
    vector=FIRST_EXTERNAL_VECTOR
    .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
648
	pushl $(~vector+0x80)	/* Note: always in signed byte range */
649 650 651 652
    vector=vector+1
	jmp	common_interrupt
	.align	8
    .endr
653 654
END(irq_entries_start)

655 656 657 658
/*
 * the CPU automatically disables interrupts when executing an IRQ vector,
 * so IRQ-flags tracing has to follow that:
 */
659
	.p2align CONFIG_X86_L1_CACHE_SHIFT
L
Linus Torvalds 已提交
660
common_interrupt:
661
	ASM_CLAC
662
	addl $-0x80,(%esp)	/* Adjust vector into the [-256,-1] range */
L
Linus Torvalds 已提交
663
	SAVE_ALL
664
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
665 666 667
	movl %esp,%eax
	call do_IRQ
	jmp ret_from_intr
668
ENDPROC(common_interrupt)
L
Linus Torvalds 已提交
669

T
Tejun Heo 已提交
670
#define BUILD_INTERRUPT3(name, nr, fn)	\
L
Linus Torvalds 已提交
671
ENTRY(name)				\
672
	ASM_CLAC;			\
673
	pushl $~(nr);		\
674
	SAVE_ALL;			\
675
	TRACE_IRQS_OFF			\
L
Linus Torvalds 已提交
676
	movl %esp,%eax;			\
T
Tejun Heo 已提交
677
	call fn;			\
678
	jmp ret_from_intr;		\
679
ENDPROC(name)
L
Linus Torvalds 已提交
680

681 682 683 684 685 686 687 688 689 690 691

#ifdef CONFIG_TRACING
#define TRACE_BUILD_INTERRUPT(name, nr)		\
	BUILD_INTERRUPT3(trace_##name, nr, smp_trace_##name)
#else
#define TRACE_BUILD_INTERRUPT(name, nr)
#endif

#define BUILD_INTERRUPT(name, nr) \
	BUILD_INTERRUPT3(name, nr, smp_##name); \
	TRACE_BUILD_INTERRUPT(name, nr)
T
Tejun Heo 已提交
692

L
Linus Torvalds 已提交
693
/* The include is where all of the SMP etc. interrupts come from */
694
#include <asm/entry_arch.h>
L
Linus Torvalds 已提交
695 696

ENTRY(coprocessor_error)
697
	ASM_CLAC
698 699
	pushl $0
	pushl $do_coprocessor_error
L
Linus Torvalds 已提交
700
	jmp error_code
701
END(coprocessor_error)
L
Linus Torvalds 已提交
702 703

ENTRY(simd_coprocessor_error)
704
	ASM_CLAC
705
	pushl $0
706 707
#ifdef CONFIG_X86_INVD_BUG
	/* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
708
	ALTERNATIVE "pushl $do_general_protection",	\
709 710
		    "pushl $do_simd_coprocessor_error", \
		    X86_FEATURE_XMM
711
#else
712
	pushl $do_simd_coprocessor_error
713
#endif
L
Linus Torvalds 已提交
714
	jmp error_code
715
END(simd_coprocessor_error)
L
Linus Torvalds 已提交
716 717

ENTRY(device_not_available)
718
	ASM_CLAC
719 720
	pushl $-1			# mark this as an int
	pushl $do_device_not_available
721
	jmp error_code
722
END(device_not_available)
L
Linus Torvalds 已提交
723

724 725
#ifdef CONFIG_PARAVIRT
ENTRY(native_iret)
I
Ingo Molnar 已提交
726
	iret
727
	_ASM_EXTABLE(native_iret, iret_exc)
728
END(native_iret)
729

730
ENTRY(native_irq_enable_sysexit)
731 732
	sti
	sysexit
733
END(native_irq_enable_sysexit)
734 735
#endif

L
Linus Torvalds 已提交
736
ENTRY(overflow)
737
	ASM_CLAC
738 739
	pushl $0
	pushl $do_overflow
L
Linus Torvalds 已提交
740
	jmp error_code
741
END(overflow)
L
Linus Torvalds 已提交
742 743

ENTRY(bounds)
744
	ASM_CLAC
745 746
	pushl $0
	pushl $do_bounds
L
Linus Torvalds 已提交
747
	jmp error_code
748
END(bounds)
L
Linus Torvalds 已提交
749 750

ENTRY(invalid_op)
751
	ASM_CLAC
752 753
	pushl $0
	pushl $do_invalid_op
L
Linus Torvalds 已提交
754
	jmp error_code
755
END(invalid_op)
L
Linus Torvalds 已提交
756 757

ENTRY(coprocessor_segment_overrun)
758
	ASM_CLAC
759 760
	pushl $0
	pushl $do_coprocessor_segment_overrun
L
Linus Torvalds 已提交
761
	jmp error_code
762
END(coprocessor_segment_overrun)
L
Linus Torvalds 已提交
763 764

ENTRY(invalid_TSS)
765
	ASM_CLAC
766
	pushl $do_invalid_TSS
L
Linus Torvalds 已提交
767
	jmp error_code
768
END(invalid_TSS)
L
Linus Torvalds 已提交
769 770

ENTRY(segment_not_present)
771
	ASM_CLAC
772
	pushl $do_segment_not_present
L
Linus Torvalds 已提交
773
	jmp error_code
774
END(segment_not_present)
L
Linus Torvalds 已提交
775 776

ENTRY(stack_segment)
777
	ASM_CLAC
778
	pushl $do_stack_segment
L
Linus Torvalds 已提交
779
	jmp error_code
780
END(stack_segment)
L
Linus Torvalds 已提交
781 782

ENTRY(alignment_check)
783
	ASM_CLAC
784
	pushl $do_alignment_check
L
Linus Torvalds 已提交
785
	jmp error_code
786
END(alignment_check)
L
Linus Torvalds 已提交
787

788
ENTRY(divide_error)
789
	ASM_CLAC
790 791
	pushl $0			# no error code
	pushl $do_divide_error
L
Linus Torvalds 已提交
792
	jmp error_code
793
END(divide_error)
L
Linus Torvalds 已提交
794 795 796

#ifdef CONFIG_X86_MCE
ENTRY(machine_check)
797
	ASM_CLAC
798 799
	pushl $0
	pushl machine_check_vector
L
Linus Torvalds 已提交
800
	jmp error_code
801
END(machine_check)
L
Linus Torvalds 已提交
802 803 804
#endif

ENTRY(spurious_interrupt_bug)
805
	ASM_CLAC
806 807
	pushl $0
	pushl $do_spurious_interrupt_bug
L
Linus Torvalds 已提交
808
	jmp error_code
809
END(spurious_interrupt_bug)
L
Linus Torvalds 已提交
810

811
#ifdef CONFIG_XEN
812 813 814 815 816 817
/* Xen doesn't set %esp to be precisely what the normal sysenter
   entrypoint expects, so fix it up before using the normal path. */
ENTRY(xen_sysenter_target)
	addl $5*4, %esp		/* remove xen-provided frame */
	jmp sysenter_past_esp

818
ENTRY(xen_hypervisor_callback)
819
	pushl $-1 /* orig_ax = -1 => not a system call */
820 821
	SAVE_ALL
	TRACE_IRQS_OFF
822 823 824 825 826 827 828 829 830 831 832 833

	/* Check to see if we got the event in the critical
	   region in xen_iret_direct, after we've reenabled
	   events and checked for pending events.  This simulates
	   iret instruction's behaviour where it delivers a
	   pending interrupt when enabling interrupts. */
	movl PT_EIP(%esp),%eax
	cmpl $xen_iret_start_crit,%eax
	jb   1f
	cmpl $xen_iret_end_crit,%eax
	jae  1f

J
Jeremy Fitzhardinge 已提交
834
	jmp  xen_iret_crit_fixup
835 836

ENTRY(xen_do_upcall)
837
1:	mov %esp, %eax
838
	call xen_evtchn_do_upcall
839 840 841
#ifndef CONFIG_PREEMPT
	call xen_maybe_preempt_hcall
#endif
842 843 844 845 846 847 848 849 850 851 852 853 854 855
	jmp  ret_from_intr
ENDPROC(xen_hypervisor_callback)

# Hypervisor uses this for application faults while it executes.
# We get here for two reasons:
#  1. Fault while reloading DS, ES, FS or GS
#  2. Fault while executing IRET
# Category 1 we fix up by reattempting the load, and zeroing the segment
# register if the load fails.
# Category 2 we fix up by jumping to do_iret_error. We cannot use the
# normal Linux return path in this case because if we use the IRET hypercall
# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
# We distinguish between categories by maintaining a status value in EAX.
ENTRY(xen_failsafe_callback)
856
	pushl %eax
857 858 859 860 861
	movl $1,%eax
1:	mov 4(%esp),%ds
2:	mov 8(%esp),%es
3:	mov 12(%esp),%fs
4:	mov 16(%esp),%gs
862 863
	/* EAX == 0 => Category 1 (Bad segment)
	   EAX != 0 => Category 2 (Bad IRET) */
864
	testl %eax,%eax
865
	popl %eax
866 867
	lea 16(%esp),%esp
	jz 5f
868
	jmp iret_exc
869
5:	pushl $-1 /* orig_ax = -1 => not a system call */
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
	SAVE_ALL
	jmp ret_from_exception

.section .fixup,"ax"
6:	xorl %eax,%eax
	movl %eax,4(%esp)
	jmp 1b
7:	xorl %eax,%eax
	movl %eax,8(%esp)
	jmp 2b
8:	xorl %eax,%eax
	movl %eax,12(%esp)
	jmp 3b
9:	xorl %eax,%eax
	movl %eax,16(%esp)
	jmp 4b
.previous
887 888 889 890
	_ASM_EXTABLE(1b,6b)
	_ASM_EXTABLE(2b,7b)
	_ASM_EXTABLE(3b,8b)
	_ASM_EXTABLE(4b,9b)
891 892
ENDPROC(xen_failsafe_callback)

893
BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
894 895
		xen_evtchn_do_upcall)

896
#endif	/* CONFIG_XEN */
897 898 899 900 901 902 903

#if IS_ENABLED(CONFIG_HYPERV)

BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
	hyperv_vector_handler)

#endif /* CONFIG_HYPERV */
904

905
#ifdef CONFIG_FUNCTION_TRACER
906 907 908 909 910 911 912 913 914 915
#ifdef CONFIG_DYNAMIC_FTRACE

ENTRY(mcount)
	ret
END(mcount)

ENTRY(ftrace_caller)
	pushl %eax
	pushl %ecx
	pushl %edx
916 917
	pushl $0	/* Pass NULL as regs pointer */
	movl 4*4(%esp), %eax
918
	movl 0x4(%ebp), %edx
919
	movl function_trace_op, %ecx
920
	subl $MCOUNT_INSN_SIZE, %eax
921 922 923 924 925

.globl ftrace_call
ftrace_call:
	call ftrace_stub

926
	addl $4,%esp	/* skip NULL pointer */
927 928 929
	popl %edx
	popl %ecx
	popl %eax
930
ftrace_ret:
931 932 933 934 935
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl ftrace_graph_call
ftrace_graph_call:
	jmp ftrace_stub
#endif
936 937 938 939 940 941

.globl ftrace_stub
ftrace_stub:
	ret
END(ftrace_caller)

942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
ENTRY(ftrace_regs_caller)
	pushf	/* push flags before compare (in cs location) */

	/*
	 * i386 does not save SS and ESP when coming from kernel.
	 * Instead, to get sp, &regs->sp is used (see ptrace.h).
	 * Unfortunately, that means eflags must be at the same location
	 * as the current return ip is. We move the return ip into the
	 * ip location, and move flags into the return ip location.
	 */
	pushl 4(%esp)	/* save return ip into ip slot */

	pushl $0	/* Load 0 into orig_ax */
	pushl %gs
	pushl %fs
	pushl %es
	pushl %ds
	pushl %eax
	pushl %ebp
	pushl %edi
	pushl %esi
	pushl %edx
	pushl %ecx
	pushl %ebx

	movl 13*4(%esp), %eax	/* Get the saved flags */
	movl %eax, 14*4(%esp)	/* Move saved flags into regs->flags location */
				/* clobbering return ip */
	movl $__KERNEL_CS,13*4(%esp)

	movl 12*4(%esp), %eax	/* Load ip (1st parameter) */
973
	subl $MCOUNT_INSN_SIZE, %eax	/* Adjust ip */
974
	movl 0x4(%ebp), %edx	/* Load parent ip (2nd parameter) */
975
	movl function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */
976
	pushl %esp		/* Save pt_regs as 4th parameter */
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003

GLOBAL(ftrace_regs_call)
	call ftrace_stub

	addl $4, %esp		/* Skip pt_regs */
	movl 14*4(%esp), %eax	/* Move flags back into cs */
	movl %eax, 13*4(%esp)	/* Needed to keep addl from modifying flags */
	movl 12*4(%esp), %eax	/* Get return ip from regs->ip */
	movl %eax, 14*4(%esp)	/* Put return ip back for ret */

	popl %ebx
	popl %ecx
	popl %edx
	popl %esi
	popl %edi
	popl %ebp
	popl %eax
	popl %ds
	popl %es
	popl %fs
	popl %gs
	addl $8, %esp		/* Skip orig_ax and ip */
	popf			/* Pop flags at end (no addl to corrupt flags) */
	jmp ftrace_ret

	popf
	jmp  ftrace_stub
1004 1005
#else /* ! CONFIG_DYNAMIC_FTRACE */

1006
ENTRY(mcount)
1007 1008 1009
	cmpl $__PAGE_OFFSET, %esp
	jb ftrace_stub		/* Paging not enabled yet? */

1010 1011
	cmpl $ftrace_stub, ftrace_trace_function
	jnz trace
1012
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
I
Ingo Molnar 已提交
1013
	cmpl $ftrace_stub, ftrace_graph_return
1014
	jnz ftrace_graph_caller
1015 1016 1017

	cmpl $ftrace_graph_entry_stub, ftrace_graph_entry
	jnz ftrace_graph_caller
1018
#endif
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
.globl ftrace_stub
ftrace_stub:
	ret

	/* taken from glibc */
trace:
	pushl %eax
	pushl %ecx
	pushl %edx
	movl 0xc(%esp), %eax
	movl 0x4(%ebp), %edx
1030
	subl $MCOUNT_INSN_SIZE, %eax
1031

1032
	call *ftrace_trace_function
1033 1034 1035 1036 1037 1038

	popl %edx
	popl %ecx
	popl %eax
	jmp ftrace_stub
END(mcount)
1039
#endif /* CONFIG_DYNAMIC_FTRACE */
1040
#endif /* CONFIG_FUNCTION_TRACER */
1041

1042 1043
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
1044 1045 1046
	pushl %eax
	pushl %ecx
	pushl %edx
1047 1048
	movl 0xc(%esp), %eax
	lea 0x4(%ebp), %edx
1049
	movl (%ebp), %ecx
1050
	subl $MCOUNT_INSN_SIZE, %eax
1051 1052 1053 1054
	call prepare_ftrace_return
	popl %edx
	popl %ecx
	popl %eax
1055
	ret
1056
END(ftrace_graph_caller)
1057 1058 1059 1060 1061

.globl return_to_handler
return_to_handler:
	pushl %eax
	pushl %edx
1062
	movl %ebp, %eax
1063
	call ftrace_return_to_handler
1064
	movl %eax, %ecx
1065 1066
	popl %edx
	popl %eax
1067
	jmp *%ecx
1068
#endif
1069

1070 1071 1072
#ifdef CONFIG_TRACING
ENTRY(trace_page_fault)
	ASM_CLAC
1073
	pushl $trace_do_page_fault
1074 1075 1076 1077
	jmp error_code
END(trace_page_fault)
#endif

1078
ENTRY(page_fault)
1079
	ASM_CLAC
1080
	pushl $do_page_fault
1081 1082
	ALIGN
error_code:
1083
	/* the function address is in %gs's slot on the stack */
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
	pushl %fs
	pushl %es
	pushl %ds
	pushl %eax
	pushl %ebp
	pushl %edi
	pushl %esi
	pushl %edx
	pushl %ecx
	pushl %ebx
1094 1095 1096 1097
	cld
	movl $(__KERNEL_PERCPU), %ecx
	movl %ecx, %fs
	UNWIND_ESPFIX_STACK
1098 1099
	GS_TO_REG %ecx
	movl PT_GS(%esp), %edi		# get the function address
1100 1101
	movl PT_ORIG_EAX(%esp), %edx	# get the error code
	movl $-1, PT_ORIG_EAX(%esp)	# no syscall to restart
1102 1103
	REG_TO_PTGS %ecx
	SET_KERNEL_GS %ecx
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
	movl $(__USER_DS), %ecx
	movl %ecx, %ds
	movl %ecx, %es
	TRACE_IRQS_OFF
	movl %esp,%eax			# pt_regs pointer
	call *%edi
	jmp ret_from_exception
END(page_fault)

/*
 * Debug traps and NMI can happen at the one SYSENTER instruction
 * that sets up the real kernel stack. Check here, since we can't
 * allow the wrong stack to be used.
 *
 * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have
 * already pushed 3 words if it hits on the sysenter instruction:
 * eflags, cs and eip.
 *
 * We just load the right stack, and push the three (known) values
 * by hand onto the new stack - while updating the return eip past
 * the instruction that would have done it for sysenter.
 */
1126 1127 1128 1129 1130
.macro FIX_STACK offset ok label
	cmpw $__KERNEL_CS, 4(%esp)
	jne \ok
\label:
	movl TSS_sysenter_sp0 + \offset(%esp), %esp
1131 1132 1133
	pushfl
	pushl $__KERNEL_CS
	pushl $sysenter_past_esp
1134
.endm
1135 1136

ENTRY(debug)
1137
	ASM_CLAC
1138
	cmpl $entry_SYSENTER_32,(%esp)
1139
	jne debug_stack_correct
1140
	FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
1141
debug_stack_correct:
1142
	pushl $-1			# mark this as an int
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
	SAVE_ALL
	TRACE_IRQS_OFF
	xorl %edx,%edx			# error code 0
	movl %esp,%eax			# pt_regs pointer
	call do_debug
	jmp ret_from_exception
END(debug)

/*
 * NMI is doubly nasty. It can happen _while_ we're handling
 * a debug fault, and the debug fault hasn't yet been able to
 * clear up the stack. So we first check whether we got  an
 * NMI on the sysenter entry path, but after that we need to
 * check whether we got an NMI on the debug path where the debug
 * fault happened on the sysenter path.
 */
ENTRY(nmi)
1160
	ASM_CLAC
1161
#ifdef CONFIG_X86_ESPFIX32
1162
	pushl %eax
1163 1164
	movl %ss, %eax
	cmpw $__ESPFIX_SS, %ax
1165
	popl %eax
1166
	je nmi_espfix_stack
1167
#endif
1168
	cmpl $entry_SYSENTER_32,(%esp)
1169
	je nmi_stack_fixup
1170
	pushl %eax
1171 1172 1173 1174 1175 1176
	movl %esp,%eax
	/* Do not access memory above the end of our stack page,
	 * it might not exist.
	 */
	andl $(THREAD_SIZE-1),%eax
	cmpl $(THREAD_SIZE-20),%eax
1177
	popl %eax
1178
	jae nmi_stack_correct
1179
	cmpl $entry_SYSENTER_32,12(%esp)
1180 1181
	je nmi_debug_stack_check
nmi_stack_correct:
1182
	pushl %eax
1183 1184 1185 1186
	SAVE_ALL
	xorl %edx,%edx		# zero error code
	movl %esp,%eax		# pt_regs pointer
	call do_nmi
1187
	jmp restore_all_notrace
1188 1189

nmi_stack_fixup:
1190
	FIX_STACK 12, nmi_stack_correct, 1
1191 1192 1193 1194 1195 1196 1197 1198 1199
	jmp nmi_stack_correct

nmi_debug_stack_check:
	cmpw $__KERNEL_CS,16(%esp)
	jne nmi_stack_correct
	cmpl $debug,(%esp)
	jb nmi_stack_correct
	cmpl $debug_esp_fix_insn,(%esp)
	ja nmi_stack_correct
1200
	FIX_STACK 24, nmi_stack_correct, 1
1201 1202
	jmp nmi_stack_correct

1203
#ifdef CONFIG_X86_ESPFIX32
1204
nmi_espfix_stack:
1205
	/*
1206 1207
	 * create the pointer to lss back
	 */
1208 1209
	pushl %ss
	pushl %esp
1210
	addl $4, (%esp)
1211 1212
	/* copy the iret frame of 12 bytes */
	.rept 3
1213
	pushl 16(%esp)
1214
	.endr
1215
	pushl %eax
1216 1217 1218 1219 1220 1221 1222
	SAVE_ALL
	FIXUP_ESPFIX_STACK		# %eax == %esp
	xorl %edx,%edx			# zero error code
	call do_nmi
	RESTORE_REGS
	lss 12+4(%esp), %esp		# back to espfix stack
	jmp irq_return
1223
#endif
1224 1225 1226
END(nmi)

ENTRY(int3)
1227
	ASM_CLAC
1228
	pushl $-1			# mark this as an int
1229 1230 1231 1232 1233 1234 1235 1236 1237
	SAVE_ALL
	TRACE_IRQS_OFF
	xorl %edx,%edx		# zero error code
	movl %esp,%eax		# pt_regs pointer
	call do_int3
	jmp ret_from_exception
END(int3)

ENTRY(general_protection)
1238
	pushl $do_general_protection
1239 1240 1241
	jmp error_code
END(general_protection)

G
Gleb Natapov 已提交
1242 1243
#ifdef CONFIG_KVM_GUEST
ENTRY(async_page_fault)
1244
	ASM_CLAC
1245
	pushl $do_async_page_fault
G
Gleb Natapov 已提交
1246
	jmp error_code
1247
END(async_page_fault)
G
Gleb Natapov 已提交
1248 1249
#endif