Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 Feb 2008 20:12:36 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 135169 for review
Message-ID:  <200802102012.m1AKCaGK070971@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=135169

Change 135169 by jb@jb_freebsd1 on 2008/02/10 20:12:28

	Add the fbt exception handling code.

Affected files ...

.. //depot/projects/dtrace/src/sys/cddl/dev/dtrace/i386/dtrace_asm.S#6 edit
.. //depot/projects/dtrace/src/sys/i386/i386/exception.s#14 edit

Differences ...

==== //depot/projects/dtrace/src/sys/cddl/dev/dtrace/i386/dtrace_asm.S#6 (text+ko) ====

@@ -30,11 +30,120 @@
 #include <sys/cpuvar_defs.h>
 #include <sys/dtrace.h>
 
+#include "assym.s"
+
+	.globl	calltrap
+	.type	calltrap,@function
+	ENTRY(dtrace_invop_start)
+
+	pushl	%eax			/* push %eax -- may be return value */
+	pushl	%esp			/* push stack pointer */
+	addl	$48, (%esp)		/* adjust to incoming args */
+	pushl	40(%esp)		/* push calling EIP */
+
+	/*
+	 * Call dtrace_invop to let it check if the exception was
+	 * a fbt one. The return value in %eax will tell us what
+	 * dtrace_invop wants us to do.
+	 */
+	call	dtrace_invop
+
+	/*
+	 * We pushed 3 times for the arguments to dtrace_invop,
+	 * so we need to increment the stack pointer to get rid of
+	 * those values.
+	 */
+	addl	$12, %esp
+	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
+	je	invop_push
+	cmpl	$DTRACE_INVOP_POPL_EBP, %eax
+	je	invop_pop
+	cmpl	$DTRACE_INVOP_LEAVE, %eax
+	je	invop_leave
+	cmpl	$DTRACE_INVOP_NOP, %eax
+	je	invop_nop
+
+	/* When all else fails handle the trap in the usual way. */
+	jmpl	*dtrace_invop_calltrap_addr
+
+invop_push:
+	/*
+	 * 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. */
+invop_pop:
+	/*
+	 * 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. */
+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.
+	 */
+	popa
+	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 */
+invop_nop:
+	/*
+	 * We must emulate a "nop".  This is obviously not hard:  we need only
+	 * advance the %eip by one.
+	 */
+	popa
+	incl	(%esp)
+	iret				/* return from interrupt */
+
+	END(dtrace_invop_start)
+
 /*
 void dtrace_invop_init(void)
 */
 	ENTRY(dtrace_invop_init)
-	/* XXX */
+	movl	$dtrace_invop_start, dtrace_invop_jump_addr
 	ret
 	END(dtrace_invop_init)
 
@@ -42,7 +151,7 @@
 void dtrace_invop_uninit(void)
 */
 	ENTRY(dtrace_invop_uninit)
-	/* XXX */
+	movl	$0, dtrace_invop_jump_addr
 	ret
 	END(dtrace_invop_uninit)
 

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

@@ -36,6 +36,7 @@
 
 #include "opt_apic.h"
 #include "opt_hwpmc_hooks.h"
+#include "opt_kdtrace.h"
 #include "opt_npx.h"
 
 #include <machine/asmacros.h>
@@ -45,7 +46,23 @@
 #include "assym.s"
 
 #define	SEL_RPL_MASK	0x0003
+#define GSEL_KPL	0x0020	/* GSEL(GCODE_SEL, SEL_KPL) */
 
+#ifdef KDTRACE_HOOKS
+	.bss
+	.globl	dtrace_invop_jump_addr
+	.align	4
+	.type	dtrace_invop_jump_addr, @object
+        .size	dtrace_invop_jump_addr, 4
+dtrace_invop_jump_addr:
+	.zero	4
+	.globl	dtrace_invop_calltrap_addr
+	.align	4
+	.type	dtrace_invop_calltrap_addr, @object
+        .size	dtrace_invop_calltrap_addr, 4
+dtrace_invop_calltrap_addr:
+	.zero	8
+#endif
 	.text
 #ifdef HWPMC_HOOKS
 	ENTRY(start_exceptions)
@@ -95,8 +112,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)
@@ -153,6 +168,43 @@
 	jmp	doreti
 
 /*
+ * Privileged instruction fault.
+ */
+	SUPERALIGN_TEXT
+IDTVEC(ill)
+	/* Check if there is no DTrace hook registered. */
+	cmpl	$0,dtrace_invop_jump_addr
+	je	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. */
+
+	/*
+	 * Set our jump address for the jump back in the event that
+	 * the exception wasn't caused by DTrace at all.
+	 */
+	movl	$norm_ill, dtrace_invop_calltrap_addr
+
+	/* Jump to the code hooked in by DTrace. */
+	jmpl	*dtrace_invop_jump_addr
+
+	/*
+	 * Process the instruction fault in the normal way.
+	 */
+norm_ill:
+	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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802102012.m1AKCaGK070971>