/* * 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 #include #include #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 = ®s */ pushl %eax /* push on_panic_stack */ pushl %ecx /* push ®s */ 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)