entry.S 21.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/*
 *  linux/arch/i386/entry.S
 *
 *  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.
 *
 * Stack layout in 'ret_from_system_call':
 * 	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
 *	24(%esp) - orig_eax
 *	28(%esp) - %eip
 *	2C(%esp) - %cs
 *	30(%esp) - %eflags
 *	34(%esp) - %oldesp
 *	38(%esp) - %oldss
 *
 * "current" is in register %ebx during any slow entries.
 */

#include <linux/linkage.h>
#include <asm/thread_info.h>
45
#include <asm/irqflags.h>
L
Linus Torvalds 已提交
46 47 48 49 50
#include <asm/errno.h>
#include <asm/segment.h>
#include <asm/smp.h>
#include <asm/page.h>
#include <asm/desc.h>
51
#include <asm/dwarf2.h>
L
Linus Torvalds 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#include "irq_vectors.h"

#define nr_syscalls ((syscall_table_size)/4)

EBX		= 0x00
ECX		= 0x04
EDX		= 0x08
ESI		= 0x0C
EDI		= 0x10
EBP		= 0x14
EAX		= 0x18
DS		= 0x1C
ES		= 0x20
ORIG_EAX	= 0x24
EIP		= 0x28
CS		= 0x2C
EFLAGS		= 0x30
OLDESP		= 0x34
OLDSS		= 0x38

CF_MASK		= 0x00000001
TF_MASK		= 0x00000100
IF_MASK		= 0x00000200
DF_MASK		= 0x00000400 
NT_MASK		= 0x00004000
VM_MASK		= 0x00020000

#ifdef CONFIG_PREEMPT
80
#define preempt_stop		cli; TRACE_IRQS_OFF
L
Linus Torvalds 已提交
81 82 83 84 85
#else
#define preempt_stop
#define resume_kernel		restore_nocheck
#endif

86 87 88 89 90 91 92 93 94
.macro TRACE_IRQS_IRET
#ifdef CONFIG_TRACE_IRQFLAGS
	testl $IF_MASK,EFLAGS(%esp)     # interrupts off?
	jz 1f
	TRACE_IRQS_ON
1:
#endif
.endm

95 96 97 98 99 100
#ifdef CONFIG_VM86
#define resume_userspace_sig	check_userspace
#else
#define resume_userspace_sig	resume_userspace
#endif

L
Linus Torvalds 已提交
101 102 103
#define SAVE_ALL \
	cld; \
	pushl %es; \
104 105
	CFI_ADJUST_CFA_OFFSET 4;\
	/*CFI_REL_OFFSET es, 0;*/\
L
Linus Torvalds 已提交
106
	pushl %ds; \
107 108
	CFI_ADJUST_CFA_OFFSET 4;\
	/*CFI_REL_OFFSET ds, 0;*/\
L
Linus Torvalds 已提交
109
	pushl %eax; \
110 111
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET eax, 0;\
L
Linus Torvalds 已提交
112
	pushl %ebp; \
113 114
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET ebp, 0;\
L
Linus Torvalds 已提交
115
	pushl %edi; \
116 117
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET edi, 0;\
L
Linus Torvalds 已提交
118
	pushl %esi; \
119 120
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET esi, 0;\
L
Linus Torvalds 已提交
121
	pushl %edx; \
122 123
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET edx, 0;\
L
Linus Torvalds 已提交
124
	pushl %ecx; \
125 126
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET ecx, 0;\
L
Linus Torvalds 已提交
127
	pushl %ebx; \
128 129
	CFI_ADJUST_CFA_OFFSET 4;\
	CFI_REL_OFFSET ebx, 0;\
L
Linus Torvalds 已提交
130 131 132 133 134 135
	movl $(__USER_DS), %edx; \
	movl %edx, %ds; \
	movl %edx, %es;

#define RESTORE_INT_REGS \
	popl %ebx;	\
136 137
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE ebx;\
L
Linus Torvalds 已提交
138
	popl %ecx;	\
139 140
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE ecx;\
L
Linus Torvalds 已提交
141
	popl %edx;	\
142 143
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE edx;\
L
Linus Torvalds 已提交
144
	popl %esi;	\
145 146
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE esi;\
L
Linus Torvalds 已提交
147
	popl %edi;	\
148 149
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE edi;\
L
Linus Torvalds 已提交
150
	popl %ebp;	\
151 152 153 154 155
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE ebp;\
	popl %eax;	\
	CFI_ADJUST_CFA_OFFSET -4;\
	CFI_RESTORE eax
