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