PERFORCE change 109253 for review

John Birrell jb at FreeBSD.org
Sun Nov 5 01:04:47 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=109253

Change 109253 by jb at jb_freebsd8 on 2006/11/05 01:04:21

	Merge the DTrace code back in.

Affected files ...

.. //depot/projects/dtrace/src/sys/i386/i386/exception.s#9 edit
.. //depot/projects/dtrace/src/sys/i386/i386/local_apic.c#9 edit

Differences ...

==== //depot/projects/dtrace/src/sys/i386/i386/exception.s#9 (text+ko) ====

@@ -30,16 +30,27 @@
  * $FreeBSD: src/sys/i386/i386/exception.s,v 1.116 2006/04/04 02:26:45 jkoshy Exp $
  */
 
+/*
+ * The DTrace parts of this file are:
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
 #include "opt_apic.h"
 #include "opt_npx.h"
 
 #include <machine/asmacros.h>
 #include <machine/psl.h>
 #include <machine/trap.h>
+#ifdef KDTRACE
+#include <machine/dtrace_asm.h>
+#endif
 
 #include "assym.s"
 
 #define	SEL_RPL_MASK	0x0003
+#define	GSEL_KPL	0x0020	/* GSEL(GCODE_SEL, SEL_KPL) */
 
 	.text
 
@@ -88,8 +99,6 @@
 	pushl $0; TRAP(T_OFLOW)
 IDTVEC(bnd)
 	pushl $0; TRAP(T_BOUND)
-IDTVEC(ill)
-	pushl $0; TRAP(T_PRIVINFLT)
 IDTVEC(dna)
 	pushl $0; TRAP(T_DNA)
 IDTVEC(fpusegm)