L
Linus Torvalds 已提交
156 157 158 159

#define RESTORE_REGS	\
	RESTORE_INT_REGS; \
1:	popl %ds;	\
160 161
	CFI_ADJUST_CFA_OFFSET -4;\
	/*CFI_RESTORE ds;*/\
L
Linus Torvalds 已提交
162
2:	popl %es;	\
163 164
	CFI_ADJUST_CFA_OFFSET -4;\
	/*CFI_RESTORE es;*/\
L
Linus Torvalds 已提交
165 166 167 168 169 170 171 172 173 174 175 176
.section .fixup,"ax";	\
3:	movl $0,(%esp);	\
	jmp 1b;		\
4:	movl $0,(%esp);	\
	jmp 2b;		\
.previous;		\
.section __ex_table,"a";\
	.align 4;	\
	.long 1b,3b;	\
	.long 2b,4b;	\
.previous

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
#define RING0_INT_FRAME \
	CFI_STARTPROC simple;\
	CFI_DEF_CFA esp, 3*4;\
	/*CFI_OFFSET cs, -2*4;*/\
	CFI_OFFSET eip, -3*4

#define RING0_EC_FRAME \
	CFI_STARTPROC simple;\
	CFI_DEF_CFA esp, 4*4;\
	/*CFI_OFFSET cs, -2*4;*/\
	CFI_OFFSET eip, -3*4

#define RING0_PTREGS_FRAME \
	CFI_STARTPROC simple;\
	CFI_DEF_CFA esp, OLDESP-EBX;\
	/*CFI_OFFSET cs, CS-OLDESP;*/\
	CFI_OFFSET eip, EIP-OLDESP;\
	/*CFI_OFFSET es, ES-OLDESP;*/\
	/*CFI_OFFSET ds, DS-OLDESP;*/\
	CFI_OFFSET eax, EAX-OLDESP;\
	CFI_OFFSET ebp, EBP-OLDESP;\
	CFI_OFFSET edi, EDI-OLDESP;\
	CFI_OFFSET esi, ESI-OLDESP;\
	CFI_OFFSET edx, EDX-OLDESP;\
	CFI_OFFSET ecx, ECX-OLDESP;\
	CFI_OFFSET ebx, EBX-OLDESP
L
Linus Torvalds 已提交
203 204

ENTRY(ret_from_fork)
205
	CFI_STARTPROC
L
Linus Torvalds 已提交
206
	pushl %eax
207
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
208 209 210
	call schedule_tail
	GET_THREAD_INFO(%ebp)
	popl %eax
211
	CFI_ADJUST_CFA_OFFSET -4
212 213 214 215
	pushl $0x0202			# Reset kernel eflags
	CFI_ADJUST_CFA_OFFSET 4
	popfl
	CFI_ADJUST_CFA_OFFSET -4
L
Linus Torvalds 已提交
216
	jmp syscall_exit
217
	CFI_ENDPROC
L
Linus Torvalds 已提交
218 219 220 221 222 223 224 225 226 227

/*
 * 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
228
	RING0_PTREGS_FRAME
L
Linus Torvalds 已提交
229 230 231 232
ret_from_exception:
	preempt_stop
ret_from_intr:
	GET_THREAD_INFO(%ebp)
233
check_userspace:
L
Linus Torvalds 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
	movb CS(%esp), %al
	testl $(VM_MASK | 3), %eax
	jz resume_kernel
ENTRY(resume_userspace)
 	cli				# make sure we don't miss an interrupt
					# setting need_resched or sigpending
					# between sampling and the iret
	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

#ifdef CONFIG_PREEMPT
ENTRY(resume_kernel)
	cli
	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
	jnz restore_nocheck
need_resched:
	movl TI_flags(%ebp), %ecx	# need_resched set ?
	testb $_TIF_NEED_RESCHED, %cl
	jz restore_all
	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
	jz restore_all
	call preempt_schedule_irq
	jmp need_resched
#endif
262
	CFI_ENDPROC
L
Linus Torvalds 已提交
263 264 265 266 267 268

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

	# sysenter call handler stub
ENTRY(sysenter_entry)
269 270 271
	CFI_STARTPROC simple
	CFI_DEF_CFA esp, 0
	CFI_REGISTER esp, ebp
L
Linus Torvalds 已提交
272 273
	movl TSS_sysenter_esp0(%esp),%esp
sysenter_past_esp:
274 275 276 277
	/*
	 * No need to follow this irqs on/off section: the syscall
	 * disabled irqs and here we enable it straight after entry:
	 */
