PERFORCE change 135169 for review
John Birrell
jb at FreeBSD.org
Sun Feb 10 12:12:37 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=135169
Change 135169 by jb at 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, at 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.
More information about the p4-projects
mailing list