Path: blob/main/sys/cddl/dev/dtrace/amd64/dtrace_asm.S
48375 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*20* Portions Copyright 2008 John Birrell <[email protected]>21*22*/23/*24* Copyright 2007 Sun Microsystems, Inc. All rights reserved.25* Use is subject to license terms.26*/2728#define _ASM2930#include <machine/asmacros.h>31#include <sys/cpuvar_defs.h>32#include <sys/dtrace.h>3334#include "assym.inc"3536#define INTR_POP \37movq TF_RDI(%rsp),%rdi; \38movq TF_RSI(%rsp),%rsi; \39movq TF_RDX(%rsp),%rdx; \40movq TF_RCX(%rsp),%rcx; \41movq TF_R8(%rsp),%r8; \42movq TF_R9(%rsp),%r9; \43movq TF_RAX(%rsp),%rax; \44movq TF_RBX(%rsp),%rbx; \45movq TF_RBP(%rsp),%rbp; \46movq TF_R10(%rsp),%r10; \47movq TF_R11(%rsp),%r11; \48movq TF_R12(%rsp),%r12; \49movq TF_R13(%rsp),%r13; \50movq TF_R14(%rsp),%r14; \51movq TF_R15(%rsp),%r15; \52testb $SEL_RPL_MASK,TF_CS(%rsp); \53jz 1f; \54cli; \55swapgs; \561: addq $TF_RIP,%rsp;5758ENTRY(dtrace_invop_start)5960KMSAN_ENTER6162/*63* #BP traps with %rip set to the next address. We need to decrement64* the value to indicate the address of the int3 (0xcc) instruction65* that we substituted.66*/67movq TF_RIP(%rsp), %rdi68decq %rdi69movq %rsp, %rsi7071/*72* Allocate some scratch space to let the invop handler return a value.73* This is needed when emulating "call" instructions.74*/75subq $16, %rsp76movq %rsp, %rdx7778call dtrace_invop79addq $16, %rsp8081#ifdef KMSAN82movq %rax, %r1283KMSAN_LEAVE84movq %r12, %rax85#endif8687cmpl $DTRACE_INVOP_PUSHL_EBP, %eax88je bp_push89cmpl $DTRACE_INVOP_CALL, %eax90je bp_call91cmpl $DTRACE_INVOP_LEAVE, %eax92je bp_leave93cmpl $DTRACE_INVOP_NOP, %eax94je bp_nop95cmpl $DTRACE_INVOP_RET, %eax96je bp_ret9798/* When all else fails handle the trap in the usual way. */99jmpq *dtrace_invop_calltrap_addr100101bp_push:102/*103* We must emulate a "pushq %rbp". To do this, we pull the stack104* down 8 bytes, and then store the base pointer.105*/106INTR_POP107subq $16, %rsp /* make room for %rbp */108pushq %rax /* push temp */109movq 24(%rsp), %rax /* load calling RIP */110movq %rax, 8(%rsp) /* store calling RIP */111movq 32(%rsp), %rax /* load calling CS */112movq %rax, 16(%rsp) /* store calling CS */113movq 40(%rsp), %rax /* load calling RFLAGS */114movq %rax, 24(%rsp) /* store calling RFLAGS */115movq 48(%rsp), %rax /* load calling RSP */116subq $8, %rax /* make room for %rbp */117movq %rax, 32(%rsp) /* store calling RSP */118movq 56(%rsp), %rax /* load calling SS */119movq %rax, 40(%rsp) /* store calling SS */120movq 32(%rsp), %rax /* reload calling RSP */121movq %rbp, (%rax) /* store %rbp there */122popq %rax /* pop off temp */123iretq /* return from interrupt */124/*NOTREACHED*/125126bp_call:127/*128* Emulate a "call" instruction. The invop handler must have already129* updated the saved copy of %rip in the register set. It's our job to130* pull the hardware-saved registers down to make space for the return131* address, which is provided by the invop handler in our scratch132* space.133*/134INTR_POP135subq $16, %rsp /* make room for %rbp */136pushq %rax /* push temp */137pushq %rbx /* push temp */138139movq 32(%rsp), %rax /* load calling RIP */140movq %rax, 16(%rsp) /* store calling RIP */141movq 40(%rsp), %rax /* load calling CS */142movq %rax, 24(%rsp) /* store calling CS */143movq 48(%rsp), %rax /* load calling RFLAGS */144movq %rax, 32(%rsp) /* store calling RFLAGS */145movq 56(%rsp), %rax /* load calling RSP */146subq $8, %rax /* make room for return address */147movq %rax, 40(%rsp) /* store calling RSP */148movq 64(%rsp), %rax /* load calling SS */149movq %rax, 48(%rsp) /* store calling SS */150151movq -(TF_RIP - 16)(%rsp), %rax /* load return address */152movq 40(%rsp), %rbx /* reload calling RSP */153movq %rax, (%rbx) /* store return address */154155popq %rbx /* pop temp */156popq %rax /* pop temp */157iretq /* return from interrupt */158/*NOTREACHED*/159160bp_leave:161/*162* We must emulate a "leave", which is the same as a "movq %rbp, %rsp"163* followed by a "popq %rbp". This is quite a bit simpler on amd64164* than it is on i386 -- we can exploit the fact that the %rsp is165* explicitly saved to effect the pop without having to reshuffle166* the other data pushed for the trap.167*/168INTR_POP169pushq %rax /* push temp */170movq 8(%rsp), %rax /* load calling RIP */171movq %rax, 8(%rsp) /* store calling RIP */172movq (%rbp), %rax /* get new %rbp */173addq $8, %rbp /* adjust new %rsp */174movq %rbp, 32(%rsp) /* store new %rsp */175movq %rax, %rbp /* set new %rbp */176popq %rax /* pop off temp */177iretq /* return from interrupt */178/*NOTREACHED*/179180bp_nop:181/* We must emulate a "nop". */182INTR_POP183iretq184/*NOTREACHED*/185186bp_ret:187INTR_POP188pushq %rax /* push temp */189movq 32(%rsp), %rax /* load %rsp */190movq (%rax), %rax /* load calling RIP */191movq %rax, 8(%rsp) /* store calling RIP */192addq $8, 32(%rsp) /* adjust new %rsp */193popq %rax /* pop off temp */194iretq /* return from interrupt */195/*NOTREACHED*/196197END(dtrace_invop_start)198199/*200greg_t dtrace_getfp(void)201*/202ENTRY(dtrace_getfp)203movq %rbp, %rax204ret205END(dtrace_getfp)206207/*208uint32_t209dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)210*/211ENTRY(dtrace_cas32)212movl %esi, %eax213lock214cmpxchgl %edx, (%rdi)215ret216END(dtrace_cas32)217218/*219void *220dtrace_casptr(void *target, void *cmp, void *new)221*/222ENTRY(dtrace_casptr)223movq %rsi, %rax224lock225cmpxchgq %rdx, (%rdi)226ret227END(dtrace_casptr)228229/*230uintptr_t231dtrace_caller(int aframes)232*/233ENTRY(dtrace_caller)234movq $-1, %rax235ret236END(dtrace_caller)237238/*239void240dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)241*/242ENTRY(dtrace_copy_nosmap)243pushq %rbp244movq %rsp, %rbp245246xchgq %rdi, %rsi /* make %rsi source, %rdi dest */247movq %rdx, %rcx /* load count */248repz /* repeat for count ... */249smovb /* move from %ds:rsi to %ed:rdi */250leave251ret252END(dtrace_copy_nosmap)253254ENTRY(dtrace_copy_smap)255pushq %rbp256movq %rsp, %rbp257258xchgq %rdi, %rsi /* make %rsi source, %rdi dest */259movq %rdx, %rcx /* load count */260stac261repz /* repeat for count ... */262smovb /* move from %ds:rsi to %ed:rdi */263clac264leave265ret266END(dtrace_copy_smap)267268/*269void270dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size,271volatile uint16_t *flags)272*/273ENTRY(dtrace_copystr_nosmap)274pushq %rbp275movq %rsp, %rbp2762770:278movb (%rdi), %al /* load from source */279movb %al, (%rsi) /* store to destination */280addq $1, %rdi /* increment source pointer */281addq $1, %rsi /* increment destination pointer */282subq $1, %rdx /* decrement remaining count */283cmpb $0, %al284je 2f285testq $0xfff, %rdx /* test if count is 4k-aligned */286jnz 1f /* if not, continue with copying */287testq $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */288jnz 2f2891:290cmpq $0, %rdx291jne 0b2922:293leave294ret295296END(dtrace_copystr_nosmap)297298ENTRY(dtrace_copystr_smap)299pushq %rbp300movq %rsp, %rbp301302stac3030:304movb (%rdi), %al /* load from source */305movb %al, (%rsi) /* store to destination */306addq $1, %rdi /* increment source pointer */307addq $1, %rsi /* increment destination pointer */308subq $1, %rdx /* decrement remaining count */309cmpb $0, %al310je 2f311testq $0xfff, %rdx /* test if count is 4k-aligned */312jnz 1f /* if not, continue with copying */313testq $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */314jnz 2f3151:316cmpq $0, %rdx317jne 0b3182:319clac320leave321ret322323END(dtrace_copystr_smap)324325/*326uintptr_t327dtrace_fulword(void *addr)328*/329ENTRY(dtrace_fulword_nosmap)330movq (%rdi), %rax331ret332END(dtrace_fulword_nosmap)333334ENTRY(dtrace_fulword_smap)335stac336movq (%rdi), %rax337clac338ret339END(dtrace_fulword_smap)340341/*342uint8_t343dtrace_fuword8_nocheck(void *addr)344*/345ENTRY(dtrace_fuword8_nocheck_nosmap)346xorq %rax, %rax347movb (%rdi), %al348ret349END(dtrace_fuword8_nocheck_nosmap)350351ENTRY(dtrace_fuword8_nocheck_smap)352stac353xorq %rax, %rax354movb (%rdi), %al355clac356ret357END(dtrace_fuword8_nocheck_smap)358359/*360uint16_t361dtrace_fuword16_nocheck(void *addr)362*/363ENTRY(dtrace_fuword16_nocheck_nosmap)364xorq %rax, %rax365movw (%rdi), %ax366ret367END(dtrace_fuword16_nocheck_nosmap)368369ENTRY(dtrace_fuword16_nocheck_smap)370stac371xorq %rax, %rax372movw (%rdi), %ax373clac374ret375END(dtrace_fuword16_nocheck_smap)376377/*378uint32_t379dtrace_fuword32_nocheck(void *addr)380*/381ENTRY(dtrace_fuword32_nocheck_nosmap)382xorq %rax, %rax383movl (%rdi), %eax384ret385END(dtrace_fuword32_nocheck_nosmap)386387ENTRY(dtrace_fuword32_nocheck_smap)388stac389xorq %rax, %rax390movl (%rdi), %eax391clac392ret393END(dtrace_fuword32_nocheck_smap)394395/*396uint64_t397dtrace_fuword64_nocheck(void *addr)398*/399ENTRY(dtrace_fuword64_nocheck_nosmap)400movq (%rdi), %rax401ret402END(dtrace_fuword64_nocheck_nosmap)403404ENTRY(dtrace_fuword64_nocheck_smap)405stac406movq (%rdi), %rax407clac408ret409END(dtrace_fuword64_nocheck_smap)410411/*412void413dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,414int fault, int fltoffs, uintptr_t illval)415*/416ENTRY(dtrace_probe_error)417pushq %rbp418movq %rsp, %rbp419subq $0x8, %rsp420movq %r9, (%rsp)421movq %r8, %r9422movq %rcx, %r8423movq %rdx, %rcx424movq %rsi, %rdx425movq %rdi, %rsi426movl dtrace_probeid_error(%rip), %edi427call dtrace_probe428addq $0x8, %rsp429leave430ret431END(dtrace_probe_error)432433/*434void435dtrace_membar_producer(void)436*/437ENTRY(dtrace_membar_producer)438rep; ret /* use 2 byte return instruction when branch target */439/* AMD Software Optimization Guide - Section 6.2 */440END(dtrace_membar_producer)441442/*443void444dtrace_membar_consumer(void)445*/446ENTRY(dtrace_membar_consumer)447rep; ret /* use 2 byte return instruction when branch target */448/* AMD Software Optimization Guide - Section 6.2 */449END(dtrace_membar_consumer)450451/*452dtrace_icookie_t453dtrace_interrupt_disable(void)454*/455ENTRY(dtrace_interrupt_disable)456pushfq457popq %rax458cli459ret460END(dtrace_interrupt_disable)461462/*463void464dtrace_interrupt_enable(dtrace_icookie_t cookie)465*/466ENTRY(dtrace_interrupt_enable)467pushq %rdi468popfq469ret470END(dtrace_interrupt_enable)471472473