L
Linus Torvalds 已提交
278 279
	sti
	pushl $(__USER_DS)
280 281
	CFI_ADJUST_CFA_OFFSET 4
	/*CFI_REL_OFFSET ss, 0*/
L
Linus Torvalds 已提交
282
	pushl %ebp
283 284
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET esp, 0
L
Linus Torvalds 已提交
285
	pushfl
286
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
287
	pushl $(__USER_CS)
288 289
	CFI_ADJUST_CFA_OFFSET 4
	/*CFI_REL_OFFSET cs, 0*/
290 291 292 293 294 295
	/*
	 * Push current_thread_info()->sysenter_return to the stack.
	 * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
	 * pushed above; +8 corresponds to copy_thread's esp0 setting.
	 */
	pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
296 297
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET eip, 0
L
Linus Torvalds 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311

/*
 * Load the potential sixth argument from user stack.
 * Careful about security.
 */
	cmpl $__PAGE_OFFSET-3,%ebp
	jae syscall_fault
1:	movl (%ebp),%ebp
.section __ex_table,"a"
	.align 4
	.long 1b,syscall_fault
.previous

	pushl %eax
312
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
313 314 315 316
	SAVE_ALL
	GET_THREAD_INFO(%ebp)

	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
317
	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
L
Linus Torvalds 已提交
318 319 320 321 322 323
	jnz syscall_trace_entry
	cmpl $(nr_syscalls), %eax
	jae syscall_badsys
	call *sys_call_table(,%eax,4)
	movl %eax,EAX(%esp)
	cli
324
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
325 326 327 328 329 330 331
	movl TI_flags(%ebp), %ecx
	testw $_TIF_ALLWORK_MASK, %cx
	jne syscall_exit_work
/* if something modifies registers it must also disable sysexit */
	movl EIP(%esp), %edx
	movl OLDESP(%esp), %ecx
	xorl %ebp,%ebp
332
	TRACE_IRQS_ON
L
Linus Torvalds 已提交
333 334
	sti
	sysexit
335
	CFI_ENDPROC
L
Linus Torvalds 已提交
336 337 338 339


	# system call handler stub
ENTRY(system_call)
340
	RING0_INT_FRAME			# can't unwind into user space anyway
L
Linus Torvalds 已提交
341
	pushl %eax			# save orig_eax
342
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
343 344
	SAVE_ALL
	GET_THREAD_INFO(%ebp)
345 346 347 348
	testl $TF_MASK,EFLAGS(%esp)
	jz no_singlestep
	orl $_TIF_SINGLESTEP,TI_flags(%ebp)
no_singlestep:
349
					# system call tracing in operation / emulation
L
Linus Torvalds 已提交
350
	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
351
	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
L
Linus Torvalds 已提交
352 353 354 355 356 357 358 359 360 361
	jnz syscall_trace_entry
	cmpl $(nr_syscalls), %eax
	jae syscall_badsys
syscall_call:
	call *sys_call_table(,%eax,4)
	movl %eax,EAX(%esp)		# store the return value
syscall_exit:
	cli				# make sure we don't miss an interrupt
					# setting need_resched or sigpending
					# between sampling and the iret
362
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
363 364 365 366 367 368
	movl TI_flags(%ebp), %ecx
	testw $_TIF_ALLWORK_MASK, %cx	# current->work
	jne syscall_exit_work

restore_all:
	movl EFLAGS(%esp), %eax		# mix EFLAGS, SS and CS
369 370 371
	# Warning: OLDSS(%esp) contains the wrong/random values if we
	# are returning to the kernel.
	# See comments in process.c:copy_thread() for details.
L
Linus Torvalds 已提交
372 373 374 375
	movb OLDSS(%esp), %ah
	movb CS(%esp), %al
	andl $(VM_MASK | (4 << 8) | 3), %eax
	cmpl $((4 << 8) | 3), %eax
376
	CFI_REMEMBER_STATE
L
Linus Torvalds 已提交
377 378
	je ldt_ss			# returning to user-space with LDT SS
restore_nocheck:
379 380
	TRACE_IRQS_IRET
restore_nocheck_notrace:
L
Linus Torvalds 已提交
381 382
	RESTORE_REGS
	addl $4, %esp
383
	CFI_ADJUST_CFA_OFFSET -4
L
Linus Torvalds 已提交
384 385 386
1:	iret
.section .fixup,"ax"
iret_exc:
387
	TRACE_IRQS_ON
L
Linus Torvalds 已提交
388
	sti
389 390 391
	pushl $0			# no error code
	pushl $do_iret_error
	jmp error_code
