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 #ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/asm_linkage.h> 29 #include <sys/trap.h> 30 #include <sys/machpcb.h> 31 #include <sys/machtrap.h> 32 #include <sys/machsig.h> 33 #include <sys/machthread.h> 34 35 #include "assym.h" 36 37 /* 38 * Floating point trap handling. 39 * 40 * The FPU is always in a V9 current configuration. 41 * 42 * When a user process is first started via exec, 43 * floating point operations will be disabled by default. 44 * Upon execution of the first floating point instruction, 45 * a fp_disabled trap will be generated; then a word in 46 * the uarea is written signifying use of the floating point 47 * registers so that subsequent context switches will save 48 * and restore the floating point them. The trapped instruction 49 * will be restarted and processing will continue as normal. 50 * 51 * When a operation occurs that the hardware cannot properly 52 * handle, an unfinshed fp_op exception will be generated. 53 * Software routines in the kernel will be executed to 54 * simulate proper handling of such conditions. 55 * 56 * Exception handling will emulate all instructions 57 * in the floating point address queue. Note that there 58 * is no %fq in sun4u, because it has precise FP traps. 59 * 60 * Floating point queues are now machine dependent, and std %fq 61 * is an illegal V9 instruction. The fp_exception code has been 62 * moved to sun4u/ml/machfloat.s. 63 * 64 * NOTE: This code DOES NOT SUPPORT KERNEL (DEVICE DRIVER) 65 * USE OF THE FPU 66 * 67 * Instructions for running without the hardware fpu: 68 * 1. Setting fpu_exists to 0 now only works on a DEBUG kernel. 69 * 2. adb -w unix and set fpu_exists, use_hw_bcopy, use_hw_copyio, and 70 * use_hw_bzero to 0 and rename libc_psr.so.1 in 71 * /usr/platform/sun4u/lib so that it will not get used by 72 * the libc bcopy routines. Then reboot the system and you 73 * should see the bootup message "FPU not in use". 74 * 3. To run kaos, you must comment out the code which sets the 75 * version number of the fsr to 7, in fldst: stfsr/stxfsr 76 * (unless you are running against a comparison system that 77 * has the same fsr version number). 78 * 4. The stqf{a}/ldqf{a} instructions cause kaos errors, for reasons 79 * that appear to be a kaos bug, so don't use them! 80 */ 81 82 .section ".data" 83 .align 8 84 fsrholder: 85 .word 0 ! dummy place to write fsr 86 .word 0 87 88 DGDEF(fpu_exists) ! always exists for V9 89 #ifdef FP_DISABLED 90 .word 0 91 #else 92 .word 1 ! sundiag (gack) uses this variable 93 #endif 94 95 DGDEF(fpu_version) 96 .word -1 97 98 /* 99 * FPU probe - read the %fsr and get fpu_version. 100 * Called from autoconf. If a %fq is created for 101 * future cpu versions, a fq_exists variable 102 * could be created by this function. 103 */ 104 105 ENTRY_NP(fpu_probe) 106 wr %g0, FPRS_FEF, %fprs ! enable fpu in fprs 107 rdpr %pstate, %g2 ! read pstate, save value in %g2 108 or %g2, PSTATE_PEF, %g1 ! new pstate with fpu enabled 109 wrpr %g1, %g0, %pstate ! write pstate 110 111 sethi %hi(fsrholder), %g2 112 stx %fsr, [%g2 + %lo(fsrholder)] 113 ldx [%g2 + %lo(fsrholder)], %g2 ! snarf the FSR 114 set FSR_VER, %g1 115 and %g2, %g1, %g2 ! get version 116 srl %g2, FSR_VER_SHIFT, %g2 ! and shift it down 117 sethi %hi(fpu_version), %g3 ! save the FPU version 118 st %g2, [%g3 + %lo(fpu_version)] 119 120 ba fp_kstat_init ! initialize the fpu_kstat 121 wr %g0, %g0, %fprs ! disable fpu and clear fprs 122 SET_SIZE(fpu_probe) 123 124 /* 125 * fp_clearregs(fp) 126 * struct v9_fpu *fp; 127 * 128 * Initialization for the hardware fpu. 129 * Clear the fsr and initialize registers to NaN (-1) 130 * The caller (fp_disabled) is supposed to update the fprs 131 * so when the return to userland is made, the fpu is enabled. 132 */ 133 134 ENTRY_NP(fp_clearregs) 135 ldx [%o0 + FPU_FSR], %fsr ! load fsr 136 137 mov -1, %g2 ! -1 is NaN 138 stx %g2, [%o0] ! initialize %f0 139 ldd [%o0], %d0 140 ldd [%o0], %d2 141 ldd [%o0], %d4 142 ldd [%o0], %d6 143 ldd [%o0], %d8 144 ldd [%o0], %d10 145 ldd [%o0], %d12 146 ldd [%o0], %d14 147 ldd [%o0], %d16 148 ldd [%o0], %d18 149 ldd [%o0], %d20 150 ldd [%o0], %d22 151 ldd [%o0], %d24 152 ldd [%o0], %d26 153 ldd [%o0], %d28 154 ldd [%o0], %d30 155 ldd [%o0], %d32 156 ldd [%o0], %d34 157 ldd [%o0], %d36 158 ldd [%o0], %d38 159 ldd [%o0], %d40 160 ldd [%o0], %d42 161 ldd [%o0], %d44 162 ldd [%o0], %d46 163 ldd [%o0], %d48 164 ldd [%o0], %d50 165 ldd [%o0], %d52 166 ldd [%o0], %d54 167 ldd [%o0], %d56 168 ldd [%o0], %d58 169 ldd [%o0], %d60 170 retl 171 ldd [%o0], %d62 172 SET_SIZE(fp_clearregs) 173 174 /* 175 * void _fp_read_pfreg(pf, n) 176 * uint32_t *pf; Old freg value. 177 * unsigned n; Want to read register n 178 * 179 * { 180 * *pf = %f[n]; 181 * } 182 * 183 * void 184 * _fp_write_pfreg(pf, n) 185 * uint32_t *pf; New freg value. 186 * unsigned n; Want to write register n. 187 * 188 * { 189 * %f[n] = *pf; 190 * } 191 */ 192 193 ENTRY_NP(_fp_read_pfreg) 194 sll %o1, 3, %o1 ! Table entries are 8 bytes each. 195 set .stable, %g1 ! g1 gets base of table. 196 jmp %g1 + %o1 ! Jump into table 197 nop ! Can't follow CTI by CTI. 198 199 ENTRY_NP(_fp_write_pfreg) 200 sll %o1, 3, %o1 ! Table entries are 8 bytes each. 201 set .ltable, %g1 ! g1 gets base of table. 202 jmp %g1 + %o1 ! Jump into table 203 nop ! Can't follow CTI by CTI. 204 205 #define STOREFP(n) jmp %o7+8 ; st %f/**/n, [%o0] 206 207 .stable: 208 STOREFP(0) 209 STOREFP(1) 210 STOREFP(2) 211 STOREFP(3) 212 STOREFP(4) 213 STOREFP(5) 214 STOREFP(6) 215 STOREFP(7) 216 STOREFP(8) 217 STOREFP(9) 218 STOREFP(10) 219 STOREFP(11) 220 STOREFP(12) 221 STOREFP(13) 222 STOREFP(14) 223 STOREFP(15) 224 STOREFP(16) 225 STOREFP(17) 226 STOREFP(18) 227 STOREFP(19) 228 STOREFP(20) 229 STOREFP(21) 230 STOREFP(22) 231 STOREFP(23) 232 STOREFP(24) 233 STOREFP(25) 234 STOREFP(26) 235 STOREFP(27) 236 STOREFP(28) 237 STOREFP(29) 238 STOREFP(30) 239 STOREFP(31) 240 241 #define LOADFP(n) jmp %o7+8 ; ld [%o0],%f/**/n 242 243 .ltable: 244 LOADFP(0) 245 LOADFP(1) 246 LOADFP(2) 247 LOADFP(3) 248 LOADFP(4) 249 LOADFP(5) 250 LOADFP(6) 251 LOADFP(7) 252 LOADFP(8) 253 LOADFP(9) 254 LOADFP(10) 255 LOADFP(11) 256 LOADFP(12) 257 LOADFP(13) 258 LOADFP(14) 259 LOADFP(15) 260 LOADFP(16) 261 LOADFP(17) 262 LOADFP(18) 263 LOADFP(19) 264 LOADFP(20) 265 LOADFP(21) 266 LOADFP(22) 267 LOADFP(23) 268 LOADFP(24) 269 LOADFP(25) 270 LOADFP(26) 271 LOADFP(27) 272 LOADFP(28) 273 LOADFP(29) 274 LOADFP(30) 275 LOADFP(31) 276 SET_SIZE(_fp_read_pfreg) 277 SET_SIZE(_fp_write_pfreg) 278 279 /* 280 * void _fp_read_pdreg( 281 * uint64_t *pd, Old dreg value. 282 * u_int n) Want to read register n 283 * 284 * { 285 * *pd = %d[n]; 286 * } 287 * 288 * void 289 * _fp_write_pdreg( 290 * uint64_t *pd, New dreg value. 291 * u_int n) Want to write register n. 292 * 293 * { 294 * %d[n] = *pd; 295 * } 296 */ 297 298 ENTRY_NP(_fp_read_pdreg) 299 sll %o1, 3, %o1 ! Table entries are 8 bytes each. 300 set .dstable, %g1 ! g1 gets base of table. 301 jmp %g1 + %o1 ! Jump into table 302 nop ! Can't follow CTI by CTI. 303 304 ENTRY_NP(_fp_write_pdreg) 305 sll %o1, 3, %o1 ! Table entries are 8 bytes each. 306 set .dltable, %g1 ! g1 gets base of table. 307 jmp %g1 + %o1 ! Jump into table 308 nop ! Can't follow CTI by CTI. 309 310 #define STOREDP(n) jmp %o7+8 ; std %d/**/n, [%o0] 311 312 .dstable: 313 STOREDP(0) 314 STOREDP(2) 315 STOREDP(4) 316 STOREDP(6) 317 STOREDP(8) 318 STOREDP(10) 319 STOREDP(12) 320 STOREDP(14) 321 STOREDP(16) 322 STOREDP(18) 323 STOREDP(20) 324 STOREDP(22) 325 STOREDP(24) 326 STOREDP(26) 327 STOREDP(28) 328 STOREDP(30) 329 STOREDP(32) 330 STOREDP(34) 331 STOREDP(36) 332 STOREDP(38) 333 STOREDP(40) 334 STOREDP(42) 335 STOREDP(44) 336 STOREDP(46) 337 STOREDP(48) 338 STOREDP(50) 339 STOREDP(52) 340 STOREDP(54) 341 STOREDP(56) 342 STOREDP(58) 343 STOREDP(60) 344 STOREDP(62) 345 346 #define LOADDP(n) jmp %o7+8 ; ldd [%o0],%d/**/n 347 348 .dltable: 349 LOADDP(0) 350 LOADDP(2) 351 LOADDP(4) 352 LOADDP(6) 353 LOADDP(8) 354 LOADDP(10) 355 LOADDP(12) 356 LOADDP(14) 357 LOADDP(16) 358 LOADDP(18) 359 LOADDP(20) 360 LOADDP(22) 361 LOADDP(24) 362 LOADDP(26) 363 LOADDP(28) 364 LOADDP(30) 365 LOADDP(32) 366 LOADDP(34) 367 LOADDP(36) 368 LOADDP(38) 369 LOADDP(40) 370 LOADDP(42) 371 LOADDP(44) 372 LOADDP(46) 373 LOADDP(48) 374 LOADDP(50) 375 LOADDP(52) 376 LOADDP(54) 377 LOADDP(56) 378 LOADDP(58) 379 LOADDP(60) 380 LOADDP(62) 381 SET_SIZE(_fp_read_pdreg) 382 SET_SIZE(_fp_write_pdreg) 383 384 ENTRY_NP(_fp_write_pfsr) 385 retl 386 ldx [%o0], %fsr 387 SET_SIZE(_fp_write_pfsr) 388 389 ENTRY_NP(_fp_read_pfsr) 390 retl 391 stx %fsr, [%o0] 392 SET_SIZE(_fp_read_pfsr) 393 394 ENTRY_NP(_fp_write_fprs) 395 retl 396 wr %o0, %g0, %fprs ! write fprs 397 SET_SIZE(_fp_write_fprs) 398 399 ENTRY_NP(_fp_read_fprs) 400 retl 401 rd %fprs, %o0 ! save fprs 402 SET_SIZE(_fp_read_fprs) 403 404 ENTRY_NP(_fp_subcc_ccr) 405 subcc %o0, %o1, %g0 406 retl 407 rd %ccr, %o0 ! save ccr 408 SET_SIZE(_fp_subcc_ccr) 409 410 /* 411 * Floating Point Exceptions handled according to type: 412 * 2) unfinished_fpop 413 * re-execute the faulty instruction(s) using 414 * software emulation (must do every instruction in FQ) 415 * 3) unimplemented_fpop 416 * an unimplemented instruction, if it is legal, 417 * will cause emulation of the instruction (and all 418 * other instuctions in the FQ) 419 * 4) sequence_error 420 * panic, this should not happen, and if it does it 421 * it is the result of a kernel bug 422 * 423 * This code assumes the trap preamble has set up the window environment 424 * for execution of kernel code. 425 * Note: this code could be changed to be part of the cpu-specific 426 * (ie, Spitfire-specific) module code before final release. 427 */ 428 429 ENTRY_NP(_fp_exception) 430 mov %o7, %l0 ! saved return address 431 mov %o0, %l1 ! saved *rp 432 set FSR_FTT, %o4 ! put FSR_FTT in %o4 433 xor %o4, 0xffffffffffffffff, %o3 ! xor FSR_FTT to get 434 and %o1, %o3, %o2 ! an fsr with a zero'd ftt 435 ldn [THREAD_REG + T_LWP], %o3 ! get lwp 436 ldn [%o3 + LWP_FPU], %l3 ! get lwp_fpu 437 stx %o2, [%l3 + FPU_FSR] ! save floating point status 438 and %o1, %o4, %g2 ! get the ftt trap type 439 #ifdef DEBUG 440 brnz,a,pt %g2, fttok 441 nop 442 set .badfpfttmsg, %o0 ! panic message 443 call panic ! %o1 has the fsr w/ftt value 444 nop 445 fttok: 446 #endif /* DEBUG */ 447 srl %g2, FSR_FTT_SHIFT, %o4 ! check ftt 448 cmp %o4, FTT_SEQ ! sanity check for bogus exceptions 449 ! 450 ! traps are already enabled to allow other 451 ! interrupts while emulating floating point instructions 452 ! 453 blt,a,pt %xcc, fpeok 454 nop 455 ! 456 ! Sequence error or unknown ftt exception. 457 ! 458 seq_error: 459 set .badfpexcpmsg, %o0 ! panic if bad ftt 460 call panic 461 sra %o4, 0, %o1 ! mov ftt to o1 for panic message 462 463 fpeok: 464 call fp_kstat_update ! fp_kstat_update(ftt) 465 mov %o4, %o0 ! ftt 466 ! 467 ! Get the floating point instruction, and run the floating 468 ! point simulator. There is no floating point queue, so we fake one. 469 ! 470 call fp_precise ! fp_precise(®s) 471 mov %l1, %o0 ! saved *rp 472 473 fp_ret: 474 rd %fprs, %g1 ! read fprs, save value in %g1 475 st %g1, [%l3 + FPU_FPRS] ! save fprs 476 jmp %l0 + 8 ! jump to saved return address 477 stx %fsr, [%l3 + FPU_FSR] ! save fsr 478 SET_SIZE(_fp_exception) 479 480 .badfpexcpmsg: 481 .asciz "unexpected floating point exception %x" 482 483 #ifdef DEBUG 484 .badfpfttmsg: 485 .asciz "No floating point ftt, fsr %llx" 486 #endif /* DEBUG */ 487 488 /* 489 * Floating Point Exceptions. 490 * handled according to type: 491 * 1) IEEE_exception 492 * re-execute the faulty instruction(s) using 493 * software emulation (must do every instruction in FQ) 494 * 495 * This code assumes the trap preamble has set up the window environment 496 * for execution of kernel code. 497 */ 498 499 ENTRY_NP(_fp_ieee_exception) 500 mov %o7, %l0 ! saved return address 501 mov %o0, %l1 ! saved *rp 502 mov %o1, %l2 ! saved fsr 503 set FSR_FTT, %o4 ! put FSR_FTT in %o4 504 xor %o4, 0xffffffffffffffff, %o3 ! ! xor FSR_FTT to get 505 and %o1, %o3, %o2 ! an fsr with a zero'd ftt 506 ldn [THREAD_REG + T_LWP], %o3 ! get lwp 507 ldn [%o3 + LWP_FPU], %l3 ! get lwp_fpu 508 stx %o2, [%l3 + FPU_FSR] ! save floating point status 509 stub %g0, [%l3 + FPU_QCNT] ! clear fpu_qcnt 510 and %o1, %o4, %g2 ! mask out trap type 511 #ifdef DEBUG 512 brnz,a,pt %g2, fttgd 513 nop 514 set .badfpfttmsg, %o0 ! panic message 515 call panic ! %o1 has the fsr w/ftt value 516 nop 517 fttgd: 518 #endif /* DEBUG */ 519 srl %g2, FSR_FTT_SHIFT, %o4 ! check ftt 520 cmp %o4, FTT_SEQ ! sanity check for bogus exceptions 521 ! 522 ! traps are already enabled to allow other 523 ! interrupts while emulating floating point instructions 524 ! 525 blt,a,pt %xcc, fpegd 526 nop 527 ! 528 ! Sequence error or unknown ftt exception. 529 ! 530 seq_err: 531 set .badfpexcpmsg, %o0 ! panic if bad ftt 532 call panic 533 sra %o4, 0, %o1 ! mov ftt to o1 for panic message 534 535 fpegd: 536 call fp_kstat_update ! fp_kstat_update(ftt) 537 mov %o4, %o0 ! ftt 538 ! 539 ! Call fpu_trap directly, don't bother to run the fp simulator. 540 ! The *rp is already in %o0. Clear fpu_qcnt. 541 ! 542 set (T_FP_EXCEPTION_IEEE), %o2 ! trap type 543 544 set FSR_CEXC, %o3 545 and %l2, %o3, %g2 ! mask out cexc 546 547 andcc %g2, FSR_CEXC_NX, %g0 ! check for inexact 548 bnz,a,pt %xcc, fpok 549 or %g0, FPE_FLTRES, %o3 ! fp inexact code 550 551 andcc %g2, FSR_CEXC_DZ, %g0 ! check for divide-by-zero 552 bnz,a,pt %xcc, fpok 553 or %g0, FPE_FLTDIV, %o3 ! fp divide by zero code 554 555 andcc %g2, FSR_CEXC_UF, %g0 ! check for underflow 556 bnz,a,pt %xcc, fpok 557 or %g0, FPE_FLTUND, %o3 ! fp underflow code 558 559 andcc %g2, FSR_CEXC_OF, %g0 ! check for overflow 560 bnz,a,pt %xcc, fpok 561 or %g0, FPE_FLTOVF, %o3 ! fp overflow code 562 563 andcc %g2, FSR_CEXC_NV, %g0 ! check for invalid 564 bnz,a,pn %xcc, fpok 565 or %g0, FPE_FLTINV, %o3 ! fp invalid code 566 567 cexec_err: 568 set .badfpcexcmsg, %o0 ! panic message 569 call panic ! panic if no cexc bit set 570 mov %g1, %o1 571 fpok: 572 mov %l1, %o0 ! saved *rp 573 call fpu_trap ! fpu_trap(®s, addr, type, code) 574 ldn [%o0 + PC_OFF], %o1 ! address of trapping instruction 575 576 rd %fprs, %g1 ! read fprs, save value in %g1 577 st %g1, [%l3 + FPU_FPRS] ! save fprs 578 jmp %l0 + 8 ! jump to saved return address 579 stx %fsr, [%l3 + FPU_FSR] ! save fsr 580 SET_SIZE(_fp_ieee_exception) 581 582 .badfpcexcmsg: 583 .asciz "No floating point exception, fsr %llx" 584