summaryrefslogtreecommitdiffstats
path: root/sys/cddl/dev/dtrace/i386/dtrace_asm.S
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cddl/dev/dtrace/i386/dtrace_asm.S')
-rw-r--r--sys/cddl/dev/dtrace/i386/dtrace_asm.S527
1 files changed, 527 insertions, 0 deletions
diff --git a/sys/cddl/dev/dtrace/i386/dtrace_asm.S b/sys/cddl/dev/dtrace/i386/dtrace_asm.S
new file mode 100644
index 0000000..787a3c8
--- /dev/null
+++ b/sys/cddl/dev/dtrace/i386/dtrace_asm.S
@@ -0,0 +1,527 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#define _ASM
+
+#include <machine/asmacros.h>
+#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
+ ALTENTRY(dtrace_invop_callsite)
+ 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)
+ movl $dtrace_invop_start, dtrace_invop_jump_addr
+ ret
+ END(dtrace_invop_init)
+
+/*
+void dtrace_invop_uninit(void)
+*/
+ ENTRY(dtrace_invop_uninit)
+ movl $0, dtrace_invop_jump_addr
+ ret
+ END(dtrace_invop_uninit)
+
+/*
+greg_t dtrace_getfp(void)
+*/
+
+ ENTRY(dtrace_getfp)
+ movl %ebp, %eax
+ ret
+ END(dtrace_getfp)
+
+/*
+uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
+*/
+
+ ENTRY(dtrace_cas32)
+ ALTENTRY(dtrace_casptr)
+ movl 4(%esp), %edx
+ movl 8(%esp), %eax
+ movl 12(%esp), %ecx
+ lock
+ cmpxchgl %ecx, (%edx)
+ ret
+ END(dtrace_casptr)
+ END(dtrace_cas32)
+
+/*
+uintptr_t dtrace_caller(int aframes)
+*/
+
+ ENTRY(dtrace_caller)
+ movl $-1, %eax
+ ret
+ END(dtrace_caller)
+
+/*
+void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
+*/
+
+ ENTRY(dtrace_copy)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+
+ movl 8(%ebp), %esi /* Load source address */
+ movl 12(%ebp), %edi /* Load destination address */
+ movl 16(%ebp), %ecx /* Load count */
+ repz /* Repeat for count... */
+ smovb /* move from %ds:si to %es:di */
+
+ popl %edi
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ END(dtrace_copy)
+
+/*
+void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size)
+*/
+
+ ENTRY(dtrace_copystr)
+
+ pushl %ebp /* Setup stack frame */
+ movl %esp, %ebp
+ pushl %ebx /* Save registers */
+
+ movl 8(%ebp), %ebx /* Load source address */
+ movl 12(%ebp), %edx /* Load destination address */
+ movl 16(%ebp), %ecx /* Load count */
+
+0:
+ movb (%ebx), %al /* Load from source */
+ movb %al, (%edx) /* Store to destination */
+ incl %ebx /* Increment source pointer */
+ incl %edx /* Increment destination pointer */
+ decl %ecx /* Decrement remaining count */
+ cmpb $0, %al
+ je 1f
+ cmpl $0, %ecx
+ jne 0b
+
+1:
+ popl %ebx
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+ END(dtrace_copystr)
+
+/*
+uintptr_t dtrace_fulword(void *addr)
+*/
+
+ ENTRY(dtrace_fulword)
+ movl 4(%esp), %ecx
+ xorl %eax, %eax
+ movl (%ecx), %eax
+ ret
+ END(dtrace_fulword)
+
+/*
+uint8_t dtrace_fuword8_nocheck(void *addr)
+*/
+
+ ENTRY(dtrace_fuword8_nocheck)
+ movl 4(%esp), %ecx
+ xorl %eax, %eax
+ movzbl (%ecx), %eax
+ ret
+ END(dtrace_fuword8_nocheck)
+
+/*
+uint16_t dtrace_fuword16_nocheck(void *addr)
+*/
+
+ ENTRY(dtrace_fuword16_nocheck)
+ movl 4(%esp), %ecx
+ xorl %eax, %eax
+ movzwl (%ecx), %eax
+ ret
+ END(dtrace_fuword16_nocheck)
+
+/*
+uint32_t dtrace_fuword32_nocheck(void *addr)
+*/
+
+ ENTRY(dtrace_fuword32_nocheck)
+ movl 4(%esp), %ecx
+ xorl %eax, %eax
+ movl (%ecx), %eax
+ ret
+ END(dtrace_fuword32_nocheck)
+
+/*
+uint64_t dtrace_fuword64_nocheck(void *addr)
+*/
+
+ ENTRY(dtrace_fuword64_nocheck)
+ movl 4(%esp), %ecx
+ xorl %eax, %eax
+ xorl %edx, %edx
+ movl (%ecx), %eax
+ movl 4(%ecx), %edx
+ ret
+ END(dtrace_fuword64_nocheck)
+
+/*
+void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)
+*/
+
+ ENTRY(dtrace_probe_error)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl 0x1c(%ebp)
+ pushl 0x18(%ebp)
+ pushl 0x14(%ebp)
+ pushl 0x10(%ebp)
+ pushl 0xc(%ebp)
+ pushl 0x8(%ebp)
+ pushl dtrace_probeid_error
+ call dtrace_probe
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ END(dtrace_probe_error)
+
+/*
+void dtrace_membar_producer(void)
+*/
+
+ ENTRY(dtrace_membar_producer)
+ rep; ret /* use 2 byte return instruction when branch target */
+ /* AMD Software Optimization Guide - Section 6.2 */
+ END(dtrace_membar_producer)
+
+/*
+void dtrace_membar_consumer(void)
+*/
+
+ ENTRY(dtrace_membar_consumer)
+ rep; ret /* use 2 byte return instruction when branch target */
+ /* AMD Software Optimization Guide - Section 6.2 */
+ END(dtrace_membar_consumer)
+
+/*
+dtrace_icookie_t dtrace_interrupt_disable(void)
+*/
+ ENTRY(dtrace_interrupt_disable)
+ pushfl
+ popl %eax
+ cli
+ ret
+ END(dtrace_interrupt_disable)
+
+/*
+void dtrace_interrupt_enable(dtrace_icookie_t cookie)
+*/
+ ENTRY(dtrace_interrupt_enable)
+ movl 4(%esp), %eax
+ pushl %eax
+ popfl
+ ret
+ END(dtrace_interrupt_enable)
+
+/*
+ * The panic() and cmn_err() functions invoke vpanic() as a common entry point
+ * into the panic code implemented in panicsys(). vpanic() is responsible
+ * for passing through the format string and arguments, and constructing a
+ * regs structure on the stack into which it saves the current register
+ * values. If we are not dying due to a fatal trap, these registers will
+ * then be preserved in panicbuf as the current processor state. Before
+ * invoking panicsys(), vpanic() activates the first panic trigger (see
+ * common/os/panic.c) and switches to the panic_stack if successful. Note that
+ * DTrace takes a slightly different panic path if it must panic from probe
+ * context. Instead of calling panic, it calls into dtrace_vpanic(), which
+ * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
+ * branches back into vpanic().
+ */
+/*
+void vpanic(const char *format, va_list alist)
+*/
+ ENTRY(vpanic) /* Initial stack layout: */
+
+ pushl %ebp /* | %eip | 20 */
+ movl %esp, %ebp /* | %ebp | 16 */
+ pushl %eax /* | %eax | 12 */
+ pushl %ebx /* | %ebx | 8 */
+ pushl %ecx /* | %ecx | 4 */
+ pushl %edx /* | %edx | 0 */
+
+ movl %esp, %ebx /* %ebx = current stack pointer */
+
+ lea panic_quiesce, %eax /* %eax = &panic_quiesce */
+ pushl %eax /* push &panic_quiesce */
+ call panic_trigger /* %eax = panic_trigger() */
+ addl $4, %esp /* reset stack pointer */
+
+vpanic_common:
+ cmpl $0, %eax /* if (%eax == 0) */
+ je 0f /* goto 0f; */
+
+ /*
+ * If panic_trigger() was successful, we are the first to initiate a
+ * panic: we now switch to the reserved panic_stack before continuing.
+ */
+ lea panic_stack, %esp /* %esp = panic_stack */
+ addl $PANICSTKSIZE, %esp /* %esp += PANICSTKSIZE */
+
+0: subl $REGSIZE, %esp /* allocate struct regs */
+
+ /*
+ * Now that we've got everything set up, store the register values as
+ * they were when we entered vpanic() to the designated location in
+ * the regs structure we allocated on the stack.
+ */
+#ifdef notyet
+ mov %gs, %edx
+ mov %edx, REGOFF_GS(%esp)
+ mov %fs, %edx
+ mov %edx, REGOFF_FS(%esp)
+ mov %es, %edx
+ mov %edx, REGOFF_ES(%esp)
+ mov %ds, %edx
+ mov %edx, REGOFF_DS(%esp)
+ movl %edi, REGOFF_EDI(%esp)
+ movl %esi, REGOFF_ESI(%esp)
+ movl 16(%ebx), %ecx
+ movl %ecx, REGOFF_EBP(%esp)
+ movl %ebx, %ecx
+ addl $20, %ecx
+ movl %ecx, REGOFF_ESP(%esp)
+ movl 8(%ebx), %ecx
+ movl %ecx, REGOFF_EBX(%esp)
+ movl 0(%ebx), %ecx
+ movl %ecx, REGOFF_EDX(%esp)
+ movl 4(%ebx), %ecx
+ movl %ecx, REGOFF_ECX(%esp)
+ movl 12(%ebx), %ecx
+ movl %ecx, REGOFF_EAX(%esp)
+ movl $0, REGOFF_TRAPNO(%esp)
+ movl $0, REGOFF_ERR(%esp)
+ lea vpanic, %ecx
+ movl %ecx, REGOFF_EIP(%esp)
+ mov %cs, %edx
+ movl %edx, REGOFF_CS(%esp)
+ pushfl
+ popl %ecx
+ movl %ecx, REGOFF_EFL(%esp)
+ movl $0, REGOFF_UESP(%esp)
+ mov %ss, %edx
+ movl %edx, REGOFF_SS(%esp)
+
+ movl %esp, %ecx /* %ecx = &regs */
+ pushl %eax /* push on_panic_stack */
+ pushl %ecx /* push &regs */
+ movl 12(%ebp), %ecx /* %ecx = alist */
+ pushl %ecx /* push alist */
+ movl 8(%ebp), %ecx /* %ecx = format */
+ pushl %ecx /* push format */
+ call panicsys /* panicsys(); */
+ addl $16, %esp /* pop arguments */
+
+ addl $REGSIZE, %esp
+#endif
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ leave
+ ret
+ END(vpanic)
+
+/*
+void dtrace_vpanic(const char *format, va_list alist)
+*/
+ ENTRY(dtrace_vpanic) /* Initial stack layout: */
+
+ pushl %ebp /* | %eip | 20 */
+ movl %esp, %ebp /* | %ebp | 16 */
+ pushl %eax /* | %eax | 12 */
+ pushl %ebx /* | %ebx | 8 */
+ pushl %ecx /* | %ecx | 4 */
+ pushl %edx /* | %edx | 0 */
+
+ movl %esp, %ebx /* %ebx = current stack pointer */
+
+ lea panic_quiesce, %eax /* %eax = &panic_quiesce */
+ pushl %eax /* push &panic_quiesce */
+ call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
+ addl $4, %esp /* reset stack pointer */
+ jmp vpanic_common /* jump back to common code */
+
+ END(dtrace_vpanic)
+
+/*
+int
+panic_trigger(int *tp)
+*/
+ ENTRY(panic_trigger)
+ xorl %eax, %eax
+ movl $0xdefacedd, %edx
+ lock
+ xchgl %edx, (%edi)
+ cmpl $0, %edx
+ je 0f
+ movl $0, %eax
+ ret
+0: movl $1, %eax
+ ret
+ END(panic_trigger)
+
+/*
+int
+dtrace_panic_trigger(int *tp)
+*/
+ ENTRY(dtrace_panic_trigger)
+ xorl %eax, %eax
+ movl $0xdefacedd, %edx
+ lock
+ xchgl %edx, (%edi)
+ cmpl $0, %edx
+ je 0f
+ movl $0, %eax
+ ret
+0: movl $1, %eax
+ ret
+ END(dtrace_panic_trigger)
OpenPOWER on IntegriCloud