L
Linus Torvalds 已提交
392 393 394 395 396 397
.previous
.section __ex_table,"a"
	.align 4
	.long 1b,iret_exc
.previous

398
	CFI_RESTORE_STATE
L
Linus Torvalds 已提交
399 400 401 402 403 404 405 406 407 408 409 410
ldt_ss:
	larl OLDSS(%esp), %eax
	jnz restore_nocheck
	testl $0x00400000, %eax		# returning to 32bit stack?
	jnz restore_nocheck		# allright, normal return
	/* If returning to userspace with 16bit stack,
	 * try to fix the higher word of ESP, as the CPU
	 * won't restore it.
	 * This is an "official" bug of all the x86-compatible
	 * CPUs, which we can try to work around to make
	 * dosemu and wine happy. */
	subl $8, %esp		# reserve space for switch16 pointer
411
	CFI_ADJUST_CFA_OFFSET 8
L
Linus Torvalds 已提交
412
	cli
413
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
414 415 416 417
	movl %esp, %eax
	/* Set up the 16bit stack frame with switch32 pointer on top,
	 * and a switch16 pointer on top of the current frame. */
	call setup_x86_bogus_stack
418
	CFI_ADJUST_CFA_OFFSET -8	# frame has moved
419
	TRACE_IRQS_IRET
L
Linus Torvalds 已提交
420 421 422 423 424 425 426
	RESTORE_REGS
	lss 20+4(%esp), %esp	# switch to 16bit stack
1:	iret
.section __ex_table,"a"
	.align 4
	.long 1b,iret_exc
.previous
427
	CFI_ENDPROC
L
Linus Torvalds 已提交
428 429 430

	# perform work that needs to be done immediately before resumption
	ALIGN
431
	RING0_PTREGS_FRAME		# can't unwind into user space anyway
L
Linus Torvalds 已提交
432 433 434 435 436 437 438 439
work_pending:
	testb $_TIF_NEED_RESCHED, %cl
	jz work_notifysig
work_resched:
	call schedule
	cli				# make sure we don't miss an interrupt
					# setting need_resched or sigpending
					# between sampling and the iret
440
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
	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
	testl $VM_MASK, EFLAGS(%esp)
	movl %esp, %eax
	jne work_notifysig_v86		# returning to kernel-space or
					# vm86-space
	xorl %edx, %edx
	call do_notify_resume
456
	jmp resume_userspace_sig
L
Linus Torvalds 已提交
457 458 459

	ALIGN
work_notifysig_v86:
460
#ifdef CONFIG_VM86
L
Linus Torvalds 已提交
461
	pushl %ecx			# save ti_flags for do_notify_resume
462
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
463 464
	call save_v86_state		# %eax contains pt_regs pointer
	popl %ecx
465
	CFI_ADJUST_CFA_OFFSET -4
L
Linus Torvalds 已提交
466 467 468
	movl %eax, %esp
	xorl %edx, %edx
	call do_notify_resume
469
	jmp resume_userspace_sig
470
#endif
L
Linus Torvalds 已提交
471 472 473 474 475 476 477 478

	# perform syscall exit tracing
	ALIGN
syscall_trace_entry:
	movl $-ENOSYS,EAX(%esp)
	movl %esp, %eax
	xorl %edx,%edx
	call do_syscall_trace
479
	cmpl $0, %eax
480
	jne resume_userspace		# ret != 0 -> running under PTRACE_SYSEMU,
481
					# so must skip actual syscall
L
Linus Torvalds 已提交
482 483 484 485 486 487 488 489 490 491
	movl ORIG_EAX(%esp), %eax
	cmpl $(nr_syscalls), %eax
	jnae syscall_call
	jmp syscall_exit

	# perform syscall exit tracing
	ALIGN
syscall_exit_work:
	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
	jz work_pending
492
	TRACE_IRQS_ON
L
Linus Torvalds 已提交
493 494 495 496 497 498
	sti				# could let do_syscall_trace() call
					# schedule() instead
	movl %esp, %eax
	movl $1, %edx
	call do_syscall_trace
	jmp resume_userspace
499
	CFI_ENDPROC
L
Linus Torvalds 已提交
500

501
	RING0_INT_FRAME			# can't unwind into user space anyway
L
Linus Torvalds 已提交
502 503
syscall_fault:
	pushl %eax			# save orig_eax
504
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
505 506 507 508 509 510 511 512
	SAVE_ALL
	GET_THREAD_INFO(%ebp)
	movl $-EFAULT,EAX(%esp)
	jmp resume_userspace

