dtrace_asm.S revision 283676
191094Sdes/* 2115619Sdes * CDDL HEADER START 3174832Sdes * 491094Sdes * The contents of this file are subject to the terms of the 591094Sdes * Common Development and Distribution License (the "License"). 691094Sdes * You may not use this file except in compliance with the License. 799158Sdes * 899158Sdes * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 999158Sdes * or http://www.opensolaris.org/os/licensing. 1091094Sdes * See the License for the specific language governing permissions 1191094Sdes * and limitations under the License. 1291094Sdes * 1391094Sdes * When distributing Covered Code, include this CDDL HEADER in each 1491094Sdes * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1591094Sdes * If applicable, add the following below this CDDL HEADER, with the 1691094Sdes * fields enclosed by brackets "[]" replaced with your own identifying 1791094Sdes * information: Portions Copyright [yyyy] [name of copyright owner] 1891094Sdes * 1991094Sdes * CDDL HEADER END 2091094Sdes * 2191094Sdes * Portions Copyright 2008 John Birrell <jb@freebsd.org> 2291094Sdes * 2391094Sdes * $FreeBSD: stable/10/sys/cddl/dev/dtrace/amd64/dtrace_asm.S 283676 2015-05-29 04:01:39Z markj $ 2491094Sdes * 2591094Sdes */ 2691094Sdes/* 2791094Sdes * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2891094Sdes * Use is subject to license terms. 2991094Sdes */ 3091094Sdes 3191094Sdes#define _ASM 3291094Sdes 3391094Sdes#include <machine/asmacros.h> 3491094Sdes#include <sys/cpuvar_defs.h> 35174832Sdes#include <sys/dtrace.h> 3691094Sdes 3791094Sdes#include "assym.s" 3891094Sdes 3991094Sdes#define INTR_POP \ 4091094Sdes MEXITCOUNT; \ 4191094Sdes movq TF_RDI(%rsp),%rdi; \ 4291094Sdes movq TF_RSI(%rsp),%rsi; \ 4391094Sdes movq TF_RDX(%rsp),%rdx; \ 4491094Sdes movq TF_RCX(%rsp),%rcx; \ 4591094Sdes movq TF_R8(%rsp),%r8; \ 46107937Sdes movq TF_R9(%rsp),%r9; \ 47107937Sdes movq TF_RAX(%rsp),%rax; \ 48107937Sdes movq TF_RBX(%rsp),%rbx; \ 49107937Sdes movq TF_RBP(%rsp),%rbp; \ 50107937Sdes movq TF_R10(%rsp),%r10; \ 51107937Sdes movq TF_R11(%rsp),%r11; \ 52107937Sdes movq TF_R12(%rsp),%r12; \ 53107937Sdes movq TF_R13(%rsp),%r13; \ 54107937Sdes movq TF_R14(%rsp),%r14; \ 5591094Sdes movq TF_R15(%rsp),%r15; \ 5691097Sdes testb $SEL_RPL_MASK,TF_CS(%rsp); \ 5791097Sdes jz 1f; \ 5891094Sdes cli; \ 5991097Sdes swapgs; \ 6091094Sdes1: addq $TF_RIP,%rsp; 6191097Sdes 6291094Sdes 6391094Sdes .globl calltrap 6491094Sdes .type calltrap,@function 65174832Sdes ENTRY(dtrace_invop_start) 6691094Sdes 6791094Sdes /* 68115619Sdes * #BP traps with %rip set to the next address. We need to decrement 6991094Sdes * the value to indicate the address of the int3 (0xcc) instruction 7091094Sdes * that we substituted. 7191094Sdes */ 7291094Sdes movq TF_RIP(%rsp), %rdi 7391684Sdes decq %rdi 7491094Sdes movq TF_RSP(%rsp), %rsi 7591094Sdes movq TF_RAX(%rsp), %rdx 7691094Sdes pushq (%rsi) 7791094Sdes movq %rsp, %rsi 7891094Sdes call dtrace_invop 7991094Sdes ALTENTRY(dtrace_invop_callsite) 8091100Sdes addq $8, %rsp 8191094Sdes cmpl $DTRACE_INVOP_PUSHL_EBP, %eax 8291094Sdes je bp_push 8391094Sdes cmpl $DTRACE_INVOP_LEAVE, %eax 8491094Sdes je bp_leave 8591830Sdes cmpl $DTRACE_INVOP_NOP, %eax 8691830Sdes je bp_nop 8791094Sdes cmpl $DTRACE_INVOP_RET, %eax 8891830Sdes je bp_ret 8991094Sdes 9091094Sdes /* When all else fails handle the trap in the usual way. */ 9191094Sdes jmpq *dtrace_invop_calltrap_addr 9291094Sdes 9391094Sdesbp_push: 9491094Sdes /* 9591094Sdes * We must emulate a "pushq %rbp". To do this, we pull the stack 9691094Sdes * down 8 bytes, and then store the base pointer. 9791094Sdes */ 9891094Sdes INTR_POP 9991094Sdes subq $16, %rsp /* make room for %rbp */ 10091094Sdes pushq %rax /* push temp */ 10191094Sdes movq 24(%rsp), %rax /* load calling RIP */ 10291094Sdes movq %rax, 8(%rsp) /* store calling RIP */ 10391094Sdes movq 32(%rsp), %rax /* load calling CS */ 10491094Sdes movq %rax, 16(%rsp) /* store calling CS */ 10591094Sdes movq 40(%rsp), %rax /* load calling RFLAGS */ 10691094Sdes movq %rax, 24(%rsp) /* store calling RFLAGS */ 10791830Sdes movq 48(%rsp), %rax /* load calling RSP */ 108115619Sdes subq $8, %rax /* make room for %rbp */ 109115619Sdes movq %rax, 32(%rsp) /* store calling RSP */ 11091094Sdes movq 56(%rsp), %rax /* load calling SS */ 11191094Sdes movq %rax, 40(%rsp) /* store calling SS */ 11291094Sdes movq 32(%rsp), %rax /* reload calling RSP */ 11391094Sdes movq %rbp, (%rax) /* store %rbp there */ 11491094Sdes popq %rax /* pop off temp */ 11591094Sdes iretq /* return from interrupt */ 11691094Sdes /*NOTREACHED*/ 11791094Sdes 11891094Sdesbp_leave: 11991094Sdes /* 12091094Sdes * We must emulate a "leave", which is the same as a "movq %rbp, %rsp" 12191094Sdes * followed by a "popq %rbp". This is quite a bit simpler on amd64 12291094Sdes * than it is on i386 -- we can exploit the fact that the %rsp is 12391094Sdes * explicitly saved to effect the pop without having to reshuffle 12491094Sdes * the other data pushed for the trap. 125116520Sdes */ 126116520Sdes INTR_POP 127115619Sdes pushq %rax /* push temp */ 128116520Sdes movq 8(%rsp), %rax /* load calling RIP */ 129115619Sdes movq %rax, 8(%rsp) /* store calling RIP */ 13091094Sdes movq (%rbp), %rax /* get new %rbp */ 131116520Sdes addq $8, %rbp /* adjust new %rsp */ 132115619Sdes movq %rbp, 32(%rsp) /* store new %rsp */ 13391094Sdes movq %rax, %rbp /* set new %rbp */ 13491094Sdes popq %rax /* pop off temp */ 13591094Sdes iretq /* return from interrupt */ 13691094Sdes /*NOTREACHED*/ 13791094Sdes 13891094Sdesbp_nop: 13991094Sdes /* We must emulate a "nop". */ 14091094Sdes INTR_POP 14195908Sdes iretq 14291094Sdes /*NOTREACHED*/ 14391094Sdes 14491094Sdesbp_ret: 145147455Sdes INTR_POP 14695908Sdes pushq %rax /* push temp */ 147147455Sdes movq 32(%rsp), %rax /* load %rsp */ 148147455Sdes movq (%rax), %rax /* load calling RIP */ 14991094Sdes movq %rax, 8(%rsp) /* store calling RIP */ 15091100Sdes addq $8, 32(%rsp) /* adjust new %rsp */ 15191100Sdes popq %rax /* pop off temp */ 15291100Sdes iretq /* return from interrupt */ 15391100Sdes /*NOTREACHED*/ 154 155 END(dtrace_invop_start) 156 157/* 158void dtrace_invop_init(void) 159*/ 160 ENTRY(dtrace_invop_init) 161 movq $dtrace_invop_start, dtrace_invop_jump_addr(%rip) 162 ret 163 END(dtrace_invop_init) 164 165/* 166void dtrace_invop_uninit(void) 167*/ 168 ENTRY(dtrace_invop_uninit) 169 movq $0, dtrace_invop_jump_addr(%rip) 170 ret 171 END(dtrace_invop_uninit) 172 173/* 174greg_t dtrace_getfp(void) 175*/ 176 ENTRY(dtrace_getfp) 177 movq %rbp, %rax 178 ret 179 END(dtrace_getfp) 180 181/* 182uint32_t 183dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) 184*/ 185 ENTRY(dtrace_cas32) 186 movl %esi, %eax 187 lock 188 cmpxchgl %edx, (%rdi) 189 ret 190 END(dtrace_cas32) 191 192/* 193void * 194dtrace_casptr(void *target, void *cmp, void *new) 195*/ 196 ENTRY(dtrace_casptr) 197 movq %rsi, %rax 198 lock 199 cmpxchgq %rdx, (%rdi) 200 ret 201 END(dtrace_casptr) 202 203/* 204uintptr_t 205dtrace_caller(int aframes) 206*/ 207 ENTRY(dtrace_caller) 208 movq $-1, %rax 209 ret 210 END(dtrace_caller) 211 212/* 213void 214dtrace_copy(uintptr_t src, uintptr_t dest, size_t size) 215*/ 216 ENTRY(dtrace_copy) 217 pushq %rbp 218 movq %rsp, %rbp 219 220 xchgq %rdi, %rsi /* make %rsi source, %rdi dest */ 221 movq %rdx, %rcx /* load count */ 222 repz /* repeat for count ... */ 223 smovb /* move from %ds:rsi to %ed:rdi */ 224 leave 225 ret 226 END(dtrace_copy) 227 228/* 229void 230dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 231 volatile uint16_t *flags) 232*/ 233 ENTRY(dtrace_copystr) 234 pushq %rbp 235 movq %rsp, %rbp 236 2370: 238 movb (%rdi), %al /* load from source */ 239 movb %al, (%rsi) /* store to destination */ 240 addq $1, %rdi /* increment source pointer */ 241 addq $1, %rsi /* increment destination pointer */ 242 subq $1, %rdx /* decrement remaining count */ 243 cmpb $0, %al 244 je 2f 245 testq $0xfff, %rdx /* test if count is 4k-aligned */ 246 jnz 1f /* if not, continue with copying */ 247 testq $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */ 248 jnz 2f 2491: 250 cmpq $0, %rdx 251 jne 0b 2522: 253 leave 254 ret 255 256 END(dtrace_copystr) 257 258/* 259uintptr_t 260dtrace_fulword(void *addr) 261*/ 262 ENTRY(dtrace_fulword) 263 movq (%rdi), %rax 264 ret 265 END(dtrace_fulword) 266 267/* 268uint8_t 269dtrace_fuword8_nocheck(void *addr) 270*/ 271 ENTRY(dtrace_fuword8_nocheck) 272 xorq %rax, %rax 273 movb (%rdi), %al 274 ret 275 END(dtrace_fuword8_nocheck) 276 277/* 278uint16_t 279dtrace_fuword16_nocheck(void *addr) 280*/ 281 ENTRY(dtrace_fuword16_nocheck) 282 xorq %rax, %rax 283 movw (%rdi), %ax 284 ret 285 END(dtrace_fuword16_nocheck) 286 287/* 288uint32_t 289dtrace_fuword32_nocheck(void *addr) 290*/ 291 ENTRY(dtrace_fuword32_nocheck) 292 xorq %rax, %rax 293 movl (%rdi), %eax 294 ret 295 END(dtrace_fuword32_nocheck) 296 297/* 298uint64_t 299dtrace_fuword64_nocheck(void *addr) 300*/ 301 ENTRY(dtrace_fuword64_nocheck) 302 movq (%rdi), %rax 303 ret 304 END(dtrace_fuword64_nocheck) 305 306/* 307void 308dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 309 int fault, int fltoffs, uintptr_t illval) 310*/ 311 ENTRY(dtrace_probe_error) 312 pushq %rbp 313 movq %rsp, %rbp 314 subq $0x8, %rsp 315 movq %r9, (%rsp) 316 movq %r8, %r9 317 movq %rcx, %r8 318 movq %rdx, %rcx 319 movq %rsi, %rdx 320 movq %rdi, %rsi 321 movl dtrace_probeid_error(%rip), %edi 322 call dtrace_probe 323 addq $0x8, %rsp 324 leave 325 ret 326 END(dtrace_probe_error) 327 328/* 329void 330dtrace_membar_producer(void) 331*/ 332 ENTRY(dtrace_membar_producer) 333 rep; ret /* use 2 byte return instruction when branch target */ 334 /* AMD Software Optimization Guide - Section 6.2 */ 335 END(dtrace_membar_producer) 336 337/* 338void 339dtrace_membar_consumer(void) 340*/ 341 ENTRY(dtrace_membar_consumer) 342 rep; ret /* use 2 byte return instruction when branch target */ 343 /* AMD Software Optimization Guide - Section 6.2 */ 344 END(dtrace_membar_consumer) 345 346/* 347dtrace_icookie_t 348dtrace_interrupt_disable(void) 349*/ 350 ENTRY(dtrace_interrupt_disable) 351 pushfq 352 popq %rax 353 cli 354 ret 355 END(dtrace_interrupt_disable) 356 357/* 358void 359dtrace_interrupt_enable(dtrace_icookie_t cookie) 360*/ 361 ENTRY(dtrace_interrupt_enable) 362 pushq %rdi 363 popfq 364 ret 365 END(dtrace_interrupt_enable) 366