17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/param.h> 297c478bd9Sstevel@tonic-gate #include <sys/signal.h> 307c478bd9Sstevel@tonic-gate #include <sys/trap.h> 317c478bd9Sstevel@tonic-gate #include <sys/machtrap.h> 327c478bd9Sstevel@tonic-gate #include <sys/fault.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/user.h> 357c478bd9Sstevel@tonic-gate #include <sys/file.h> 367c478bd9Sstevel@tonic-gate #include <sys/proc.h> 377c478bd9Sstevel@tonic-gate #include <sys/core.h> 387c478bd9Sstevel@tonic-gate #include <sys/pcb.h> 397c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 407c478bd9Sstevel@tonic-gate #include <sys/thread.h> 417c478bd9Sstevel@tonic-gate #include <sys/disp.h> 427c478bd9Sstevel@tonic-gate #include <sys/stack.h> 437c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 447c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h> 487c478bd9Sstevel@tonic-gate #include <sys/fpu/globals.h> 497c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate int fpdispr = 0; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * For use by procfs to save the floating point context of the thread. 557c478bd9Sstevel@tonic-gate * Note the if (ttolwp(lwp) == curthread) in prstop, which calls 567c478bd9Sstevel@tonic-gate * this function, ensures that it is safe to read the fprs here. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate void 597c478bd9Sstevel@tonic-gate fp_prsave(kfpu_t *fp) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate if ((fp->fpu_en) || (fp->fpu_fprs & FPRS_FEF)) { 627c478bd9Sstevel@tonic-gate kpreempt_disable(); 637c478bd9Sstevel@tonic-gate if (fpu_exists) { 647c478bd9Sstevel@tonic-gate fp->fpu_fprs = _fp_read_fprs(); 657c478bd9Sstevel@tonic-gate if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 667c478bd9Sstevel@tonic-gate uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate _fp_write_fprs(fprs); 697c478bd9Sstevel@tonic-gate fp->fpu_fprs = fprs; 707c478bd9Sstevel@tonic-gate #ifdef DEBUG 717c478bd9Sstevel@tonic-gate if (fpdispr) 727c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 737c478bd9Sstevel@tonic-gate "fp_prsave with fp disabled!"); 747c478bd9Sstevel@tonic-gate #endif 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate fp_fksave(fp); 777c478bd9Sstevel@tonic-gate } 787c478bd9Sstevel@tonic-gate kpreempt_enable(); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * Copy the floating point context of the forked thread. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate void 867c478bd9Sstevel@tonic-gate fp_fork(klwp_t *lwp, klwp_t *clwp) 877c478bd9Sstevel@tonic-gate { 887c478bd9Sstevel@tonic-gate kfpu_t *cfp, *pfp; 897c478bd9Sstevel@tonic-gate int i; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate cfp = lwptofpu(clwp); 927c478bd9Sstevel@tonic-gate pfp = lwptofpu(lwp); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * copy the parents fpq 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate cfp->fpu_qcnt = pfp->fpu_qcnt; 987c478bd9Sstevel@tonic-gate for (i = 0; i < pfp->fpu_qcnt; i++) 997c478bd9Sstevel@tonic-gate cfp->fpu_q[i] = pfp->fpu_q[i]; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * save the context of the parent into the childs fpu structure 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate cfp->fpu_fprs = pfp->fpu_fprs; 1057c478bd9Sstevel@tonic-gate if (ttolwp(curthread) == lwp && fpu_exists) { 1067c478bd9Sstevel@tonic-gate fp_fksave(cfp); 1077c478bd9Sstevel@tonic-gate } else { 1087c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 1097c478bd9Sstevel@tonic-gate cfp->fpu_fr.fpu_regs[i] = pfp->fpu_fr.fpu_regs[i]; 1107c478bd9Sstevel@tonic-gate for (i = 16; i < 32; i++) 1117c478bd9Sstevel@tonic-gate cfp->fpu_fr.fpu_dregs[i] = pfp->fpu_fr.fpu_dregs[i]; 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate cfp->fpu_en = 1; 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* 1177c478bd9Sstevel@tonic-gate * Free any state associated with floating point context. 1187c478bd9Sstevel@tonic-gate * Fp_free can be called in two cases: 1197c478bd9Sstevel@tonic-gate * 1) from reaper -> thread_free -> lwp_freeregs -> fp_free 1207c478bd9Sstevel@tonic-gate * fp context belongs to a thread on deathrow 1217c478bd9Sstevel@tonic-gate * nothing to do, thread will never be resumed 1227c478bd9Sstevel@tonic-gate * thread calling ctxfree is reaper 1237c478bd9Sstevel@tonic-gate * 1247c478bd9Sstevel@tonic-gate * 2) from exec -> lwp_freeregs -> fp_free 1257c478bd9Sstevel@tonic-gate * fp context belongs to the current thread 1267c478bd9Sstevel@tonic-gate * must disable fpu, thread calling ctxfree is curthread 1277c478bd9Sstevel@tonic-gate */ 1287c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 1297c478bd9Sstevel@tonic-gate void 1307c478bd9Sstevel@tonic-gate fp_free(kfpu_t *fp, int isexec) 1317c478bd9Sstevel@tonic-gate { 1327c478bd9Sstevel@tonic-gate int s; 1337c478bd9Sstevel@tonic-gate uint32_t fprs = 0; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate if (curthread->t_lwp != NULL && lwptofpu(curthread->t_lwp) == fp) { 1367c478bd9Sstevel@tonic-gate fp->fpu_en = 0; 1377c478bd9Sstevel@tonic-gate fp->fpu_fprs = fprs; 1387c478bd9Sstevel@tonic-gate s = splhigh(); 1397c478bd9Sstevel@tonic-gate _fp_write_fprs(fprs); 1407c478bd9Sstevel@tonic-gate splx(s); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate #ifdef SF_ERRATA_30 /* call causes fp-disabled */ 1467c478bd9Sstevel@tonic-gate extern int spitfire_call_bug; 1477c478bd9Sstevel@tonic-gate int ill_fpcalls; 1487c478bd9Sstevel@tonic-gate #endif 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate void 1517c478bd9Sstevel@tonic-gate fp_enable(void) 1527c478bd9Sstevel@tonic-gate { 1537c478bd9Sstevel@tonic-gate klwp_id_t lwp; 1547c478bd9Sstevel@tonic-gate kfpu_t *fp; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate lwp = ttolwp(curthread); 1577c478bd9Sstevel@tonic-gate ASSERT(lwp != NULL); 1587c478bd9Sstevel@tonic-gate fp = lwptofpu(lwp); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate if (fpu_exists) { 1617c478bd9Sstevel@tonic-gate if (fp->fpu_en) { 1627c478bd9Sstevel@tonic-gate #ifdef DEBUG 1637c478bd9Sstevel@tonic-gate if (fpdispr) 1647c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 1657c478bd9Sstevel@tonic-gate "fpu disabled, but already enabled\n"); 1667c478bd9Sstevel@tonic-gate #endif 1677c478bd9Sstevel@tonic-gate if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 1687c478bd9Sstevel@tonic-gate fp->fpu_fprs = FPRS_FEF; 1697c478bd9Sstevel@tonic-gate #ifdef DEBUG 1707c478bd9Sstevel@tonic-gate if (fpdispr) 1717c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 1727c478bd9Sstevel@tonic-gate "fpu disabled, saved fprs disabled\n"); 1737c478bd9Sstevel@tonic-gate #endif 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate _fp_write_fprs(FPRS_FEF); 1767c478bd9Sstevel@tonic-gate fp_restore(fp); 1777c478bd9Sstevel@tonic-gate } else { 1787c478bd9Sstevel@tonic-gate fp->fpu_en = 1; 1797c478bd9Sstevel@tonic-gate fp->fpu_fsr = 0; 1807c478bd9Sstevel@tonic-gate fp->fpu_fprs = FPRS_FEF; 1817c478bd9Sstevel@tonic-gate _fp_write_fprs(FPRS_FEF); 1827c478bd9Sstevel@tonic-gate fp_clearregs(fp); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate } else { 1857c478bd9Sstevel@tonic-gate int i; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate if (!fp->fpu_en) { 1887c478bd9Sstevel@tonic-gate fp->fpu_en = 1; 1897c478bd9Sstevel@tonic-gate fp->fpu_fsr = 0; 1907c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 1917c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_regs[i] = (uint_t)-1; /* NaN */ 1927c478bd9Sstevel@tonic-gate for (i = 16; i < 32; i++) /* NaN */ 1937c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[i] = (uint64_t)-1; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * fp_disabled normally occurs when the first floating point in a non-threaded 2007c478bd9Sstevel@tonic-gate * program causes an fp_disabled trap. For threaded programs, the ILP32 threads 2017c478bd9Sstevel@tonic-gate * library calls the .setpsr fasttrap, which has been modified to also set the 2027c478bd9Sstevel@tonic-gate * appropriate bits in fpu_en and fpu_fprs, as well as to enable the %fprs, 2037c478bd9Sstevel@tonic-gate * as before. The LP64 threads library will write to the %fprs directly, 2047c478bd9Sstevel@tonic-gate * so fpu_en will never get updated for LP64 threaded programs, 2057c478bd9Sstevel@tonic-gate * although fpu_fprs will, via resume. 2067c478bd9Sstevel@tonic-gate */ 2077c478bd9Sstevel@tonic-gate void 2087c478bd9Sstevel@tonic-gate fp_disabled(struct regs *rp) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate klwp_id_t lwp; 2117c478bd9Sstevel@tonic-gate kfpu_t *fp; 2127c478bd9Sstevel@tonic-gate int ftt; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate #ifdef SF_ERRATA_30 /* call causes fp-disabled */ 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * This code is here because sometimes the call instruction 2177c478bd9Sstevel@tonic-gate * generates an fp_disabled trap when the call offset is large. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate if (spitfire_call_bug) { 2207c478bd9Sstevel@tonic-gate uint_t instr = 0; 2217c478bd9Sstevel@tonic-gate extern void trap(struct regs *rp, caddr_t addr, uint32_t type, 2227c478bd9Sstevel@tonic-gate uint32_t mmu_fsr); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 2257c478bd9Sstevel@tonic-gate (void) fuword32((void *)rp->r_pc, &instr); 2267c478bd9Sstevel@tonic-gate } else { 2277c478bd9Sstevel@tonic-gate instr = *(uint_t *)(rp->r_pc); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate if ((instr & 0xc0000000) == 0x40000000) { 2307c478bd9Sstevel@tonic-gate ill_fpcalls++; 2317c478bd9Sstevel@tonic-gate trap(rp, NULL, T_UNIMP_INSTR, 0); 2327c478bd9Sstevel@tonic-gate return; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_30 - call causes fp-disabled */ 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate #ifdef CHEETAH_ERRATUM_109 /* interrupts not taken during fpops */ 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * UltraSPARC III will report spurious fp-disabled exceptions when 2407c478bd9Sstevel@tonic-gate * the pipe is full of fpops and an interrupt is triggered. By the 2417c478bd9Sstevel@tonic-gate * time we get here the interrupt has been taken and we just need 2427c478bd9Sstevel@tonic-gate * to return to where we came from and try again. 2437c478bd9Sstevel@tonic-gate */ 2447c478bd9Sstevel@tonic-gate if (fpu_exists && _fp_read_fprs() & FPRS_FEF) 2457c478bd9Sstevel@tonic-gate return; 2467c478bd9Sstevel@tonic-gate #endif /* CHEETAH_ERRATUM_109 */ 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate lwp = ttolwp(curthread); 2497c478bd9Sstevel@tonic-gate ASSERT(lwp != NULL); 2507c478bd9Sstevel@tonic-gate fp = lwptofpu(lwp); 2517c478bd9Sstevel@tonic-gate if (fpu_exists) { 2527c478bd9Sstevel@tonic-gate kpreempt_disable(); 2537c478bd9Sstevel@tonic-gate if (fp->fpu_en) { 2547c478bd9Sstevel@tonic-gate #ifdef DEBUG 2557c478bd9Sstevel@tonic-gate if (fpdispr) 2567c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 2577c478bd9Sstevel@tonic-gate "fpu disabled, but already enabled\n"); 2587c478bd9Sstevel@tonic-gate #endif 2597c478bd9Sstevel@tonic-gate if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 2607c478bd9Sstevel@tonic-gate fp->fpu_fprs = FPRS_FEF; 2617c478bd9Sstevel@tonic-gate #ifdef DEBUG 2627c478bd9Sstevel@tonic-gate if (fpdispr) 2637c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 2647c478bd9Sstevel@tonic-gate "fpu disabled, saved fprs disabled\n"); 2657c478bd9Sstevel@tonic-gate #endif 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate _fp_write_fprs(FPRS_FEF); 2687c478bd9Sstevel@tonic-gate fp_restore(fp); 2697c478bd9Sstevel@tonic-gate } else { 2707c478bd9Sstevel@tonic-gate fp->fpu_en = 1; 2717c478bd9Sstevel@tonic-gate fp->fpu_fsr = 0; 2727c478bd9Sstevel@tonic-gate fp->fpu_fprs = FPRS_FEF; 2737c478bd9Sstevel@tonic-gate _fp_write_fprs(FPRS_FEF); 2747c478bd9Sstevel@tonic-gate fp_clearregs(fp); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate kpreempt_enable(); 2777c478bd9Sstevel@tonic-gate } else { 2787c478bd9Sstevel@tonic-gate fp_simd_type fpsd; 2797c478bd9Sstevel@tonic-gate int i; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 2827c478bd9Sstevel@tonic-gate if (!fp->fpu_en) { 2837c478bd9Sstevel@tonic-gate fp->fpu_en = 1; 2847c478bd9Sstevel@tonic-gate fp->fpu_fsr = 0; 2857c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 2867c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_regs[i] = (uint_t)-1; /* NaN */ 2877c478bd9Sstevel@tonic-gate for (i = 16; i < 32; i++) /* NaN */ 2887c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[i] = (uint64_t)-1; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate if (ftt = fp_emulator(&fpsd, (fp_inst_type *)rp->r_pc, 2917c478bd9Sstevel@tonic-gate rp, (ulong_t *)rp->r_sp, fp)) { 292*bc0e9132SGordon Ross fp->fpu_q_entrysize = sizeof (struct _fpq); 2937c478bd9Sstevel@tonic-gate fp_traps(&fpsd, ftt, rp); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * Process the floating point queue in lwp->lwp_pcb. 3007c478bd9Sstevel@tonic-gate * 3017c478bd9Sstevel@tonic-gate * Each entry in the floating point queue is processed in turn. 3027c478bd9Sstevel@tonic-gate * If processing an entry results in an exception fp_traps() is called to 3037c478bd9Sstevel@tonic-gate * handle the exception - this usually results in the generation of a signal 3047c478bd9Sstevel@tonic-gate * to be delivered to the user. There are 2 possible outcomes to this (note 3057c478bd9Sstevel@tonic-gate * that hardware generated signals cannot be held!): 3067c478bd9Sstevel@tonic-gate * 3077c478bd9Sstevel@tonic-gate * 1. If the signal is being ignored we continue to process the rest 3087c478bd9Sstevel@tonic-gate * of the entries in the queue. 3097c478bd9Sstevel@tonic-gate * 3107c478bd9Sstevel@tonic-gate * 2. If arrangements have been made for return to a user signal handler, 3117c478bd9Sstevel@tonic-gate * sendsig() will have copied the floating point queue onto the user's 3127c478bd9Sstevel@tonic-gate * signal stack and zero'ed the queue count in the u_pcb. Note that 3137c478bd9Sstevel@tonic-gate * this has the side effect of terminating fp_runq's processing loop. 3147c478bd9Sstevel@tonic-gate * We will re-run the floating point queue on return from the user 3157c478bd9Sstevel@tonic-gate * signal handler if necessary as part of normal setcontext processing. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate void 3187c478bd9Sstevel@tonic-gate fp_runq(struct regs *rp) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(curthread->t_lwp); 321*bc0e9132SGordon Ross struct _fq *fqp = fp->fpu_q; 3227c478bd9Sstevel@tonic-gate fp_simd_type fpsd; 3237c478bd9Sstevel@tonic-gate uint64_t gsr = get_gsr(fp); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * don't preempt while manipulating the queue 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate kpreempt_disable(); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate while (fp->fpu_qcnt) { 3317c478bd9Sstevel@tonic-gate int fptrap; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate fptrap = fpu_simulator((fp_simd_type *)&fpsd, 3347c478bd9Sstevel@tonic-gate (fp_inst_type *)fqp->FQu.fpq.fpq_addr, 3357c478bd9Sstevel@tonic-gate (fsr_type *)&fp->fpu_fsr, gsr, 3367c478bd9Sstevel@tonic-gate fqp->FQu.fpq.fpq_instr); 3377c478bd9Sstevel@tonic-gate if (fptrap) { 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * Instruction could not be simulated so we will 3407c478bd9Sstevel@tonic-gate * attempt to deliver a signal. 3417c478bd9Sstevel@tonic-gate * We may be called again upon signal exit (setcontext) 3427c478bd9Sstevel@tonic-gate * and can continue to process the queue then. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate if (fqp != fp->fpu_q) { 3457c478bd9Sstevel@tonic-gate int i; 346*bc0e9132SGordon Ross struct _fq *fqdp; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * We need to normalize the floating queue so 3507c478bd9Sstevel@tonic-gate * the excepting instruction is at the head, 3517c478bd9Sstevel@tonic-gate * so that the queue may be copied onto the 3527c478bd9Sstevel@tonic-gate * user signal stack by sendsig(). 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate fqdp = fp->fpu_q; 3557c478bd9Sstevel@tonic-gate for (i = fp->fpu_qcnt; i; i--) { 3567c478bd9Sstevel@tonic-gate *fqdp++ = *fqp++; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate fqp = fp->fpu_q; 3597c478bd9Sstevel@tonic-gate } 360*bc0e9132SGordon Ross fp->fpu_q_entrysize = sizeof (struct _fpq); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * fpu_simulator uses the fp registers directly but it 3647c478bd9Sstevel@tonic-gate * uses the software copy of the fsr. We need to write 3657c478bd9Sstevel@tonic-gate * that back to fpu so that fpu's state is current for 3667c478bd9Sstevel@tonic-gate * ucontext. 3677c478bd9Sstevel@tonic-gate */ 3687c478bd9Sstevel@tonic-gate if (fpu_exists) 3697c478bd9Sstevel@tonic-gate _fp_write_pfsr(&fp->fpu_fsr); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* post signal */ 3727c478bd9Sstevel@tonic-gate fp_traps(&fpsd, fptrap, rp); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Break from loop to allow signal to be sent. 3767c478bd9Sstevel@tonic-gate * If there are other instructions in the fp queue 3777c478bd9Sstevel@tonic-gate * they will be processed when/if the user retuns 3787c478bd9Sstevel@tonic-gate * from the signal handler with a non-empty queue. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate break; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate fp->fpu_qcnt--; 3837c478bd9Sstevel@tonic-gate fqp++; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * fpu_simulator uses the fp registers directly, so we have 3887c478bd9Sstevel@tonic-gate * to update the pcb copies to keep current, but it uses the 3897c478bd9Sstevel@tonic-gate * software copy of the fsr, so we write that back to fpu 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate if (fpu_exists) { 3927c478bd9Sstevel@tonic-gate int i; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 3957c478bd9Sstevel@tonic-gate _fp_read_pfreg(&fp->fpu_fr.fpu_regs[i], i); 3967c478bd9Sstevel@tonic-gate for (i = 16; i < 32; i++) 3977c478bd9Sstevel@tonic-gate _fp_read_pdreg(&fp->fpu_fr.fpu_dregs[i], i); 3987c478bd9Sstevel@tonic-gate _fp_write_pfsr(&fp->fpu_fsr); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate kpreempt_enable(); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * Get the precise trapped V9 floating point instruction. 4067c478bd9Sstevel@tonic-gate * Fake up a queue to process. If getting the instruction results 4077c478bd9Sstevel@tonic-gate * in an exception fp_traps() is called to handle the exception - this 4087c478bd9Sstevel@tonic-gate * usually results in the generation of a signal to be delivered to the user. 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate void 4127c478bd9Sstevel@tonic-gate fp_precise(struct regs *rp) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate fp_simd_type fpsd; 4157c478bd9Sstevel@tonic-gate int inst_ftt; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate union { 4187c478bd9Sstevel@tonic-gate uint_t i; 4197c478bd9Sstevel@tonic-gate fp_inst_type inst; 4207c478bd9Sstevel@tonic-gate } kluge; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 4237c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 4247c478bd9Sstevel@tonic-gate uint64_t gsr; 4257c478bd9Sstevel@tonic-gate int mstate; 4267c478bd9Sstevel@tonic-gate if (fpu_exists) 4277c478bd9Sstevel@tonic-gate save_gsr(fp); 4287c478bd9Sstevel@tonic-gate gsr = get_gsr(fp); 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* 4317c478bd9Sstevel@tonic-gate * Get the instruction to be emulated from the pc saved by the trap. 4327c478bd9Sstevel@tonic-gate * Note that the kernel is NOT prepared to handle a kernel fp 4337c478bd9Sstevel@tonic-gate * exception if it can't pass successfully through the fp simulator. 4347c478bd9Sstevel@tonic-gate * 4357c478bd9Sstevel@tonic-gate * If the trap occurred in user mode, set lwp_state to LWP_SYS for the 4367c478bd9Sstevel@tonic-gate * purposes of clock accounting and switch to the LMS_TRAP microstate. 4377c478bd9Sstevel@tonic-gate */ 4387c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 4397c478bd9Sstevel@tonic-gate inst_ftt = _fp_read_inst((uint32_t *)rp->r_pc, &kluge.i, &fpsd); 4407c478bd9Sstevel@tonic-gate mstate = new_mstate(curthread, LMS_TRAP); 4417c478bd9Sstevel@tonic-gate lwp->lwp_state = LWP_SYS; 4427c478bd9Sstevel@tonic-gate } else { 4437c478bd9Sstevel@tonic-gate kluge.i = *(uint_t *)rp->r_pc; 4447c478bd9Sstevel@tonic-gate inst_ftt = ftt_none; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if (inst_ftt != ftt_none) { 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * Save the bad address and post the signal. 4507c478bd9Sstevel@tonic-gate * It can only be an ftt_alignment or ftt_fault trap. 4517c478bd9Sstevel@tonic-gate * XXX - How can this work w/mainsail and do_unaligned? 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate fpsd.fp_trapaddr = (caddr_t)rp->r_pc; 4547c478bd9Sstevel@tonic-gate fp_traps(&fpsd, inst_ftt, rp); 4557c478bd9Sstevel@tonic-gate } else { 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * Conjure up a floating point queue and advance the pc/npc 4587c478bd9Sstevel@tonic-gate * to fake a deferred fp trap. We now run the fp simulator 4597c478bd9Sstevel@tonic-gate * in fp_precise, while allowing setfpregs to call fp_runq, 4607c478bd9Sstevel@tonic-gate * because this allows us to do the ugly machinations to 4617c478bd9Sstevel@tonic-gate * inc/dec the pc depending on the trap type, as per 4627c478bd9Sstevel@tonic-gate * bugid 1210159. fp_runq is still going to have the 4637c478bd9Sstevel@tonic-gate * generic "how do I connect the "fp queue to the pc/npc" 4647c478bd9Sstevel@tonic-gate * problem alluded to in bugid 1192883, which is only a 4657c478bd9Sstevel@tonic-gate * problem for a restorecontext of a v8 fp queue on a 4667c478bd9Sstevel@tonic-gate * v9 system, which seems like the .000000001% case (on v9)! 4677c478bd9Sstevel@tonic-gate */ 468*bc0e9132SGordon Ross struct _fpq *pfpq = &fp->fpu_q->FQu.fpq; 4697c478bd9Sstevel@tonic-gate fp_simd_type fpsd; 4707c478bd9Sstevel@tonic-gate int fptrap; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate pfpq->fpq_addr = (uint_t *)rp->r_pc; 4737c478bd9Sstevel@tonic-gate pfpq->fpq_instr = kluge.i; 4747c478bd9Sstevel@tonic-gate fp->fpu_qcnt = 1; 475*bc0e9132SGordon Ross fp->fpu_q_entrysize = sizeof (struct _fpq); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate kpreempt_disable(); 4787c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 4797c478bd9Sstevel@tonic-gate fptrap = fpu_vis_sim((fp_simd_type *)&fpsd, 4807c478bd9Sstevel@tonic-gate (fp_inst_type *)pfpq->fpq_addr, rp, 4817c478bd9Sstevel@tonic-gate (fsr_type *)&fp->fpu_fsr, gsr, kluge.i); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* update the hardware fp fsr state for sake of ucontext */ 4847c478bd9Sstevel@tonic-gate if (fpu_exists) 4857c478bd9Sstevel@tonic-gate _fp_write_pfsr(&fp->fpu_fsr); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate if (fptrap) { 4887c478bd9Sstevel@tonic-gate /* back up the pc if the signal needs to be precise */ 4897c478bd9Sstevel@tonic-gate if (fptrap != ftt_ieee) { 4907c478bd9Sstevel@tonic-gate fp->fpu_qcnt = 0; 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate /* post signal */ 4937c478bd9Sstevel@tonic-gate fp_traps(&fpsd, fptrap, rp); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* decrement queue count for ieee exceptions */ 4967c478bd9Sstevel@tonic-gate if (fptrap == ftt_ieee) { 4977c478bd9Sstevel@tonic-gate fp->fpu_qcnt = 0; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate } else { 5007c478bd9Sstevel@tonic-gate fp->fpu_qcnt = 0; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate /* update the software pcb copies of hardware fp registers */ 5037c478bd9Sstevel@tonic-gate if (fpu_exists) { 5047c478bd9Sstevel@tonic-gate fp_save(fp); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate kpreempt_enable(); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * Reset lwp_state to LWP_USER for the purposes of clock accounting, 5117c478bd9Sstevel@tonic-gate * and restore the previously saved microstate. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 5147c478bd9Sstevel@tonic-gate (void) new_mstate(curthread, mstate); 5157c478bd9Sstevel@tonic-gate lwp->lwp_state = LWP_USER; 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* 5207c478bd9Sstevel@tonic-gate * Handle floating point traps generated by simulation/emulation. 5217c478bd9Sstevel@tonic-gate */ 5227c478bd9Sstevel@tonic-gate void 5237c478bd9Sstevel@tonic-gate fp_traps( 5247c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to simulator data */ 5257c478bd9Sstevel@tonic-gate enum ftt_type ftt, /* trap type */ 5267c478bd9Sstevel@tonic-gate struct regs *rp) /* ptr to regs fro trap */ 5277c478bd9Sstevel@tonic-gate { 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * If we take a user's exception in kernel mode, we want to trap 5307c478bd9Sstevel@tonic-gate * with the user's registers. 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate switch (ftt) { 5337c478bd9Sstevel@tonic-gate case ftt_ieee: 5347c478bd9Sstevel@tonic-gate fpu_trap(rp, pfpsd->fp_trapaddr, T_FP_EXCEPTION_IEEE, 5357c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode); 5367c478bd9Sstevel@tonic-gate break; 5377c478bd9Sstevel@tonic-gate case ftt_fault: 5387c478bd9Sstevel@tonic-gate fpu_trap(rp, pfpsd->fp_trapaddr, T_DATA_EXCEPTION, 0); 5397c478bd9Sstevel@tonic-gate break; 5407c478bd9Sstevel@tonic-gate case ftt_alignment: 5417c478bd9Sstevel@tonic-gate fpu_trap(rp, pfpsd->fp_trapaddr, T_ALIGNMENT, 0); 5427c478bd9Sstevel@tonic-gate break; 5437c478bd9Sstevel@tonic-gate case ftt_unimplemented: 5447c478bd9Sstevel@tonic-gate fpu_trap(rp, pfpsd->fp_trapaddr, T_UNIMP_INSTR, 0); 5457c478bd9Sstevel@tonic-gate break; 5467c478bd9Sstevel@tonic-gate default: 5477c478bd9Sstevel@tonic-gate /* 5487c478bd9Sstevel@tonic-gate * We don't expect any of the other types here. 5497c478bd9Sstevel@tonic-gate */ 5507c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "fp_traps: bad ftt"); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate } 553