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 2005 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 /* Main procedures for sparc FPU simulator. */ 30 31 #include <sys/fpu/fpu_simulator.h> 32 #include <sys/fpu/globals.h> 33 #include <sys/fpu/fpusystm.h> 34 #include <sys/proc.h> 35 #include <sys/signal.h> 36 #include <sys/siginfo.h> 37 #include <sys/thread.h> 38 #include <sys/cpuvar.h> 39 #include <sys/cmn_err.h> 40 #include <sys/atomic.h> 41 #include <sys/privregs.h> 42 #include <sys/vis_simulator.h> 43 44 45 #define FPUINFO_KSTAT(opcode) { \ 46 extern void __dtrace_probe___fpuinfo_##opcode(uint64_t *); \ 47 uint64_t *stataddr = &fpuinfo.opcode.value.ui64; \ 48 __dtrace_probe___fpuinfo_##opcode(stataddr); \ 49 atomic_add_64(&fpuinfo.opcode.value.ui64, 1); \ 50 } 51 52 #define FPUINFO_KSTAT_PREC(prec, kstat_s, kstat_d, kstat_q) \ 53 if (prec < 2) { \ 54 FPUINFO_KSTAT(kstat_s); \ 55 } else if (prec == 2) { \ 56 FPUINFO_KSTAT(kstat_d); \ 57 } else { \ 58 FPUINFO_KSTAT(kstat_q); \ 59 } 60 61 /* 62 * FPU simulator global kstat data 63 */ 64 struct fpuinfo_kstat fpuinfo = { 65 { "fpu_sim_fmovs", KSTAT_DATA_UINT64}, 66 { "fpu_sim_fmovd", KSTAT_DATA_UINT64}, 67 { "fpu_sim_fmovq", KSTAT_DATA_UINT64}, 68 { "fpu_sim_fnegs", KSTAT_DATA_UINT64}, 69 { "fpu_sim_fnegd", KSTAT_DATA_UINT64}, 70 { "fpu_sim_fnegq", KSTAT_DATA_UINT64}, 71 { "fpu_sim_fabss", KSTAT_DATA_UINT64}, 72 { "fpu_sim_fabsd", KSTAT_DATA_UINT64}, 73 { "fpu_sim_fabsq", KSTAT_DATA_UINT64}, 74 { "fpu_sim_fsqrts", KSTAT_DATA_UINT64}, 75 { "fpu_sim_fsqrtd", KSTAT_DATA_UINT64}, 76 { "fpu_sim_fsqrtq", KSTAT_DATA_UINT64}, 77 { "fpu_sim_fadds", KSTAT_DATA_UINT64}, 78 { "fpu_sim_faddd", KSTAT_DATA_UINT64}, 79 { "fpu_sim_faddq", KSTAT_DATA_UINT64}, 80 { "fpu_sim_fsubs", KSTAT_DATA_UINT64}, 81 { "fpu_sim_fsubd", KSTAT_DATA_UINT64}, 82 { "fpu_sim_fsubq", KSTAT_DATA_UINT64}, 83 { "fpu_sim_fmuls", KSTAT_DATA_UINT64}, 84 { "fpu_sim_fmuld", KSTAT_DATA_UINT64}, 85 { "fpu_sim_fmulq", KSTAT_DATA_UINT64}, 86 { "fpu_sim_fdivs", KSTAT_DATA_UINT64}, 87 { "fpu_sim_fdivd", KSTAT_DATA_UINT64}, 88 { "fpu_sim_fdivq", KSTAT_DATA_UINT64}, 89 { "fpu_sim_fcmps", KSTAT_DATA_UINT64}, 90 { "fpu_sim_fcmpd", KSTAT_DATA_UINT64}, 91 { "fpu_sim_fcmpq", KSTAT_DATA_UINT64}, 92 { "fpu_sim_fcmpes", KSTAT_DATA_UINT64}, 93 { "fpu_sim_fcmped", KSTAT_DATA_UINT64}, 94 { "fpu_sim_fcmpeq", KSTAT_DATA_UINT64}, 95 { "fpu_sim_fsmuld", KSTAT_DATA_UINT64}, 96 { "fpu_sim_fdmulx", KSTAT_DATA_UINT64}, 97 { "fpu_sim_fstox", KSTAT_DATA_UINT64}, 98 { "fpu_sim_fdtox", KSTAT_DATA_UINT64}, 99 { "fpu_sim_fqtox", KSTAT_DATA_UINT64}, 100 { "fpu_sim_fxtos", KSTAT_DATA_UINT64}, 101 { "fpu_sim_fxtod", KSTAT_DATA_UINT64}, 102 { "fpu_sim_fxtoq", KSTAT_DATA_UINT64}, 103 { "fpu_sim_fitos", KSTAT_DATA_UINT64}, 104 { "fpu_sim_fitod", KSTAT_DATA_UINT64}, 105 { "fpu_sim_fitoq", KSTAT_DATA_UINT64}, 106 { "fpu_sim_fstoi", KSTAT_DATA_UINT64}, 107 { "fpu_sim_fdtoi", KSTAT_DATA_UINT64}, 108 { "fpu_sim_fqtoi", KSTAT_DATA_UINT64}, 109 { "fpu_sim_fmovcc", KSTAT_DATA_UINT64}, 110 { "fpu_sim_fmovr", KSTAT_DATA_UINT64}, 111 }; 112 113 struct visinfo_kstat visinfo = { 114 { "vis_edge8", KSTAT_DATA_UINT64}, 115 { "vis_edge8n", KSTAT_DATA_UINT64}, 116 { "vis_edge8l", KSTAT_DATA_UINT64}, 117 { "vis_edge8ln", KSTAT_DATA_UINT64}, 118 { "vis_edge16", KSTAT_DATA_UINT64}, 119 { "vis_edge16n", KSTAT_DATA_UINT64}, 120 { "vis_edge16l", KSTAT_DATA_UINT64}, 121 { "vis_edge16ln", KSTAT_DATA_UINT64}, 122 { "vis_edge32", KSTAT_DATA_UINT64}, 123 { "vis_edge32n", KSTAT_DATA_UINT64}, 124 { "vis_edge32l", KSTAT_DATA_UINT64}, 125 { "vis_edge32ln", KSTAT_DATA_UINT64}, 126 { "vis_array8", KSTAT_DATA_UINT64}, 127 { "vis_array16", KSTAT_DATA_UINT64}, 128 { "vis_array32", KSTAT_DATA_UINT64}, 129 { "vis_bmask", KSTAT_DATA_UINT64}, 130 { "vis_fcmple16", KSTAT_DATA_UINT64}, 131 { "vis_fcmpne16", KSTAT_DATA_UINT64}, 132 { "vis_fcmpgt16", KSTAT_DATA_UINT64}, 133 { "vis_fcmpeq16", KSTAT_DATA_UINT64}, 134 { "vis_fcmple32", KSTAT_DATA_UINT64}, 135 { "vis_fcmpne32", KSTAT_DATA_UINT64}, 136 { "vis_fcmpgt32", KSTAT_DATA_UINT64}, 137 { "vis_fcmpeq32", KSTAT_DATA_UINT64}, 138 { "vis_fmul8x16", KSTAT_DATA_UINT64}, 139 { "vis_fmul8x16au", KSTAT_DATA_UINT64}, 140 { "vis_fmul8x16al", KSTAT_DATA_UINT64}, 141 { "vis_fmul8sux16", KSTAT_DATA_UINT64}, 142 { "vis_fmul8ulx16", KSTAT_DATA_UINT64}, 143 { "vis_fmuld8sux16", KSTAT_DATA_UINT64}, 144 { "vis_fmuld8ulx16", KSTAT_DATA_UINT64}, 145 { "vis_fpack16", KSTAT_DATA_UINT64}, 146 { "vis_fpack32", KSTAT_DATA_UINT64}, 147 { "vis_fpackfix", KSTAT_DATA_UINT64}, 148 { "vis_fexpand", KSTAT_DATA_UINT64}, 149 { "vis_fpmerge", KSTAT_DATA_UINT64}, 150 { "vis_pdist", KSTAT_DATA_UINT64}, 151 { "vis_bshuffle", KSTAT_DATA_UINT64}, 152 153 }; 154 155 /* PUBLIC FUNCTIONS */ 156 157 int fp_notp = 1; /* fp checking not a problem */ 158 159 /* ARGSUSED */ 160 static enum ftt_type 161 _fp_fpu_simulator( 162 fp_simd_type *pfpsd, /* Pointer to fpu simulator data */ 163 fp_inst_type inst, /* FPU instruction to simulate. */ 164 fsr_type *pfsr, /* Pointer to image of FSR to read and write. */ 165 uint64_t gsr) /* Image of GSR to read */ 166 { 167 unpacked us1, us2, ud; /* Unpacked operands and result. */ 168 uint32_t nrs1, nrs2, nrd; /* Register number fields. */ 169 uint32_t usr, andexcep; 170 fsr_type fsr; 171 enum fcc_type cc; 172 uint32_t nfcc; /* fcc number field. */ 173 uint64_t lusr; 174 175 nrs1 = inst.rs1; 176 nrs2 = inst.rs2; 177 nrd = inst.rd; 178 fsr = *pfsr; 179 pfpsd->fp_current_exceptions = 0; /* Init current exceptions. */ 180 pfpsd->fp_fsrtem = fsr.tem; /* Obtain fsr's tem */ 181 /* 182 * Obtain rounding direction and precision 183 */ 184 pfpsd->fp_direction = GSR_IM(gsr) ? GSR_IRND(gsr) : fsr.rnd; 185 pfpsd->fp_precision = fsr.rnp; 186 nfcc = nrd & 0x3; 187 if (inst.op3 == 0x35) { /* fpop2 */ 188 fsr.cexc = 0; 189 *pfsr = fsr; 190 if ((inst.opcode & 0xf) == 0) { 191 if ((fp_notp) && (inst.prec == 0)) 192 return (ftt_unimplemented); 193 FPUINFO_KSTAT(fpu_sim_fmovcc); 194 return (fmovcc(pfpsd, inst, pfsr)); /* fmovcc */ 195 } else if ((inst.opcode & 0x7) == 1) { 196 if ((fp_notp) && (inst.prec == 0)) 197 return (ftt_unimplemented); 198 FPUINFO_KSTAT(fpu_sim_fmovr); 199 return (fmovr(pfpsd, inst)); /* fmovr */ 200 } 201 } 202 /* ibit not valid for fpop1 instructions */ 203 if ((fp_notp) && (inst.ibit != 0)) 204 return (ftt_unimplemented); 205 if ((fp_notp) && (inst.prec == 0)) { /* fxto[sdq], fito[sdq] */ 206 if ((inst.opcode != flltos) && 207 (inst.opcode != flltod) && 208 (inst.opcode != flltox) && 209 (inst.opcode != fitos) && 210 (inst.opcode != fitod) && 211 (inst.opcode != fitox)) { 212 return (ftt_unimplemented); 213 } 214 } 215 switch (inst.opcode) { 216 case fmovs: /* also covers fmovd, fmovq */ 217 if (inst.prec < 2) { /* fmovs */ 218 _fp_unpack_word(pfpsd, &usr, nrs2); 219 _fp_pack_word(pfpsd, &usr, nrd); 220 FPUINFO_KSTAT(fpu_sim_fmovs); 221 } else { /* fmovd */ 222 _fp_unpack_extword(pfpsd, &lusr, nrs2); 223 _fp_pack_extword(pfpsd, &lusr, nrd); 224 if (inst.prec > 2) { /* fmovq */ 225 _fp_unpack_extword(pfpsd, &lusr, nrs2+2); 226 _fp_pack_extword(pfpsd, &lusr, nrd+2); 227 FPUINFO_KSTAT(fpu_sim_fmovq); 228 } else { 229 FPUINFO_KSTAT(fpu_sim_fmovd); 230 } 231 } 232 break; 233 case fabss: /* also covers fabsd, fabsq */ 234 if (inst.prec < 2) { /* fabss */ 235 _fp_unpack_word(pfpsd, &usr, nrs2); 236 usr &= 0x7fffffff; 237 _fp_pack_word(pfpsd, &usr, nrd); 238 FPUINFO_KSTAT(fpu_sim_fabss); 239 } else { /* fabsd */ 240 _fp_unpack_extword(pfpsd, &lusr, nrs2); 241 lusr &= 0x7fffffffffffffff; 242 _fp_pack_extword(pfpsd, &lusr, nrd); 243 if (inst.prec > 2) { /* fabsq */ 244 _fp_unpack_extword(pfpsd, &lusr, nrs2+2); 245 _fp_pack_extword(pfpsd, &lusr, nrd+2); 246 FPUINFO_KSTAT(fpu_sim_fabsq); 247 } else { 248 FPUINFO_KSTAT(fpu_sim_fabsd); 249 } 250 } 251 break; 252 case fnegs: /* also covers fnegd, fnegq */ 253 if (inst.prec < 2) { /* fnegs */ 254 _fp_unpack_word(pfpsd, &usr, nrs2); 255 usr ^= 0x80000000; 256 _fp_pack_word(pfpsd, &usr, nrd); 257 FPUINFO_KSTAT(fpu_sim_fnegs); 258 } else { /* fnegd */ 259 _fp_unpack_extword(pfpsd, &lusr, nrs2); 260 lusr ^= 0x8000000000000000; 261 _fp_pack_extword(pfpsd, &lusr, nrd); 262 if (inst.prec > 2) { /* fnegq */ 263 _fp_unpack_extword(pfpsd, &lusr, nrs2+2); 264 lusr ^= 0x0000000000000000; 265 _fp_pack_extword(pfpsd, &lusr, nrd+2); 266 FPUINFO_KSTAT(fpu_sim_fnegq); 267 } else { 268 FPUINFO_KSTAT(fpu_sim_fnegd); 269 } 270 } 271 break; 272 case fadd: 273 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 274 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 275 _fp_add(pfpsd, &us1, &us2, &ud); 276 _fp_pack(pfpsd, &ud, nrd, inst.prec); 277 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds, 278 fpu_sim_faddd, fpu_sim_faddq); 279 break; 280 case fsub: 281 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 282 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 283 _fp_sub(pfpsd, &us1, &us2, &ud); 284 _fp_pack(pfpsd, &ud, nrd, inst.prec); 285 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs, 286 fpu_sim_fsubd, fpu_sim_fsubq); 287 break; 288 case fmul: 289 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 290 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 291 _fp_mul(pfpsd, &us1, &us2, &ud); 292 _fp_pack(pfpsd, &ud, nrd, inst.prec); 293 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls, 294 fpu_sim_fmuld, fpu_sim_fmulq); 295 break; 296 case fsmuld: 297 if ((fp_notp) && (inst.prec != 1)) 298 return (ftt_unimplemented); 299 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 300 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 301 _fp_mul(pfpsd, &us1, &us2, &ud); 302 _fp_pack(pfpsd, &ud, nrd, (enum fp_op_type) ((int)inst.prec+1)); 303 FPUINFO_KSTAT(fpu_sim_fsmuld); 304 break; 305 case fdmulx: 306 if ((fp_notp) && (inst.prec != 2)) 307 return (ftt_unimplemented); 308 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 309 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 310 _fp_mul(pfpsd, &us1, &us2, &ud); 311 _fp_pack(pfpsd, &ud, nrd, (enum fp_op_type) ((int)inst.prec+1)); 312 FPUINFO_KSTAT(fpu_sim_fdmulx); 313 break; 314 case fdiv: 315 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 316 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 317 _fp_div(pfpsd, &us1, &us2, &ud); 318 _fp_pack(pfpsd, &ud, nrd, inst.prec); 319 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs, 320 fpu_sim_fdivd, fpu_sim_fdivq); 321 break; 322 case fcmp: 323 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 324 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 325 cc = _fp_compare(pfpsd, &us1, &us2, 0); 326 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 327 switch (nfcc) { 328 case fcc_0: 329 fsr.fcc0 = cc; 330 break; 331 case fcc_1: 332 fsr.fcc1 = cc; 333 break; 334 case fcc_2: 335 fsr.fcc2 = cc; 336 break; 337 case fcc_3: 338 fsr.fcc3 = cc; 339 break; 340 } 341 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps, 342 fpu_sim_fcmpd, fpu_sim_fcmpq); 343 break; 344 case fcmpe: 345 _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 346 _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 347 cc = _fp_compare(pfpsd, &us1, &us2, 1); 348 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 349 switch (nfcc) { 350 case fcc_0: 351 fsr.fcc0 = cc; 352 break; 353 case fcc_1: 354 fsr.fcc1 = cc; 355 break; 356 case fcc_2: 357 fsr.fcc2 = cc; 358 break; 359 case fcc_3: 360 fsr.fcc3 = cc; 361 break; 362 } 363 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes, 364 fpu_sim_fcmped, fpu_sim_fcmpeq); 365 break; 366 case fsqrt: 367 _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 368 _fp_sqrt(pfpsd, &us1, &ud); 369 _fp_pack(pfpsd, &ud, nrd, inst.prec); 370 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts, 371 fpu_sim_fsqrtd, fpu_sim_fsqrtq); 372 break; 373 case ftoi: 374 _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 375 pfpsd->fp_direction = fp_tozero; 376 /* Force rounding toward zero. */ 377 _fp_pack(pfpsd, &us1, nrd, fp_op_int32); 378 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi, 379 fpu_sim_fdtoi, fpu_sim_fqtoi); 380 break; 381 case ftoll: 382 _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 383 pfpsd->fp_direction = fp_tozero; 384 /* Force rounding toward zero. */ 385 _fp_pack(pfpsd, &us1, nrd, fp_op_int64); 386 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox, 387 fpu_sim_fdtox, fpu_sim_fqtox); 388 break; 389 case flltos: 390 _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); 391 _fp_pack(pfpsd, &us1, nrd, fp_op_single); 392 FPUINFO_KSTAT(fpu_sim_fxtos); 393 break; 394 case flltod: 395 _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); 396 _fp_pack(pfpsd, &us1, nrd, fp_op_double); 397 FPUINFO_KSTAT(fpu_sim_fxtod); 398 break; 399 case flltox: 400 _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); 401 _fp_pack(pfpsd, &us1, nrd, fp_op_extended); 402 FPUINFO_KSTAT(fpu_sim_fxtoq); 403 break; 404 case fitos: 405 _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 406 _fp_pack(pfpsd, &us1, nrd, fp_op_single); 407 FPUINFO_KSTAT(fpu_sim_fitos); 408 break; 409 case fitod: 410 _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 411 _fp_pack(pfpsd, &us1, nrd, fp_op_double); 412 FPUINFO_KSTAT(fpu_sim_fitod); 413 break; 414 case fitox: 415 _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 416 _fp_pack(pfpsd, &us1, nrd, fp_op_extended); 417 FPUINFO_KSTAT(fpu_sim_fitoq); 418 break; 419 default: 420 return (ftt_unimplemented); 421 } 422 fsr.cexc = pfpsd->fp_current_exceptions; 423 if (pfpsd->fp_current_exceptions) { /* Exception(s) occurred. */ 424 andexcep = pfpsd->fp_current_exceptions & fsr.tem; 425 if (andexcep != 0) { /* Signal an IEEE SIGFPE here. */ 426 if (andexcep & (1 << fp_invalid)) { 427 pfpsd->fp_trapcode = FPE_FLTINV; 428 fsr.cexc = FSR_CEXC_NV; 429 } else if (andexcep & (1 << fp_overflow)) { 430 pfpsd->fp_trapcode = FPE_FLTOVF; 431 fsr.cexc = FSR_CEXC_OF; 432 } else if (andexcep & (1 << fp_underflow)) { 433 pfpsd->fp_trapcode = FPE_FLTUND; 434 fsr.cexc = FSR_CEXC_UF; 435 } else if (andexcep & (1 << fp_division)) { 436 pfpsd->fp_trapcode = FPE_FLTDIV; 437 fsr.cexc = FSR_CEXC_DZ; 438 } else if (andexcep & (1 << fp_inexact)) { 439 pfpsd->fp_trapcode = FPE_FLTRES; 440 fsr.cexc = FSR_CEXC_NX; 441 } else { 442 pfpsd->fp_trapcode = 0; 443 } 444 *pfsr = fsr; 445 return (ftt_ieee); 446 } else { /* Just set accrued exception field. */ 447 fsr.aexc |= pfpsd->fp_current_exceptions; 448 } 449 } 450 *pfsr = fsr; 451 return (ftt_none); 452 } 453 454 /* 455 * fpu_vis_sim simulates fpu and vis instructions; 456 * It can work with both real and pcb image registers. 457 */ 458 enum ftt_type 459 fpu_vis_sim( 460 fp_simd_type *pfpsd, /* Pointer to simulator data */ 461 fp_inst_type *pinst, /* Address of FPU instruction to simulate */ 462 struct regs *pregs, /* Pointer to PCB image of registers. */ 463 fsr_type *pfsr, /* Pointer to image of FSR to read and write */ 464 uint64_t gsr, /* Image of GSR to read */ 465 uint32_t inst) /* The FPU instruction to simulate */ 466 { 467 klwp_id_t lwp = ttolwp(curthread); 468 union { 469 uint32_t i; 470 fp_inst_type inst; 471 } fp; 472 kfpu_t *pfp = lwptofpu(lwp); 473 enum ftt_type ftt; 474 475 fp.i = inst; 476 pfpsd->fp_trapaddr = (caddr_t)pinst; 477 if (fpu_exists) { 478 pfpsd->fp_current_read_freg = _fp_read_pfreg; 479 pfpsd->fp_current_write_freg = _fp_write_pfreg; 480 pfpsd->fp_current_read_dreg = _fp_read_pdreg; 481 pfpsd->fp_current_write_dreg = _fp_write_pdreg; 482 pfpsd->get_gsr = get_phys_gsr; 483 pfpsd->set_gsr = set_phys_gsr; 484 pfpsd->get_ccr = get_ccr; 485 pfpsd->set_ccr = set_ccr; 486 pfpsd->get_pstate = get_pstate; 487 } else { 488 pfpsd->fp_current_pfregs = pfp; 489 pfpsd->fp_current_read_freg = _fp_read_vfreg; 490 pfpsd->fp_current_write_freg = _fp_write_vfreg; 491 pfpsd->fp_current_read_dreg = _fp_read_vdreg; 492 pfpsd->fp_current_write_dreg = _fp_write_vdreg; 493 pfpsd->get_gsr = get_gsr; 494 pfpsd->set_gsr = set_gsr; 495 496 /* There are no virtual routines */ 497 /* for getting/setting ccr and pstate */ 498 pfpsd->get_ccr = get_ccr; 499 pfpsd->set_ccr = set_ccr; 500 pfpsd->get_pstate = get_pstate; 501 } 502 503 if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) { 504 ftt = vis_fpu_simulator(pfpsd, fp.inst, 505 pregs, (ulong_t *)pregs->r_sp, pfp); 506 return (ftt); 507 } else if ((fp.inst.hibits == 2) && 508 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) { 509 ftt = _fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr); 510 if (ftt == ftt_none || ftt == ftt_ieee) { 511 pregs->r_pc = pregs->r_npc; 512 pregs->r_npc += 4; 513 } 514 return (ftt); 515 } else { 516 ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, 517 (ulong_t *)pregs->r_sp, pfp); 518 return (ftt); 519 } 520 } 521 522 /* 523 * fpu_simulator simulates FPU instructions only; 524 * reads and writes FPU data registers directly. 525 */ 526 enum ftt_type 527 fpu_simulator( 528 fp_simd_type *pfpsd, /* Pointer to simulator data */ 529 fp_inst_type *pinst, /* Address of FPU instruction to simulate */ 530 fsr_type *pfsr, /* Pointer to image of FSR to read and write */ 531 uint64_t gsr, /* Image of GSR to read */ 532 uint32_t inst) /* The FPU instruction to simulate */ 533 { 534 union { 535 uint32_t i; 536 fp_inst_type inst; 537 } fp; 538 539 fp.i = inst; 540 pfpsd->fp_trapaddr = (caddr_t)pinst; 541 pfpsd->fp_current_read_freg = _fp_read_pfreg; 542 pfpsd->fp_current_write_freg = _fp_write_pfreg; 543 pfpsd->fp_current_read_dreg = _fp_read_pdreg; 544 pfpsd->fp_current_write_dreg = _fp_write_pdreg; 545 pfpsd->get_gsr = get_phys_gsr; 546 pfpsd->set_gsr = set_phys_gsr; 547 pfpsd->get_ccr = get_ccr; 548 pfpsd->set_ccr = set_ccr; 549 pfpsd->get_pstate = get_pstate; 550 return (_fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr)); 551 } 552 553 /* 554 * fp_emulator simulates FPU and CPU-FPU instructions; reads and writes FPU 555 * data registers from image in pfpu. 556 */ 557 enum ftt_type 558 fp_emulator( 559 fp_simd_type *pfpsd, /* Pointer to simulator data */ 560 fp_inst_type *pinst, /* Pointer to FPU instruction to simulate. */ 561 struct regs *pregs, /* Pointer to PCB image of registers. */ 562 void *prw, /* Pointer to locals and ins. */ 563 kfpu_t *pfpu) /* Pointer to FPU register block. */ 564 { 565 klwp_id_t lwp = ttolwp(curthread); 566 union { 567 uint32_t i; 568 fp_inst_type inst; 569 } fp; 570 enum ftt_type ftt; 571 uint64_t gsr = get_gsr(pfpu); 572 kfpu_t *pfp = lwptofpu(lwp); 573 uint64_t tfsr; 574 575 tfsr = pfpu->fpu_fsr; 576 pfpsd->fp_current_pfregs = pfpu; 577 pfpsd->fp_current_read_freg = _fp_read_vfreg; 578 pfpsd->fp_current_write_freg = _fp_write_vfreg; 579 pfpsd->fp_current_read_dreg = _fp_read_vdreg; 580 pfpsd->fp_current_write_dreg = _fp_write_vdreg; 581 pfpsd->get_gsr = get_gsr; 582 pfpsd->set_gsr = set_gsr; 583 584 /* There are no virtual routines */ 585 /* for getting/setting ccr and pstate */ 586 pfpsd->get_ccr = get_ccr; 587 pfpsd->set_ccr = set_ccr; 588 pfpsd->get_pstate = get_pstate; 589 pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */ 590 ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd); 591 if (ftt != ftt_none) 592 return (ftt); 593 594 if ((fp.inst.hibits == 2) && 595 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) { 596 ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr); 597 /* Do not retry emulated instruction. */ 598 pregs->r_pc = pregs->r_npc; 599 pregs->r_npc += 4; 600 pfpu->fpu_fsr = tfsr; 601 if (ftt != ftt_none) { 602 /* 603 * Simulation generated an exception of some kind, 604 * simulate the fp queue for a signal. 605 */ 606 pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst; 607 pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i; 608 pfpu->fpu_qcnt = 1; 609 } 610 } else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) { 611 ftt = vis_fpu_simulator(pfpsd, fp.inst, 612 pregs, prw, pfp); 613 } else 614 ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu); 615 616 if (ftt != ftt_none) 617 return (ftt); 618 619 /* 620 * If we are single-stepping, don't emulate any more instructions. 621 */ 622 if (lwp->lwp_pcb.pcb_step != STEP_NONE) 623 return (ftt); 624 again: 625 /* 626 * now read next instruction and see if it can be emulated 627 */ 628 pinst = (fp_inst_type *)pregs->r_pc; 629 pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */ 630 ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd); 631 if (ftt != ftt_none) 632 return (ftt); 633 if ((fp.inst.hibits == 2) && /* fpops */ 634 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) { 635 ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr); 636 /* Do not retry emulated instruction. */ 637 pfpu->fpu_fsr = tfsr; 638 pregs->r_pc = pregs->r_npc; 639 pregs->r_npc += 4; 640 if (ftt != ftt_none) { 641 /* 642 * Simulation generated an exception of some kind, 643 * simulate the fp queue for a signal. 644 */ 645 pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst; 646 pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i; 647 pfpu->fpu_qcnt = 1; 648 } 649 } else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) { 650 ftt = vis_fpu_simulator(pfpsd, fp.inst, 651 pregs, prw, pfp); 652 } else if ( 653 /* rd %gsr */ 654 ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x28) && 655 (fp.inst.rs1 == 0x13)) || 656 /* wr %gsr */ 657 ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x30) && 658 (fp.inst.rd == 0x13)) || 659 /* movcc */ 660 ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x2c) && 661 (((fp.i>>18) & 0x1) == 0)) || 662 /* fbpcc */ 663 ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 5)) || 664 /* fldst */ 665 ((fp.inst.hibits == 3) && ((fp.inst.op3 & 0x38) == 0x20)) || 666 /* fbcc */ 667 ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 6))) { 668 ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu); 669 } else 670 return (ftt); 671 672 if (ftt != ftt_none) 673 return (ftt); 674 else 675 goto again; 676 } 677 678 /* 679 * FPU simulator global kstat data 680 */ 681 struct fpustat_kstat fpustat = { 682 { "fpu_ieee_traps", KSTAT_DATA_UINT64 }, 683 { "fpu_unfinished_traps", KSTAT_DATA_UINT64 }, 684 { "fpu_unimplemented", KSTAT_DATA_UINT64 }, 685 }; 686 687 kstat_t *fpu_kstat = NULL; 688 kstat_t *fpuinfo_kstat = NULL; 689 kstat_t *visinfo_kstat = NULL; 690 691 void 692 fp_kstat_init(void) 693 { 694 const uint_t fpustat_ndata = sizeof (fpustat) / sizeof (kstat_named_t); 695 const uint_t fpuinfo_ndata = sizeof (fpuinfo) / sizeof (kstat_named_t); 696 const uint_t visinfo_ndata = sizeof (visinfo) /sizeof (kstat_named_t); 697 698 ASSERT(fpu_kstat == NULL); 699 if ((fpu_kstat = kstat_create("unix", 0, "fpu_traps", "misc", 700 KSTAT_TYPE_NAMED, fpustat_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) { 701 cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_traps failed", 702 CPU->cpu_id); 703 } else { 704 fpu_kstat->ks_data = (void *)&fpustat; 705 kstat_install(fpu_kstat); 706 } 707 708 ASSERT(fpuinfo_kstat == NULL); 709 if ((fpuinfo_kstat = kstat_create("unix", 0, "fpu_info", "misc", 710 KSTAT_TYPE_NAMED, fpuinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) { 711 cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_info failed", 712 CPU->cpu_id); 713 } else { 714 fpuinfo_kstat->ks_data = (void *)&fpuinfo; 715 kstat_install(fpuinfo_kstat); 716 } 717 ASSERT(visinfo_kstat == NULL); 718 if ((visinfo_kstat = kstat_create("unix", 0, "vis_info", "misc", 719 KSTAT_TYPE_NAMED, visinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) { 720 cmn_err(CE_WARN, "CPU%d: kstat_create for vis_info failed", 721 CPU->cpu_id); 722 } else { 723 visinfo_kstat->ks_data = (void *)&visinfo; 724 kstat_install(visinfo_kstat); 725 } 726 } 727 728 void 729 fp_kstat_update(enum ftt_type ftt) 730 { 731 ASSERT((ftt == ftt_ieee) || (ftt == ftt_unfinished) || 732 (ftt == ftt_unimplemented)); 733 if (ftt == ftt_ieee) 734 atomic_add_64(&fpustat.fpu_ieee_traps.value.ui64, 1); 735 else if (ftt == ftt_unfinished) 736 atomic_add_64(&fpustat.fpu_unfinished_traps.value.ui64, 1); 737 else if (ftt == ftt_unimplemented) 738 atomic_add_64(&fpustat.fpu_unimplemented_traps.value.ui64, 1); 739 } 740