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