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