dtrace_asm.S revision 1.7
1/* $NetBSD: dtrace_asm.S,v 1.7 2018/05/28 21:05:03 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: head/sys/cddl/dev/dtrace/i386/dtrace_asm.S 298171 2016-04-17 23:08:47Z markj $ 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 subl $8, %ebx /* adjust for three pushes, one pop */ 150 movl %ebx, 8(%esp) /* temporarily store new %esp */ 151 popl %ebx /* pop off temp */ 152 popl %eax /* pop off temp */ 153 movl (%esp), %esp /* set stack pointer */ 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 ALTENTRY(dtrace_casptr) 197 movl 4(%esp), %edx 198 movl 8(%esp), %eax 199 movl 12(%esp), %ecx 200 lock 201 cmpxchgl %ecx, (%edx) 202 ret 203 END(dtrace_casptr) 204 END(dtrace_cas32) 205 206/* 207uintptr_t dtrace_caller(int aframes) 208*/ 209 210 ENTRY(dtrace_caller) 211 movl $-1, %eax 212 ret 213 END(dtrace_caller) 214 215/* 216void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size) 217*/ 218 219 ENTRY(dtrace_copy) 220 pushl %ebp 221 movl %esp, %ebp 222 pushl %esi 223 pushl %edi 224 225 movl 8(%ebp), %esi /* Load source address */ 226 movl 12(%ebp), %edi /* Load destination address */ 227 movl 16(%ebp), %ecx /* Load count */ 228 repz /* Repeat for count... */ 229 smovb /* move from %ds:si to %es:di */ 230 231 popl %edi 232 popl %esi 233 movl %ebp, %esp 234 popl %ebp 235 ret 236 END(dtrace_copy) 237 238/* 239void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size) 240*/ 241 242 ENTRY(dtrace_copystr) 243 244 pushl %ebp /* Setup stack frame */ 245 movl %esp, %ebp 246 pushl %ebx /* Save registers */ 247 248 movl 8(%ebp), %ebx /* Load source address */ 249 movl 12(%ebp), %edx /* Load destination address */ 250 movl 16(%ebp), %ecx /* Load count */ 251 2520: 253 movb (%ebx), %al /* Load from source */ 254 movb %al, (%edx) /* Store to destination */ 255 incl %ebx /* Increment source pointer */ 256 incl %edx /* Increment destination pointer */ 257 decl %ecx /* Decrement remaining count */ 258 cmpb $0, %al 259 je 1f 260 cmpl $0, %ecx 261 jne 0b 262 2631: 264 popl %ebx 265 movl %ebp, %esp 266 popl %ebp 267 ret 268 269 END(dtrace_copystr) 270 271/* 272uintptr_t dtrace_fulword(void *addr) 273*/ 274 275 ENTRY(dtrace_fulword) 276 movl 4(%esp), %ecx 277 xorl %eax, %eax 278 movl (%ecx), %eax 279 ret 280 END(dtrace_fulword) 281 282/* 283uint8_t dtrace_fuword8_nocheck(void *addr) 284*/ 285 286 ENTRY(dtrace_fuword8_nocheck) 287 movl 4(%esp), %ecx 288 xorl %eax, %eax 289 movzbl (%ecx), %eax 290 ret 291 END(dtrace_fuword8_nocheck) 292 293/* 294uint16_t dtrace_fuword16_nocheck(void *addr) 295*/ 296 297 ENTRY(dtrace_fuword16_nocheck) 298 movl 4(%esp), %ecx 299 xorl %eax, %eax 300 movzwl (%ecx), %eax 301 ret 302 END(dtrace_fuword16_nocheck) 303 304/* 305uint32_t dtrace_fuword32_nocheck(void *addr) 306*/ 307 308 ENTRY(dtrace_fuword32_nocheck) 309 movl 4(%esp), %ecx 310 xorl %eax, %eax 311 movl (%ecx), %eax 312 ret 313 END(dtrace_fuword32_nocheck) 314 315/* 316uint64_t dtrace_fuword64_nocheck(void *addr) 317*/ 318 319 ENTRY(dtrace_fuword64_nocheck) 320 movl 4(%esp), %ecx 321 xorl %eax, %eax 322 xorl %edx, %edx 323 movl (%ecx), %eax 324 movl 4(%ecx), %edx 325 ret 326 END(dtrace_fuword64_nocheck) 327 328/* 329void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval) 330*/ 331 332 ENTRY(dtrace_probe_error) 333 pushl %ebp 334 movl %esp, %ebp 335 pushl 0x1c(%ebp) 336 pushl 0x18(%ebp) 337 pushl 0x14(%ebp) 338 pushl 0x10(%ebp) 339 pushl 0xc(%ebp) 340 pushl 0x8(%ebp) 341 pushl dtrace_probeid_error 342 call dtrace_probe 343 movl %ebp, %esp 344 popl %ebp 345 ret 346 END(dtrace_probe_error) 347 348/* 349void dtrace_membar_producer(void) 350*/ 351 352 ENTRY(dtrace_membar_producer) 353 rep; ret /* use 2 byte return instruction when branch target */ 354 /* AMD Software Optimization Guide - Section 6.2 */ 355 END(dtrace_membar_producer) 356 357/* 358void dtrace_membar_consumer(void) 359*/ 360 361 ENTRY(dtrace_membar_consumer) 362 rep; ret /* use 2 byte return instruction when branch target */ 363 /* AMD Software Optimization Guide - Section 6.2 */ 364 END(dtrace_membar_consumer) 365 366/* 367dtrace_icookie_t dtrace_interrupt_disable(void) 368*/ 369 ENTRY(dtrace_interrupt_disable) 370 pushfl 371 popl %eax 372 cli 373 ret 374 END(dtrace_interrupt_disable) 375 376/* 377void dtrace_interrupt_enable(dtrace_icookie_t cookie) 378*/ 379 ENTRY(dtrace_interrupt_enable) 380 movl 4(%esp), %eax 381 pushl %eax 382 popfl 383 ret 384 END(dtrace_interrupt_enable) 385