syscall_badsys:
	movl $-ENOSYS,EAX(%esp)
	jmp resume_userspace
513
	CFI_ENDPROC
L
Linus Torvalds 已提交
514 515 516 517 518 519 520 521 522 523 524

#define FIXUP_ESPFIX_STACK \
	movl %esp, %eax; \
	/* switch to 32bit stack using the pointer on top of 16bit stack */ \
	lss %ss:CPU_16BIT_STACK_SIZE-8, %esp; \
	/* copy data from 16bit stack to 32bit stack */ \
	call fixup_x86_bogus_stack; \
	/* put ESP to the proper location */ \
	movl %eax, %esp;
#define UNWIND_ESPFIX_STACK \
	pushl %eax; \
525
	CFI_ADJUST_CFA_OFFSET 4; \
L
Linus Torvalds 已提交
526 527 528
	movl %ss, %eax; \
	/* see if on 16bit stack */ \
	cmpw $__ESPFIX_SS, %ax; \
529 530 531 532 533 534 535
	je 28f; \
27:	popl %eax; \
	CFI_ADJUST_CFA_OFFSET -4; \
.section .fixup,"ax"; \
28:	movl $__KERNEL_DS, %eax; \
	movl %eax, %ds; \
	movl %eax, %es; \
L
Linus Torvalds 已提交
536
	/* switch to 32bit stack */ \
537 538 539
	FIXUP_ESPFIX_STACK; \
	jmp 27b; \
.previous
L
Linus Torvalds 已提交
540 541 542 543 544 545 546 547 548 549 550

/*
 * Build the entry stubs and pointer table with
 * some assembler magic.
 */
.data
ENTRY(interrupt)
.text

vector=0
ENTRY(irq_entries_start)
551
	RING0_INT_FRAME
L
Linus Torvalds 已提交
552 553
.rept NR_IRQS
	ALIGN
554 555 556
 .if vector
	CFI_ADJUST_CFA_OFFSET -4
 .endif
557
1:	pushl $~(vector)
558
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
559 560 561 562 563 564 565
	jmp common_interrupt
.data
	.long 1b
.text
vector=vector+1
.endr

566 567 568 569
/*
 * the CPU automatically disables interrupts when executing an IRQ vector,
 * so IRQ-flags tracing has to follow that:
 */
L
Linus Torvalds 已提交
570 571 572
	ALIGN
common_interrupt:
	SAVE_ALL
573
	TRACE_IRQS_OFF
L
Linus Torvalds 已提交
574 575 576
	movl %esp,%eax
	call do_IRQ
	jmp ret_from_intr
577
	CFI_ENDPROC
L
Linus Torvalds 已提交
578 579 580

#define BUILD_INTERRUPT(name, nr)	\
ENTRY(name)				\
581
	RING0_INT_FRAME;		\
582
	pushl $~(nr);			\
583 584
	CFI_ADJUST_CFA_OFFSET 4;	\
	SAVE_ALL;			\
585
	TRACE_IRQS_OFF			\
L
Linus Torvalds 已提交
586 587
	movl %esp,%eax;			\
	call smp_/**/name;		\
588
	jmp ret_from_intr;		\
589
	CFI_ENDPROC
L
Linus Torvalds 已提交
590 591 592 593

/* The include is where all of the SMP etc. interrupts come from */
#include "entry_arch.h"

594 595 596
KPROBE_ENTRY(page_fault)
	RING0_EC_FRAME
	pushl $do_page_fault
597
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
598 599 600
	ALIGN
error_code:
	pushl %ds
601 602
	CFI_ADJUST_CFA_OFFSET 4
	/*CFI_REL_OFFSET ds, 0*/
L
Linus Torvalds 已提交
603
	pushl %eax
604 605
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET eax, 0
L
Linus Torvalds 已提交
606 607
	xorl %eax, %eax
	pushl %ebp
608 609
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET ebp, 0
L
Linus Torvalds 已提交
610
	pushl %edi
611 612
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET edi, 0
L
Linus Torvalds 已提交
613
	pushl %esi
614 615
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET esi, 0
L
Linus Torvalds 已提交
616
	pushl %edx
617 618
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET edx, 0
L
Linus Torvalds 已提交
619 620
	decl %eax			# eax = -1
	pushl %ecx
621 622
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET ecx, 0
L
Linus Torvalds 已提交
623
	pushl %ebx
624 625
	CFI_ADJUST_CFA_OFFSET 4
	CFI_REL_OFFSET ebx, 0
