1164190Sjkoshy/* $NetBSD: dtrace_asm.S,v 1.8 2023/11/03 09:07:57 chs Exp $ */ 2164190Sjkoshy 3164190Sjkoshy/* 4164190Sjkoshy * CDDL HEADER START 5164190Sjkoshy * 6164190Sjkoshy * The contents of this file are subject to the terms of the 7164190Sjkoshy * Common Development and Distribution License, Version 1.0 only 8164190Sjkoshy * (the "License"). You may not use this file except in compliance 9164190Sjkoshy * with the License. 10164190Sjkoshy * 11164190Sjkoshy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 12164190Sjkoshy * or http://www.opensolaris.org/os/licensing. 13164190Sjkoshy * See the License for the specific language governing permissions 14164190Sjkoshy * and limitations under the License. 15164190Sjkoshy * 16164190Sjkoshy * When distributing Covered Code, include this CDDL HEADER in each 17164190Sjkoshy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 18164190Sjkoshy * If applicable, add the following below this CDDL HEADER, with the 19164190Sjkoshy * fields enclosed by brackets "[]" replaced with your own identifying 20164190Sjkoshy * information: Portions Copyright [yyyy] [name of copyright owner] 21164190Sjkoshy * 22164190Sjkoshy * CDDL HEADER END 23164190Sjkoshy * 24164190Sjkoshy * $FreeBSD: head/sys/cddl/dev/dtrace/i386/dtrace_asm.S 298171 2016-04-17 23:08:47Z markj $ 25164190Sjkoshy */ 26164190Sjkoshy/* 27164190Sjkoshy * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28164190Sjkoshy * Use is subject to license terms. 29164190Sjkoshy */ 30164190Sjkoshy 31164190Sjkoshy#define _ASM 32164190Sjkoshy 33164190Sjkoshy#include "assym.h" 34164190Sjkoshy 35164190Sjkoshy#include <sys/cpuvar_defs.h> 36164190Sjkoshy#include <sys/dtrace.h> 37164190Sjkoshy#include <machine/asm.h> 38164190Sjkoshy#include <machine/frameasm.h> 39164190Sjkoshy#include <machine/trap.h> 40164190Sjkoshy 41164190Sjkoshy#define DTRACE_SMAP_DISABLE \ 42164190Sjkoshy call dtrace_smap_disable 43164190Sjkoshy#define DTRACE_SMAP_ENABLE \ 44164190Sjkoshy call dtrace_smap_enable 45164190Sjkoshy 46164190Sjkoshy#define INTR_POP \ 47164190Sjkoshy addl $16, %esp; \ 48164190Sjkoshy popl %edi; \ 49164190Sjkoshy popl %esi; \ 50164190Sjkoshy popl %ebp; \ 51164190Sjkoshy popl %ebx; \ 52164190Sjkoshy popl %edx; \ 53164190Sjkoshy popl %ecx; \ 54164190Sjkoshy popl %eax; \ 55164190Sjkoshy addl $8, %esp 56164190Sjkoshy 57164190Sjkoshy ENTRY(dtrace_invop_start) 58164190Sjkoshy 59164190Sjkoshy /* Store a trapframe for dtrace. */ 60164190Sjkoshy pushl $0 61164190Sjkoshy pushl $T_PRIVINFLT 62164190Sjkoshy pushl %eax 63164190Sjkoshy pushl %ecx 64164190Sjkoshy pushl %edx 65165316Sjkoshy pushl %ebx 66164190Sjkoshy pushl %ebp 67164190Sjkoshy pushl %esi 68164190Sjkoshy pushl %edi 69164190Sjkoshy subl $16,%esp /* dummy for segment regs */ 70164190Sjkoshy cld 71165316Sjkoshy 72164190Sjkoshy /* Store the args to dtrace_invop(). */ 73164190Sjkoshy pushl %eax /* push %eax -- may be return value */ 74164190Sjkoshy pushl %esp /* push stack pointer */ 75164190Sjkoshy addl $4, (%esp) /* skip first arg and segment regs */ 76165316Sjkoshy pushl TF_EIP+8(%esp) /* push calling EIP */ 77164190Sjkoshy 78164190Sjkoshy /* 79164190Sjkoshy * Call dtrace_invop to let it check if the exception was 80164190Sjkoshy * a fbt one. The return value in %eax will tell us what 81164190Sjkoshy * dtrace_invop wants us to do. 82164190Sjkoshy */ 83164190Sjkoshy call dtrace_invop 84164190Sjkoshy ALTENTRY(dtrace_invop_callsite) 85164190Sjkoshy addl $12, %esp 86164190Sjkoshy cmpl $DTRACE_INVOP_PUSHL_EBP, %eax 87165316Sjkoshy je invop_push 88164190Sjkoshy cmpl $DTRACE_INVOP_POPL_EBP, %eax 89164190Sjkoshy je invop_pop 90164190Sjkoshy cmpl $DTRACE_INVOP_LEAVE, %eax 91164190Sjkoshy je invop_leave 92164190Sjkoshy cmpl $DTRACE_INVOP_NOP, %eax 93164190Sjkoshy je invop_nop 94164190Sjkoshy 95164190Sjkoshy /* When all else fails handle the trap in the usual way. */ 96164190Sjkoshy jmpl *dtrace_invop_calltrap_addr 97164190Sjkoshy 98164190Sjkoshyinvop_push: 99164190Sjkoshy /* 100164190Sjkoshy * We must emulate a "pushl %ebp". To do this, we pull the stack 101164190Sjkoshy * down 4 bytes, and then store the base pointer. 102164190Sjkoshy */ 103164190Sjkoshy INTR_POP 104164190Sjkoshy subl $4, %esp /* make room for %ebp */ 105164190Sjkoshy pushl %eax /* push temp */ 106164190Sjkoshy movl 8(%esp), %eax /* load calling EIP */ 107164190Sjkoshy incl %eax /* increment over LOCK prefix */ 108164190Sjkoshy movl %eax, 4(%esp) /* store calling EIP */ 109164190Sjkoshy movl 12(%esp), %eax /* load calling CS */ 110164190Sjkoshy movl %eax, 8(%esp) /* store calling CS */ 111164190Sjkoshy movl 16(%esp), %eax /* load calling EFLAGS */ 112164190Sjkoshy movl %eax, 12(%esp) /* store calling EFLAGS */ 113165316Sjkoshy movl %ebp, 16(%esp) /* push %ebp */ 114164190Sjkoshy popl %eax /* pop off temp */ 115164190Sjkoshy iret /* Return from interrupt. */ 116164190Sjkoshyinvop_pop: 117164190Sjkoshy /* 118164190Sjkoshy * We must emulate a "popl %ebp". To do this, we do the opposite of 119165316Sjkoshy * the above: we remove the %ebp from the stack, and squeeze up the 120164190Sjkoshy * saved state from the trap. 121164190Sjkoshy */ 122164190Sjkoshy INTR_POP 123164190Sjkoshy pushl %eax /* push temp */ 124165316Sjkoshy movl 16(%esp), %ebp /* pop %ebp */ 125164190Sjkoshy movl 12(%esp), %eax /* load calling EFLAGS */ 126164190Sjkoshy movl %eax, 16(%esp) /* store calling EFLAGS */ 127164190Sjkoshy movl 8(%esp), %eax /* load calling CS */ 128164190Sjkoshy movl %eax, 12(%esp) /* store calling CS */ 129164190Sjkoshy movl 4(%esp), %eax /* load calling EIP */ 130164190Sjkoshy incl %eax /* increment over LOCK prefix */ 131164190Sjkoshy movl %eax, 8(%esp) /* store calling EIP */ 132164190Sjkoshy popl %eax /* pop off temp */ 133164190Sjkoshy addl $4, %esp /* adjust stack pointer */ 134164190Sjkoshy iret /* Return from interrupt. */ 135165316Sjkoshyinvop_leave: 136164190Sjkoshy /* 137164190Sjkoshy * We must emulate a "leave", which is the same as a "movl %ebp, %esp" 138164190Sjkoshy * followed by a "popl %ebp". This looks similar to the above, but 139164190Sjkoshy * requires two temporaries: one for the new base pointer, and one 140164190Sjkoshy * for the staging register. 141164190Sjkoshy */ 142164190Sjkoshy INTR_POP 143164190Sjkoshy pushl %eax /* push temp */ 144164190Sjkoshy pushl %ebx /* push temp */ 145164190Sjkoshy movl %ebp, %ebx /* set temp to old %ebp */ 146164190Sjkoshy movl (%ebx), %ebp /* pop %ebp */ 147164190Sjkoshy movl 16(%esp), %eax /* load calling EFLAGS */ 148164190Sjkoshy movl %eax, (%ebx) /* store calling EFLAGS */ 149164190Sjkoshy movl 12(%esp), %eax /* load calling CS */ 150164190Sjkoshy movl %eax, -4(%ebx) /* store calling CS */ 151164190Sjkoshy movl 8(%esp), %eax /* load calling EIP */ 152164190Sjkoshy incl %eax /* increment over LOCK prefix */ 153164190Sjkoshy movl %eax, -8(%ebx) /* store calling EIP */ 154164190Sjkoshy subl $8, %ebx /* adjust for three pushes, one pop */ 155 movl %ebx, 8(%esp) /* temporarily store new %esp */ 156 popl %ebx /* pop off temp */ 157 popl %eax /* pop off temp */ 158 movl (%esp), %esp /* set stack pointer */ 159 iret /* return from interrupt */ 160invop_nop: 161 /* 162 * We must emulate a "nop". This is obviously not hard: we need only 163 * advance the %eip by one. 164 */ 165 INTR_POP 166 incl (%esp) 167 iret /* return from interrupt */ 168 169 END(dtrace_invop_start) 170 171/* 172void dtrace_invop_init(void) 173*/ 174 ENTRY(dtrace_invop_init) 175 movl $dtrace_invop_start, dtrace_invop_jump_addr 176 ret 177 END(dtrace_invop_init) 178 179/* 180void dtrace_invop_uninit(void) 181*/ 182 ENTRY(dtrace_invop_uninit) 183 movl $0, dtrace_invop_jump_addr 184 ret 185 END(dtrace_invop_uninit) 186 187/* 188greg_t dtrace_getfp(void) 189*/ 190 191 ENTRY(dtrace_getfp) 192 movl %ebp, %eax 193 ret 194 END(dtrace_getfp) 195 196/* 197uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) 198*/ 199 200 ENTRY(dtrace_cas32) 201 ALTENTRY(dtrace_casptr) 202 movl 4(%esp), %edx 203 movl 8(%esp), %eax 204 movl 12(%esp), %ecx 205 lock 206 cmpxchgl %ecx, (%edx) 207 ret 208 END(dtrace_casptr) 209 END(dtrace_cas32) 210 211/* 212uintptr_t dtrace_caller(int aframes) 213*/ 214 215 ENTRY(dtrace_caller) 216 movl $-1, %eax 217 ret 218 END(dtrace_caller) 219 220/* 221void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size) 222*/ 223 224 ENTRY(dtrace_copy) 225 pushl %ebp 226 movl %esp, %ebp 227 pushl %esi 228 pushl %edi 229 230 movl 8(%ebp), %esi /* Load source address */ 231 movl 12(%ebp), %edi /* Load destination address */ 232 movl 16(%ebp), %ecx /* Load count */ 233 DTRACE_SMAP_DISABLE 234 repz /* Repeat for count... */ 235 smovb /* move from %ds:si to %es:di */ 236 DTRACE_SMAP_ENABLE 237 238 popl %edi 239 popl %esi 240 movl %ebp, %esp 241 popl %ebp 242 ret 243 END(dtrace_copy) 244 245/* 246void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size) 247*/ 248 249 ENTRY(dtrace_copystr) 250 251 pushl %ebp /* Setup stack frame */ 252 movl %esp, %ebp 253 pushl %ebx /* Save registers */ 254 255 movl 8(%ebp), %ebx /* Load source address */ 256 movl 12(%ebp), %edx /* Load destination address */ 257 movl 16(%ebp), %ecx /* Load count */ 258 DTRACE_SMAP_DISABLE 259 2600: 261 movb (%ebx), %al /* Load from source */ 262 movb %al, (%edx) /* Store to destination */ 263 incl %ebx /* Increment source pointer */ 264 incl %edx /* Increment destination pointer */ 265 decl %ecx /* Decrement remaining count */ 266 cmpb $0, %al 267 je 1f 268 cmpl $0, %ecx 269 jne 0b 270 2711: 272 DTRACE_SMAP_ENABLE 273 popl %ebx 274 movl %ebp, %esp 275 popl %ebp 276 ret 277 278 END(dtrace_copystr) 279 280/* 281uintptr_t dtrace_fulword(void *addr) 282*/ 283 284 ENTRY(dtrace_fulword) 285 movl 4(%esp), %ecx 286 xorl %eax, %eax 287 DTRACE_SMAP_DISABLE 288 movl (%ecx), %eax 289 DTRACE_SMAP_ENABLE 290 ret 291 END(dtrace_fulword) 292 293/* 294uint8_t dtrace_fuword8_nocheck(void *addr) 295*/ 296 297 ENTRY(dtrace_fuword8_nocheck) 298 movl 4(%esp), %ecx 299 xorl %eax, %eax 300 DTRACE_SMAP_DISABLE 301 movzbl (%ecx), %eax 302 DTRACE_SMAP_ENABLE 303 ret 304 END(dtrace_fuword8_nocheck) 305 306/* 307uint16_t dtrace_fuword16_nocheck(void *addr) 308*/ 309 310 ENTRY(dtrace_fuword16_nocheck) 311 movl 4(%esp), %ecx 312 xorl %eax, %eax 313 DTRACE_SMAP_DISABLE 314 movzwl (%ecx), %eax 315 DTRACE_SMAP_ENABLE 316 ret 317 END(dtrace_fuword16_nocheck) 318 319/* 320uint32_t dtrace_fuword32_nocheck(void *addr) 321*/ 322 323 ENTRY(dtrace_fuword32_nocheck) 324 movl 4(%esp), %ecx 325 xorl %eax, %eax 326 DTRACE_SMAP_DISABLE 327 movl (%ecx), %eax 328 DTRACE_SMAP_ENABLE 329 ret 330 END(dtrace_fuword32_nocheck) 331 332/* 333uint64_t dtrace_fuword64_nocheck(void *addr) 334*/ 335 336 ENTRY(dtrace_fuword64_nocheck) 337 movl 4(%esp), %ecx 338 xorl %eax, %eax 339 xorl %edx, %edx 340 DTRACE_SMAP_DISABLE 341 movl (%ecx), %eax 342 movl 4(%ecx), %edx 343 DTRACE_SMAP_ENABLE 344 ret 345 END(dtrace_fuword64_nocheck) 346 347/* 348void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval) 349*/ 350 351 ENTRY(dtrace_probe_error) 352 pushl %ebp 353 movl %esp, %ebp 354 pushl 0x1c(%ebp) 355 pushl 0x18(%ebp) 356 pushl 0x14(%ebp) 357 pushl 0x10(%ebp) 358 pushl 0xc(%ebp) 359 pushl 0x8(%ebp) 360 pushl dtrace_probeid_error 361 call dtrace_probe 362 movl %ebp, %esp 363 popl %ebp 364 ret 365 END(dtrace_probe_error) 366 367/* 368void dtrace_membar_producer(void) 369*/ 370 371 ENTRY(dtrace_membar_producer) 372 rep; ret /* use 2 byte return instruction when branch target */ 373 /* AMD Software Optimization Guide - Section 6.2 */ 374 END(dtrace_membar_producer) 375 376/* 377void dtrace_membar_consumer(void) 378*/ 379 380 ENTRY(dtrace_membar_consumer) 381 rep; ret /* use 2 byte return instruction when branch target */ 382 /* AMD Software Optimization Guide - Section 6.2 */ 383 END(dtrace_membar_consumer) 384 385/* 386dtrace_icookie_t dtrace_interrupt_disable(void) 387*/ 388 ENTRY(dtrace_interrupt_disable) 389 pushfl 390 popl %eax 391 cli 392 ret 393 END(dtrace_interrupt_disable) 394 395/* 396void dtrace_interrupt_enable(dtrace_icookie_t cookie) 397*/ 398 ENTRY(dtrace_interrupt_enable) 399 movl 4(%esp), %eax 400 pushl %eax 401 popfl 402 ret 403 END(dtrace_interrupt_enable) 404