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