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