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