/* $NetBSD: dtrace_asm.S,v 1.8 2023/11/03 09:07:57 chs Exp $ */ /* * 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: head/sys/cddl/dev/dtrace/i386/dtrace_asm.S 298171 2016-04-17 23:08:47Z markj $ */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #define _ASM #include "assym.h" #include #include #include #include #include #define DTRACE_SMAP_DISABLE \ call dtrace_smap_disable #define DTRACE_SMAP_ENABLE \ call dtrace_smap_enable #define INTR_POP \ addl $16, %esp; \ popl %edi; \ popl %esi; \ popl %ebp; \ popl %ebx; \ popl %edx; \ popl %ecx; \ popl %eax; \ addl $8, %esp ENTRY(dtrace_invop_start) /* Store a trapframe for dtrace. */ pushl $0 pushl $T_PRIVINFLT pushl %eax pushl %ecx pushl %edx pushl %ebx pushl %ebp pushl %esi pushl %edi subl $16,%esp /* dummy for segment regs */ cld /* Store the args to dtrace_invop(). */ pushl %eax /* push %eax -- may be return value */ pushl %esp /* push stack pointer */ addl $4, (%esp) /* skip first arg and segment regs */ pushl TF_EIP+8(%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 ALTENTRY(dtrace_invop_callsite) 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. */ INTR_POP 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. */ INTR_POP 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. */ INTR_POP 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 */ subl $8, %ebx /* adjust for three pushes, one pop */ movl %ebx, 8(%esp) /* temporarily store new %esp */ popl %ebx /* pop off temp */ popl %eax /* pop off temp */ movl (%esp), %esp /* set stack pointer */ iret /* return from interrupt */ invop_nop: /* * We must emulate a "nop". This is obviously not hard: we need only * advance the %eip by one. */ INTR_POP 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 */ DTRACE_SMAP_DISABLE repz /* Repeat for count... */ smovb /* move from %ds:si to %es:di */ DTRACE_SMAP_ENABLE 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 */ DTRACE_SMAP_DISABLE 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: DTRACE_SMAP_ENABLE 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 DTRACE_SMAP_DISABLE movl (%ecx), %eax DTRACE_SMAP_ENABLE ret END(dtrace_fulword) /* uint8_t dtrace_fuword8_nocheck(void *addr) */ ENTRY(dtrace_fuword8_nocheck) movl 4(%esp), %ecx xorl %eax, %eax DTRACE_SMAP_DISABLE movzbl (%ecx), %eax DTRACE_SMAP_ENABLE ret END(dtrace_fuword8_nocheck) /* uint16_t dtrace_fuword16_nocheck(void *addr) */ ENTRY(dtrace_fuword16_nocheck) movl 4(%esp), %ecx xorl %eax, %eax DTRACE_SMAP_DISABLE movzwl (%ecx), %eax DTRACE_SMAP_ENABLE ret END(dtrace_fuword16_nocheck) /* uint32_t dtrace_fuword32_nocheck(void *addr) */ ENTRY(dtrace_fuword32_nocheck) movl 4(%esp), %ecx xorl %eax, %eax DTRACE_SMAP_DISABLE movl (%ecx), %eax DTRACE_SMAP_ENABLE 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 DTRACE_SMAP_DISABLE movl (%ecx), %eax movl 4(%ecx), %edx DTRACE_SMAP_ENABLE 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)