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$ 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 ENTRY(dtrace_invop_start) 38 39 pushl %eax /* push %eax -- may be return value */ 40 pushl %esp /* push stack pointer */ 41 addl $48, (%esp) /* adjust to incoming args */ 42 pushl 40(%esp) /* push calling EIP */ 43 44 /* 45 * Call dtrace_invop to let it check if the exception was 46 * a fbt one. The return value in %eax will tell us what 47 * dtrace_invop wants us to do. 48 */ 49 call dtrace_invop 50 ALTENTRY(dtrace_invop_callsite) 51 addl $12, %esp 52 cmpl $DTRACE_INVOP_PUSHL_EBP, %eax 53 je invop_push 54 cmpl $DTRACE_INVOP_POPL_EBP, %eax 55 je invop_pop 56 cmpl $DTRACE_INVOP_LEAVE, %eax 57 je invop_leave 58 cmpl $DTRACE_INVOP_NOP, %eax 59 je invop_nop 60 61 /* When all else fails handle the trap in the usual way. */ 62 jmpl *dtrace_invop_calltrap_addr 63 64invop_push: 65 /* 66 * We must emulate a "pushl %ebp". To do this, we pull the stack 67 * down 4 bytes, and then store the base pointer. 68 */ 69 popal 70 subl $4, %esp /* make room for %ebp */ 71 pushl %eax /* push temp */ 72 movl 8(%esp), %eax /* load calling EIP */ 73 incl %eax /* increment over LOCK prefix */ 74 movl %eax, 4(%esp) /* store calling EIP */ 75 movl 12(%esp), %eax /* load calling CS */ 76 movl %eax, 8(%esp) /* store calling CS */ 77 movl 16(%esp), %eax /* load calling EFLAGS */ 78 movl %eax, 12(%esp) /* store calling EFLAGS */ 79 movl %ebp, 16(%esp) /* push %ebp */ 80 popl %eax /* pop off temp */ 81 iret /* Return from interrupt. */ 82invop_pop: 83 /* 84 * We must emulate a "popl %ebp". To do this, we do the opposite of 85 * the above: we remove the %ebp from the stack, and squeeze up the 86 * saved state from the trap. 87 */ 88 popal 89 pushl %eax /* push temp */ 90 movl 16(%esp), %ebp /* pop %ebp */ 91 movl 12(%esp), %eax /* load calling EFLAGS */ 92 movl %eax, 16(%esp) /* store calling EFLAGS */ 93 movl 8(%esp), %eax /* load calling CS */ 94 movl %eax, 12(%esp) /* store calling CS */ 95 movl 4(%esp), %eax /* load calling EIP */ 96 incl %eax /* increment over LOCK prefix */ 97 movl %eax, 8(%esp) /* store calling EIP */ 98 popl %eax /* pop off temp */ 99 addl $4, %esp /* adjust stack pointer */ 100 iret /* Return from interrupt. */ 101invop_leave: 102 /* 103 * We must emulate a "leave", which is the same as a "movl %ebp, %esp" 104 * followed by a "popl %ebp". This looks similar to the above, but 105 * requires two temporaries: one for the new base pointer, and one 106 * for the staging register. 107 */ 108 popa 109 pushl %eax /* push temp */ 110 pushl %ebx /* push temp */ 111 movl %ebp, %ebx /* set temp to old %ebp */ 112 movl (%ebx), %ebp /* pop %ebp */ 113 movl 16(%esp), %eax /* load calling EFLAGS */ 114 movl %eax, (%ebx) /* store calling EFLAGS */ 115 movl 12(%esp), %eax /* load calling CS */ 116 movl %eax, -4(%ebx) /* store calling CS */ 117 movl 8(%esp), %eax /* load calling EIP */ 118 incl %eax /* increment over LOCK prefix */ 119 movl %eax, -8(%ebx) /* store calling EIP */ 120 subl $8, %ebx /* adjust for three pushes, one pop */ 121 movl %ebx, 8(%esp) /* temporarily store new %esp */ 122 popl %ebx /* pop off temp */ 123 popl %eax /* pop off temp */ 124 movl (%esp), %esp /* set stack pointer */ 125 iret /* return from interrupt */ 126invop_nop: 127 /* 128 * We must emulate a "nop". This is obviously not hard: we need only 129 * advance the %eip by one. 130 */ 131 popa 132 incl (%esp) 133 iret /* return from interrupt */ 134 135 END(dtrace_invop_start) 136 137/* 138void dtrace_invop_init(void) 139*/ 140 ENTRY(dtrace_invop_init) 141 movl $dtrace_invop_start, dtrace_invop_jump_addr 142 ret 143 END(dtrace_invop_init) 144 145/* 146void dtrace_invop_uninit(void) 147*/ 148 ENTRY(dtrace_invop_uninit) 149 movl $0, dtrace_invop_jump_addr 150 ret 151 END(dtrace_invop_uninit) 152 153/* 154greg_t dtrace_getfp(void) 155*/ 156 157 ENTRY(dtrace_getfp) 158 movl %ebp, %eax 159 ret 160 END(dtrace_getfp) 161 162/* 163uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) 164*/ 165 166 ENTRY(dtrace_cas32) 167 ALTENTRY(dtrace_casptr) 168 movl 4(%esp), %edx 169 movl 8(%esp), %eax 170 movl 12(%esp), %ecx 171 lock 172 cmpxchgl %ecx, (%edx) 173 ret 174 END(dtrace_casptr) 175 END(dtrace_cas32) 176 177/* 178uintptr_t dtrace_caller(int aframes) 179*/ 180 181 ENTRY(dtrace_caller) 182 movl $-1, %eax 183 ret 184 END(dtrace_caller) 185 186/* 187void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size) 188*/ 189 190 ENTRY(dtrace_copy) 191 pushl %ebp 192 movl %esp, %ebp 193 pushl %esi 194 pushl %edi 195 196 movl 8(%ebp), %esi /* Load source address */ 197 movl 12(%ebp), %edi /* Load destination address */ 198 movl 16(%ebp), %ecx /* Load count */ 199 repz /* Repeat for count... */ 200 smovb /* move from %ds:si to %es:di */ 201 202 popl %edi 203 popl %esi 204 movl %ebp, %esp 205 popl %ebp 206 ret 207 END(dtrace_copy) 208 209/* 210void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size) 211*/ 212 213 ENTRY(dtrace_copystr) 214 215 pushl %ebp /* Setup stack frame */ 216 movl %esp, %ebp 217 pushl %ebx /* Save registers */ 218 219 movl 8(%ebp), %ebx /* Load source address */ 220 movl 12(%ebp), %edx /* Load destination address */ 221 movl 16(%ebp), %ecx /* Load count */ 222 2230: 224 movb (%ebx), %al /* Load from source */ 225 movb %al, (%edx) /* Store to destination */ 226 incl %ebx /* Increment source pointer */ 227 incl %edx /* Increment destination pointer */ 228 decl %ecx /* Decrement remaining count */ 229 cmpb $0, %al 230 je 1f 231 cmpl $0, %ecx 232 jne 0b 233 2341: 235 popl %ebx 236 movl %ebp, %esp 237 popl %ebp 238 ret 239 240 END(dtrace_copystr) 241 242/* 243uintptr_t dtrace_fulword(void *addr) 244*/ 245 246 ENTRY(dtrace_fulword) 247 movl 4(%esp), %ecx 248 xorl %eax, %eax 249 movl (%ecx), %eax 250 ret 251 END(dtrace_fulword) 252 253/* 254uint8_t dtrace_fuword8_nocheck(void *addr) 255*/ 256 257 ENTRY(dtrace_fuword8_nocheck) 258 movl 4(%esp), %ecx 259 xorl %eax, %eax 260 movzbl (%ecx), %eax 261 ret 262 END(dtrace_fuword8_nocheck) 263 264/* 265uint16_t dtrace_fuword16_nocheck(void *addr) 266*/ 267 268 ENTRY(dtrace_fuword16_nocheck) 269 movl 4(%esp), %ecx 270 xorl %eax, %eax 271 movzwl (%ecx), %eax 272 ret 273 END(dtrace_fuword16_nocheck) 274 275/* 276uint32_t dtrace_fuword32_nocheck(void *addr) 277*/ 278 279 ENTRY(dtrace_fuword32_nocheck) 280 movl 4(%esp), %ecx 281 xorl %eax, %eax 282 movl (%ecx), %eax 283 ret 284 END(dtrace_fuword32_nocheck) 285 286/* 287uint64_t dtrace_fuword64_nocheck(void *addr) 288*/ 289 290 ENTRY(dtrace_fuword64_nocheck) 291 movl 4(%esp), %ecx 292 xorl %eax, %eax 293 xorl %edx, %edx 294 movl (%ecx), %eax 295 movl 4(%ecx), %edx 296 ret 297 END(dtrace_fuword64_nocheck) 298 299/* 300void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval) 301*/ 302 303 ENTRY(dtrace_probe_error) 304 pushl %ebp 305 movl %esp, %ebp 306 pushl 0x1c(%ebp) 307 pushl 0x18(%ebp) 308 pushl 0x14(%ebp) 309 pushl 0x10(%ebp) 310 pushl 0xc(%ebp) 311 pushl 0x8(%ebp) 312 pushl dtrace_probeid_error 313 call dtrace_probe 314 movl %ebp, %esp 315 popl %ebp 316 ret 317 END(dtrace_probe_error) 318 319/* 320void dtrace_membar_producer(void) 321*/ 322 323 ENTRY(dtrace_membar_producer) 324 rep; ret /* use 2 byte return instruction when branch target */ 325 /* AMD Software Optimization Guide - Section 6.2 */ 326 END(dtrace_membar_producer) 327 328/* 329void dtrace_membar_consumer(void) 330*/ 331 332 ENTRY(dtrace_membar_consumer) 333 rep; ret /* use 2 byte return instruction when branch target */ 334 /* AMD Software Optimization Guide - Section 6.2 */ 335 END(dtrace_membar_consumer) 336 337/* 338dtrace_icookie_t dtrace_interrupt_disable(void) 339*/ 340 ENTRY(dtrace_interrupt_disable) 341 pushfl 342 popl %eax 343 cli 344 ret 345 END(dtrace_interrupt_disable) 346 347/* 348void dtrace_interrupt_enable(dtrace_icookie_t cookie) 349*/ 350 ENTRY(dtrace_interrupt_enable) 351 movl 4(%esp), %eax 352 pushl %eax 353 popfl 354 ret 355 END(dtrace_interrupt_enable) 356