@@ -144,6 +153,164 @@
 	jmp	doreti
 
 /*
+ * Privileged instruction fault.
+ */
+	SUPERALIGN_TEXT
+IDTVEC(ill)
+#ifdef KDTRACE
+	/*
+	 * DTrace uses invalid instructions to hook itself into
+	 * the executable code. A privileged instruction fault in
+	 * kernel code probably is the result of a 'Function Boundary
+	 * Tracing' (FBT) or 'Statically Defined Tracing' (SDT)
+	 * probe.
+	 *
+	 * Check if there is an invalid instruction function registered.
+	 * (see trap.c for the global variable referenced)
+	 */
+	cmpl	$0, (dtrace_invop_func)
+
+	/* If not, just handle it as a normal trap. */
+	jz	norm_ill
+
+	/* Check if this is a user fault. */
+	cmpl	$GSEL_KPL, 4(%esp)	/* Check the code segment. */
+
+	/* If so, just handle it as a normal trap. */
+	jne	norm_ill
+
+	/*
+	 * This is a kernel instruction fault that might have been caused
+	 * by a DTrace provider.
+	 */
+	pushal				/* Push all registers onto the stack. */
+
+	/*
+	 * Setup the stack to contain the arguments to:
+	 * int dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax);
+	 */
+	pushl	%eax			/* Push %eax -- may contain the return value. */
+	pushl	%esp			/* Push the stack pointer. */
+	addl	$48, (%esp)		/* Adjust to incoming args. */
+	pushl	40(%esp)		/* Push the calling EIP. */
+
+	/* Call the registered function (dtrace_invop). */
+	call	*dtrace_invop_func	/* Call the registered function. */
+
+ALTENTRY(dtrace_invop_callsite)
+	/*
+	 * Drop the arguments to dtrace_invop from the stack, leaving
+	 * the registers.
+	 */
+	addl	$12, %esp
+
+	/* Process according to the return value from dtrace_invop. */
+	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
+	je	__dtrace_invop_pushl_ebp
+	cmpl	$DTRACE_INVOP_POPL_EBP, %eax
+	je	__dtrace_invop_popl_ebp
+	cmpl	$DTRACE_INVOP_LEAVE, %eax
+	je	__dtrace_invop_leave
+	cmpl	$DTRACE_INVOP_NOP, %eax
+	je	__dtrace_invop_nop
+
+	/*
+	 * The registered DTrace invalid instruction functions didn't
+	 * match the fault address to a probe, so process the trap in
+	 * the normal way.
+	 &/
+	 * normal way because the registered DTrace invalid instruction
+	 * functions didn't match it to a probe.
+	 */
+	jmp	norm_ill
+
+	/* case DTRACE_INVOP_PUSHL_EBP: */
+__dtrace_invop_pushl_ebp:
+	/*
+	 * We must emulate a "pushl %ebp".  To do this, we pull the stack
+	 * down 4 bytes, and then store the base pointer.
+	 */
+	popal
+	subl	$4, %esp		/* make room for %ebp */
+	pushl	%eax			/* push temp */
+	movl	8(%esp), %eax		/* load calling EIP */
+	incl	%eax			/* increment over LOCK prefix */
+	movl	%eax, 4(%esp)		/* store calling EIP */
+	movl	12(%esp), %eax		/* load calling CS */
+	movl	%eax, 8(%esp)		/* store calling CS */
+	movl	16(%esp), %eax		/* load calling EFLAGS */
+	movl	%eax, 12(%esp)		/* store calling EFLAGS */
+	movl	%ebp, 16(%esp)		/* push %ebp */
+	popl	%eax			/* pop off temp */
+	iret				/* return from interrupt */
+
+	/* case DTRACE_INVOP_POPL_EBP: */
+__dtrace_invop_popl_ebp:
+	/*
+	 * We must emulate a "popl %ebp".  To do this, we do the opposite of
+	 * the above:  we remove the %ebp from the stack, and squeeze up the
+	 * saved state from the trap.
+	 */
+	popal
+	pushl	%eax			/* push temp */
+	movl	16(%esp), %ebp		/* pop %ebp */
+	movl	12(%esp), %eax		/* load calling EFLAGS */
+	movl	%eax, 16(%esp)		/* store calling EFLAGS */
+	movl	8(%esp), %eax		/* load calling CS */
+	movl	%eax, 12(%esp)		/* store calling CS */
+	movl	4(%esp), %eax		/* load calling EIP */
+	incl	%eax			/* increment over LOCK prefix */
+	movl	%eax, 8(%esp)		/* store calling EIP */
+	popl	%eax			/* pop off temp */
+	addl	$4, %esp		/* adjust stack pointer */
+	iret				/* return from interrupt */
+
+	/* case DTRACE_INVOP_LEAVE: */
+__dtrace_invop_leave:
+	/*
+	 * We must emulate a "leave", which is the same as a "movl %ebp, %esp"
+	 * followed by a "popl %ebp".  This looks similar to the above, but
+	 * requires two temporaries:  one for the new base pointer, and one
+	 * for the staging register.
+	 */
+	popal
+	pushl	%eax			/* push temp */
+	pushl	%ebx			/* push temp */
+	movl	%ebp, %ebx		/* set temp to old %ebp */
+	movl	(%ebx), %ebp		/* pop %ebp */
+	movl	16(%esp), %eax		/* load calling EFLAGS */
+	movl	%eax, (%ebx)		/* store calling EFLAGS */
+	movl	12(%esp), %eax		/* load calling CS */
+	movl	%eax, -4(%ebx)		/* store calling CS */
+	movl	8(%esp), %eax		/* load calling EIP */
+	incl	%eax			/* increment over LOCK prefix */
+	movl	%eax, -8(%ebx)		/* store calling EIP */
+	movl	%ebx, -4(%esp)		/* temporarily store new %esp */
+	popl	%ebx			/* pop off temp */
+	popl	%eax			/* pop off temp */
+	movl	-12(%esp), %esp		/* set stack pointer */
+	subl	$8, %esp		/* adjust for three pushes, one pop */
+	iret				/* return from interrupt */
+
+	/* case DTRACE_INVOP_NOP: */
+__dtrace_invop_nop:
+	/*
+	 * We must emulate a "nop".  This is obviously not hard:  we need only
+	 * advance the %eip by one.
+	 */
+	popal
+	incl	(%esp)
+	iret
+
+norm_ill:
+#endif
+	/*
+	 * Process the instruction fault in the normal way.
+	 */
+	pushl $0
+	TRAP(T_PRIVINFLT)
+
+/*
  * SYSCALL CALL GATE (old entry point for a.out binaries)
  *
  * The intersegment call has been set up to specify one dummy parameter.

==== //depot/projects/dtrace/src/sys/i386/i386/local_apic.c#9 (text+ko) ====

@@ -36,6 +36,7 @@
 
 #include "opt_hwpmc_hooks.h"
 
+#include "opt_cyclic.h"
 #include "opt_ddb.h"
 
 #include <sys/param.h>
@@ -65,6 +66,10 @@
 #include <ddb/ddb.h>
 #endif
 
+#if defined(CYCLIC) || defined(KDTRACE)
+cyclic_clock_func_t	lapic_cyclic_clock_func;
+#endif
+
 /*
  * We can handle up to 60 APICs via our logical cluster IDs, but currently
  * the physical IDs on Intel processors up to the Pentium 4 are limited to
@@ -659,6 +664,19 @@
 			hardclock(TRAPF_USERMODE(&frame), TRAPF_PC(&frame));
 		else
 			hardclock_cpu(TRAPF_USERMODE(&frame));
+
+		/*
+		 * If the cyclic subsystem is configured and a callback
+		 * function has been registered, then call it to process
+		 * the high speed timers. If this function is registered
+		 * here, then there mustn't be a High Performance Event
+		 * Timer (HPET) on the CPU. A HPET provides higher
+		 * performance timer interrupts.
+		 */
+#if defined(CYCLIC) || defined(KDTRACE)
+		if (lapic_cyclic_clock_func != NULL)
+			(*lapic_cyclic_clock_func)();
+#endif
 	}
 
 	/* Fire statclock at stathz. */


More information about the p4-projects mailing list