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