L
Linus Torvalds 已提交
626 627
	cld
	pushl %es
628 629
	CFI_ADJUST_CFA_OFFSET 4
	/*CFI_REL_OFFSET es, 0*/
L
Linus Torvalds 已提交
630 631
	UNWIND_ESPFIX_STACK
	popl %ecx
632 633
	CFI_ADJUST_CFA_OFFSET -4
	/*CFI_REGISTER es, ecx*/
L
Linus Torvalds 已提交
634 635 636 637
	movl ES(%esp), %edi		# get the function address
	movl ORIG_EAX(%esp), %edx	# get the error code
	movl %eax, ORIG_EAX(%esp)
	movl %ecx, ES(%esp)
638
	/*CFI_REL_OFFSET es, ES*/
L
Linus Torvalds 已提交
639 640 641 642 643 644
	movl $(__USER_DS), %ecx
	movl %ecx, %ds
	movl %ecx, %es
	movl %esp,%eax			# pt_regs pointer
	call *%edi
	jmp ret_from_exception
645
	CFI_ENDPROC
646
KPROBE_END(page_fault)
L
Linus Torvalds 已提交
647 648

ENTRY(coprocessor_error)
649
	RING0_INT_FRAME
L
Linus Torvalds 已提交
650
	pushl $0
651
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
652
	pushl $do_coprocessor_error
653
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
654
	jmp error_code
655
	CFI_ENDPROC
L
Linus Torvalds 已提交
656 657

ENTRY(simd_coprocessor_error)
658
	RING0_INT_FRAME
L
Linus Torvalds 已提交
659
	pushl $0
660
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
661
	pushl $do_simd_coprocessor_error
662
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
663
	jmp error_code
664
	CFI_ENDPROC
L
Linus Torvalds 已提交
665 666

ENTRY(device_not_available)
667
	RING0_INT_FRAME
L
Linus Torvalds 已提交
668
	pushl $-1			# mark this as an int
669
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
670 671 672 673 674 675 676 677 678
	SAVE_ALL
	movl %cr0, %eax
	testl $0x4, %eax		# EM (math emulation bit)
	jne device_not_available_emulate
	preempt_stop
	call math_state_restore
	jmp ret_from_exception
device_not_available_emulate:
	pushl $0			# temporary storage for ORIG_EIP
679
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
680 681
	call math_emulate
	addl $4, %esp
682
	CFI_ADJUST_CFA_OFFSET -4
L
Linus Torvalds 已提交
683
	jmp ret_from_exception
684
	CFI_ENDPROC
L
Linus Torvalds 已提交
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703

/*
 * 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_esp0+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.
 */
#define FIX_STACK(offset, ok, label)		\
	cmpw $__KERNEL_CS,4(%esp);		\
	jne ok;					\
label:						\
	movl TSS_sysenter_esp0+offset(%esp),%esp;	\
704 705
	CFI_DEF_CFA esp, 0;			\
	CFI_UNDEFINED eip;			\
L
Linus Torvalds 已提交
706
	pushfl;					\
707
	CFI_ADJUST_CFA_OFFSET 4;		\
L
Linus Torvalds 已提交
708
	pushl $__KERNEL_CS;			\
709 710 711 712
	CFI_ADJUST_CFA_OFFSET 4;		\
	pushl $sysenter_past_esp;		\
	CFI_ADJUST_CFA_OFFSET 4;		\
	CFI_REL_OFFSET eip, 0
L
Linus Torvalds 已提交
713

714
KPROBE_ENTRY(debug)
715
	RING0_INT_FRAME
L
Linus Torvalds 已提交
716 717 718 719 720
	cmpl $sysenter_entry,(%esp)
	jne debug_stack_correct
	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
debug_stack_correct:
	pushl $-1			# mark this as an int
721
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
722 723 724 725 726
	SAVE_ALL
	xorl %edx,%edx			# error code 0
	movl %esp,%eax			# pt_regs pointer
	call do_debug
	jmp ret_from_exception
727
	CFI_ENDPROC
728 729
KPROBE_END(debug)

L
Linus Torvalds 已提交
730 731 732 733 734 735 736 737
/*
 * 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.
 */
738
KPROBE_ENTRY(nmi)
739
	RING0_INT_FRAME
L
Linus Torvalds 已提交
740
	pushl %eax
741
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
742 743 744
	movl %ss, %eax
	cmpw $__ESPFIX_SS, %ax
	popl %eax
745
	CFI_ADJUST_CFA_OFFSET -4
