dtrace_asm.S revision 1.6
1/* $NetBSD: dtrace_asm.S,v 1.6 2017/02/27 06:47:00 chs 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, Version 1.0 only 8 * (the "License"). You may not use this file except in compliance 9 * with the License. 10 * 11 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 12 * or http://www.opensolaris.org/os/licensing. 13 * See the License for the specific language governing permissions 14 * and limitations under the License. 15 * 16 * When distributing Covered Code, include this CDDL HEADER in each 17 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 18 * If applicable, add the following below this CDDL HEADER, with the 19 * fields enclosed by brackets "[]" replaced with your own identifying 20 * information: Portions Copyright [yyyy] [name of copyright owner] 21 * 22 * CDDL HEADER END 23 * 24 * $FreeBSD: src/sys/cddl/dev/dtrace/i386/dtrace_asm.S,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $ 25 */ 26/* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31#define _ASM 32 33#include "assym.h" 34 35#include <sys/cpuvar_defs.h> 36#include <sys/dtrace.h> 37#include <machine/asm.h> 38#include <machine/frameasm.h> 39#include <machine/trap.h> 40 41#define INTR_POP \ 42 addl $16, %esp; \ 43 popl %edi; \ 44 popl %esi; \ 45 popl %ebp; \ 46 popl %ebx; \ 47 popl %edx; \ 48 popl %ecx; \ 49 popl %eax; \ 50 addl $8, %esp 51 52 ENTRY(dtrace_invop_start) 53 54 /* Store a trapframe for dtrace. */ 55 pushl $0 56 pushl $T_PRIVINFLT 57 pushl %eax 58 pushl %ecx 59 pushl %edx 60 pushl %ebx 61 pushl %ebp 62 pushl %esi 63 pushl %edi 64 subl $16,%esp /* dummy for segment regs */ 65 cld 66 67 /* Store the args to dtrace_invop(). */ 68 pushl %eax /* push %eax -- may be return value */ 69 pushl %esp /* push stack pointer */ 70 addl $4, (%esp) /* skip first arg and segment regs */ 71 pushl TF_EIP+8(%esp) /* push calling EIP */ 72 73 /* 74 * Call dtrace_invop to let it check if the exception was 75 * a fbt one. The return value in %eax will tell us what 76 * dtrace_invop wants us to do. 77 */ 78 call dtrace_invop 79 ALTENTRY(dtrace_invop_callsite) 80 addl $12, %esp 81 cmpl $DTRACE_INVOP_PUSHL_EBP, %eax 82 je invop_push 83 cmpl $DTRACE_INVOP_POPL_EBP, %eax 84 je invop_pop 85 cmpl $DTRACE_INVOP_LEAVE, %eax 86 je invop_leave 87 cmpl $DTRACE_INVOP_NOP, %eax 88 je invop_nop 89 90 /* When all else fails handle the trap in the usual way. */ 91 jmpl *dtrace_invop_calltrap_addr 92 93invop_push: 94 /* 95 * We must emulate a "pushl %ebp". To do this, we pull the stack 96 * down 4 bytes, and then store the base pointer. 97 */ 98 INTR_POP 99 subl $4, %esp /* make room for %ebp */ 100 pushl %eax /* push temp */ 101 movl 8(%esp), %eax /* load calling EIP */ 102 incl %eax /* increment over LOCK prefix */ 103 movl %eax, 4(%esp) /* store calling EIP */ 104 movl 12(%esp), %eax /* load calling CS */ 105 movl %eax, 8(%esp) /* store calling CS */ 106 movl 16(%esp), %eax /* load calling EFLAGS */ 107 movl %eax, 12(%esp) /* store calling EFLAGS */ 108 movl %ebp, 16(%esp) /* push %ebp */ 109 popl %eax /* pop off temp */ 110 iret /* Return from interrupt. */ 111invop_pop: 112 /* 113 * We must emulate a "popl %ebp". To do this, we do the opposite of 114 * the above: we remove the %ebp from the stack, and squeeze up the 115 * saved state from the trap. 116 */ 117 INTR_POP 118 pushl %eax /* push temp */ 119 movl 16(%esp), %ebp /* pop %ebp */ 120 movl 12(%esp), %eax /* load calling EFLAGS */ 121 movl %eax, 16(%esp) /* store calling EFLAGS */ 122 movl 8(%esp), %eax /* load calling CS */ 123 movl %eax, 12(%esp) /* store calling CS */ 124 movl 4(%esp), %eax /* load calling EIP */ 125 incl %eax /* increment over LOCK prefix */ 126 movl %eax, 8(%esp) /* store calling EIP */ 127 popl %eax /* pop off temp */ 128 addl $4, %esp /* adjust stack pointer */ 129 iret /* Return from interrupt. */ 130invop_leave: 131 /* 132 * We must emulate a "leave", which is the same as a "movl %ebp, %esp" 133 * followed by a "popl %ebp". This looks similar to the above, but 134 * requires two temporaries: one for the new base pointer, and one 135 * for the staging register. 136 */ 137 INTR_POP 138 pushl %eax /* push temp */ 139 pushl %ebx /* push temp */ 140 movl %ebp, %ebx /* set temp to old %ebp */ 141 movl (%ebx), %ebp /* pop %ebp */ 142 movl 16(%esp), %eax /* load calling EFLAGS */ 143 movl %eax, (%ebx) /* store calling EFLAGS */ 144 movl 12(%esp), %eax /* load calling CS */ 145 movl %eax, -4(%ebx) /* store calling CS */ 146 movl 8(%esp), %eax /* load calling EIP */ 147 incl %eax /* increment over LOCK prefix */ 148 movl %eax, -8(%ebx) /* store calling EIP */ 149 movl %ebx, -4(%esp) /* temporarily store new %esp */ 150 popl %ebx /* pop off temp */ 151 popl %eax /* pop off temp */ 152 movl -12(%esp), %esp /* set stack pointer */ 153 subl $8, %esp /* adjust for three pushes, one pop */ 154 iret /* return from interrupt */ 155invop_nop: 156 /* 157 * We must emulate a "nop". This is obviously not hard: we need only 158 * advance the %eip by one. 159 */ 160 INTR_POP 161 incl (%esp) 162 iret /* return from interrupt */ 163 164 END(dtrace_invop_start) 165 166/* 167void dtrace_invop_init(void) 168*/ 169 ENTRY(dtrace_invop_init) 170 movl $dtrace_invop_start, dtrace_invop_jump_addr 171 ret 172 END(dtrace_invop_init) 173 174/* 175void dtrace_invop_uninit(void) 176*/ 177 ENTRY(dtrace_invop_uninit) 178 movl $0, dtrace_invop_jump_addr 179 ret 180 END(dtrace_invop_uninit) 181 182/* 183greg_t dtrace_getfp(void) 184*/ 185 186 ENTRY(dtrace_getfp) 187 movl %ebp, %eax 188 ret 189 END(dtrace_getfp) 190 191/* 192uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) 193*/ 194 195 ENTRY(dtrace_cas32) 196 movl 4(%esp), %edx 197 movl 8(%esp), %eax 198 movl 12(%esp), %ecx 199 lock 200 cmpxchgl %ecx, (%edx) 201 ret 202 END(dtrace_cas32) 203 204/* 205uint32_t dtrace_casptr(uint32_t *target, uint32_t cmp, uint32_t new) 206*/ 207 208 ENTRY(dtrace_casptr) 209 movl 4(%esp), %edx 210 movl 8(%esp), %eax 211 movl 12(%esp), %ecx 212 lock 213 cmpxchgl %ecx, (%edx) 214 ret 215 END(dtrace_casptr) 216 217 218/* 219uintptr_t dtrace_caller(int aframes) 220*/ 221 222 ENTRY(dtrace_caller) 223 movl $-1, %eax 224 ret 225 END(dtrace_caller) 226 227/* 228void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size) 229*/ 230 231 ENTRY(dtrace_copy) 232 pushl %ebp 233 movl %esp, %ebp 234 pushl %esi 235 pushl %edi 236 237 movl 8(%ebp), %esi /* Load source address */ 238 movl 12(%ebp), %edi /* Load destination address */ 239 movl 16(%ebp), %ecx /* Load count */ 240 repz /* Repeat for count... */ 241 smovb /* move from %ds:si to %es:di */ 242 243 popl %edi 244 popl %esi 245 movl %ebp, %esp 246 popl %ebp 247 ret 248 END(dtrace_copy) 249 250/* 251void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size) 252*/ 253 254 ENTRY(dtrace_copystr) 255 256 pushl %ebp /* Setup stack frame */ 257 movl %esp, %ebp 258 pushl %ebx /* Save registers */ 259 260 movl 8(%ebp), %ebx /* Load source address */ 261 movl 12(%ebp), %edx /* Load destination address */ 262 movl 16(%ebp), %ecx /* Load count */ 263 2640: 265 movb (%ebx), %al /* Load from source */ 266 movb %al, (%edx) /* Store to destination */ 267 incl %ebx /* Increment source pointer */ 268 incl %edx /* Increment destination pointer */ 269 decl %ecx /* Decrement remaining count */ 270 cmpb $0, %al 271 je 1f 272 cmpl $0, %ecx 273 jne 0b 274 2751: 276 popl %ebx 277 movl %ebp, %esp 278 popl %ebp 279 ret 280 281 END(dtrace_copystr) 282 283/* 284uintptr_t dtrace_fulword(void *addr) 285*/ 286 287 ENTRY(dtrace_fulword) 288 movl 4(%esp), %ecx 289 xorl %eax, %eax 290 movl (%ecx), %eax 291 ret 292 END(dtrace_fulword) 293 294/* 295uint8_t dtrace_fuword8_nocheck(void *addr) 296*/ 297 298 ENTRY(dtrace_fuword8_nocheck) 299 movl 4(%esp), %ecx 300 xorl %eax, %eax 301 movzbl (%ecx), %eax 302 ret 303 END(dtrace_fuword8_nocheck) 304 305/* 306uint16_t dtrace_fuword16_nocheck(void *addr) 307*/ 308 309 ENTRY(dtrace_fuword16_nocheck) 310 movl 4(%esp), %ecx 311 xorl %eax, %eax 312 movzwl (%ecx), %eax 313 ret 314 END(dtrace_fuword16_nocheck) 315 316/* 317uint32_t dtrace_fuword32_nocheck(void *addr) 318*/ 319 320 ENTRY(dtrace_fuword32_nocheck) 321 movl 4(%esp), %ecx 322 xorl %eax, %eax 323 movl (%ecx), %eax 324 ret 325 END(dtrace_fuword32_nocheck) 326 327/* 328uint64_t dtrace_fuword64_nocheck(void *addr) 329*/ 330 331 ENTRY(dtrace_fuword64_nocheck) 332 movl 4(%esp), %ecx 333 xorl %eax, %eax 334 xorl %edx, %edx 335 movl (%ecx), %eax 336 movl 4(%ecx), %edx 337 ret 338 END(dtrace_fuword64_nocheck) 339 340/* 341void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval) 342*/ 343 344 ENTRY(dtrace_probe_error) 345 pushl %ebp 346 movl %esp, %ebp 347 pushl 0x1c(%ebp) 348 pushl 0x18(%ebp) 349 pushl 0x14(%ebp) 350 pushl 0x10(%ebp) 351 pushl 0xc(%ebp) 352 pushl 0x8(%ebp) 353 pushl dtrace_probeid_error 354 call dtrace_probe 355 movl %ebp, %esp 356 popl %ebp 357 ret 358 END(dtrace_probe_error) 359 360/* 361void dtrace_membar_producer(void) 362*/ 363 364 ENTRY(dtrace_membar_producer) 365 rep; ret /* use 2 byte return instruction when branch target */ 366 /* AMD Software Optimization Guide - Section 6.2 */ 367 END(dtrace_membar_producer) 368 369/* 370void dtrace_membar_consumer(void) 371*/ 372 373 ENTRY(dtrace_membar_consumer) 374 rep; ret /* use 2 byte return instruction when branch target */ 375 /* AMD Software Optimization Guide - Section 6.2 */ 376 END(dtrace_membar_consumer) 377 378/* 379dtrace_icookie_t dtrace_interrupt_disable(void) 380*/ 381 ENTRY(dtrace_interrupt_disable) 382 pushfl 383 popl %eax 384 cli 385 ret 386 END(dtrace_interrupt_disable) 387 388/* 389void dtrace_interrupt_enable(dtrace_icookie_t cookie) 390*/ 391 ENTRY(dtrace_interrupt_enable) 392 movl 4(%esp), %eax 393 pushl %eax 394 popfl 395 ret 396 END(dtrace_interrupt_enable) 397