diff options
Diffstat (limited to 'arch/x86/kernel/entry_32.S')
-rw-r--r-- | arch/x86/kernel/entry_32.S | 162 |
1 files changed, 139 insertions, 23 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index c778e4fa55a2..109792bc7cfa 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -51,14 +51,25 @@ | |||
51 | #include <asm/percpu.h> | 51 | #include <asm/percpu.h> |
52 | #include <asm/dwarf2.h> | 52 | #include <asm/dwarf2.h> |
53 | #include <asm/processor-flags.h> | 53 | #include <asm/processor-flags.h> |
54 | #include "irq_vectors.h" | 54 | #include <asm/ftrace.h> |
55 | #include <asm/irq_vectors.h> | ||
56 | |||
57 | /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ | ||
58 | #include <linux/elf-em.h> | ||
59 | #define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE) | ||
60 | #define __AUDIT_ARCH_LE 0x40000000 | ||
61 | |||
62 | #ifndef CONFIG_AUDITSYSCALL | ||
63 | #define sysenter_audit syscall_trace_entry | ||
64 | #define sysexit_audit syscall_exit_work | ||
65 | #endif | ||
55 | 66 | ||
56 | /* | 67 | /* |
57 | * We use macros for low-level operations which need to be overridden | 68 | * We use macros for low-level operations which need to be overridden |
58 | * for paravirtualization. The following will never clobber any registers: | 69 | * for paravirtualization. The following will never clobber any registers: |
59 | * INTERRUPT_RETURN (aka. "iret") | 70 | * INTERRUPT_RETURN (aka. "iret") |
60 | * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax") | 71 | * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax") |
61 | * ENABLE_INTERRUPTS_SYSCALL_RET (aka "sti; sysexit"). | 72 | * ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit"). |
62 | * | 73 | * |
63 | * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must | 74 | * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must |
64 | * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY). | 75 | * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY). |
@@ -331,8 +342,9 @@ sysenter_past_esp: | |||
331 | GET_THREAD_INFO(%ebp) | 342 | GET_THREAD_INFO(%ebp) |
332 | 343 | ||
333 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ | 344 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ |
334 | testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) | 345 | testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) |
335 | jnz syscall_trace_entry | 346 | jnz sysenter_audit |
347 | sysenter_do_call: | ||
336 | cmpl $(nr_syscalls), %eax | 348 | cmpl $(nr_syscalls), %eax |
337 | jae syscall_badsys | 349 | jae syscall_badsys |
338 | call *sys_call_table(,%eax,4) | 350 | call *sys_call_table(,%eax,4) |
@@ -342,14 +354,54 @@ sysenter_past_esp: | |||
342 | TRACE_IRQS_OFF | 354 | TRACE_IRQS_OFF |
343 | movl TI_flags(%ebp), %ecx | 355 | movl TI_flags(%ebp), %ecx |
344 | testw $_TIF_ALLWORK_MASK, %cx | 356 | testw $_TIF_ALLWORK_MASK, %cx |
345 | jne syscall_exit_work | 357 | jne sysexit_audit |
358 | sysenter_exit: | ||
346 | /* if something modifies registers it must also disable sysexit */ | 359 | /* if something modifies registers it must also disable sysexit */ |
347 | movl PT_EIP(%esp), %edx | 360 | movl PT_EIP(%esp), %edx |
348 | movl PT_OLDESP(%esp), %ecx | 361 | movl PT_OLDESP(%esp), %ecx |
349 | xorl %ebp,%ebp | 362 | xorl %ebp,%ebp |
350 | TRACE_IRQS_ON | 363 | TRACE_IRQS_ON |
351 | 1: mov PT_FS(%esp), %fs | 364 | 1: mov PT_FS(%esp), %fs |
352 | ENABLE_INTERRUPTS_SYSCALL_RET | 365 | ENABLE_INTERRUPTS_SYSEXIT |
366 | |||
367 | #ifdef CONFIG_AUDITSYSCALL | ||
368 | sysenter_audit: | ||
369 | testw $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%ebp) | ||
370 | jnz syscall_trace_entry | ||
371 | addl $4,%esp | ||
372 | CFI_ADJUST_CFA_OFFSET -4 | ||
373 | /* %esi already in 8(%esp) 6th arg: 4th syscall arg */ | ||
374 | /* %edx already in 4(%esp) 5th arg: 3rd syscall arg */ | ||
375 | /* %ecx already in 0(%esp) 4th arg: 2nd syscall arg */ | ||
376 | movl %ebx,%ecx /* 3rd arg: 1st syscall arg */ | ||
377 | movl %eax,%edx /* 2nd arg: syscall number */ | ||
378 | movl $AUDIT_ARCH_I386,%eax /* 1st arg: audit arch */ | ||
379 | call audit_syscall_entry | ||
380 | pushl %ebx | ||
381 | CFI_ADJUST_CFA_OFFSET 4 | ||
382 | movl PT_EAX(%esp),%eax /* reload syscall number */ | ||
383 | jmp sysenter_do_call | ||
384 | |||
385 | sysexit_audit: | ||
386 | testw $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %cx | ||
387 | jne syscall_exit_work | ||
388 | TRACE_IRQS_ON | ||
389 | ENABLE_INTERRUPTS(CLBR_ANY) | ||
390 | movl %eax,%edx /* second arg, syscall return value */ | ||
391 | cmpl $0,%eax /* is it < 0? */ | ||
392 | setl %al /* 1 if so, 0 if not */ | ||
393 | movzbl %al,%eax /* zero-extend that */ | ||
394 | inc %eax /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ | ||
395 | call audit_syscall_exit | ||
396 | DISABLE_INTERRUPTS(CLBR_ANY) | ||
397 | TRACE_IRQS_OFF | ||
398 | movl TI_flags(%ebp), %ecx | ||
399 | testw $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %cx | ||
400 | jne syscall_exit_work | ||
401 | movl PT_EAX(%esp),%eax /* reload syscall return value */ | ||
402 | jmp sysenter_exit | ||
403 | #endif | ||
404 | |||
353 | CFI_ENDPROC | 405 | CFI_ENDPROC |
354 | .pushsection .fixup,"ax" | 406 | .pushsection .fixup,"ax" |
355 | 2: movl $0,PT_FS(%esp) | 407 | 2: movl $0,PT_FS(%esp) |
@@ -369,7 +421,7 @@ ENTRY(system_call) | |||
369 | GET_THREAD_INFO(%ebp) | 421 | GET_THREAD_INFO(%ebp) |
370 | # system call tracing in operation / emulation | 422 | # system call tracing in operation / emulation |
371 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ | 423 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ |
372 | testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) | 424 | testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) |
373 | jnz syscall_trace_entry | 425 | jnz syscall_trace_entry |
374 | cmpl $(nr_syscalls), %eax | 426 | cmpl $(nr_syscalls), %eax |
375 | jae syscall_badsys | 427 | jae syscall_badsys |
@@ -382,10 +434,6 @@ syscall_exit: | |||
382 | # setting need_resched or sigpending | 434 | # setting need_resched or sigpending |
383 | # between sampling and the iret | 435 | # between sampling and the iret |
384 | TRACE_IRQS_OFF | 436 | TRACE_IRQS_OFF |
385 | testl $X86_EFLAGS_TF,PT_EFLAGS(%esp) # If tracing set singlestep flag on exit | ||
386 | jz no_singlestep | ||
387 | orl $_TIF_SINGLESTEP,TI_flags(%ebp) | ||
388 | no_singlestep: | ||
389 | movl TI_flags(%ebp), %ecx | 437 | movl TI_flags(%ebp), %ecx |
390 | testw $_TIF_ALLWORK_MASK, %cx # current->work | 438 | testw $_TIF_ALLWORK_MASK, %cx # current->work |
391 | jne syscall_exit_work | 439 | jne syscall_exit_work |
@@ -513,12 +561,8 @@ END(work_pending) | |||
513 | syscall_trace_entry: | 561 | syscall_trace_entry: |
514 | movl $-ENOSYS,PT_EAX(%esp) | 562 | movl $-ENOSYS,PT_EAX(%esp) |
515 | movl %esp, %eax | 563 | movl %esp, %eax |
516 | xorl %edx,%edx | 564 | call syscall_trace_enter |
517 | call do_syscall_trace | 565 | /* What it returned is what we'll actually use. */ |
518 | cmpl $0, %eax | ||
519 | jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, | ||
520 | # so must skip actual syscall | ||
521 | movl PT_ORIG_EAX(%esp), %eax | ||
522 | cmpl $(nr_syscalls), %eax | 566 | cmpl $(nr_syscalls), %eax |
523 | jnae syscall_call | 567 | jnae syscall_call |
524 | jmp syscall_exit | 568 | jmp syscall_exit |
@@ -527,14 +571,13 @@ END(syscall_trace_entry) | |||
527 | # perform syscall exit tracing | 571 | # perform syscall exit tracing |
528 | ALIGN | 572 | ALIGN |
529 | syscall_exit_work: | 573 | syscall_exit_work: |
530 | testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl | 574 | testb $_TIF_WORK_SYSCALL_EXIT, %cl |
531 | jz work_pending | 575 | jz work_pending |
532 | TRACE_IRQS_ON | 576 | TRACE_IRQS_ON |
533 | ENABLE_INTERRUPTS(CLBR_ANY) # could let do_syscall_trace() call | 577 | ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call |
534 | # schedule() instead | 578 | # schedule() instead |
535 | movl %esp, %eax | 579 | movl %esp, %eax |
536 | movl $1, %edx | 580 | call syscall_trace_leave |
537 | call do_syscall_trace | ||
538 | jmp resume_userspace | 581 | jmp resume_userspace |
539 | END(syscall_exit_work) | 582 | END(syscall_exit_work) |
540 | CFI_ENDPROC | 583 | CFI_ENDPROC |
@@ -874,10 +917,10 @@ ENTRY(native_iret) | |||
874 | .previous | 917 | .previous |
875 | END(native_iret) | 918 | END(native_iret) |
876 | 919 | ||
877 | ENTRY(native_irq_enable_syscall_ret) | 920 | ENTRY(native_irq_enable_sysexit) |
878 | sti | 921 | sti |
879 | sysexit | 922 | sysexit |
880 | END(native_irq_enable_syscall_ret) | 923 | END(native_irq_enable_sysexit) |
881 | #endif | 924 | #endif |
882 | 925 | ||
883 | KPROBE_ENTRY(int3) | 926 | KPROBE_ENTRY(int3) |
@@ -1023,7 +1066,9 @@ ENDPROC(kernel_thread_helper) | |||
1023 | ENTRY(xen_sysenter_target) | 1066 | ENTRY(xen_sysenter_target) |
1024 | RING0_INT_FRAME | 1067 | RING0_INT_FRAME |
1025 | addl $5*4, %esp /* remove xen-provided frame */ | 1068 | addl $5*4, %esp /* remove xen-provided frame */ |
1069 | CFI_ADJUST_CFA_OFFSET -5*4 | ||
1026 | jmp sysenter_past_esp | 1070 | jmp sysenter_past_esp |
1071 | CFI_ENDPROC | ||
1027 | 1072 | ||
1028 | ENTRY(xen_hypervisor_callback) | 1073 | ENTRY(xen_hypervisor_callback) |
1029 | CFI_STARTPROC | 1074 | CFI_STARTPROC |
@@ -1110,6 +1155,77 @@ ENDPROC(xen_failsafe_callback) | |||
1110 | 1155 | ||
1111 | #endif /* CONFIG_XEN */ | 1156 | #endif /* CONFIG_XEN */ |
1112 | 1157 | ||
1158 | #ifdef CONFIG_FTRACE | ||
1159 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
1160 | |||
1161 | ENTRY(mcount) | ||
1162 | pushl %eax | ||
1163 | pushl %ecx | ||
1164 | pushl %edx | ||
1165 | movl 0xc(%esp), %eax | ||
1166 | subl $MCOUNT_INSN_SIZE, %eax | ||
1167 | |||
1168 | .globl mcount_call | ||
1169 | mcount_call: | ||
1170 | call ftrace_stub | ||
1171 | |||
1172 | popl %edx | ||
1173 | popl %ecx | ||
1174 | popl %eax | ||
1175 | |||
1176 | ret | ||
1177 | END(mcount) | ||
1178 | |||
1179 | ENTRY(ftrace_caller) | ||
1180 | pushl %eax | ||
1181 | pushl %ecx | ||
1182 | pushl %edx | ||
1183 | movl 0xc(%esp), %eax | ||
1184 | movl 0x4(%ebp), %edx | ||
1185 | subl $MCOUNT_INSN_SIZE, %eax | ||
1186 | |||
1187 | .globl ftrace_call | ||
1188 | ftrace_call: | ||
1189 | call ftrace_stub | ||
1190 | |||
1191 | popl %edx | ||
1192 | popl %ecx | ||
1193 | popl %eax | ||
1194 | |||
1195 | .globl ftrace_stub | ||
1196 | ftrace_stub: | ||
1197 | ret | ||
1198 | END(ftrace_caller) | ||
1199 | |||
1200 | #else /* ! CONFIG_DYNAMIC_FTRACE */ | ||
1201 | |||
1202 | ENTRY(mcount) | ||
1203 | cmpl $ftrace_stub, ftrace_trace_function | ||
1204 | jnz trace | ||
1205 | .globl ftrace_stub | ||
1206 | ftrace_stub: | ||
1207 | ret | ||
1208 | |||
1209 | /* taken from glibc */ | ||
1210 | trace: | ||
1211 | pushl %eax | ||
1212 | pushl %ecx | ||
1213 | pushl %edx | ||
1214 | movl 0xc(%esp), %eax | ||
1215 | movl 0x4(%ebp), %edx | ||
1216 | subl $MCOUNT_INSN_SIZE, %eax | ||
1217 | |||
1218 | call *ftrace_trace_function | ||
1219 | |||
1220 | popl %edx | ||
1221 | popl %ecx | ||
1222 | popl %eax | ||
1223 | |||
1224 | jmp ftrace_stub | ||
1225 | END(mcount) | ||
1226 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
1227 | #endif /* CONFIG_FTRACE */ | ||
1228 | |||
1113 | .section .rodata,"a" | 1229 | .section .rodata,"a" |
1114 | #include "syscall_table_32.S" | 1230 | #include "syscall_table_32.S" |
1115 | 1231 | ||