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 */