L
Linus Torvalds 已提交
746 747 748 749
	je nmi_16bit_stack
	cmpl $sysenter_entry,(%esp)
	je nmi_stack_fixup
	pushl %eax
750
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
751 752 753 754 755 756 757
	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
	popl %eax
758
	CFI_ADJUST_CFA_OFFSET -4
L
Linus Torvalds 已提交
759 760 761 762
	jae nmi_stack_correct
	cmpl $sysenter_entry,12(%esp)
	je nmi_debug_stack_check
nmi_stack_correct:
763
	/* We have a RING0_INT_FRAME here */
L
Linus Torvalds 已提交
764
	pushl %eax
765
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
766 767 768 769
	SAVE_ALL
	xorl %edx,%edx		# zero error code
	movl %esp,%eax		# pt_regs pointer
	call do_nmi
770
	jmp restore_nocheck_notrace
771
	CFI_ENDPROC
L
Linus Torvalds 已提交
772 773

nmi_stack_fixup:
774
	RING0_INT_FRAME
L
Linus Torvalds 已提交
775 776
	FIX_STACK(12,nmi_stack_correct, 1)
	jmp nmi_stack_correct
777

L
Linus Torvalds 已提交
778
nmi_debug_stack_check:
779
	/* We have a RING0_INT_FRAME here */
L
Linus Torvalds 已提交
780 781
	cmpw $__KERNEL_CS,16(%esp)
	jne nmi_stack_correct
782 783
	cmpl $debug,(%esp)
	jb nmi_stack_correct
L
Linus Torvalds 已提交
784
	cmpl $debug_esp_fix_insn,(%esp)
785
	ja nmi_stack_correct
L
Linus Torvalds 已提交
786 787 788 789
	FIX_STACK(24,nmi_stack_correct, 1)
	jmp nmi_stack_correct

nmi_16bit_stack:
790 791 792 793
	/* We have a RING0_INT_FRAME here.
	 *
	 * create the pointer to lss back
	 */
L
Linus Torvalds 已提交
794
	pushl %ss
795
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
796
	pushl %esp
797
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
798 799 800 801 802
	movzwl %sp, %esp
	addw $4, (%esp)
	/* copy the iret frame of 12 bytes */
	.rept 3
	pushl 16(%esp)
803
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
804 805
	.endr
	pushl %eax
806
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
807 808
	SAVE_ALL
	FIXUP_ESPFIX_STACK		# %eax == %esp
809
	CFI_ADJUST_CFA_OFFSET -20	# the frame has now moved
L
Linus Torvalds 已提交
810 811 812 813 814
	xorl %edx,%edx			# zero error code
	call do_nmi
	RESTORE_REGS
	lss 12+4(%esp), %esp		# back to 16bit stack
1:	iret
815
	CFI_ENDPROC
L
Linus Torvalds 已提交
816 817 818 819
.section __ex_table,"a"
	.align 4
	.long 1b,iret_exc
.previous
820
KPROBE_END(nmi)
L
Linus Torvalds 已提交
821

822
KPROBE_ENTRY(int3)
823
	RING0_INT_FRAME
L
Linus Torvalds 已提交
824
	pushl $-1			# mark this as an int
825
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
826 827 828 829 830
	SAVE_ALL
	xorl %edx,%edx		# zero error code
	movl %esp,%eax		# pt_regs pointer
	call do_int3
	jmp ret_from_exception
831
	CFI_ENDPROC
832
KPROBE_END(int3)
L
Linus Torvalds 已提交
833 834

ENTRY(overflow)
835
	RING0_INT_FRAME
L
Linus Torvalds 已提交
836
	pushl $0
837
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
838
	pushl $do_overflow
839
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
840
	jmp error_code
841
	CFI_ENDPROC
L
Linus Torvalds 已提交
842 843

ENTRY(bounds)
844
	RING0_INT_FRAME
L
Linus Torvalds 已提交
845
	pushl $0
846
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
847
	pushl $do_bounds
848
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
849
	jmp error_code
850
	CFI_ENDPROC
L
Linus Torvalds 已提交
851 852

ENTRY(invalid_op)
853
	RING0_INT_FRAME
L
Linus Torvalds 已提交
854
	pushl $0
855
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
856
	pushl $do_invalid_op
857
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
858
	jmp error_code
859
	CFI_ENDPROC
L
Linus Torvalds 已提交
860 861

ENTRY(coprocessor_segment_overrun)
862
	RING0_INT_FRAME
L
Linus Torvalds 已提交
863
	pushl $0
864
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
865
	pushl $do_coprocessor_segment_overrun
