dtrace_asm.S revision 1.5
1/* $NetBSD: dtrace_asm.S,v 1.5 2015/05/18 14:41:41 christos Exp $ */ 2 3/* 4 * CDDL HEADER START 5 * 6 * The contents of this file are subject to the terms of the 7 * Common Development and Distribution License (the "License"). 8 * You may not use this file except in compliance with the License. 9 * 10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11 * or http://www.opensolaris.org/os/licensing. 12 * See the License for the specific language governing permissions 13 * and limitations under the License. 14 * 15 * When distributing Covered Code, include this CDDL HEADER in each 16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17 * If applicable, add the following below this CDDL HEADER, with the 18 * fields enclosed by brackets "[]" replaced with your own identifying 19 * information: Portions Copyright [yyyy] [name of copyright owner] 20 * 21 * CDDL HEADER END 22 * 23 * Portions Copyright 2008 John Birrell <jb@freebsd.org> 24 * 25 * $FreeBSD: src/sys/cddl/dev/dtrace/amd64/dtrace_asm.S,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $ 26 * 27 */ 28/* 29 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 32 33#define _ASM 34 35#include <sys/cpuvar_defs.h> 36#include <sys/dtrace.h> 37#include <machine/asm.h> 38#define MEXITCOUNT 39 40#include "assym.h" 41 42#define INTR_POP \ 43 MEXITCOUNT; \ 44 movq TF_RDI(%rsp),%rdi; \ 45 movq TF_RSI(%rsp),%rsi; \ 46 movq TF_RDX(%rsp),%rdx; \ 47 movq TF_RCX(%rsp),%rcx; \ 48 movq TF_R8(%rsp),%r8; \ 49 movq TF_R9(%rsp),%r9; \ 50 movq TF_RAX(%rsp),%rax; \ 51 movq TF_RBX(%rsp),%rbx; \ 52 movq TF_RBP(%rsp),%rbp; \ 53 movq TF_R10(%rsp),%r10; \ 54 movq TF_R11(%rsp),%r11; \ 55 movq TF_R12(%rsp),%r12; \ 56 movq TF_R13(%rsp),%r13; \ 57 movq TF_R14(%rsp),%r14; \ 58 movq TF_R15(%rsp),%r15; \ 59 testb $SEL_RPL_MASK,TF_CS(%rsp); \ 60 jz 1f; \ 61 cli; \ 62 swapgs; \ 631: addq $TF_RIP,%rsp; 64 65 66 ENTRY(dtrace_invop_start) 67 68 /* 69 * #BP traps with %rip set to the next address. We need to decrement 70 * the value to indicate the address of the int3 (0xcc) instruction 71 * that we substituted. 72 */ 73 movq TF_RIP(%rsp), %rdi 74 decq %rdi 75 movq TF_RSP(%rsp), %rsi 76 movq TF_RAX(%rsp), %rdx 77 pushq (%rsi) 78 movq %rsp, %rsi 79 call dtrace_invop 80 ALTENTRY(dtrace_invop_callsite) 81 addq $8, %rsp 82 cmpl $DTRACE_INVOP_PUSHL_EBP, %eax 83 je bp_push 84 cmpl $DTRACE_INVOP_LEAVE, %eax 85 je bp_leave 86 cmpl $DTRACE_INVOP_NOP, %eax 87 je bp_nop 88 cmpl $DTRACE_INVOP_RET, %eax 89 je bp_ret 90 91 /* When all else fails handle the trap in the usual way. */ 92 jmpq *dtrace_invop_calltrap_addr 93 94bp_push: 95 /* 96 * We must emulate a "pushq %rbp". To do this, we pull the stack 97 * down 8 bytes, and then store the base pointer. 98 */ 99 INTR_POP 100 subq $16, %rsp /* make room for %rbp */ 101 pushq %rax /* push temp */ 102 movq 24(%rsp), %rax /* load calling RIP */ 103 movq %rax, 8(%rsp) /* store calling RIP */ 104 movq 32(%rsp), %rax /* load calling CS */ 105 movq %rax, 16(%rsp) /* store calling CS */ 106 movq 40(%rsp), %rax /* load calling RFLAGS */ 107 movq %rax, 24(%rsp) /* store calling RFLAGS */ 108 movq 48(%rsp), %rax /* load calling RSP */ 109 subq $8, %rax /* make room for %rbp */ 110 movq %rax, 32(%rsp) /* store calling RSP */ 111 movq 56(%rsp), %rax /* load calling SS */ 112 movq %rax, 40(%rsp) /* store calling SS */ 113 movq 32(%rsp), %rax /* reload calling RSP */ 114 movq %rbp, (%rax) /* store %rbp there */ 115 popq %rax /* pop off temp */ 116 iretq /* return from interrupt */ 117 /*NOTREACHED*/ 118 119bp_leave: 120 /* 121 * We must emulate a "leave", which is the same as a "movq %rbp, %rsp" 122 * followed by a "popq %rbp". This is quite a bit simpler on amd64 123 * than it is on i386 -- we can exploit the fact that the %rsp is 124 * explicitly saved to effect the pop without having to reshuffle 125 * the other data pushed for the trap. 126 */ 127 INTR_POP 128 pushq %rax /* push temp */ 129 movq 8(%rsp), %rax /* load calling RIP */ 130 movq %rax, 8(%rsp) /* store calling RIP */ 131 movq (%rbp), %rax /* get new %rbp */ 132 addq $8, %rbp /* adjust new %rsp */ 133 movq %rbp, 32(%rsp) /* store new %rsp */ 134 movq %rax, %rbp /* set new %rbp */ 135 popq %rax /* pop off temp */ 136 iretq /* return from interrupt */ 137 /*NOTREACHED*/ 138 139bp_nop: 140 /* We must emulate a "nop". */ 141 INTR_POP 142 iretq 143 /*NOTREACHED*/ 144 145bp_ret: 146 INTR_POP 147 pushq %rax /* push temp */ 148 movq 32(%rsp), %rax /* load %rsp */ 149 movq (%rax), %rax /* load calling RIP */ 150 movq %rax, 8(%rsp) /* store calling RIP */ 151 addq $8, 32(%rsp) /* adjust new %rsp */ 152 popq %rax /* pop off temp */ 153 iretq /* return from interrupt */ 154 /*NOTREACHED*/ 155 156 END(dtrace_invop_start) 157 158/* 159void dtrace_invop_init(void) 160*/ 161 ENTRY(dtrace_invop_init) 162 movq $dtrace_invop_start, dtrace_invop_jump_addr(%rip) 163 ret 164 END(dtrace_invop_init) 165 166/* 167void dtrace_invop_uninit(void) 168*/ 169 ENTRY(dtrace_invop_uninit) 170 movq $0, dtrace_invop_jump_addr(%rip) 171 ret 172 END(dtrace_invop_uninit) 173 174/* 175greg_t dtrace_getfp(void) 176*/ 177 ENTRY(dtrace_getfp) 178 movq %rbp, %rax 179 ret 180 END(dtrace_getfp) 181 182/* 183uint32_t 184dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) 185*/ 186 ENTRY(dtrace_cas32) 187 movl %esi, %eax 188 lock 189 cmpxchgl %edx, (%rdi) 190 ret 191 END(dtrace_cas32) 192 193/* 194void * 195dtrace_casptr(void *target, void *cmp, void *new) 196*/ 197 ENTRY(dtrace_casptr) 198 movq %rsi, %rax 199 lock 200 cmpxchgq %rdx, (%rdi) 201 ret 202 END(dtrace_casptr) 203 204/* 205uintptr_t 206dtrace_caller(int aframes) 207*/ 208 ENTRY(dtrace_caller) 209 movq $-1, %rax 210 ret 211 END(dtrace_caller) 212 213/* 214void 215dtrace_copy(uintptr_t src, uintptr_t dest, size_t size) 216*/ 217 ENTRY(dtrace_copy) 218 pushq %rbp 219 movq %rsp, %rbp 220 221 xchgq %rdi, %rsi /* make %rsi source, %rdi dest */ 222 movq %rdx, %rcx /* load count */ 223 repz /* repeat for count ... */ 224 smovb /* move from %ds:rsi to %ed:rdi */ 225 leave 226 ret 227 END(dtrace_copy) 228 229/* 230void 231dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 232 volatile uint16_t *flags) 233*/ 234 ENTRY(dtrace_copystr) 235 pushq %rbp 236 movq %rsp, %rbp 237 2380: 239 movb (%rdi), %al /* load from source */ 240 movb %al, (%rsi) /* store to destination */ 241 addq $1, %rdi /* increment source pointer */ 242 addq $1, %rsi /* increment destination pointer */ 243 subq $1, %rdx /* decrement remaining count */ 244 cmpb $0, %al 245 je 2f 246 testq $0xfff, %rdx /* test if count is 4k-aligned */ 247 jnz 1f /* if not, continue with copying */ 248 testq $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */ 249 jnz 2f 2501: 251 cmpq $0, %rdx 252 jne 0b 2532: 254 leave 255 ret 256 257 END(dtrace_copystr) 258 259/* 260uintptr_t 261dtrace_fulword(void *addr) 262*/ 263 ENTRY(dtrace_fulword) 264 movq (%rdi), %rax 265 ret 266 END(dtrace_fulword) 267 268/* 269uint8_t 270dtrace_fuword8_nocheck(void *addr) 271*/ 272 ENTRY(dtrace_fuword8_nocheck) 273 xorq %rax, %rax 274 movb (%rdi), %al 275 ret 276 END(dtrace_fuword8_nocheck) 277 278/* 279uint16_t 280dtrace_fuword16_nocheck(void *addr) 281*/ 282 ENTRY(dtrace_fuword16_nocheck) 283 xorq %rax, %rax 284 movw (%rdi), %ax 285 ret 286 END(dtrace_fuword16_nocheck) 287 288/* 289uint32_t 290dtrace_fuword32_nocheck(void *addr) 291*/ 292 ENTRY(dtrace_fuword32_nocheck) 293 xorq %rax, %rax 294 movl (%rdi), %eax 295 ret 296 END(dtrace_fuword32_nocheck) 297 298/* 299uint64_t 300dtrace_fuword64_nocheck(void *addr) 301*/ 302 ENTRY(dtrace_fuword64_nocheck) 303 movq (%rdi), %rax 304 ret 305 END(dtrace_fuword64_nocheck) 306 307/* 308void 309dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 310 int fault, int fltoffs, uintptr_t illval) 311*/ 312 ENTRY(dtrace_probe_error) 313 pushq %rbp 314 movq %rsp, %rbp 315 subq $0x8, %rsp 316 movq %r9, (%rsp) 317 movq %r8, %r9 318 movq %rcx, %r8 319 movq %rdx, %rcx 320 movq %rsi, %rdx 321 movq %rdi, %rsi 322 movl dtrace_probeid_error(%rip), %edi 323 call dtrace_probe 324 addq $0x8, %rsp 325 leave 326 ret 327 END(dtrace_probe_error) 328 329/* 330void 331dtrace_membar_producer(void) 332*/ 333 ENTRY(dtrace_membar_producer) 334 rep; ret /* use 2 byte return instruction when branch target */ 335 /* AMD Software Optimization Guide - Section 6.2 */ 336 END(dtrace_membar_producer) 337 338/* 339void 340dtrace_membar_consumer(void) 341*/ 342 ENTRY(dtrace_membar_consumer) 343 rep; ret /* use 2 byte return instruction when branch target */ 344 /* AMD Software Optimization Guide - Section 6.2 */ 345 END(dtrace_membar_consumer) 346 347/* 348dtrace_icookie_t 349dtrace_interrupt_disable(void) 350*/ 351 ENTRY(dtrace_interrupt_disable) 352 pushfq 353 popq %rax 354 cli 355 ret 356 END(dtrace_interrupt_disable) 357 358/* 359void 360dtrace_interrupt_enable(dtrace_icookie_t cookie) 361*/ 362 ENTRY(dtrace_interrupt_enable) 363 pushq %rdi 364 popfq 365 ret 366 END(dtrace_interrupt_enable) 367 368/* 369 * The panic() and cmn_err() functions invoke vpanic() as a common entry point 370 * into the panic code implemented in panicsys(). vpanic() is responsible 371 * for passing through the format string and arguments, and constructing a 372 * regs structure on the stack into which it saves the current register 373 * values. If we are not dying due to a fatal trap, these registers will 374 * then be preserved in panicbuf as the current processor state. Before 375 * invoking panicsys(), vpanic() activates the first panic trigger (see 376 * common/os/panic.c) and switches to the panic_stack if successful. Note that 377 * DTrace takes a slightly different panic path if it must panic from probe 378 * context. Instead of calling panic, it calls into dtrace_vpanic(), which 379 * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and 380 * branches back into vpanic(). 381 */ 382 383/* 384void 385vpanic(const char *format, va_list alist) 386*/ 387 ENTRY(vpanic) /* Initial stack layout: */ 388 389 pushq %rbp /* | %rip | 0x60 */ 390 movq %rsp, %rbp /* | %rbp | 0x58 */ 391 pushfq /* | rfl | 0x50 */ 392 pushq %r11 /* | %r11 | 0x48 */ 393 pushq %r10 /* | %r10 | 0x40 */ 394 pushq %rbx /* | %rbx | 0x38 */ 395 pushq %rax /* | %rax | 0x30 */ 396 pushq %r9 /* | %r9 | 0x28 */ 397 pushq %r8 /* | %r8 | 0x20 */ 398 pushq %rcx /* | %rcx | 0x18 */ 399 pushq %rdx /* | %rdx | 0x10 */ 400 pushq %rsi /* | %rsi | 0x8 alist */ 401 pushq %rdi /* | %rdi | 0x0 format */ 402 403 movq %rsp, %rbx /* %rbx = current %rsp */ 404 405 leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */ 406 call panic_trigger /* %eax = panic_trigger() */ 407 408vpanic_common: 409 /* 410 * The panic_trigger result is in %eax from the call above, and 411 * dtrace_panic places it in %eax before branching here. 412 * The rdmsr instructions that follow below will clobber %eax so 413 * we stash the panic_trigger result in %r11d. 414 */ 415 movl %eax, %r11d 416 cmpl $0, %r11d 417 je 0f 418 419 /* 420 * If panic_trigger() was successful, we are the first to initiate a 421 * panic: we now switch to the reserved panic_stack before continuing. 422 */ 423 leaq panic_stack(%rip), %rsp 424 addq $PANICSTKSIZE, %rsp 4250: subq $REGSIZE, %rsp 426 /* 427 * Now that we've got everything set up, store the register values as 428 * they were when we entered vpanic() to the designated location in 429 * the regs structure we allocated on the stack. 430 */ 431#ifdef notyet 432 movq 0x0(%rbx), %rcx 433 movq %rcx, REGOFF_RDI(%rsp) 434 movq 0x8(%rbx), %rcx 435 movq %rcx, REGOFF_RSI(%rsp) 436 movq 0x10(%rbx), %rcx 437 movq %rcx, REGOFF_RDX(%rsp) 438 movq 0x18(%rbx), %rcx 439 movq %rcx, REGOFF_RCX(%rsp) 440 movq 0x20(%rbx), %rcx 441 442 movq %rcx, REGOFF_R8(%rsp) 443 movq 0x28(%rbx), %rcx 444 movq %rcx, REGOFF_R9(%rsp) 445 movq 0x30(%rbx), %rcx 446 movq %rcx, REGOFF_RAX(%rsp) 447 movq 0x38(%rbx), %rcx 448 movq %rcx, REGOFF_RBX(%rsp) 449 movq 0x58(%rbx), %rcx 450 451 movq %rcx, REGOFF_RBP(%rsp) 452 movq 0x40(%rbx), %rcx 453 movq %rcx, REGOFF_R10(%rsp) 454 movq 0x48(%rbx), %rcx 455 movq %rcx, REGOFF_R11(%rsp) 456 movq %r12, REGOFF_R12(%rsp) 457 458 movq %r13, REGOFF_R13(%rsp) 459 movq %r14, REGOFF_R14(%rsp) 460 movq %r15, REGOFF_R15(%rsp) 461 462 xorl %ecx, %ecx 463 movw %ds, %cx 464 movq %rcx, REGOFF_DS(%rsp) 465 movw %es, %cx 466 movq %rcx, REGOFF_ES(%rsp) 467 movw %fs, %cx 468 movq %rcx, REGOFF_FS(%rsp) 469 movw %gs, %cx 470 movq %rcx, REGOFF_GS(%rsp) 471 472 movq $0, REGOFF_TRAPNO(%rsp) 473 474 movq $0, REGOFF_ERR(%rsp) 475 leaq vpanic(%rip), %rcx 476 movq %rcx, REGOFF_RIP(%rsp) 477 movw %cs, %cx 478 movzwq %cx, %rcx 479 movq %rcx, REGOFF_CS(%rsp) 480 movq 0x50(%rbx), %rcx 481 movq %rcx, REGOFF_RFL(%rsp) 482 movq %rbx, %rcx 483 addq $0x60, %rcx 484 movq %rcx, REGOFF_RSP(%rsp) 485 movw %ss, %cx 486 movzwq %cx, %rcx 487 movq %rcx, REGOFF_SS(%rsp) 488 489 /* 490 * panicsys(format, alist, rp, on_panic_stack) 491 */ 492 movq REGOFF_RDI(%rsp), %rdi /* format */ 493 movq REGOFF_RSI(%rsp), %rsi /* alist */ 494 movq %rsp, %rdx /* struct regs */ 495 movl %r11d, %ecx /* on_panic_stack */ 496 call panicsys 497 addq $REGSIZE, %rsp 498#endif 499 popq %rdi 500 popq %rsi 501 popq %rdx 502 popq %rcx 503 popq %r8 504 popq %r9 505 popq %rax 506 popq %rbx 507 popq %r10 508 popq %r11 509 popfq 510 leave 511 ret 512 END(vpanic) 513 514/* 515void 516dtrace_vpanic(const char *format, va_list alist) 517*/ 518 ENTRY(dtrace_vpanic) /* Initial stack layout: */ 519 520 pushq %rbp /* | %rip | 0x60 */ 521 movq %rsp, %rbp /* | %rbp | 0x58 */ 522 pushfq /* | rfl | 0x50 */ 523 pushq %r11 /* | %r11 | 0x48 */ 524 pushq %r10 /* | %r10 | 0x40 */ 525 pushq %rbx /* | %rbx | 0x38 */ 526 pushq %rax /* | %rax | 0x30 */ 527 pushq %r9 /* | %r9 | 0x28 */ 528 pushq %r8 /* | %r8 | 0x20 */ 529 pushq %rcx /* | %rcx | 0x18 */ 530 pushq %rdx /* | %rdx | 0x10 */ 531 pushq %rsi /* | %rsi | 0x8 alist */ 532 pushq %rdi /* | %rdi | 0x0 format */ 533 534 movq %rsp, %rbx /* %rbx = current %rsp */ 535 536 leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */ 537 call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */ 538 jmp vpanic_common 539 540 END(dtrace_vpanic) 541 542/* 543int 544panic_trigger(int *tp) 545*/ 546 ENTRY(panic_trigger) 547 xorl %eax, %eax 548 movl $0xdefacedd, %edx 549 lock 550 xchgl %edx, (%rdi) 551 cmpl $0, %edx 552 je 0f 553 movl $0, %eax 554 ret 5550: movl $1, %eax 556 ret 557 END(panic_trigger) 558 559/* 560int 561dtrace_panic_trigger(int *tp) 562*/ 563 ENTRY(dtrace_panic_trigger) 564 xorl %eax, %eax 565 movl $0xdefacedd, %edx 566 lock 567 xchgl %edx, (%rdi) 568 cmpl $0, %edx 569 je 0f 570 movl $0, %eax 571 ret 5720: movl $1, %eax 573 ret 574 END(dtrace_panic_trigger) 575