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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/asm_linkage.h> 27 #include <sys/privregs.h> 28 #include <sys/fsr.h> 29 #include <sys/asi.h> 30 #include "assym.h" 31 32 ENTRY_NP(dtrace_getipl) 33 retl 34 rdpr %pil, %o0 35 SET_SIZE(dtrace_getipl) 36 37 ENTRY_NP(dtrace_getotherwin) 38 retl 39 rdpr %otherwin, %o0 40 SET_SIZE(dtrace_getotherwin) 41 42 ENTRY_NP(dtrace_getfprs) 43 retl 44 rd %fprs, %o0 45 SET_SIZE(dtrace_getfprs) 46 47 ENTRY_NP(dtrace_getfsr) 48 rdpr %pstate, %o1 49 andcc %o1, PSTATE_PEF, %g0 50 bz,pn %xcc, 1f 51 nop 52 rd %fprs, %o1 53 andcc %o1, FPRS_FEF, %g0 54 bz,pn %xcc, 1f 55 nop 56 retl 57 stx %fsr, [%o0] 58 1: 59 retl 60 stx %g0, [%o0] 61 SET_SIZE(dtrace_getfsr) 62 63 ENTRY_NP(dtrace_getfp) 64 retl 65 mov %fp, %o0 66 SET_SIZE(dtrace_getfp) 67 68 ENTRY_NP(dtrace_flush_user_windows) 69 rdpr %otherwin, %g1 70 brz %g1, 3f 71 clr %g2 72 1: 73 save %sp, -WINDOWSIZE, %sp 74 rdpr %otherwin, %g1 75 brnz %g1, 1b 76 add %g2, 1, %g2 77 2: 78 sub %g2, 1, %g2 ! restore back to orig window 79 brnz %g2, 2b 80 restore 81 3: 82 retl 83 nop 84 SET_SIZE(dtrace_flush_user_windows) 85 86 ENTRY(dtrace_cas32) 87 cas [%o0], %o1, %o2 88 retl 89 mov %o2, %o0 90 SET_SIZE(dtrace_cas32) 91 92 ENTRY(dtrace_casptr) 93 casn [%o0], %o1, %o2 94 retl 95 mov %o2, %o0 96 SET_SIZE(dtrace_casptr) 97 98 ENTRY(dtrace_caller) 99 sethi %hi(nwin_minus_one), %g4 100 ld [%g4 + %lo(nwin_minus_one)], %g4 101 rdpr %canrestore, %g2 102 cmp %g2, %o0 103 bl %icc, 1f 104 rdpr %cwp, %g1 105 sub %g1, %o0, %g3 106 brgez,a,pt %g3, 0f 107 wrpr %g3, %cwp 108 109 ! 110 ! CWP minus the number of frames is negative; we must perform the 111 ! arithmetic modulo MAXWIN. 112 ! 113 add %g4, %g3, %g3 114 inc %g3 115 wrpr %g3, %cwp 116 0: 117 mov %i7, %g4 118 wrpr %g1, %cwp 119 retl 120 mov %g4, %o0 121 1: 122 ! 123 ! The caller has been flushed to the stack. This is unlikely 124 ! (interrupts are disabled in dtrace_probe()), but possible (the 125 ! interrupt inducing the spill may have been taken before the 126 ! call to dtrace_probe()). 127 ! 128 retl 129 mov -1, %o0 130 SET_SIZE(dtrace_caller) 131 132 ENTRY(dtrace_fish) 133 134 rd %pc, %g5 135 ba 0f 136 add %g5, 12, %g5 137 mov %l0, %g4 138 mov %l1, %g4 139 mov %l2, %g4 140 mov %l3, %g4 141 mov %l4, %g4 142 mov %l5, %g4 143 mov %l6, %g4 144 mov %l7, %g4 145 mov %i0, %g4 146 mov %i1, %g4 147 mov %i2, %g4 148 mov %i3, %g4 149 mov %i4, %g4 150 mov %i5, %g4 151 mov %i6, %g4 152 mov %i7, %g4 153 0: 154 sub %o1, 16, %o1 ! Can only retrieve %l's and %i's 155 sll %o1, 2, %o1 ! Multiply by instruction size 156 add %g5, %o1, %g5 ! %g5 now contains the instr. to pick 157 158 sethi %hi(nwin_minus_one), %g4 159 ld [%g4 + %lo(nwin_minus_one)], %g4 160 161 ! 162 ! First we need to see if the frame that we're fishing in is still 163 ! contained in the register windows. 164 ! 165 rdpr %canrestore, %g2 166 cmp %g2, %o0 167 bl %icc, 2f 168 rdpr %cwp, %g1 169 sub %g1, %o0, %g3 170 brgez,a,pt %g3, 0f 171 wrpr %g3, %cwp 172 173 ! 174 ! CWP minus the number of frames is negative; we must perform the 175 ! arithmetic modulo MAXWIN. 176 ! 177 add %g4, %g3, %g3 178 inc %g3 179 wrpr %g3, %cwp 180 0: 181 jmp %g5 182 ba 1f 183 1: 184 wrpr %g1, %cwp 185 stn %g4, [%o2] 186 retl 187 clr %o0 ! Success; return 0. 188 2: 189 ! 190 ! The frame that we're looking for has been flushed to the stack; the 191 ! caller will be forced to 192 ! 193 retl 194 add %g2, 1, %o0 ! Failure; return deepest frame + 1 195 SET_SIZE(dtrace_fish) 196 197 ENTRY(dtrace_copyin) 198 tst %o2 199 bz 2f 200 clr %g1 201 lduba [%o0 + %g1]ASI_USER, %g2 202 0: 203 ! check for an error if the count is 4k-aligned 204 andcc %g1, 0xfff, %g0 205 bnz,pt %icc, 1f 206 stub %g2, [%o1 + %g1] 207 lduh [%o3], %g3 208 andcc %g3, CPU_DTRACE_BADADDR, %g0 209 bnz,pn %icc, 2f 210 nop 211 1: 212 inc %g1 213 cmp %g1, %o2 214 bl,a 0b 215 lduba [%o0 + %g1]ASI_USER, %g2 216 2: 217 retl 218 nop 219 220 SET_SIZE(dtrace_copyin) 221 222 ENTRY(dtrace_copyinstr) 223 tst %o2 224 bz 2f 225 clr %g1 226 lduba [%o0 + %g1]ASI_USER, %g2 227 0: 228 stub %g2, [%o1 + %g1] ! Store byte 229 230 ! check for an error if the count is 4k-aligned 231 andcc %g1, 0xfff, %g0 232 bnz,pt %icc, 1f 233 inc %g1 234 lduh [%o3], %g3 235 andcc %g3, CPU_DTRACE_BADADDR, %g0 236 bnz,pn %icc, 2f 237 nop 238 1: 239 cmp %g2, 0 ! Was that '\0'? 240 be 2f ! If so, we're done 241 cmp %g1, %o2 ! Compare to limit 242 bl,a 0b ! If less, take another lap 243 lduba [%o0 + %g1]ASI_USER, %g2 ! delay: load user byte 244 2: 245 retl 246 nop 247 248 SET_SIZE(dtrace_copyinstr) 249 250 ENTRY(dtrace_copyout) 251 tst %o2 252 bz 2f 253 clr %g1 254 ldub [%o0 + %g1], %g2 255 0: 256 ! check for an error if the count is 4k-aligned 257 andcc %g1, 0xfff, %g0 258 bnz,pt %icc, 1f 259 stba %g2, [%o1 + %g1]ASI_USER 260 lduh [%o3], %g3 261 andcc %g3, CPU_DTRACE_BADADDR, %g0 262 bnz,pn %icc, 2f 263 nop 264 1: 265 inc %g1 266 cmp %g1, %o2 267 bl,a 0b 268 ldub [%o0 + %g1], %g2 269 2: 270 retl 271 nop 272 SET_SIZE(dtrace_copyout) 273 274 ENTRY(dtrace_copyoutstr) 275 tst %o2 276 bz 2f 277 clr %g1 278 ldub [%o0 + %g1], %g2 279 0: 280 stba %g2, [%o1 + %g1]ASI_USER 281 282 ! check for an error if the count is 4k-aligned 283 andcc %g1, 0xfff, %g0 284 bnz,pt %icc, 1f 285 inc %g1 286 lduh [%o3], %g3 287 andcc %g3, CPU_DTRACE_BADADDR, %g0 288 bnz,pn %icc, 2f 289 nop 290 1: 291 cmp %g2, 0 292 be 2f 293 cmp %g1, %o2 294 bl,a 0b 295 ldub [%o0 + %g1], %g2 296 2: 297 retl 298 nop 299 SET_SIZE(dtrace_copyoutstr) 300 301 ENTRY(dtrace_fulword) 302 clr %o1 303 ldna [%o0]ASI_USER, %o1 304 retl 305 mov %o1, %o0 306 SET_SIZE(dtrace_fulword) 307 308 ENTRY(dtrace_fuword8) 309 clr %o1 310 lduba [%o0]ASI_USER, %o1 311 retl 312 mov %o1, %o0 313 SET_SIZE(dtrace_fuword8) 314 315 ENTRY(dtrace_fuword16) 316 clr %o1 317 lduha [%o0]ASI_USER, %o1 318 retl 319 mov %o1, %o0 320 SET_SIZE(dtrace_fuword16) 321 322 ENTRY(dtrace_fuword32) 323 clr %o1 324 lda [%o0]ASI_USER, %o1 325 retl 326 mov %o1, %o0 327 SET_SIZE(dtrace_fuword32) 328 329 ENTRY(dtrace_fuword64) 330 clr %o1 331 ldxa [%o0]ASI_USER, %o1 332 retl 333 mov %o1, %o0 334 SET_SIZE(dtrace_fuword64) 335 336 /* 337 * %g1 pcstack 338 * %g2 current window 339 * %g3 maxwin (nwindows - 1) 340 * %g4 saved %cwp (so we can get back to the original window) 341 * %g5 iteration count 342 * %g6 saved %fp 343 * 344 * %o0 pcstack / return value (iteration count) 345 * %o1 pcstack_limit 346 * %o2 last_fp 347 */ 348 349 ENTRY(dtrace_getupcstack_top) 350 mov %o0, %g1 ! we need the pcstack pointer while 351 ! we're visiting other windows 352 353 rdpr %otherwin, %g5 ! compute the number of iterations 354 cmp %g5, %o1 ! (windows to observe) by taking the 355 movg %icc, %o1, %g5 ! min of %otherwin and pcstack_limit 356 357 brlez,a,pn %g5, 2f ! return 0 if count <= 0 358 clr %o0 359 360 sethi %hi(nwin_minus_one), %g3 ! hang onto maxwin since we'll need 361 ld [%g3 + %lo(nwin_minus_one)], %g3 ! it for our modular arithmetic 362 363 rdpr %cwp, %g4 ! remember our window so we can return 364 rdpr %canrestore, %g2 ! compute the first non-user window 365 subcc %g4, %g2, %g2 ! current = %cwp - %canrestore 366 367 bge,pt %xcc, 1f ! good to go if current is >= 0 368 mov %g5, %o0 ! we need to return the count 369 370 add %g2, %g3, %g2 ! normalize our current window if it's 371 add %g2, 1, %g2 ! less than zero 372 373 ! note that while it's tempting, we can't execute restore to decrement 374 ! the %cwp by one (mod nwindows) because we're in the user's windows 375 1: 376 deccc %g2 ! decrement the current window 377 movl %xcc, %g3, %g2 ! normalize if it's negative (-1) 378 379 wrpr %g2, %cwp ! change windows 380 381 stx %i7, [%g1] ! stash the return address in pcstack 382 383 deccc %g5 ! decrement the count 384 bnz,pt %icc, 1b ! we iterate until the count reaches 0 385 add %g1, 8, %g1 ! increment the pcstack pointer 386 387 mov %i6, %g6 ! stash the last frame pointer we 388 ! encounter so the caller can 389 ! continue the stack walk in memory 390 391 wrpr %g4, %cwp ! change back to the original window 392 393 stn %g6, [%o2] ! return the last frame pointer 394 395 2: 396 retl 397 nop 398 SET_SIZE(dtrace_getupcstack_top) 399 400 ENTRY(dtrace_getustackdepth_top) 401 mov %o0, %o2 402 rdpr %otherwin, %o0 403 404 brlez,a,pn %o0, 2f ! return 0 if there are no user wins 405 clr %o0 406 407 rdpr %cwp, %g4 ! remember our window so we can return 408 rdpr %canrestore, %g2 ! compute the first user window 409 sub %g4, %g2, %g2 ! current = %cwp - %canrestore - 410 subcc %g2, %o0, %g2 ! %otherwin 411 412 bge,pt %xcc, 1f ! normalize the window if necessary 413 sethi %hi(nwin_minus_one), %g3 414 ld [%g3 + %lo(nwin_minus_one)], %g3 415 add %g2, %g3, %g2 416 add %g2, 1, %g2 417 418 1: 419 wrpr %g2, %cwp ! change to the first user window 420 mov %i6, %g6 ! stash the frame pointer 421 wrpr %g4, %cwp ! change back to the original window 422 423 stn %g6, [%o2] ! return the frame pointer 424 425 2: 426 retl 427 nop 428 SET_SIZE(dtrace_getustackdepth_top) 429 430 ENTRY(dtrace_getreg_win) 431 sub %o0, 16, %o0 432 cmp %o0, 16 ! %o0 must begin in the range [16..32) 433 blu,pt %xcc, 1f 434 nop 435 retl 436 clr %o0 437 438 1: 439 set dtrace_getreg_win_table, %g3 440 sll %o0, 2, %o0 441 add %g3, %o0, %g3 442 443 rdpr %canrestore, %o3 444 rdpr %cwp, %g2 445 446 ! Set %cwp to be (%cwp - %canrestore - %o1) mod NWINDOWS 447 448 sub %g2, %o3, %o2 ! %o2 is %cwp - %canrestore 449 subcc %o2, %o1, %o4 450 bge,a,pn %xcc, 2f 451 wrpr %o4, %cwp 452 453 sethi %hi(nwin_minus_one), %o3 454 ld [%o3 + %lo(nwin_minus_one)], %o3 455 456 add %o2, %o3, %o4 457 wrpr %o4, %cwp 458 2: 459 jmp %g3 460 ba 3f 461 3: 462 wrpr %g2, %cwp 463 retl 464 mov %g1, %o0 465 466 dtrace_getreg_win_table: 467 mov %l0, %g1 468 mov %l1, %g1 469 mov %l2, %g1 470 mov %l3, %g1 471 mov %l4, %g1 472 mov %l5, %g1 473 mov %l6, %g1 474 mov %l7, %g1 475 mov %i0, %g1 476 mov %i1, %g1 477 mov %i2, %g1 478 mov %i3, %g1 479 mov %i4, %g1 480 mov %i5, %g1 481 mov %i6, %g1 482 mov %i7, %g1 483 SET_SIZE(dtrace_getreg_win) 484 485 ENTRY(dtrace_putreg_win) 486 sub %o0, 16, %o0 487 cmp %o0, 16 ! %o0 must be in the range [16..32) 488 blu,pt %xcc, 1f 489 nop 490 retl 491 nop 492 493 1: 494 mov %o1, %g1 ! move the value into a global register 495 496 set dtrace_putreg_table, %g3 497 sll %o0, 2, %o0 498 add %g3, %o0, %g3 499 500 rdpr %canrestore, %o3 501 rdpr %cwp, %g2 502 503 ! Set %cwp to be (%cwp - %canrestore - 1) mod NWINDOWS 504 505 sub %g2, %o3, %o2 ! %o2 is %cwp - %canrestore 506 subcc %o2, 1, %o4 507 bge,a,pn %xcc, 2f 508 wrpr %o4, %cwp 509 510 sethi %hi(nwin_minus_one), %o3 511 ld [%o3 + %lo(nwin_minus_one)], %o3 512 add %o2, %o3, %o4 513 wrpr %o4, %cwp 514 2: 515 jmp %g3 516 ba 3f 517 3: 518 wrpr %g2, %cwp 519 retl 520 nop 521 522 dtrace_putreg_table: 523 mov %g1, %l0 524 mov %g1, %l1 525 mov %g1, %l2 526 mov %g1, %l3 527 mov %g1, %l4 528 mov %g1, %l5 529 mov %g1, %l6 530 mov %g1, %l7 531 mov %g1, %i0 532 mov %g1, %i1 533 mov %g1, %i2 534 mov %g1, %i3 535 mov %g1, %i4 536 mov %g1, %i5 537 mov %g1, %i6 538 mov %g1, %i7 539 SET_SIZE(dtrace_putreg_win) 540 541 ENTRY(dtrace_probe_error) 542 save %sp, -SA(MINFRAME), %sp 543 sethi %hi(dtrace_probeid_error), %l0 544 ld [%l0 + %lo(dtrace_probeid_error)], %o0 545 mov %i0, %o1 546 mov %i1, %o2 547 mov %i2, %o3 548 mov %i3, %o4 549 call dtrace_probe 550 mov %i4, %o5 551 ret 552 restore 553 SET_SIZE(dtrace_probe_error) 554