866
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
867
	jmp error_code
868
	CFI_ENDPROC
L
Linus Torvalds 已提交
869 870

ENTRY(invalid_TSS)
871
	RING0_EC_FRAME
L
Linus Torvalds 已提交
872
	pushl $do_invalid_TSS
873
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
874
	jmp error_code
875
	CFI_ENDPROC
L
Linus Torvalds 已提交
876 877

ENTRY(segment_not_present)
878
	RING0_EC_FRAME
L
Linus Torvalds 已提交
879
	pushl $do_segment_not_present
880
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
881
	jmp error_code
882
	CFI_ENDPROC
L
Linus Torvalds 已提交
883 884

ENTRY(stack_segment)
885
	RING0_EC_FRAME
L
Linus Torvalds 已提交
886
	pushl $do_stack_segment
887
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
888
	jmp error_code
889
	CFI_ENDPROC
L
Linus Torvalds 已提交
890

891
KPROBE_ENTRY(general_protection)
892
	RING0_EC_FRAME
L
Linus Torvalds 已提交
893
	pushl $do_general_protection
894
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
895
	jmp error_code
896
	CFI_ENDPROC
897
KPROBE_END(general_protection)
L
Linus Torvalds 已提交
898 899

ENTRY(alignment_check)
900
	RING0_EC_FRAME
L
Linus Torvalds 已提交
901
	pushl $do_alignment_check
902
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
903
	jmp error_code
904
	CFI_ENDPROC
L
Linus Torvalds 已提交
905

906 907 908 909 910
ENTRY(divide_error)
	RING0_INT_FRAME
	pushl $0			# no error code
	CFI_ADJUST_CFA_OFFSET 4
	pushl $do_divide_error
911
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
912
	jmp error_code
913
	CFI_ENDPROC
L
Linus Torvalds 已提交
914 915 916

#ifdef CONFIG_X86_MCE
ENTRY(machine_check)
917
	RING0_INT_FRAME
L
Linus Torvalds 已提交
918
	pushl $0
919
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
920
	pushl machine_check_vector
921
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
922
	jmp error_code
923
	CFI_ENDPROC
L
Linus Torvalds 已提交
924 925 926
#endif

ENTRY(spurious_interrupt_bug)
927
	RING0_INT_FRAME
L
Linus Torvalds 已提交
928
	pushl $0
929
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
930
	pushl $do_spurious_interrupt_bug
931
	CFI_ADJUST_CFA_OFFSET 4
L
Linus Torvalds 已提交
932
	jmp error_code
933
	CFI_ENDPROC
L
Linus Torvalds 已提交
934

935 936
#ifdef CONFIG_STACK_UNWIND
ENTRY(arch_unwind_init_running)
937
	CFI_STARTPROC
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
	movl	4(%esp), %edx
	movl	(%esp), %ecx
	leal	4(%esp), %eax
	movl	%ebx, EBX(%edx)
	xorl	%ebx, %ebx
	movl	%ebx, ECX(%edx)
	movl	%ebx, EDX(%edx)
	movl	%esi, ESI(%edx)
	movl	%edi, EDI(%edx)
	movl	%ebp, EBP(%edx)
	movl	%ebx, EAX(%edx)
	movl	$__USER_DS, DS(%edx)
	movl	$__USER_DS, ES(%edx)
	movl	%ebx, ORIG_EAX(%edx)
	movl	%ecx, EIP(%edx)
	movl	12(%esp), %ecx
	movl	$__KERNEL_CS, CS(%edx)
	movl	%ebx, EFLAGS(%edx)
	movl	%eax, OLDESP(%edx)
	movl	8(%esp), %eax
	movl	%ecx, 8(%esp)
	movl	EBX(%edx), %ebx
	movl	$__KERNEL_DS, OLDSS(%edx)
	jmpl	*%eax
962
	CFI_ENDPROC
963 964 965
ENDPROC(arch_unwind_init_running)
#endif

966 967 968 969 970 971 972 973 974 975 976 977 978
ENTRY(kernel_thread_helper)
	pushl $0		# fake return address for unwinder
	CFI_STARTPROC
	movl %edx,%eax
	push %edx
	CFI_ADJUST_CFA_OFFSET 4
	call *%ebx
	push %eax
	CFI_ADJUST_CFA_OFFSET 4
	call do_exit
	CFI_ENDPROC
ENDPROC(kernel_thread_helper)

979
.section .rodata,"a"
980
#include "syscall_table.S"
L
Linus Torvalds 已提交
981 982

syscall_table_size=(.-sys_call_table)