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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * General machine architecture & implementation specific
  28  * assembly language routines.
  29  */
  30 #if defined(lint)
  31 #include <sys/types.h>
  32 #include <sys/t_lock.h>
  33 #else   /* lint */
  34 #include "assym.h"
  35 #endif  /* lint */
  36 
  37 #include <sys/asm_linkage.h>
  38 #include <sys/machsystm.h>
  39 #include <sys/machthread.h>
  40 #include <sys/privregs.h>
  41 #include <sys/cmpregs.h>
  42 #include <sys/clock.h>
  43 #include <sys/fpras.h>
  44 
  45 #if defined(lint)
  46 
  47 uint64_t
  48 ultra_gettick(void)
  49 { return (0); }
  50 
  51 #else   /* lint */
  52 
  53 /*
  54  * This isn't the routine you're looking for.
  55  *
  56  * The routine simply returns the value of %tick on the *current* processor.
  57  * Most of the time, gettick() [which in turn maps to %stick on platforms
  58  * that have different CPU %tick rates] is what you want.
  59  */
  60 
  61         ENTRY(ultra_gettick)
  62         retl
  63         rdpr    %tick, %o0
  64         SET_SIZE(ultra_gettick)
  65 
  66 #endif  /* lint */
  67 
  68 #if defined(lint)
  69 
  70 /*ARGSUSED*/
  71 int
  72 getprocessorid(void)
  73 { return (0); }
  74 
  75 #else   /* lint */
  76 
  77 /*
  78  * Get the processor ID.
  79  * === MID reg as specified in 15dec89 sun4u spec, sec 5.4.3
  80  */
  81 
  82         ENTRY(getprocessorid)
  83         CPU_INDEX(%o0, %o1)
  84         retl
  85         nop
  86         SET_SIZE(getprocessorid)
  87 
  88 #endif  /* lint */
  89 
  90 #if defined(lint)
  91 /*ARGSUSED*/
  92 void
  93 set_error_enable_tl1(uint64_t neer, uint64_t action)
  94 {}
  95 
  96 /* ARGSUSED */
  97 void
  98 set_error_enable(uint64_t neer)
  99 {}
 100 
 101 uint64_t
 102 get_error_enable()
 103 {
 104         return ((uint64_t)0);
 105 }
 106 #else /* lint */
 107 
 108         ENTRY(set_error_enable_tl1)
 109         cmp     %g2, EER_SET_ABSOLUTE
 110         be      %xcc, 1f
 111           nop
 112         ldxa    [%g0]ASI_ESTATE_ERR, %g3
 113         membar  #Sync
 114         cmp     %g2, EER_SET_SETBITS
 115         be,a    %xcc, 1f
 116           or    %g3, %g1, %g1
 117         andn    %g3, %g1, %g1                   /* EER_SET_CLRBITS */
 118 1:
 119         stxa    %g1, [%g0]ASI_ESTATE_ERR        /* ecache error enable reg */
 120         membar  #Sync
 121         retry
 122         SET_SIZE(set_error_enable_tl1)
 123 
 124         ENTRY(set_error_enable)
 125         stxa    %o0, [%g0]ASI_ESTATE_ERR        /* ecache error enable reg */
 126         membar  #Sync
 127         retl
 128         nop
 129         SET_SIZE(set_error_enable)
 130 
 131         ENTRY(get_error_enable)
 132         retl
 133         ldxa    [%g0]ASI_ESTATE_ERR, %o0        /* ecache error enable reg */
 134         SET_SIZE(get_error_enable)
 135 
 136 #endif /* lint */
 137 
 138 #if defined(lint)
 139 void
 140 get_asyncflt(uint64_t *afsr)
 141 {
 142         afsr = afsr;
 143 }
 144 #else /* lint */
 145 
 146         ENTRY(get_asyncflt)
 147         ldxa    [%g0]ASI_AFSR, %o1              ! afsr reg
 148         retl
 149         stx     %o1, [%o0]
 150         SET_SIZE(get_asyncflt)
 151 
 152 #endif /* lint */
 153 
 154 #if defined(lint)
 155 void
 156 set_asyncflt(uint64_t afsr)
 157 {
 158         afsr = afsr;
 159 }
 160 #else /* lint */
 161 
 162         ENTRY(set_asyncflt)
 163         stxa    %o0, [%g0]ASI_AFSR              ! afsr reg
 164         membar  #Sync
 165         retl
 166         nop
 167         SET_SIZE(set_asyncflt)
 168 
 169 #endif /* lint */
 170 
 171 #if defined(lint)
 172 void
 173 get_asyncaddr(uint64_t *afar)
 174 {
 175         afar = afar;
 176 }
 177 #else /* lint */
 178 
 179         ENTRY(get_asyncaddr)
 180         ldxa    [%g0]ASI_AFAR, %o1              ! afar reg
 181         retl
 182         stx     %o1, [%o0]
 183         SET_SIZE(get_asyncaddr)
 184 
 185 #endif /* lint */
 186 
 187 #if defined(lint) || defined(__lint)
 188 
 189 /* ARGSUSED */
 190 hrtime_t
 191 tick2ns(hrtime_t tick, uint_t cpuid)
 192 { return 0; }
 193 
 194 #else   /* lint */
 195 
 196         ENTRY_NP(tick2ns)
 197         sethi   %hi(cpunodes), %o4
 198         or      %o4, %lo(cpunodes), %o4         ! %o4 = &cpunodes
 199         ! Register usage:
 200         !
 201         ! o0 = timestamp
 202         ! o2 = byte offset into cpunodes for tick_nsec_scale of this CPU
 203         ! o4 = &cpunodes
 204         !
 205         mulx    %o1, CPU_NODE_SIZE, %o2 ! %o2 = byte offset into cpunodes
 206         add     %o2, TICK_NSEC_SCALE, %o2
 207         ld      [%o4 + %o2], %o2        ! %o2 = cpunodes[cpuid].tick_nsec_scale
 208         NATIVE_TIME_TO_NSEC_SCALE(%o0, %o2, %o3, TICK_NSEC_SHIFT)
 209         retl
 210         nop
 211         SET_SIZE(tick2ns)
 212 
 213 #endif  /* lint */
 214 
 215 #if defined(lint)
 216 
 217 /* ARGSUSED */
 218 void
 219 set_cmp_error_steering(void)
 220 {}
 221 
 222 #else   /* lint */
 223 
 224         ENTRY(set_cmp_error_steering)
 225         membar  #Sync
 226         set     ASI_CORE_ID, %o0                ! %o0 = ASI_CORE_ID
 227         ldxa    [%o0]ASI_CMP_PER_CORE, %o0      ! get ASI_CORE_ID
 228         and     %o0, COREID_MASK, %o0
 229         set     ASI_CMP_ERROR_STEERING, %o1     ! %o1 = ERROR_STEERING_REG
 230         stxa    %o0, [%o1]ASI_CMP_SHARED        ! this core now hadles
 231         membar  #Sync                           !  non-core specific errors
 232         retl
 233         nop
 234         SET_SIZE(set_cmp_error_steering)
 235 
 236 #endif  /* lint */
 237 
 238 #if defined(lint)
 239 
 240 /* ARGSUSED */
 241 uint64_t
 242 ultra_getver(void)
 243 {
 244         return (0); 
 245 }
 246 
 247 #else /* lint */
 248 
 249         ENTRY(ultra_getver)
 250         retl
 251         rdpr    %ver, %o0
 252         SET_SIZE(ultra_getver)
 253 
 254 #endif /* lint */
 255 
 256 #if defined(lint)
 257 
 258 int
 259 fpras_chkfn_type1(void)
 260 { return 0; }
 261 
 262 #else   /* lint */
 263 
 264         /*
 265          * Check instructions using just the AX pipelines, designed by
 266          * C.B. Liaw of PNP.
 267          *
 268          * This function must match a struct fpras_chkfn and must be
 269          * block aligned.  A zero return means all was well.  These
 270          * instructions are chosen to be sensitive to bit corruptions
 271          * on the fpras rewrite, so if a bit corruption still produces
 272          * a valid instruction we should still get an incorrect result
 273          * here.  This function is never called directly - it is copied
 274          * into per-cpu and per-operation buffers;  it must therefore
 275          * be absolutely position independent.  If an illegal instruction
 276          * is encountered then the trap handler trampolines to the final
 277          * three instructions of this function.
 278          *
 279          * We want two instructions that are complements of one another,
 280          * and which can perform a calculation with a known result.
 281          *
 282          * SETHI:
 283          *
 284          * | 0 0 |  rd   | 1 0 0 |      imm22                           |
 285          *  31 30 29   25 24   22 21                                   0
 286          *
 287          * ADDCCC with two source registers:
 288          *
 289          * | 1 0 |  rd   | 0 1 1   0 0 0 |  rs1  | 0 |     -    |  rs2  |
 290          *  31 30 29   25 24           19 18   14 13  12       5 4     0
 291          *
 292          * We can choose rd and imm2 of the SETHI and rd, rs1 and rs2 of
 293          * the ADDCCC to obtain instructions that are complements in all but
 294          * bit 30.
 295          *
 296          * Registers are numbered as follows:
 297          *
 298          * r[31]        %i7
 299          * r[30]        %i6
 300          * r[29]        %i5
 301          * r[28]        %i4
 302          * r[27]        %i3
 303          * r[26]        %i2
 304          * r[25]        %i1
 305          * r[24]        %i0
 306          * r[23]        %l7
 307          * r[22]        %l6
 308          * r[21]        %l5
 309          * r[20]        %l4
 310          * r[19]        %l3
 311          * r[18]        %l2
 312          * r[17]        %l1
 313          * r[16]        %l0
 314          * r[15]        %o7
 315          * r[14]        %o6
 316          * r[13]        %o5
 317          * r[12]        %o4
 318          * r[11]        %o3
 319          * r[10]        %o2
 320          * r[9]         %o1
 321          * r[8]         %o0     
 322          * r[7]         %g7
 323          * r[6]         %g6
 324          * r[5]         %g5
 325          * r[4]         %g4
 326          * r[3]         %g3
 327          * r[2]         %g2
 328          * r[1]         %g1
 329          * r[0]         %g0
 330          *
 331          * For register r[n], register r[31-n] is the complement.  We must
 332          * avoid use of %i6/%i7 and %o6/%o7 as well as %g7.  Clearly we need
 333          * to use a local or input register as one half of the pair, which
 334          * requires us to obtain our own register window or take steps
 335          * to preserve any local or input we choose to use.  We choose
 336          * %o1 as rd for the SETHI, so rd of the ADDCCC must be %l6.
 337          * We'll use %o1 as rs1 and %l6 as rs2 of the ADDCCC, which then
 338          * requires that imm22 be 0b111 10110 1 11111111 01001 or 0x3dbfe9,
 339          * or %hi(0xf6ffa400).  This determines the value of the constant
 340          * CBV2 below.
 341          *
 342          * The constant CBV1 is chosen such that an initial subcc %g0, CBV1
 343          * will set the carry bit and every addccc thereafter will continue
 344          * to generate a carry.  Other values are possible for CBV1 - this
 345          * is just one that works this way.
 346          *
 347          * Finally CBV3 is the expected answer when we perform our repeated
 348          * calculations on CBV1 and CBV2 - it is not otherwise specially
 349          * derived.  If this result is not obtained then a corruption has
 350          * occured during the FPRAS_REWRITE of one of the two blocks of
 351          * 16 instructions.  A corruption could also result in an illegal
 352          * instruction or other unexpected trap - we catch illegal
 353          * instruction traps in the PC range and trampoline to the
 354          * last instructions of the function to return a failure indication.
 355          *
 356          */
 357 
 358 #define CBV1            0xc11
 359 #define CBV2            0xf6ffa400
 360 #define CBV3            0x66f9d800
 361 #define CBR1            %o1
 362 #define CBR2            %l6
 363 #define CBO2            %o2
 364 #define SETHI_CBV2_CBR1         sethi %hi(CBV2), CBR1
 365 #define ADDCCC_CBR1_CBR2_CBR2   addccc CBR1, CBR2, CBR2
 366 
 367         .align  64
 368         ENTRY_NP(fpras_chkfn_type1)
 369         mov     CBR2, CBO2              ! 1, preserve CBR2 of (callers) window
 370         mov     FPRAS_OK, %o0           ! 2, default return value
 371         ba,pt   %icc, 1f                ! 3
 372           subcc %g0, CBV1, CBR2         ! 4
 373                                         ! 5 - 16
 374         .align  64
 375 1:      SETHI_CBV2_CBR1                 ! 1
 376         ADDCCC_CBR1_CBR2_CBR2           ! 2
 377         SETHI_CBV2_CBR1                 ! 3
 378         ADDCCC_CBR1_CBR2_CBR2           ! 4
 379         SETHI_CBV2_CBR1                 ! 5
 380         ADDCCC_CBR1_CBR2_CBR2           ! 6
 381         SETHI_CBV2_CBR1                 ! 7
 382         ADDCCC_CBR1_CBR2_CBR2           ! 8
 383         SETHI_CBV2_CBR1                 ! 9
 384         ADDCCC_CBR1_CBR2_CBR2           ! 10
 385         SETHI_CBV2_CBR1                 ! 11
 386         ADDCCC_CBR1_CBR2_CBR2           ! 12
 387         SETHI_CBV2_CBR1                 ! 13
 388         ADDCCC_CBR1_CBR2_CBR2           ! 14
 389         SETHI_CBV2_CBR1                 ! 15
 390         ADDCCC_CBR1_CBR2_CBR2           ! 16
 391 
 392         ADDCCC_CBR1_CBR2_CBR2           ! 1
 393         SETHI_CBV2_CBR1                 ! 2
 394         ADDCCC_CBR1_CBR2_CBR2           ! 3
 395         SETHI_CBV2_CBR1                 ! 4
 396         ADDCCC_CBR1_CBR2_CBR2           ! 5
 397         SETHI_CBV2_CBR1                 ! 6
 398         ADDCCC_CBR1_CBR2_CBR2           ! 7
 399         SETHI_CBV2_CBR1                 ! 8
 400         ADDCCC_CBR1_CBR2_CBR2           ! 9
 401         SETHI_CBV2_CBR1                 ! 10
 402         ADDCCC_CBR1_CBR2_CBR2           ! 11
 403         SETHI_CBV2_CBR1                 ! 12
 404         ADDCCC_CBR1_CBR2_CBR2           ! 13
 405         SETHI_CBV2_CBR1                 ! 14
 406         ADDCCC_CBR1_CBR2_CBR2           ! 15
 407         SETHI_CBV2_CBR1                 ! 16
 408 
 409         addc    CBR1, CBR2, CBR2        ! 1
 410         sethi   %hi(CBV3), CBR1         ! 2
 411         cmp     CBR1, CBR2              ! 3
 412         movnz   %icc, FPRAS_BADCALC, %o0! 4, how detected
 413         retl                            ! 5
 414           mov   CBO2, CBR2              ! 6, restore borrowed register
 415         .skip 4*(13-7+1)                ! 7 - 13
 416                                         !
 417                                         ! illegal instr'n trap comes here
 418                                         !
 419         mov     CBO2, CBR2              ! 14, restore borrowed register
 420         retl                            ! 15
 421           mov   FPRAS_BADTRAP, %o0      ! 16, how detected
 422         SET_SIZE(fpras_chkfn_type1)
 423 
 424 #endif  /* lint */
 425 
 426 /*
 427  * fp_zero() - clear all fp data registers and the fsr
 428  */
 429 
 430 #if defined(lint) || defined(__lint)
 431 
 432 void
 433 fp_zero(void)
 434 {}
 435 
 436 #else   /* lint */
 437 
 438         ENTRY_NP(fp_zero)
 439         std     %g0, [%sp + ARGPUSH + STACK_BIAS]
 440         fzero   %f0
 441         fzero   %f2
 442         ldd     [%sp + ARGPUSH + STACK_BIAS], %fsr
 443         faddd   %f0, %f2, %f4
 444         fmuld   %f0, %f2, %f6
 445         faddd   %f0, %f2, %f8
 446         fmuld   %f0, %f2, %f10
 447         faddd   %f0, %f2, %f12
 448         fmuld   %f0, %f2, %f14
 449         faddd   %f0, %f2, %f16
 450         fmuld   %f0, %f2, %f18
 451         faddd   %f0, %f2, %f20
 452         fmuld   %f0, %f2, %f22
 453         faddd   %f0, %f2, %f24
 454         fmuld   %f0, %f2, %f26
 455         faddd   %f0, %f2, %f28
 456         fmuld   %f0, %f2, %f30
 457         faddd   %f0, %f2, %f32
 458         fmuld   %f0, %f2, %f34
 459         faddd   %f0, %f2, %f36
 460         fmuld   %f0, %f2, %f38
 461         faddd   %f0, %f2, %f40
 462         fmuld   %f0, %f2, %f42
 463         faddd   %f0, %f2, %f44
 464         fmuld   %f0, %f2, %f46
 465         faddd   %f0, %f2, %f48
 466         fmuld   %f0, %f2, %f50
 467         faddd   %f0, %f2, %f52
 468         fmuld   %f0, %f2, %f54
 469         faddd   %f0, %f2, %f56
 470         fmuld   %f0, %f2, %f58
 471         faddd   %f0, %f2, %f60
 472         retl
 473         fmuld   %f0, %f2, %f62
 474         SET_SIZE(fp_zero)
 475 
 476 #endif  /* lint */